tags:

views:

49

answers:

2

How can I convert this XML

<albums>
    <album title="New Zealand">
        <album title="Auckland">
            <image title="Mt Eden railroad station"/>
            <image title="Morgan St"/>
        </album>
    </album>
    <album title="Russia">
        <image title="Capital of Siberia"/>
    </album>
</albums>

into that

<div class="level-0">
    New Zealand
    Russia
</div>

<div class="level-1">
    Auckland
</div>

<div class="level-1">
    <img alt="Capital of Siberia"/>
</div>

<div class="level-2">
    <img alt="Mt Eden railroad station"/>
    <img alt="Morgan St"/>
</div>

?

+2  A: 
<xsl:template match="/">
  <xsl:apply-templates select="/albums | //album"/>
</xsl:template>

<xsl:template match="albums | album">
  <div class="level-{count(ancestor-or-self::album)}">
    <xsl:apply-templates select="album/@title | image"/>
  </div>
</xsl:template>

<xsl:template match="album/@title">
  <xsl:value-of select="concat(.,'&#xA;')"/>
</xsl:template>

<xsl:template match="image">
  <img alt="{@title}"/>
</xsl:template>
Nick Jones
Nick, this doesn't work; `xsl:value-of` can't be a child of the `xsl:apply-templates` element.
Flynn1179
@Flynn1179: Sorry should be fixed now.
Nick Jones
If the order's relevant, you can add `<xsl:sort select="count(ancestor-or-self::album)" />` to the `xsl:apply-templates` call in the first template.
Flynn1179
+1 Good answer.
Alejandro
+4  A: 

It's difficult to tell exactly what you're trying to do from this sample, but generally, you can flatten an XML tree with a slight modification to the identity template:

<xsl:template match="@* | node()">
  <xsl:copy>
    <xsl:apply-templates select="@*"/>
  </xsl:copy>
  <xsl:apply-templates select="node()" />
</xsl:template>

You can probably adapt this to your specific needs.

Flynn1179
+1 for a good answer.
Dimitre Novatchev
+1 Because if order isn't relevant this is a better answer.
Alejandro