[XSL-LIST Mailing List Archive Home] [By Thread] [By Date] [Recent Entries] [Reply To This Message]

Re: Tree from directory listing

Subject: Re: Tree from directory listing
From: Geert Josten <Geert.Josten@xxxxxxxxxxx>
Date: Thu, 16 Dec 2004 10:23:28 +0100
xsl tree
Hi,

Hi Geert,
  Thanks a lot for pointing the bug.. I was infact
testing my stylesheet again, and was getting
StackOverFlow error. And your mail pointed the bug..
Thanks for saving my time!

I was actually considering whether the node-set could be eliminated or not. My first impression was: easily, but then I noticed you used the keys on the document fragment. Which is actually quite nice.


Can anyone tell me how that fits into the XSLT 1 recommendation?

By the way, I realize that it opens an alternative to the node-set function! Wrap your fragment in some obscure element name (or just use some namespace) and add a key that only matches that element. Should work, I guess..

I suggest, please post your XSL. It'll help the
original poster.

Very true, here it comes:


<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:exslt="http://exslt.org/common"
    exclude-result-prefixes="exslt">

<xsl:output method="xml" indent="yes" encoding="utf-8" />

<xsl:key name="folders" match="folder" use="@path" />

  <xsl:template match="root">
    <xsl:variable name="folders">
      <!-- create a temporary tree with a folder structure -->
      <xsl:copy>
        <xsl:copy-of select="@*" />

        <xsl:for-each select="file">
          <!-- sort the files for nicer output -->
          <xsl:sort select="@path" />
          <xsl:sort select="@name" />

          <!-- build a folder structure for each file (separately) -->
          <xsl:apply-templates select="." mode="build-folders">
            <xsl:with-param name="path" select="concat(@path, @name)" />
          </xsl:apply-templates>
        </xsl:for-each>
      </xsl:copy>
    </xsl:variable>

    <!-- we have files in separate folder elements, now merge them -->
    <xsl:apply-templates select="exslt:node-set($folders)/node()" mode="merge" />
  </xsl:template>

  <xsl:template match="file" mode="build-folders">
    <xsl:param name="path-base" />
    <xsl:param name="path" /> <!-- assumption: path always starts with '/' -->

<!-- folder-count equals the number of slashes in the path, minus one for the file name -->
<xsl:param name="folder-count" select="string-length($path) - string-length(translate($path, '/', '')) - 1"/>


    <xsl:choose>
      <!-- should not occur, actually -->
      <xsl:when test="string-length($path) = 0" />

      <!-- path contains slashes, output a folder -->
      <xsl:when test="$folder-count > 0">
        <!-- Note: folder-count = 1 means at least two slashes -->
        <xsl:variable name="folder-name" select="substring-before(substring-after($path, '/'), '/')" />
        <xsl:variable name="folder-path" select="concat($path-base, '/', $folder-name)" />
        <xsl:variable name="remainder" select="substring-after(substring-after($path, '/'), '/')" />

        <folder name="{$folder-name}" path="{$folder-path}">
          <!-- and recurse to add sub folders -->
          <xsl:apply-templates select="." mode="build-folders">
            <xsl:with-param name="path" select="concat('/', $remainder)" />
            <xsl:with-param name="path-base" select="$folder-path" />
          </xsl:apply-templates>
        </folder>
      </xsl:when>

      <!-- no more slashes, output the file -->
      <xsl:otherwise>
        <!-- note: could do a xsl:copy-of select="." as well -->
        <file name="{@name}" />
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>

  <xsl:template match="root" mode="merge">
    <xsl:copy>
      <xsl:copy-of select="@*" />

      <!-- insert top-level files -->
      <xsl:copy-of select="file" />

<!-- apply those folders that are the first ones with a specific path -->
<xsl:apply-templates select="folder[generate-id(.) = generate-id(key('folders', @path)[1])]" mode="merge"/>
</xsl:copy>
</xsl:template>


  <xsl:template match="folder" mode="merge">
    <xsl:copy>
      <!-- note: one might want to suppress the path attribute -->
      <xsl:copy-of select="@*" />

<xsl:copy-of select="key('folders', @path)/file" />

<xsl:apply-templates select="key('folders', @path)/folder[generate-id(.) = generate-id(key('folders', @path)[1])]" mode="merge"/>
</xsl:copy>
</xsl:template>


</xsl:stylesheet>

Current Thread

PURCHASE STYLUS STUDIO ONLINE TODAY!

Purchasing Stylus Studio from our online shop is Easy, Secure and Value Priced!

Buy Stylus Studio Now

Download The World's Best XML IDE!

Accelerate XML development with our award-winning XML IDE - Download a free trial today!

Don't miss another message! Subscribe to this list today.
Email
First Name
Last Name
Company
Subscribe in XML format
RSS 2.0
Atom 0.3
Site Map | Privacy Policy | Terms of Use | Trademarks
Free Stylus Studio XML Training:
W3C Member
Stylus Studio® and DataDirect XQuery ™are products from DataDirect Technologies, is a registered trademark of Progress Software Corporation, in the U.S. and other countries. © 2004-2013 All Rights Reserved.