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

Re: Positional Grouping Problem - Add hierarchy to a f

Subject: Re: Positional Grouping Problem - Add hierarchy to a flat structure
From: Jeni Tennison <jeni@xxxxxxxxxxxxxxxx>
Date: Wed, 2 Jul 2003 10:29:20 +0100
positional hierarchy
Hi Tom,

> Basically, I want to replace the <BeginFile> node, with a <File>
> node. And then copy all elements between <BeginFile file="x"> and
> its corresponding <EndFile file="x"> as subelements to this new
> <File> node. Nesting <File> nodes if a second <BeginFile> node is
> found before the corresponding <EndFile> node is found. For each
> <BeginFile file="x"/>, there will always be a corresponding <EndFile
> file="x"/> element. And the LineNum attribute is not that important,
> but are in the original document, are valid, and can be used in the
> solution.

Thankfully, because you have filenames on both the <BeginFile> and
<EndFile> elements, this isn't too hard to do...

There are several approaches, but I find the easiest approach to be a
recursive step-by-step approach. Basically, we're going to step
through the elements in <LogFile> one by one. When we come across a
<BeginFile> element, we'll create a <File> element. For the content of
the <File> element, we'll process its following sibling, and for the
part after the new <File> element, we'll jump on to the element after
the matching <EndFile> element for the <BeginFile>.

Because we need to jump from a <BeginFile> element to its matching
<EndFile> element easily, it's a good idea to set up a key to index
the <EndFile> elements by their fileName:

<xsl:key name="EndFile" match="EndFile" use="@fileName" />

Within a template matching a <BeginFile> element, we can now find the
matching <EndFile> element with:

  key('EndFile', @fileName)

We then need to test whether there is a matching <EndFile> element or
not; if there isn't, we need an empty element:

<xsl:template match="BeginFile">
  <xsl:variable name="EndFile" select="key('EndFile', @fileName)" />
  <xsl:choose>
    <xsl:when test="$EndFile">
      <File lineNum="{@lineNum}" fileName="{@fileName}">
        ...
      </File>
      ...
    </xsl:when>
    <xsl:otherwise>
      <File lineNum="{@lineNum}" fileName="{@fileName}" />
      ...
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

In the case where we're creating a <File> element with content, the
content comes from processing the following siblings of the
<BeginFile> element recursively. The stuff after the <File> element
comes from processing whatever comes after the matching <EndFile>
element, again recursively:

<xsl:template match="BeginFile">
  <xsl:variable name="EndFile" select="key('EndFile', @fileName)" />
  <xsl:choose>
    <xsl:when test="$EndFile">
      <File lineNum="{@lineNum}" fileName="{@fileName}">
        <xsl:apply-templates select="following-sibling::*[1]" />
      </File>
      <xsl:apply-templates select="$EndFile/following-sibling::*[1]" />
    </xsl:when>
    <xsl:otherwise>
      <File lineNum="{@lineNum}" fileName="{@fileName}" />
      ...
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

When we're creating an empty element, the stuff after the empty <File>
element comes from processing the following siblings of the
<BeginFile> element recursively:

<xsl:template match="BeginFile">
  <xsl:variable name="EndFile" select="key('EndFile', @fileName)" />
  <xsl:choose>
    <xsl:when test="$EndFile">
      <File lineNum="{@lineNum}" fileName="{@fileName}">
        <xsl:apply-templates select="following-sibling::*[1]" />
      </File>
      <xsl:apply-templates select="$EndFile/following-sibling::*[1]" />
    </xsl:when>
    <xsl:otherwise>
      <File lineNum="{@lineNum}" fileName="{@fileName}" />
      <xsl:apply-templates select="following-sibling::*[1]" />
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

If you consider the content of a <File> element, most of it is made up
of other elements that you just want copied:

<xsl:template match="*">
  <xsl:copy-of select="." />
  ...
</xsl:template>

But to support the recursion through the siblings, once we've copied
that element, we need to go on to its immediately following sibling:

<xsl:template match="*">
  <xsl:copy-of select="." />
  <xsl:apply-templates select="following-sibling::*[1]" />
</xsl:template>

Currently the above template will process the <EndFile> elements as
well, but we know that as soon as we encounter an <EndFile> element,
we've come to the end of the content of the <File> element that we're
currently building. So we need a template matching <EndFile> elements
that just does nothing:

<xsl:template match="EndFile" />

Finally, to kick the whole process off, we have to apply templates to
the first element within the <LogFile> element:

<xsl:template match="LogFile">
  <xsl:apply-templates select="*[1]" />
</xsl:template>

And there you have it. If you need any help/explanation, let us know.

Cheers,

Jeni

---
Jeni Tennison
http://www.jenitennison.com/


 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


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.