Re: [xsl] recursive problem with full path and position info

Subject: Re: [xsl] recursive problem with full path and position info
From: Jeni Tennison <mail@xxxxxxxxxxxxxxxx>
Date: Sun, 29 Apr 2001 16:58:16 +0100
Hi Dan,

> How would you approach this problem? I do not know *any* of the tag
> names ahead of time. I have an approach that works which matches on
> the leaf nodes with child::*[not(child::*)] and crawls up, but it is
> very slow and I don't think it is the correct approach. I think I
> need a strategy that matches from the top and decends.

That's a reasonable approach, and it's the one that I'd use most of
the time when I want to get a path because often you want to target a
path to a particular node. If you're getting paths for all the leaf
nodes, as you are in your case, it has the disadvantage that you
revisit nodes higher in the node tree multiple times, which is why
it's slow.

With the descending approach, you only visit each node once, but you
need to pass down a string holding the path information about the
ancestor nodes.  One way would be a default element-matching template
that just applied templates to element children, adding its own
information to the path:

<xsl:template match="*">
   <xsl:param name="path" />
   <xsl:apply-templates select="*">
      <xsl:with-param name="path"
         select="concat($path, name(), '(', position(), ').')" />

And then another template for elements at the bottom of the node tree,
which outputs the path that it's got from its parent, plus its own
information, and then the value as you desired.

<xsl:template match="*[not(*)]">
   <xsl:param name="path" />
   <xsl:value-of select="$path" />
   <xsl:value-of select="name()" />(<xsl:value-of select="position()" />
   <xsl:text>) = '</xsl:text>
   <xsl:value-of select="." />'&#xA;<xsl:text />

I wasn't sure about the numbering that you were using - in the above,
the number represents the index of the element child within its
parent. You may be after the index of the element within its siblings
with the same name, in which case you could use xsl:number or count
them with:

  count(preceding-sibling::*[name() = name(current())])

I hope that helps,


Jeni Tennison

 XSL-List info and archive:

Current Thread