How to put nodes to variable - xslt

I have short question.
I have 2 Lines but why it dispays 'mixed' one time?
<xsl:variable name="relItems-nodes">
<xsl:for-each select="Lines/Line">
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:variable>
<xsl:for-each select="msxsl:node-set($relItems-nodes)">
mixed
</xsl:for-each>

Your variable relItems-nodes is a result tree fragment with a root node containing various Line elements, the use of msxsl:node-set($relItems-nodes) converts that into a node-set with a root node containing various Line elements so if you don't want to process the root node but the contained Line elements use <xsl:for-each select="msxsl:node-set($relItems-nodes)/Line">...</xsl:for-each>.
By the way,
<xsl:for-each select="Lines/Line">
<xsl:copy-of select="."/>
</xsl:for-each>
could be shortened to <xsl:copy-of select="Lines/Line"/>.

Related

XSLT to convert elements in a concatenated line

I have this situation:
Two variables:
<xsl:variable name="varDep" select="DepAir"/>
<xsl:variable name="varArr" select="ArrAir"/>
Value of variables:
<testa>
<DepAir>SDU</DepAir>
<DepAir>CGH</DepAir>
</testa>
<testb>
<ArrAir>CGH</ArrAir>
<ArrAir>SDU</ArrAir>
</testb>
And I need transform in a concatenated line, like this:
<db:P_IAT>SDU;CGH;CGH;SDU;</db:P_IAT>
How can I do that?
Kind dynamic way will be to put loop for DepAir and ArrAir inside above variables as below:
<xsl:variable name="varDep">
<xsl:for-each select="//DepAir">
<xsl:value-of select="concat(., ';')"/>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="varArr">
<xsl:for-each select="//ArrAir">
<xsl:value-of select="concat(., ';')"/>
</xsl:for-each>
</xsl:variable>
And then use concat inside required node:
<required_node><xsl:value-of select="concat($varDep, $varArr)"/></required_node>
Note! In next questions please put your XSL (what you have tried) to avoid "Down Votes". Hope it will help in your case.

Selecting the following sibling of a sorted node

Trying to work out how to select the following-sibling of an XSLT node when the node has been sorted in XSLT 1.0. I've searched but can't find anything for sorted nodes, as it only selects the sibling of the unsorted node.
Data
<data>
<number order='4'>Four</number>
<number order='1'>One</number>
<number order='3'>Three</number>
<number order='2'>Two</number>
</data>
Code
<xsl:for-each select="/data/number">
<xsl:sort select="#order"/>
<xsl:if test="position() mod 2 = 1">
<xsl:value-of select="text()"/>
<xsl:text> - </xsl:text>
<xsl:value-of select="following-sibling::*/text()"/>
</xsl:if>
</xsl:for-each>
Expected output
One - Two
Three - Four
Actual Output
One - Three
Three - Two
When you sort a sequence of nodes, you get the same nodes in a new sequence. Because they are the same nodes, they have the same siblings that they always had. If you copy the nodes to a result tree, then the copies will have new siblings, but that's because of the action of writing them to a result tree, not because of the sorting action.
Another way of putting this: you are processing a sequence of nodes that aren't siblings, so you can't use following-sibling to get the next node in the sequence.
Processing a sorted sequence of nodes becomes much easier in XSLT 2.0, which allows such a sequence to be bound to a variable. XSLT 1.0 only has node-sets, so sequences of nodes in a particular order can only exist transiently.
But in this particular case, it seems easy enough to do
<xsl:value-of select="."/>
<xsl:if test="position() mod 2 = 1">
<xsl:text> - </xsl:text>
</xsl:if>
it only selects the sibling of the unsorted node.
That is correct. Why don't you do simply:
<xsl:for-each select="/data/number">
<xsl:sort select="#order"/>
<xsl:value-of select="."/>
<xsl:choose>
<xsl:when test="position() mod 2 = 1">
<xsl:text>-</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text>
</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
Note that the default sort data-type is text; you probably want to make it:
<xsl:sort select="#order" data-type="number"/>

XSLT: Get Element Name of "Tokenized Item"

Is there a way to gather element name of a tokenized value? I have been trying to do it but it is giving me an error "[Saxon-PE 9.6.0.7] XPTY0004: Required item type of first argument of name() is node(); supplied value has item type xs:string"
Here are my sample set of data:
<SET>
<REAL_TAGNAME> 1 2 3 4 </REAL_TAGNAME>
</SET>
If I have use this code:
<xsl:for-each select="SET/REAL_TAGNAME">
<xsl:for-each select="tokenize(normalize-space(.),'\s+')">
<Hardcode_Tag>
<xsl:value-of select="."/>
</Hardcode_Tag>
</xsl:for-each>
</xsl:for-each>
then I will successfully have the following:
<Hardcode_Tag>1</Hardcode_Tag>
<Hardcode_Tag>2</Hardcode_Tag>
<Hardcode_Tag>3</Hardcode_Tag>
<Hardcode_Tag>4</Hardcode_Tag>
But I want to move away from hard-coding and would like to use its original tag name to have something like:
<REAL_TAGNAME>1</REAL_TAGNAME>
<REAL_TAGNAME>2</REAL_TAGNAME>
<REAL_TAGNAME>3</REAL_TAGNAME>
<REAL_TAGNAME>4</REAL_TAGNAME>
While I try below with the xsl:element, it keeps giving me an error mentioned above:
<xsl:for-each select="SET/REAL_TAGNAME">
<xsl:for-each select="tokenize(normalize-space(.),'\s+')">
<xsl:element name="{name(.)}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:for-each>
</xsl:for-each>
does anyone have any idea on how I can fix this? Thanks in advance for your help!
Within the xsl:for-each, the expression . refers to the current item, i.e. the current token extracted from the string value of the element. If you want to remember the name of the element that was the current element before you entered the for-each, just set a variable before the inner xsl:for-each:
<xsl:for-each select="SET/REAL_TAGNAME">
<xsl:variable name="element-name" select="name(.)"/>
<xsl:for-each select="tokenize(normalize-space(.),'\s+')">
<xsl:element name="{$element-name}">
<xsl:value-of select="."/>
</xsl:element>
</xsl:for-each>
</xsl:for-each>
In the code you show, of course, the value of $element-name will invariably be 'REAL_TAGNAME'. I'm assuming that's not true in the general case.

XSLT 1.0: if statement when position matches a variable value

I'm trying to insert an IF statement into an existing FOR-EACH loop to do something slightly different if it matches a variable from another node (the node I want is actually a sibling of it's parent - if that makes sense!?).
The value is a simple integer. I basically want to say: If the position is equal to the variable number then do XXXX.
Here is the XSLT, it's only v1.0 and not 2.0 that I can use.
<xsl:for-each select="/Properties/Data/Datum[#ID='ID1']/DCR[#Type='accordion_tab']/accordion_tab/sections">
<h3 class="accordionButton">
<xsl:if test="position()='openpane value to go here'">
<xsl:attribute name="class">
<xsl:text>new text</xsl:text>
</xsl:attribute>
</xsl:if>
</xsl:for-each>
My XML extract is here:
<sections>
<title>title</title>
<text>some text</text>
</sections>
<openpane>2</openpane>
You didn't make this clear in your question, but I assume you iterate over the sections elements in your for-each loop. From the for-each loop you can reach the openpane element by going through the parent of the current sections element:
<xsl:for-each select="sections">
<xsl:if test="position() = ../openpane">
...
</xsl:if>
</xsl:for-each>
You could also define a variable referring to the openpane element first:
<xsl:variable name="openpane" select="openpane"/>
<xsl:for-each select="sections">
<xsl:if test="position() = $openpane">
...
</xsl:if>
</xsl:for-each>

how to check repeated elements in as string sequence/array?

I am using xslt 1.0 stylesheet to worlk on xml file data.
I have a variable in xslt which conatins many string separated by white space or new line charater.
i.e. the variable is "ServiceList", when I print it using follwong,
<xsl:value-of select="$ServiceList"/>
It prints following out put
hgd.sdf.gsdf sdf.sdh.duyg dsf.sdf.suos
jhs.sdu.sdfi
hdf.sdi.seij dsf.dsf.diuh
edr.sdi.sdhg dfh.dfg.dfg.fdg.idjf kjs.dfh.dfgj djg.dfs.dgji
I used follwing code to get each string separately.
<xsl:variable name="tokenizedSample" select="str:tokenize($ServiceList,'
')"/>
<xsl:for-each select="$tokenizedSample">
<xsl:variable name="serviceProvide" select="."/>
<xsl:variable name="tokenized1" select="str:tokenize($serviceProvide,' ')"/>
<xsl:for-each select="$tokenized1">
<xsl:variable name="serviceP" select="."/>
<xsl:value-of select="$serviceP"/>
</xsl:for-each>
</xsl:for-each>
the above code give me each string as separate one.
I have to chek is there any repeating string in above sequence/array. If it repeates it should show me the string is repeating.
This would be so much easier in XSLT 2.0
<xsl:variable name="tokenizedSample" select="tokenize($ServiceList, '
')"/>
<xsl:if test="count($tokenizedSample) != count(distinct-values($tokenizedSample))">...