Re: [xsl] Counting indent level

Subject: Re: [xsl] Counting indent level
From: Nicholas Orr <nick@xxxxxxxxxxx>
Date: Mon, 29 Sep 2008 12:51:14 +1000
On 29/09/2008, at 11:38 AM, G. Ken Holman wrote:

I've got some XML that contains a list of items and groups, and each
group could contain either more items or more groups like so :

<catalog>
       <item />
       <group>
               < group >
               < item />
               < item />
               < group >
                       < group >
                               < item />
etc

So groups can contain either items or more groups or nothing.  Items
only exist at the root (catalog) of this part of the tree or inside
groups.  I'm outputting a single list of all of the items and group
currently using this :

<xsl:for-each select="item|descendant::group|descendant::group/item">

I expect you would have a more easily maintained stylesheet if you had:

This entire xslt file is pretty simple, it's basically just that one for each and produces a single list of elements. Is there any other advantages (other than easier maintenance) to use templates over the for-each?


<xsl:template match="catalog">
 <xsl:apply-templates select="*"/>
</xsl:template>
<xsl:template match="group">
 <!--report on the group-->
 <xsl:apply-templates select="item"/>
</xsl:template>
<xsl:template match="item">
 <!--report on the item-->
</xsl:template>

The reason for that is that a item node might also contain child nodes
that are also called <item> nodes that I don't want. I only want a
item node that has it's immediate parent a group node.

Every node (except the root node above the document element) has only a single parent node, so I'm not sure what you mean by "immediate parent". Unless you meant to say "immediate ancestor" which is the parent.


Above you also state you want an item whose parent is catalogue and not just those whose parent is group. If I'm wrong, then you'll have to change the above to the following to not process items that are not a child of a group:

<xsl:template match="catalog">
 <xsl:apply-templates select="*"/>
</xsl:template>

This is the same as the above, the first three lines at least - is that what you meant?


But yes, you're right, I want all of the items whose parent is either catalog or group as well as all of the groups.

(There may be an easier way to do that...)

See above ... only items that are immediate children of the catalogue or a group are processed.


I am assuming that a group is never a descendant of an item as the code above will not process the descendants of an item, whereas your posited for-each statement would.

No, this isn't an issue, so the for-each works because the data won't ever have this.


I can change the for-each that I'm using, although it has to remain in
the same order, so I can't process them out of order.

The code I give you above will process groups and items in document order.

Ken, does this mean it will retain the overall order though? I want to process them (from my original), as an export (like csv) in the same order so the export would mix and match items and groups :


item
group
group
item
item
etc

So it's one single export with both types mixed in the original order. This is why I used a single for-each with the "or" to pick up everything in one go. Plus the code to generate the export line item data is the same for both group and item, so I don't have to have separate templates for them.



<xsl:value-of select="count(ancestor::group)"/>

This is what i was after, thanks.


Thanks for your help.

Cheers,
Nick

Current Thread