Hello,
This should work:
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<body>
<xsl:apply-templates/>
</body>
</xsl:template>
<xsl:template match="menuItems">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="menuItem">
<p id="{(_at_)label}">
<xsl:apply-templates select="ancestor-or-self::menuItem"
mode="uic"/>
</p>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="menuItem" mode="uic">
<uicontrol>
<xsl:value-of select="@label"/>
</uicontrol>
</xsl:template>
What this does is, for every menuItem in the source,
creates a p element, then populates it with all ancestors
of the current menuItem (including itself) renamed as
uicontrol and having the @label as content.
Regards,
EB
-----Original Message-----
From: Mark Peters [mailto:flickrmeister(_at_)gmail(_dot_)com]
Sent: Wednesday, April 01, 2009 3:58 PM
To: xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com
Subject: [xsl] Looping through a tree and retaining parent values
Hi Everyone,
I'm puzzling over a transformation that I thought would be simple but
which becomes progressively more complex as I try to wrap my mind
around it.
Here is a series of menuItem nodes, which are nested in menuItems
nodes. Each menuItem node has a label attribute.
<menuConfig>
<menu id="A">
<menuItems>
<menuItem label="1">
<menuItems>
<menuItem label="a"/>
<menuItems>
<menuItem
label="1a">
<menuItems>
<menuItem label="1a.a"/>
<menuItem label="1a.b"/>
</menuItems>
</menuItem>
</menuItems>
<menuItem label="b">
</menuItem>
</menuItems>
</menuItem>
<menuItem label="2">
<menuItems>
<menuItem label="c"/>
<menuItem label="d">
<menuItems>
<menuItem
label="2d">
<menuItems>
<menuItem label="2d.d"/>
<menuItem label="2d.e"/>
<menuItem label="2d.f"/>
</menuItems>
</menuItem>
</menuItems>
</menuItem>
<menuItem label="e">
<menuItems>
<menuItem
label="2e">
<menuItems>
<menuItem label="2e.g"/>
</menuItems>
</menuItem>
</menuItems>
</menuItem>
</menuItems>
</menuItem>
</menuItems>
</menu>
</menuConfig>
What I'm trying to do is create a set of p nodes which nest a series
of uicontrol nodes, one uicontrol node for each level of menuItem in
the original XML document. In other words, for each menuItem in the
original XML, there should be a uicontrol element. The first uicontrol
node in the series contains the @label value for the parent menuItem
node. The next uiconcontrol node in the series contains the @label
value for the first child menuItem node, and so on.
The p node should have an id attribute whose value is the @label value
of the last child node in each tree.
Here is an example:
<body>
<p id="1">
<uicontrol>1</uicontrol>
</p>
<p id="a">
<uicontrol>1</uicontrol> >
<uicontrol>a</uicontrol></p>
<p id="1a">
<uicontrol>1</uicontrol> >
<uicontrol>a</uicontrol> >
<uicontrol>1a</uicontrol>
</p>
<p id="1.1a">
<uicontrol>1</uicontrol> >
<uicontrol>a</uicontrol> >
<uicontrol>1a</uicontrol> >
<uicontrol>1a.a</uicontrol>
</p>
<p id="1.1b">
<uicontrol>1</uicontrol> >
<uicontrol>a</uicontrol> >
<uicontrol>1a</uicontrol> >
<uicontrol>1b.b</uicontrol>
</p>
<p id="b">
<uicontrol>1</uicontrol> >
<uicontrol>b</uicontrol>
</p>
<p id="2">
<uicontrol>2</uicontrol>
<p id="c">
<uicontrol>2</uicontrol> >
<uicontrol>c</uicontrol>
</p>
<p id="d">
<uicontrol>2</uicontrol> >
<uicontrol>d</uicontrol>
</p>
<p id="2d">
<uicontrol>2</uicontrol> >
<uicontrol>d</uicontrol> >
<uicontrol>2d</uicontrol>
</p>
<p id="2d.d">
<uicontrol>2</uicontrol> >
<uicontrol>d</uicontrol> >
<uicontrol>2d</uicontrol> >
<uicontrol>2d.d</uicontrol>
</p>
<p id="2d.e">
<uicontrol>2</uicontrol> >
<uicontrol>d</uicontrol> >
<uicontrol>2d</uicontrol> >
<uicontrol>2d.e</uicontrol>
</p>
<p id="e">
<uicontrol>2</uicontrol> >
<uicontrol>e</uicontrol>
</p>
<p id="2e">
<uicontrol>2</uicontrol> >
<uicontrol>e</uicontrol> >
<uicontrol>2e</uicontrol></p>
<p id="2e.g">
<uicontrol>2</uicontrol> >
<uicontrol>e</uicontrol> >
<uicontrol>2e</uicontrol> >
<uicontrol>2e.g</uicontrol>
</p>
</body>
So far, I've come up with a stylesheet that produces a single p node
for every parent menuItem. It's a start. I've thought about trying to
use variables to retain the menuItem/@label values at each level in
the tree; but, reading about variables, I'm not sure this is possible.
Likewise, I've thought about defining each loop in a separate template
and then calling each template from the "master" template. But then,
I'm not sure how I'd retrieve the final menuItem/@label value for the
p/@id value.
And I must not understand the last() function correctly. The p/@id
values inserted by the stylesheet are "1a" and "2e.g," and not the
@label value for the last menuItem in each tree.
<xsl:template match="/">
<xsl:for-each select="//menu">
<body>
<xsl:for-each select="menuItems">
<xsl:for-each select="menuItem">
<p>
<xsl:attribute name="id">
<xsl:value-of select="descendant::menuItem[last()]/@label"/>
</xsl:attribute>
<uicontrol>
<xsl:value-of select="@label"/>
</uicontrol> >
<xsl:for-each select="descendant::menuItem[2]">
<uicontrol>
<xsl:value-of select="@label"/>
</uicontrol> >
<xsl:for-each select="descendant::menuItem[3]">
<uicontrol>
<xsl:value-of select="@label"/>
</uicontrol> >
<xsl:for-each select="descendant::menuItem[4]">
<uicontrol>
<xsl:value-of select="@label"/>
</uicontrol> >
<xsl:for-each select="descendant::menuItem[5]">
<uicontrol>
<xsl:value-of select="@label"/>
</uicontrol> >
</xsl:for-each>
</xsl:for-each>
</xsl:for-each>
</xsl:for-each>
</p>
</xsl:for-each>
</xsl:for-each>
</body>
</xsl:for-each>
</xsl:template>
I'd appreciate any help you could offer.
Thanks,
Mark
--
Mark Peters
Senior Technical Writer
Saba Software
--~------------------------------------------------------------------
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>
--~--
--~------------------------------------------------------------------
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>
--~--