xsl-list
[Top] [All Lists]

Re: Find elements whose ancestors are the same

2005-09-26 14:00:37
Ted,

In XSLT 2.0, this is much easier with a key:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"; version="2.0">

<xsl:key name="folder-by-ancestry" match="folder" use="string-join(ancestor-or-self::*/@name,'#')"/>

  <xsl:template match="folder">
<xsl:copy-of select="key('folder-by-ancestry',string-join(ancestor-or-self::*/@name,'#'))"/>
  </xsl:template>
</xsl:stylesheet>

(# is used as a delimiter on the assumption it's not allowed inside names.)

Unfortunately, XSLT/XPath 1.0 give no function that allows you to stitch together all the names you need into a single key value. Accordingly I'd probably use two passes to do this in 1.0: in the first pass, annotate all the elements with a code (created by walking through the tree and collecting @name attributes); in the second, retrieve elements with the same code.

Pass 1:

<xsl:template match="folder">
  <xsl:copy>
    <xsl:copy-of select="@*"/>
    <xsl:attribute name="ancestry">
      <xsl:for-each select="ancestor-or-self::*/@name">
        <xsl:value-of select="."/>
        <xsl:text>#</xsl:text>
      </xsl:for-each>
    </xsl:attribute>
  </xsl:copy>
</xsl:template>

Pass 2

<xsl:key name="folder-by-ancestry" match="folder" use="@ancestry"/>

<xsl:template match="folder">
  <xsl:variable name="ancestry">
    <xsl:for-each select="ancestor-or-self::*/@name">
      <xsl:value-of select="."/>
    </xsl:for-each>
  </xsl:variable>
  <xsl:copy-of select="key('folder-by-ancestry',$ancestry)"/>
</xsl:template>

Cheers,
Wendell

I'd At 04:38 PM 9/26/2005, you wrote:
Thanks again to everyone who has replied to these messages. I had no idea how hard this would be. It seemed so simple when I explained it to the client ;-)

I'm looking for an XPath expression that will find all elements whose ancestors are the same. By "same" I mean their @name is the same at each level of ancestry (and they appear in the same order).

For example, this expression would return a count of 2 for the following XML when filtered on the "daughter" folder (or "mother" or "grandfather" for that matter).

<root>
    <folder name="grandfather">
        <folder name="mother">
            <folder name="daughter" />
        </folder>
    </folder>
    <folder name="grandfather">
        <folder name="mother">
            <folder name="daughter" />
        </folder>
    </folder>
    <folder name="grandmother">
        <folder name="father">
            <folder name="son" />
        </folder>
    </folder>
</root>

I know it's going to be something like this, but I just can't get my head around it!

<xsl:copy-of select="/root//folder[(_at_)name = following-sibling::*/@name and ancestor-or-self::*/@name = following-sibling::*/@name/ancestor-or-self::*/@name" />


======================================================================
Wendell Piez                            
mailto:wapiez(_at_)mulberrytech(_dot_)com
Mulberry Technologies, Inc.                http://www.mulberrytech.com
17 West Jefferson Street                    Direct Phone: 301/315-9635
Suite 207                                          Phone: 301/315-9631
Rockville, MD  20850                                 Fax: 301/315-8285
----------------------------------------------------------------------
  Mulberry Technologies: A Consultancy Specializing in SGML and XML
======================================================================


--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--



<Prev in Thread] Current Thread [Next in Thread>