Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

XSL xsl:evaluate multiple nodes

Tags:

xslt

xslt-3.0

How can I make sure, that xsl:evaluate returns a sequence of nodes, in case the xPath matches multiple nodes.

Suppose the following input.xml

<numlist key="K1">
 <numlitm key="K2">C1</numlitm>
 <numlitm key="K2">C2</numlitm>
 <numlitm key="K3">C3</numlitm>                            
</numlist>

And the following XSL

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xst="http://www.w3.org/1999/XSL/Transform"
                exclude-result-prefixes="xs"
                version="3.0">

    <xsl:variable name="main-doc" select="/"/>

    <xsl:template match="/">
        <xsl:variable name="var">//*[@key='K2']</xsl:variable>
        <xsl:variable name="eval">
            <xsl:evaluate xpath="$var" context-item="$main-doc" />
        </xsl:variable>
        <xsl:copy-of select="$eval"/>
    </xsl:template>

</xsl:stylesheet>

The result is

<numlitm key="K2">C1</numlitm>
<numlitm key="K2">C2</numlitm>

I would like the result, stored in eval, to be a sequence of two elements, so that I can iterate over the two numlitm via a for-each loop (I need this to construct a key). The issue is that the result seems not to be a node sequence, thus a for-each iteration will yield both numlitm rows, instead of each row in one seperate iteration

like image 399
sboti8m Avatar asked Feb 27 '26 13:02

sboti8m


2 Answers

The default type for a variable is a document-node. So, type your variable as a sequence of element(), or at least a sequence of item().

<xsl:variable name="eval" as="element()*">

or

<xsl:variable name="eval" as="item()*">

and then the $eval will be a sequence of the selected items from the evaluated XPath.

like image 115
Mads Hansen Avatar answered Mar 02 '26 13:03

Mads Hansen


If I understand you correctly, you want a serial string for the same key. → Than you could try something like this:

<root>
 <xsl:for-each-group select="//numlitm" group-by="@key">
 <xsl:variable name="currentKey" select="@key"/>
 <SameKey>
  <!-- Serialize Nodestrings -->
  <xsl:variable name="nodestrings">
    <xsl:apply-templates select="//numlitm[@key=$currentKey]/text()" mode="serialize"/> <!-- get all tag-values for current group-key --> 
  </xsl:variable>
  <key><xsl:value-of select="$currentKey"/></key>
  <keyValues><xsl:value-of select="$nodestrings"/></keyValues>
 </SameKey>
 </xsl:for-each-group>
</root>

For this you will receive this output:

<root>
 <SameKey>
  <key>K2</key>
  <keyValues>C1C2</keyValues>
 </SameKey>
 <SameKey>
  <key>K3</key>
  <keyValues>C3</keyValues>
 </SameKey>
</root>
like image 24
Andreas Hauser Avatar answered Mar 02 '26 13:03

Andreas Hauser



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!