[XSL-LIST Mailing List Archive Home] [By Thread] [By Date] [Recent Entries] [Reply To This Message]

Re: concatenated key

Subject: Re: concatenated key
From: Jeni Tennison <jeni@xxxxxxxxxxxxxxxx>
Date: Wed, 23 Apr 2003 12:41:21 +0100
xsl test node name
DaveP wrote:
>> Given a node, I'm trying to identify/pull out those nodes in the
>> document having the same set of identically named child nodes. For
>> example, given the node Alpha in the following, I'd like to pull
>> out the "Alpha2" node.
>> 
>> <node name="Alpha">
>>   <node name="a"/>
>>   <node name="b"/>
>> </node>
>> <node name="roman">
>>   <node name="i"/>
>>   <node name="ii"/>
>> </node>
>> <node name="Alpha2">
>>   <node name="a"/>
>>   <node name="b"/>
>> </node>
>
> Beating Jeni to it for once :-)
> In xslt 2 this is
>
> <xsl:template match="node">
>   <xsl:variable name="theseChildren" select="node/@name"/>
>   <xsl:if test="some $x in ../node/node/@name satisfies ($x =
> $theseChildren)">
>       <xsl:variable name="this" select="generate-id()"/>
>       (I am <xsl:value-of select="@name"/>)
>     <xsl:for-each select="../node">
>       <xsl:if test="(node/@name = $theseChildren ) and not(generate-id() =
> $this)">
>         Match at         <xsl:value-of select="position()"/>  <br />
>       </xsl:if>
>   </xsl:for-each>
> </xsl:if>
> </xsl:template>

I don't think that works. The test "node/@name = $theseChildren" tests
whether *any* of the name attributes within the current node is the
same as *any* of the name attributes in $theseChildren (just as it
does in XSLT 1.0). So if you had:

<node name="Alpha">
  <node name="a" />
  ...
  <node name="i" />
</node>
<node name="roman">
  <node name="i" />
  <node name="ii" />
</node>

then the above code would say that "roman" was the same as "Alpha"
because they both contain <node name="i" />.

Also note that you don't need to test generate-id() with XPath 2.0 --
you can use the 'is' and 'isnot' operators. Plus you can use "except"
to create a sequence of nodes that doesn't include a node you know.

I think that the best way to approach this problem in XSLT 2.0 would
be to use the string-join() function to concatenate the values of the
name attributes together and then use a key:

<xsl:key name="nodes" match="node[node]"
         use="string-join(node/@name, ' ')" />

<xsl:template match="node">
  <xsl:variable name="others"
    select="key('nodes', string-join(node/@name, ' ')) except ." />
  <xsl:if test="$others">
    <xsl:value-of select="@name" /> matches...
    <xsl:for-each select="$others">
      ...<xsl:value-of select="@name" />
    </xsl:for-each>
  </xsl:if>
</xsl:template>

I would be tempted to turn the "string-join(node/@name, ' ')"
expression into a function to prevent myself from making a mistake by
using a different separator or something in the two places where it's
used.

Cheers,

Jeni

---
Jeni Tennison
http://www.jenitennison.com/


 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


Current Thread

PURCHASE STYLUS STUDIO ONLINE TODAY!

Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced!

Buy Stylus Studio Now

Download The World's Best XML IDE!

Accelerate XML development with our award-winning XML IDE - Download a free trial today!

Don't miss another message! Subscribe to this list today.
Email
First Name
Last Name
Company
Subscribe in XML format
RSS 2.0
Atom 0.3
Site Map | Privacy Policy | Terms of Use | Trademarks
Free Stylus Studio XML Training:
W3C Member
Stylus Studio® and DataDirect XQuery ™are products from DataDirect Technologies, is a registered trademark of Progress Software Corporation, in the U.S. and other countries. © 2004-2013 All Rights Reserved.