Search code examples
xmlxsltxpathxpath-1.0

XPath get all attributes filter returning value of a single instance only


Suppose I have the following xml structure,

<foos>
    <bar id="0001"></bar>
    <bar id="0002"></bar>
    <bar id="0003"></bar>
    <bar id="0004"></bar>
</foos>

How come the following xpath returns only the last id? Why not all id attributes? Is XPath doing a distinct by default?

And then if I change copy-of with value-of, it returns the value of the first instance of id? Hows this ordering re LIFO for copy of and FIFO for value-of happening?

<xsl:output method="xml"/>
<xsl:template match="/">
    <info>
        <xsl:copy-of select="//bar/@*"/>
    </info>
</xsl:template>

Solution

  • The answer with regard to copy-of is roughly this: the first instance of @id creates an attribute named id with a value of 0001. The second instance overwrites this attribute with a value of 0002, and so on.

    If, OTOH, you would have this XML as the input:

    <foos>
        <bar id="0001"></bar>
        <bar ie="0002"></bar>
        <bar if="0003"></bar>
        <bar ig="0004"></bar>
    </foos>
    

    then:

    <info>
        <xsl:copy-of select="//bar/@*"/>
    </info>
    

    would have returned:

    <info id="0001" ie="0002" if="0003" ig="0004"/>
    

    because now there's no conflict between successive instances of @*.


    The answer with regard to value-of is that in XSLT 1.0:

    <xsl:value-of select="$node-set"/>
    

    will return the value of the first node in $node-set.