Skip to content

Instantly share code, notes, and snippets.

@vicmortelmans
Created January 28, 2011 15:04
Show Gist options
  • Save vicmortelmans/800354 to your computer and use it in GitHub Desktop.
Save vicmortelmans/800354 to your computer and use it in GitHub Desktop.
templates for flattening a purely hierarchical XML structure
<!-- templates for flattening a purely hierarchical XML structure
into a list of <item> records -->
<xsl:template match="*" mode="flatten">
<xsl:apply-templates mode="flatten"/>
</xsl:template>
<xsl:template match="*[not(*)]" mode="flatten">
<!-- working upwards starting from leaf nodes -->
<item>
<xsl:apply-templates select="." mode="flatten-ancestor"/>
</item>
</xsl:template>
<xsl:template match="*" mode="flatten-ancestor">
<xsl:copy>
<xsl:copy-of select="@*"/>
</xsl:copy>
<xsl:apply-templates select="ancestor::*[1]" mode="flatten-ancestor"/>
</xsl:template>
@mykelangelo
Copy link

Can you give an example of input and output XML?

@vicmortelmans
Copy link
Author

Can you give an example of input and output XML?

Input:

<?xml version="1.0"?>
<root>
  <a a="this">
    <b b="hierarchy">
      <c c="is"/>
      <c c="going"/>
    </b>
    <b b="to"/>
    <b b="be">
      <c c="broken"/>
      <c c="down">
        <d d="in"/>
      </c>
    </b>
  </a>
  <a a="the"/>
  <a a="blink">
    <b b="of"/>
    <b b="an"/>
  </a>
  <a a="eye"/>
</root>

Output:

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <item>
      <c c="is"/>
      <b b="hierarchy"/>
      <a a="this"/>
      <root/>
   </item>
   <item>
      <c c="going"/>
      <b b="hierarchy"/>
      <a a="this"/>
      <root/>
   </item>
   <item>
      <b b="to"/>
      <a a="this"/>
      <root/>
   </item>
   <item>
      <c c="broken"/>
      <b b="be"/>
      <a a="this"/>
      <root/>
   </item>
   <item>
      <d d="in"/>
      <c c="down"/>
      <b b="be"/>
      <a a="this"/>
      <root/>
   </item>
   <item>
      <a a="the"/>
      <root/>
   </item>
   <item>
      <b b="of"/>
      <a a="blink"/>
      <root/>
   </item>
   <item>
      <b b="an"/>
      <a a="blink"/>
      <root/>
   </item>
   <item>
      <a a="eye"/>
      <root/>
   </item>
</root>

using this complet stylesheet:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" 
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="/root">
    <xsl:copy>
      <xsl:apply-templates select="*" mode="flatten"/>
    </xsl:copy>
  </xsl:template>

  <!-- templates for flattening a purely hierarchical XML structure 
       into a list of <item> records -->
  
  <xsl:template match="*" mode="flatten">
    <xsl:apply-templates mode="flatten"/>
  </xsl:template>
  
  <xsl:template match="*[not(*)]" mode="flatten">
    <!-- working upwards starting from leaf nodes -->
    <item>
      <xsl:apply-templates select="." mode="flatten-ancestor"/>
    </item>
  </xsl:template>
  
  <xsl:template match="*" mode="flatten-ancestor">
    <xsl:copy>
      <xsl:copy-of select="@*"/>
    </xsl:copy>
    <xsl:apply-templates select="ancestor::*[1]" mode="flatten-ancestor"/>
  </xsl:template>

</xsl:stylesheet>

So what it does: it's taking each bottom-most element in the hiearchy and giving it it's own <item>, containing all the parent values, thus breaking down the hierarchy.

@mykelangelo
Copy link

Cool, thanks! It's not what I needed, though... but I have already found what I was looking for.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment