Union of two node-set results leads to duplicated set member

2.2k views Asked by At

I'm using xslt 1.0, and I need a union of two variables which means I have to use node-set function.

The test case below creates a union of a single node with a set that contains this node. Since A contains B, the union operation should return B. But I get a new set with duplicate A's.

If I use xpath directly, union behaves as expected. If I use variables and node-set function, I face the unexpected case. My scenario requires that I use node-set. I've simplified the test case as much as I can.

This is the xml content:

<?xml version="1.0" encoding="utf-8" ?>
<root>
  <event>
    <id>3</id>
    <eventType>TYPE1</eventType>
  </event>
  <event>
    <id>2</id>
    <eventType>TYPE2</eventType>
    <parent>3</parent>
  </event>
  <event>
    <id>1</id>
    <eventType>TYPE2</eventType>
    <parent>3</parent>
  </event>
</root>

and this is the xslt:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" 
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:msxsl="urn:schemas-microsoft-com:xslt" 
                xmlns:ext="http://exslt.org/common"
                exclude-result-prefixes="msxsl"
>
    <xsl:output method="xml" indent="yes"/>

    <xsl:template match="/">      

      <xsl:variable name="t2-events">
        <xsl:copy-of 
          select="root/event
                  [eventType = 'TYPE2' and parent = '3']"/>
      </xsl:variable>

      <xsl:variable name="specific-t2">
          <xsl:copy-of 
            select="root/event
                    [eventType = 'TYPE2' and id = '2']"/>        
      </xsl:variable>

      <DEBUG>        

          <results>            
            <xsl:variable name="dummy" 
                          select="root/event
                                  [eventType = 'TYPE2'] 
                                  | 
                                  root/event[id = '2']"/>
            <xsl:variable name="dummy2" 
                          select="ext:node-set($t2-events)
                                | ext:node-set($specific-t2) "/>

            <xsl:comment>Works as expected</xsl:comment>
            <dummy>              
                <xsl:copy-of select="$dummy"/>
            </dummy>
            <dummy2>
              <xsl:comment>There are 3 elements here, where we should have 2</xsl:comment>
                <xsl:copy-of select="$dummy2"/>
             </dummy2>            
          </results>

      </DEBUG>            
    </xsl:template>  
</xsl:stylesheet>

How do I apply a union on two node-set() calls?

1

There are 1 answers

1
C. M. Sperberg-McQueen On BEST ANSWER

I don't think node-set() is the culprit here.

You've defined your variables t2-events and specific-t2 using xsl:copy-of. So your variables should (and do) contain fresh copies (new element nodes) of the nodes selected by the select expressions on xsl:copy-of. It follows that none of the event elements in the two variables is identical with any of the event elements in the input, and similarly that the two copies of event 2 made in the two variables are two copies, not two references to a single copy.

Note that when we add a few more variables to your debugging code (nice job cutting the example down, by the way!), the union happens as we might expect, regardless of whether we use node-set() or not. (At least in xsltproc.)

After your initial two variables, I added two more:

<xsl:variable name="T2-EVENTS" 
              select="root/event
                      [eventType = 'TYPE2' and parent = '3']"/>
<xsl:variable name="SPECIFIC-T2" 
              select="root/event
                      [eventType = 'TYPE2' and id = '2']"/>        

Then within your DEBUG element, I added:

<xsl:variable name="dummy3" 
              select="$T2-EVENTS | $SPECIFIC-T2 "/>
<xsl:variable name="dummy4" 
              select="ext:node-set($T2-EVENTS) 
                    | ext:node-set($SPECIFIC-T2) "/>

and

<dummy3>
  <xsl:comment>How many here?</xsl:comment>
  <xsl:copy-of select="$dummy3"/>
</dummy3>
<dummy4>
  <xsl:comment>How many here?</xsl:comment>
  <xsl:copy-of select="$dummy4"/>
</dummy4>

When I run the resulting stylesheet with xsltproc, I get two elements in dummy3 and two in dummy4; the call to node-set() made no difference.

(That said, I cannot see anything in the description of the node-set() function on the EXSLT site that says anything about node-set() preserving node identity or not preserving it. So I would be leery of relying on it either way.)