Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

XSL store node-set in variable

Tags:

xslt

(XSLT 1.0.) Given a variable called Rows which contains the following (example):

Input

<AllResults>
    <Result>
      <subject>can be filtered by filter 1</subject>
      <type>can be filtered by filter 2</type>
      <date>can be filtered by filter 3</date>
    </Result>
    <Result> ...
    </Result>
</AllResults>

I have 3 filter variables. For each filter, I'd like to apply the filter to the input shown above if the filter variable is not empty. I'd like to store the filtered result, the items that match the filters, into a new variable. I tried the following, but I got an error message about it (filterResult) being a "result tree instead of a node-set". The Rows variable is a node-set, as I have determined by using a debugger.

Part of the XSL

<xsl:variable name="filterResult">
    <xsl:choose>
        <xsl:when test="$filter1 != '' and $filter2 != '' and $filter3 != ''">
            <xsl:copy-of select="$Rows[date=$filter1 and type=$filter2 and subject=$filter3]" />
        </xsl:when>
        <xsl:when test="$filter1 != '' and $filter2 != ''">
            <xsl:copy-of select="$Rows[date=$filter1 and type=$filter2]" />
        </xsl:when>
        <xsl:when test="$filter1 != '' and $filter3 != ''">
            <xsl:copy-of select="$Rows[date=$filter1 and subject=$filter3]" />
        </xsl:when>
        <xsl:when test="$filter3 != '' and $filter2 != ''">
            <xsl:copy-of select="$Rows[type=$filter2 and subject=$filter3]" />
        </xsl:when>
        <xsl:when test="$filter1 != ''">
            <xsl:copy-of select="$Rows[date=$filter1]" />
        </xsl:when>
        <xsl:when test="$filter3 != ''">
            <xsl:copy-of select="$Rows[subject=$filter3]" />
        </xsl:when>
        <xsl:when test="$filter2 != ''">
            <xsl:copy-of select="$Rows[type=$filter2]" />
        </xsl:when>
        <xsl:otherwise> 
            <xsl:copy-of select="$Rows" />
        </xsl:otherwise>
    </xsl:choose>
</xsl:variable>

I realize that copy-of produces a result tree and not a node-set, but I am not sure HOW to produce a node set given my 3 filters requirement that I described above.

Additional Info

I do know that I could do something like <xsl:variable name="me" select="/set/node"/> which would create a variable containing a node set but I don't see how that helps me, since I have a lot of possible conditions (given the three filters).

like image 566
KyleM Avatar asked Mar 14 '11 18:03

KyleM


People also ask

What is a node set in XSLT?

exsl:node-set() returns a node-set from a result tree fragment, which is what you get when you look at the xsl:variable instead of its select attribute to fetch a variable's value. This lets you process the XML created within a variable to process it in multiple steps.

How do you use variables in XSLT?

XSLT <xsl:variable>The <xsl:variable> element is used to declare a local or global variable. Note: The variable is global if it's declared as a top-level element, and local if it's declared within a template. Note: Once you have set a variable's value, you cannot change or modify that value!

What is XPath NodeSet?

An XML::XPath::NodeSet object contains an ordered list of nodes. The nodes each take the same format as described in XML::XPath::XMLParser.

Why do we use the select @|node() in the XSL apply templates /> element in an XSLT?

The short answer is: because of the XSLT processing model. matches any element, text-node, comment or processing-instruction. The document- (root)-node is also matched by node() .


1 Answers

In XSLT 1.0, the only way to create a variable containing a set of nodes from the source document is by evaluating an XPath expression in the select attribute:

<xsl:variable name="name" select="xpath_expression"/>

You can't use copy-of, apply-templates, or call-template; those will all produce a result tree fragment.

Every XSLT processor I'm aware of implements an extension function that converts result tree fragments into node sets, so unless you need your transform to be utterly cross-platform, you can do something like this (this example uses Microsoft's XSLT processor):

<xsl:variable name="filterResultNodeSet" select="msxsl:node-set($filterResult)"/>

But you don't need to do even this: as Alejandro has pointed out, you can get the result you're looking for just by writing a single XPath expression. There are applications where node selection is so complicated that you have to use a node-set() function, but yours isn't one of them.

like image 200
Robert Rossney Avatar answered Oct 18 '22 20:10

Robert Rossney