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

Re: Nested sections from flat structure

Subject: Re: Nested sections from flat structure
From: Jeni Tennison <mail@xxxxxxxxxxxxxxxx>
Date: Mon, 14 May 2001 11:30:00 +0100
disadvantage of flat structure
Hi Linda,

> My source documents are a bit troublesome. They have a structure
> like HTML. There are two elements that indicate start of a section,
> <head> and <a name="">. Both appear inside a p element. A source
> document can be:
> - without subsections
> - with subsections indicated by <head>
> - with subsections indicated by <a name="">
> - with subsections indicated by <a name="">, and <head> subsections
> inside the first subsections
> - with subsections indicated by <head>, and <a name=""> subsections
> inside the first subsections

When you have troublesome source then it's sometimes better to take a
two-pass approach on the problem - transform it into something more
approachable, and then transform *that* into the output that you want.

Your source would be a lot more approachable if it was clear what was
a 'top' section and what were sections underneath them.  In the
following stylesheet, I first convert the source into:

<GeneralSection/>
<Paragraph>first some intro text</Paragraph>
<TopSection/>
<SectionTitle>A</SectionTitle>
<Paragraph>goes with A.</Paragraph>
<SubSection ID="A.1"/>
<Paragraph>Text with A.1</Paragraph>
<Paragraph>More text with A.1</Paragraph>
<SubSection ID="A.2"/>
<Paragraph>text with A.2</Paragraph>
<Paragraph>Goes with A.2</Paragraph>
<TopSection/>
<SectionTitle>B</SectionTitle>
<Paragraph>Goes with B.</Paragraph>
<Paragraph>Goes with  B.</Paragraph>
<TopSection/>
<SectionTitle>C</SectionTitle>
<Paragraph>Goes with C</Paragraph>
<Paragraph>Goes with C</Paragraph>

And from there using the Muenchian method to create the hierarchy.

The advantage is that both transformations are relatively
straight-forward; the disadvantage is that you need to either use a
node-set extension in your stylesheet or split the stylesheet in two
and use the second on the output of the first.

If you want to use a one-pass approach, like your stylesheet is at the
moment, the only suggestion I'd make for simplifying it is to split up
all those xsl:for-eaches into separate templates, using modes to
distinguish between the different types of processing you do within
each.

Anyway, here's my approach (unless you're using a processor that
supports exsl:node-set(), you'll need to change the namespace for the
node-set() function):

<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:exsl="http://exslt.org/common"
                extension-element-prefixes="exsl">

<xsl:output method="xml" indent="yes" />

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

<xsl:variable name="top" select="topic/text/p[head or a/@name][1]" />

<xsl:template match="/">
   <xsl:variable name="sections">
      <GeneralSection />
      <xsl:apply-templates mode="convert" />
   </xsl:variable>
   <xsl:apply-templates select="exsl:node-set($sections)/GeneralSection"
                        mode="group" />
</xsl:template>

<xsl:template match="p" mode="convert">
   <Paragraph><xsl:apply-templates /></Paragraph>
</xsl:template>

<xsl:template match="p[head]" mode="convert">
   <xsl:choose>
      <xsl:when test="$top/head"><TopSection /></xsl:when>
      <xsl:otherwise><SubSection /></xsl:otherwise>
   </xsl:choose>
   <SectionTitle><xsl:apply-templates select="head" /></SectionTitle>
   <Paragraph>
      <xsl:apply-templates select="node()[not(self::head)]" />
   </Paragraph>
</xsl:template>

<xsl:template match="p[a/@name]" mode="convert">
   <xsl:choose>
      <xsl:when test="$top/a/@name">
         <TopSection ID="{a/@name}" />
      </xsl:when>
      <xsl:otherwise><SubSection ID="{a/@name}" /></xsl:otherwise>
   </xsl:choose>
</xsl:template>

<xsl:key name="children" match="Paragraph | SectionTitle"
         use="generate-id(preceding-sibling::*
                             [self::GeneralSection or self::TopSection or
                              self::SubSection][1])" />
<xsl:key name="children" match="TopSection"
         use="generate-id(preceding-sibling::GeneralSection[1])" />
<xsl:key name="children" match="SubSection"
         use="generate-id(preceding-sibling::TopSection[1])" />

<xsl:template match="GeneralSection | TopSection | SubSection"
              mode="group">
   <GeneralSection>
      <xsl:copy-of select="@*" />
      <xsl:apply-templates select="key('children', generate-id())"
                           mode="group" />
   </GeneralSection>
</xsl:template>

<xsl:template match="Paragraph" mode="group">
   <xsl:copy-of select="." />
</xsl:template>

</xsl:stylesheet>

I hope that helps,

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.