1
votes

I want to dynamically build match in xslt template. I use xls fo and apache fop and saxon9he. In best way I want to pass param from java but firstly I try set this in xslt.

When i create variable example like this:

<xsl:variable name="testPath" select="/abc:Files/def:Description" /> 

also work correctly if I try use this in apply-templates:

<xsl:apply-templates select="$testPath/qwe:Test"/>

But i want dynamically set testPath variable. I try use choose tag:

<xsl:variable name="testPath"> 
    <xsl:choose>
        <xsl:when test="$versionNo = '2'">
             <xsl:value-of select="/abc:Files/def:Description" />   
        </xsl:when>
        <xsl:otherwise>
             <xsl:value-of select="/abc:Files/def:Names" /> 
        </xsl:otherwise>
    </xsl:choose>
</xsl:variable> 

But this approach not working and when I try use this variable:

<xsl:apply-templates select="$testPath/qwe:Test"/>

I get this error:

Error evaluating ((attr{table-layout=...}, ...)) on line 82 column 21 of pdf_gen.xsl: SXCH0003: org.apache.fop.fo.ValidationException: "fo:table-body" is missing child elements. Required content model: marker* (table-row+|table-cell+) (See position 82:21):
file:/C:/Users/SuperUser/workspace/project/xls-editor/target/classes/pdf/xsl/pdf_gen.xsl:82:21: "fo:table-body" is missing child elements. Required content model: marker* (table-row+|table-cell+) (See position 82:21)

In best option I want to pass $testPath variable from Java as param, example:

transformer.setParameter("testPath ", "/abc:Files/def:Description");

and use in xslt

<xsl:param name="testPath "/>

and apply in templates:

<xsl:apply-templates select="$testPath/qwe:Test"/>

but i get following error:

Type error evaluating ($testPath) in xsl:apply-templates/@select on line 74 column 60 of pdf_gen.xsl: XPTY0019: The required item type of the first operand of '/' is node(); the supplied value
u"/abc:Files/def:Description" is an atomic value

Why is not any solution working how to achieve it?

2
Which XSLT processor are you using?michael.hor257k
I use xsl fo and apache fop and saxon.The Nightmare
The first error is raised by the FOP processor and just telling you that the XSL-FO you constructed in your XSLT code is not valid, a table-body does not have the required children. So to get help with that you would need to show minimal but complete snippets relevant to allow us to see which XML you have, which XSL-FO you want to create and which one you currently get. The second error XPTY0019 suggests you use an XSLT 2 or 3 processor, find out whether it is Saxon 9.8 or 9.9, there you would have the option to use static parameters and shadow attributes, but probably only with the s9api.Martin Honnen
First approach works good when I use inline declaraion: <xsl:variable name="testPath" select="/abc:Files/def:Description" /> but in choose tag this not work good even if I put the same value in when and otherwise. I think te problem is <xsl:value-of> But what I can use instead it.The Nightmare
Which version of Saxon 9 do you use? Is that 9.8 or 9.9? These implement XSLT 3 where you can do e.g. <xsl:param name="testPath" as="xs:string" static="yes"/> and then a shadow attribute <xsl:apply-templates _select="{$testPath}/qwe:Test"/> if that approach is really needed. On the other hand, as static parameters need to be set before compiling, I am not sure you can set them with the JAXP API, it might be better or even necessary to use Saxon 9's s9api for that.Martin Honnen

2 Answers

1
votes

As you use Saxon 9 you do use at least XSLT 2 with XPath 2 and there I would suggest to implement the variable selection in XPath with e.g.

<xsl:variable name="testPath" select="if ($versionNo = '2') then /abc:Files/def:Description else /abc:Files/def:Names"/> 

That way your

<xsl:apply-templates select="$testPath/qwe:Test"/>

should work fine to process the qwe:Test child element(s) of the previously selected def:Description or def:Names elements.

It is of course also possible to use e.g.

<xsl:apply-templates select="(if ($versionNo = '2') then /abc:Files/def:Description else /abc:Files/def:Names)/qwe:Test"/>

or do e.g.

<xsl:apply-templates select="(/abc:Files/def:Description[$versionNo = '2'], /abc:Files/def:Names[$versionNo != '2'])/qwe:Test"/>
0
votes

I'm dealing with a similar problem. It seems to me that variables visibility is only inside the <xsl:choose> block and I could suggest you to make templates blocks and to call them in this way:

<xsl:choose>
    <xsl:when test="$versionNo = '2'" >
        <xsl:call-template name="TemplateOne">
            <xsl:with-param name="testPath" select="'/abc:Files/def:Description'" />
        </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
        <xsl:call-template name="TemplateTwo">
            <xsl:with-param name="testPath" select="'/abc:Files/def:Names'" />
        </xsl:call-template>
    </xsl:otherwise>
</xsl:choose>

with templates definition as:

<xsl:template name="TemplateOne">
    <xsl:param name="testPath" />
    ...
    bla bla bla
    remember to use variable in this template as "{$testPath}"
    ...
</xsl:template>