Leiru
Leiru

Reputation: 33

How to use variable node-set in Xpath "contains()" function

I want to check if node value contains a string that occurs in an attribute of a node with-in variable made as a node-set.

<xsl:variable name="Var">
<root>
   <tag atr="x3"> some string <tag> 
   <tag atr="x4"> some string <tag>
<root>
<xsl:variable>

xml contains:

<name>one x3 two<name> 

i've tried something like :

<xsl:value-of select="contains(name,msxsl:node-set($Var)/root/tag/@atr)"/>

but it just output's nothing and move on.

Upvotes: 3

Views: 6768

Answers (1)

Dimitre Novatchev
Dimitre Novatchev

Reputation: 243459

In XPath 1.0 if a function or operator expects a string and is passed a node-set, only the string value of the first (in document order) node of the node-set is produced and used by this function or operator.

Therefore, an expression such as:

contains(name, msxsl:node-set($Var)/root/tag/@atr)

tests only whether the string value of the first of the msxsl:node-set($Var)/root/tag/@atr nodes is contained in the string value of the first name node.

You actually want to see if the string value of any of the nodes in msxsl:node-set($Var)/root/tag/@atr is contained in a the string value of a given element, named name.

One correct XPath expression evaluating this condition:

boolean(msxsl:node-set($Var)/root/tag/@atr[contains($name, .)])

where $name is defined to contain exactly the element name.

A complete code example:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:msxsl="urn:schemas-microsoft-com:xslt">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:variable name="name" select="'x42'"/>

 <xsl:variable name="Var">
   <root>
     <tag atr="x3"> some string </tag>
     <tag atr="x4"> some string </tag>
   </root>
 </xsl:variable>

 <xsl:template match="/">
  <xsl:value-of select=
  "boolean(msxsl:node-set($Var)
              /root/tag/@atr[contains($name, .)])"/>
 </xsl:template>
</xsl:stylesheet>

when this transformation is applied on any XML document (not used), the wanted, correct result is produced:

true

However, if we substitute in the above transformation the XPath expression offered in the another answer (by Siva Charan) :

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:msxsl="urn:schemas-microsoft-com:xslt">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:variable name="name" select="'x42'"/>

 <xsl:variable name="Var">
   <root>
     <tag atr="x3"> some string </tag>
     <tag atr="x4"> some string </tag>
   </root>
 </xsl:variable>

 <xsl:template match="/">
  <xsl:value-of select=
  "contains(name, msxsl:node-set($Var)/root/tag/@atr)"/>
 </xsl:template>
</xsl:stylesheet>

this transformation produces the wrong answer:

false

because it only tests for containment the first of all attr attributes.

Upvotes: 3

Related Questions