tags:

views:

66

answers:

2

I have the following xml:

<root>
    <Element1>
       <Hierarchy attr="value"/>
       <Hierarchy attr="value"/>
       <Hierarchy attr="value"/>
       <Hierarchy attr="value"/>
    </Element1>
    <AnotherElement>
         <YetAnotherElement>
            <Hierarchy attr="value"/>
            <Hierarchy attr="value"/>
            <Hierarchy attr="value"/>
            <Hierarchy attr="value"/>
         </YetAnotherElement>
    </AnotherElement>
</root>

How to convert 'Hierarchy' messages into tree? i.e.

<root>
    <Element1>
       <Hierarchy attr="value">
         <Hierarchy attr="value">
           <Hierarchy attr="value">
             <Hierarchy attr="value"/>
           </Hierarchy>
         </Hierarchy>
       </Hierarchy>
    </Element1>
    <AnotherElement>
         <YetAnotherElement>
            <Hierarchy attr="value">
               <Hierarchy attr="value">
                  <Hierarchy attr="value">
                     <Hierarchy attr="value"/>
                  </Hierarchy>
               </Hierarchy>
            </Hierarchy>
         </YetAnotherElement>
    </AnotherElement>
</root>
+3  A: 

This stylesheet:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="Hierarchy[position() != 1]"/>
    <xsl:template match="Hierarchy[1]">
        <xsl:apply-templates select="." mode="Hierarchy"/>
    </xsl:template>
    <xsl:template match="Hierarchy" mode="Hierarchy">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
            <xsl:apply-templates select="following-sibling::Hierarchy[1]" mode="Hierarchy"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

Result:

<root>
    <Element1>
        <Hierarchy attr="value">
            <Hierarchy attr="value">
                <Hierarchy attr="value">
                    <Hierarchy attr="value"></Hierarchy>
                </Hierarchy>
            </Hierarchy>
        </Hierarchy>
    </Element1>
    <AnotherElement>
        <YetAnotherElement>
            <Hierarchy attr="value">
                <Hierarchy attr="value">
                    <Hierarchy attr="value">
                        <Hierarchy attr="value"></Hierarchy>
                    </Hierarchy>
                </Hierarchy>
            </Hierarchy>
        </YetAnotherElement>
    </AnotherElement>
</root>
Alejandro
+1 for the perfect solution and for being faster than me :)
Dimitre Novatchev
@Dimitre: +1. That really is an achievement, ja!
Alejandro
A: 
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
  <xsl:output method="xml" indent="yes"/>

  <xsl:strip-space elements="*" />

  <xsl:template match="@* | node()">
    <xsl:if test="name() != 'Hierarchy'">
      <xsl:copy>
        <xsl:apply-templates select="@* | node()"/>
      </xsl:copy>
    </xsl:if>
  </xsl:template>

  <xsl:template match="Hierarchy">
    <xsl:if test="position() = 1">
      <xsl:call-template name="makeTree">
        <xsl:with-param name="elem" select="." />
      </xsl:call-template>
    </xsl:if>
  </xsl:template>

  <xsl:template name="makeTree">
    <xsl:param name="elem" />
    <xsl:copy>
      <xsl:apply-templates select="$elem/@*" />
      <xsl:if test="count($elem/following-sibling::node()) > 0">
        <xsl:call-template name="makeTree">
          <xsl:with-param name="elem" select="$elem/following-sibling::node()[1]" />
        </xsl:call-template>
      </xsl:if>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>
svick