How to combine two node-sets, such that the order is respected?

My understanding was that although XSLTs are called “node-sets” called “sets,” they are actually ordered lists of nodes (so each node is associated with an index). So I tried to use "|" an operator for concatenating a node network, so that the order of nodes is respected.

What I'm trying to execute is similar to the following JavaScript code:

[o1,o2,o3].concat([o4,o5,o6]) 

What gives:

 [o1,o2,o3,o4,o5,o6] 

But consider the following example:

testFlatten.xsl

 <?xml version="1.0"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:output method="xml"/> <xsl:template match="/"> <xsl:variable name="parentTransition" select="//*[@id='parentTransition']"/> <xsl:variable name="childTransition" select="//*[@id='childTransition']"/> <xsl:variable name="parentThenChildTransitions" select="$parentTransition | $childTransition"/> <xsl:variable name="childThenParentTransitions" select="$childTransition | $parentTransition"/> <return> <parentThenChildTransitions> <xsl:copy-of select="$parentThenChildTransitions"/> </parentThenChildTransitions> <childThenParentTransitions> <xsl:copy-of select="$childThenParentTransitions"/> </childThenParentTransitions> </return> </xsl:template> </xsl:stylesheet> 

Given the following input:

 <?xml version="1.0"?> <root> <element id="parentTransition"/> <element id="childTransition"/> </root> 

What gives (with xsltproc):

 <?xml version="1.0"?> <return> <parentThenChildTransitions> <element id="parentTransition"/><element id="childTransition"/> </parentThenChildTransitions> <childThenParentTransitions> <element id="parentTransition"/><element id="childTransition"/> </childThenParentTransitions> </return> 

So, "|" the operator does not actually take into account the order of the node-set operands. Is there a way that I can combine node sets such that the order is respected?

+4
source share
3 answers

This is actually not an XSLT, but an XPath question.

In XPath 1.0, there is nothing like the list data type. A node -set is a collection, and it has no order.

In XPath 2.0, there is a sequence data type. Any items in the sequence are ordered. This has nothing to do with the order of the document. In addition, the same element (or node) may appear more than once in a sequence.

So, in XSLT 2.0, the XPath 2.0 sequence concatenation operator is simply used:

 //*[@id='parentTransition'] , //*[@id='childTransition'] 

and this evaluates the sequence of all elements in the document with the id attribute 'parentTransition' , followed by all elements of the document with the id attribute 'childTransition'

In XSLT, it is still possible to access and process nodes in a different document order : for example, using the <xsl:sort> command - however, the set of nodes that are processed as a result of <xsl:apply-templates> or <xsl:for-each> is node-list is not a node-set.

Another example of evaluating nodes that are not in the order of a document is the position() function in <xsl:apply-templates> or <xsl:for-each> , which has a child element <xsl:sort> or inside a location step predicate (from XPath expression) that uses the inverse axis (for example, ancesstor:: or preceeding::

+8
source

In XSLT 1.0, you can process nodes in a selected order (for example, using xsl: sort), but you cannot contain a list of nodes in a variable. The only thing you can save in a variable (or go to a template, etc.) is node-set; node-sets do not have an internal order, but when you process them, they are always processed in document order unless you use xsl: sort to request a different processing order.

Perhaps you can solve your problem by copying the nodes:

 <xsl:variable name="temp"> <xsl:copy-of select="$ns0"/> <xsl:copy-of select="$ns1"/> </xsl:variable> ... <xsl:apply-templates select="exslt:node-set($temp/*)"/> 

but it depends on your use case.

Upgrade to XSLT 2.0 if you can!

+3
source

"|" the operator will save the nodes in the order of the document. In XSLT 1.0, you'll need sequential copy or for-each operations.

 <xsl:copy-of select="$parentTransition"/> <xsl:copy-of select="$childTransition"/> 
+1
source

Source: https://habr.com/ru/post/1334448/


All Articles