Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Check if node with attribute equals value exists

I have the following XSLT variable:

<xsl:variable name="superid" select="/contentdata/id"/>

Furthermore, I have a node with subnodes:

<nodes>
    <node name="foo" id="bar" />
    <node name="john" id="doe" />
    <node name="jane" id="tarzan" />
</nodes>

Now, I'd like to check if a node with an id attribute that equals superid exists.

I've tried the following (which obviously doesn't work):

<xsl:if test="/nodes/node[@id = $superid]">Yes, Sir!</xsl:if>
like image 272
Helge Avatar asked Dec 07 '11 07:12

Helge


4 Answers

What you have seems to work for me (xsl 1.0) - as per here.

I've tried to recreate your xslt:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                version="1.0"
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <xsl:output omit-xml-declaration="yes" method="xml" version="1.0" indent="yes" />

    <xsl:template match="/xml">
        <xml>
            <xsl:apply-templates select="contentdata/id" />
        </xml>
    </xsl:template>

    <xsl:template match="id">
        <Result>
        <xsl:variable name="superid" select="."/>
        <SearchFor>
            <xsl:value-of select="$superid"/>
        </SearchFor>
        <IsPresent>
            <xsl:if test="/xml/nodes/node[@id = $superid]">Node is present</xsl:if>
        </IsPresent>
    </Result>
    </xsl:template>

</xsl:stylesheet>

Given the xml:

<xml>
    <contentdata>
        <id>doe</id>
        <id>unobtanium</id>
    </contentdata>
    <nodes>
        <node name='foo' id='bar' />
        <node name='john' id='doe' />
        <node name='jane' id='tarzan' />
    </nodes>
</xml>

Output:

<xml xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <Result>
        <SearchFor>doe</SearchFor>
        <IsPresent>Node is present</IsPresent>
    </Result>
    <Result>
        <SearchFor>unobtanium</SearchFor>
        <IsPresent />
    </Result>
</xml>
like image 97
StuartLC Avatar answered Nov 11 '22 22:11

StuartLC


Use:

boolean(/nodes/node/@id = $superid)

Here is a complete transformation, showing this in action:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text"/>
 <xsl:strip-space elements="*"/>

 <xsl:variable name="vDoe" select="'doe'"/>
 <xsl:variable name="vXyz" select="'xyz'"/>

 <xsl:template match="/">
     id attribute with value "doe' exists: <xsl:text/>
     <xsl:value-of select="boolean(/nodes/node/@id = $vDoe)"/>
==========
     id attribute with value "xyz' exists: <xsl:text/>
     <xsl:value-of select="boolean(/nodes/node/@id = $vXyz)"/>
 </xsl:template>
</xsl:stylesheet>

when this transformation is applied on the provided XML document:

<nodes>
    <node name="foo" id="bar" />
    <node name="john" id="doe" />
    <node name="jane" id="tarzan" />
</nodes>

the wanted, correct result is produced:

     id attribute with value "doe' exists: true
==========
     id attribute with value "xyz' exists: false
like image 45
Dimitre Novatchev Avatar answered Nov 12 '22 00:11

Dimitre Novatchev


If you are using the xpath expression /nodes/node[@id = $superid]"> then this would be looking for a root node of nodes in your XML document. However, in your question you seem to imply nodes is just a node within your document, not necessarily the root element. Try this instead

<xsl:if test="//nodes/node[@id = $superid]">Yes, Sir!</xsl:if>

The double-slash selects nodes in the document wherever they are in the hierarchy, not just the top-level node.

like image 3
Tim C Avatar answered Nov 12 '22 00:11

Tim C


This should be working as you expect. One of your expressions (either in the variable's select or in the test attribute) must not be selecting what you think it is. (You haven't provided your full input, so it's hard to help there.)

Note a few things about xsl:if:

  • First, see this part of the XSLT spec (emphasis my own):

    The xsl:if element has a test attribute, which specifies an expression. The content is a template. The expression is evaluated and the resulting object is converted to a boolean as if by a call to the boolean function. If the result is true, then the content template is instantiated; otherwise, nothing is created.

  • So how would a call to the boolean function work on your input? See this part of the XPath spec (again, emphasis mine):

    The boolean function converts its argument to a boolean as follows :

    • a number is true if and only if it is neither positive or negative zero nor NaN

    • a node-set is true if and only if it is non-empty

    • a string is true if and only if its length is non-zero

    • an object of a type other than the four basic types is converted to a boolean in a way that is dependent on that type

So, if /contentdata/id actually selects an id for which /nodes/node[@id = $superid] returns a non-empty node-set, then the body of the xsl:if should execute.

like image 1
Wayne Avatar answered Nov 12 '22 00:11

Wayne