having an or condition between two values - xslt-1.0

I have an below xsl tag condtion as shown below ..
<xsl:for-each select="/abc/def">
<xsl:if test="./Scheme='xxx' and ./Reference='TRE' and string(./tId)">
Now the change that i want to made in this condition is that is the Reference value can be 'TRE' or it can be 'ARE'
so i want to go for both that is if it is coming as 'TRE' then it is also ok or if it is coming as 'ARE' then it is also ok so in other words i want an 'OR, condition between them please advise how to achieve this..
folks please advise

Try:
<xsl:if test="Scheme='xxx' and (Reference='TRE' or Reference='ARE') and string(tId)">

Related

Dynamically call parameters using concat(), select element name

I want to dynamically call parameters in a template based on another paramaters value, something like:
Let's say I have a list of Values that are dermined in several ways:
<xsl:param name="One"/>
<xsl:param name="Two"/>
<xsl:param name="Three"/>
from which I'd like to create matching elements from such as:
<One>1111</One>
<Two>2222</Two>
<Three>3333</Three>
Instead of creating all of the elements individually I like to create a seperate template or function to do that.
I was attempting something like:
<xsl:template name="AddElement">
<xsl:param name="Name" select="/foo/bar/text()"/>
...
<xsl:variable name="Value" select="concat('$', $Name)"/>
<xsl:element name="$ElementName">
<xsl:value-of select="$Value"/>
</xsl:element>
...
</xsl:template>
I want to avoid doing that multiple times the same way:
<xsl:if test="string-length($One) != 0">
<One>
<xsl:value-of select="$One"/>
</One>
</xsl:when>
Ideally it could just be
<xsl:call-template name="AddElement">
<xsl:with-param name="ElementName">One</xsl:with-param>
</xsl:call-template>
I think Change following Code:-
<xsl:element name="{$ElementName}">
No, you can't construct variable references (or other XPath expressions) dynamically as strings and then evaluate them. XSLT isn't a macro language.
In XSLT 3.0 you could put the data in a map and select dynamically from the map. I tried to put together an example for you, but I really couldn't get to the bottom of what your hypothetical code was trying to achieve.

XSL Test error at least one contains instead of only the one

With several xml documents containing topic elements and only one file containing a topic element with attribute product="OPTION".
I'd like to write OPTION if the attribute is set for the topic and TOTO if no attribute exists for the topic.
The problem is that actally if at least one file contains the attribute product="OPTION" OPTION is written on every generated pdf page.
<xsl:template name="insertBodyEvenHeader">
<xsl:param as="xs:string" name="flow-name" select="'even-body-header'" />
<fo:static-content flow-name="{$flow-name}">
<fo:block xsl:use-attribute-sets="__body__even__header">
<xsl:choose>
<xsl:when test="topic/#product='OPTION'">
<fo:inline xsl:use-attribute-sets="title__option">
<xsl:text>OPTION</xsl:text>
</fo:inline>
</xsl:when>
<xsl:otherwise>TOTO</xsl:otherwise>
</xsl:choose>
</fo:block>
</fo:static-content>
</xsl:template>
Would you be so kind to help me dealing with that test? thansks, best regards
It is likely that your context for this template is something above topic (which makes sense because you test on topic/#product). That is why if you have 10 topic elements and one has #product='OPTION' then the WHEN is true.
If that is true and you want to test on current topic being output, then you would use retrieve-marker in the header and then create markers in the topic template and pull those markers into header.
Your choose would then become #product (because you are in the topic template) and you would just drop an fo:marker that would have your choose inside, then use fo:retrieve-marker and some retrieve-position depending on how you want them to be processed. If a topic always starts a page then you would use first-including-carryover.

XSLT Attribute name needs to be separated

I am working backwards to create an XML based on a client's desired outcome. I have an attribute in my XSL that I want the end result to look like this
<AlternateId idType="ADID">XYZ</AlternateId>
I have it incorrectly as
<xsl:attribute name="idType">ADID<xsl:value-of select="add:XYZ"/></xsl:attribute>
This, of course, groups ADID and XYZ together.
How do I get them separated and looking like what I want them to look like?
The value-of needs to go outside the attribute as you want it to be element content rather than part of the attribute value.
<xsl:element name="AlternateId">
<xsl:attribute name="idType">ADID</xsl:attribute>
<xsl:value-of select="add:XYZ"/>
</xsl:element>
But if the attribute name is a fixed string you might as well use a literal result element instead:
<AlternateId idType="ADID">
<xsl:value-of select="add:XYZ"/>
</AlternateId>

xslt result tree changing element position

Is it possible to move the result generated by the XSLT processor. e.g. in the below case i wanted Benefit type="Main" and its child elements to be displayed before Benefit type="Rider"
Two separate templates are applied for Rider and Main, hence i think xsl:sort cannot be applied, since it sorts within a single collection.
<Policy>
<Benefit type="Rider">
<ProductAbbreviatedName>BBB</ProductAbbreviatedName>
<ProductCode>U30</ProductCode>
<ProductName>BBB</ProductName>
</Benefit>
<Benefit type="Main">
<ProductAbbreviatedName>AAA</ProductAbbreviatedName>
<ProductCode>231Y</ProductCode>
<ProductName>AAAA</ProductName>
</Benefit>
</Policy>
Kindly advice on some ideas to perform the desired output. Many thanks.
Just use in your code:
<xsl:apply-templates select="Benefit[#type='Main']"/>
<xsl:apply-templates select="Benefit[#type='Rider']"/>

Using a variable as part of a XPath selection

I'm looking to use a variable as part of an XPath expression.
My problem might be the msxsl node-set function... not sure. But don't let that cloud your judgement... read on...
I'm using a .NET function to load up the content file, which is passed in via bespoke XML content. The #file results in an XML file.
The bespoke XML the sits on the page looks like :
<control name="import" file="information.xml" node="r:container/r:group[#id='set01']/r:item[1]" />
The XSL looks like :
<xsl:variable name="document">
<xsl:copy-of select="ext:getIncludedContent(#file)" />
</xsl:variable>
I'm then translating this to a node-set so I can query the document
<xsl:variable name="preset-xml" select="msxsl:node-set($document)" />
The source file I am loading in looks like :
<container>
<group id="set01">
<item>value01</item>
<item>value02</item>
<item>value03</item>
</group>
<group id="set02">
<item>value04</item>
<item>value05</item>
</group>
</container>
It works up until this point. I can see the source file being brought thru and output as XML.
My problem comes in when I am trying to query the source file with an XPath expression fed in from the content.
I've tried :
<xsl:value-of select="$preset-xml/#node" />
Clearly that doesn't work as it looks for #node as a direct child of the loaded in XML.
I've tried :
<xsl:variable name="node" select="#node" />
<xsl:value-of select="$preset-xml/$node" />
But it doesn't like the second variable.
I've tried concat($preset-xml,'/',$node), but that still draws out the entire document in the result.
The only way I can get this working at the moment is to write out the full expression in the template :
<xsl:value-of select="$preset-xml/r:container/r:group[#id='set01']/r:item[1]" />
Which correctly brings thru value01
But that is then a hard coded solution.
I want to develop a solution which can be manipulated from the content to suit any sort of imported content, with the parameters declared in the content file.
p.s. I'm using XSLT 1.0 because the tech admin won't change the Microsoft parser to support later versions of XSL, so any solution would need to be written with that in mind.
There is no feature similar to reflection in XSLT. MS XSLT engine, in particular, compiles XPath queries when the XSLT was loaded, not when it was applied to your XML document. There is a reason to this: it separates the code (XSLT) from the data (input XML).
What are you trying to achieve by mixing up code and data; are you sure you really need to execute an arbitrary XPath expression from the input XML? Think, for example, what if the user will pass in the #name equal to e.g. //*, and then you'll send to the output the content of the entire input XML document, which might contain some sensitive data.
If you really need to do the thing you described, you may write your own XSLT extension object, which will accept the document root and the XPath query and will return the latter applied to the former. Then you'll be able to call it like that:
<xsl:value-of select="myExtensionNs:apply-xpath($preset-xml, #node)"/>
As for your original attempt with concat($preset-xml,'/',$node), concat is the string concatenating function. You supply some arguments to it, and it returns the concatenation of its string representations. So, concat($preset-xml,'/',$node) will return the string value of $preset-xml, concatenated with /, concatenated with the string value of $node. If you were trying to write a needed XPath query, concat('$preset-xml','/',$node) would seem more logical (note the quotes); still, there is no way to evaluate the resulted string (e.g. $preset-xml/r:container/r:group[#id='set01']/r:item[1]) to the value of corresponging XPath query; it could only be sent to output.
One possible trick is to call an parametrized xsl:template which carries out the crucial select comparison part and evaluate it's output as string.
I had a similar problem (count all nodes of an arbitrary attribute value) which I solved this way (btw: $sd = 'document($filename)' so I load a secondary xml files content):
<xsl:template match="/">
<xsl:variable name="string_cntsuccess">
<xsl:for-each select="./Testcase">
<xsl:variable name="tcname" select="#location"/>
<xsl:for-each select="$sd//TestCase[#state='Passed']">
<xsl:call-template name="producedots">
<xsl:with-param name="name" select="$tcname"/>
</xsl:call-template>
</xsl:for-each>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="cntsuccess" select="string-length($string_cntsuccess)"/>
</xsl:template>
<xsl:template name="producedots">
<xsl:param name="name"/>
<xsl:variable name="ename" select="#name"/>
<xsl:if test="$name = $ename">
<xsl:text>.</xsl:text>
</xsl:if>
</xsl:template>