Forum Moderators: open

Message Too Old, No Replies

XSLT help

Trying to get desired output

         

skube

6:37 pm on Jul 8, 2005 (gmt 0)

10+ Year Member



Hi, I'm trying to do some xslt and running into some problems. If anyone could offer any suggestions I would be most grateful...I'm at my wits end and I don't know what else to try.

I have a sample XML source file and a sample XSLT below, excuse the formatting, it tends to get lost during posting...

SAMPLE SOURCE XML:


<doc>
<section level="1">
<heading>Some heading 1</heading>
<par>Some text</par>
<par>Some text</par>
<section level="2">
<heading>Some heading 2a</heading>
<par>Some text</par>
<par>Some text</par>
<section level="3">
<heading>Some heading 3a</heading>
<par>Some text</par>
<par>Some text</par>
<list>
<item>
<par>Some text</par>
</item>
<item>
<par>Some text</par>
</item>
</list>
<par>Some text</par>
</section>
<section level="3">
<heading>Some heading 3b</heading>
<par>Some text</par>
</section>
</section>
<section level="2">
<heading>Some heading 2b</heading>
<par>Some text</par>
<par>Some text</par>
</section>
</section>
</doc>

I would like to transform the above into the following:


<section id="Some heading 1">
<page id="intro">
<h1>Some heading 1</h1>
<p>Some text</p>
<p>Some text</p>
</page>
<section id="Some heading 2a">
<page id ="intro">
<h1>Some heading 2</h1>
<p>Some text</p>
<p>Some text</p>
</page>
<page id="Some heading 3a">
<h1>Some heading 3</h1>
<p>Some text</p>
<p>Some text</p>
<ul>
<li>Some text</li>
<li>Some text</li>
</ul>
<p>Some text</p>
</page>
<page id="Some heading 3b">
<h1>Some heading 3</h1>
<p>Some text</p>
</page>
</section>
<page id="Some heading 2b">
<h1>Some heading 2b</h1>
<p>Some text</p>
<p>Some text</p>
</page>
</section>

I am using the following XSLT:


<?xml version="1.0" encoding="iso-8859-1"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
>
<!--match document root -->
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
<!-- Match Sections -->
<xsl:template match="section">
<xsl:choose>
<xsl:when test="@level=3">
<xsl:element name="page">
<xsl:variable name="currNode"><xsl:value-of select="node()"/></xsl:variable>
<xsl:if test="position()=1"><xsl:attribute name="id">intro</xsl:attribute></xsl:if>
<xsl:apply-templates/>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:element name="section">
<xsl:variable name="currNode"><xsl:value-of select="heading/node()"/></xsl:variable>
<xsl:attribute name="id"><xsl:value-of select="$currNode"/></xsl:attribute>
<xsl:apply-templates/>
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<!-- Match Headings -->
<xsl:template match="heading">
<xsl:element name="page">
<xsl:variable name="currNode"><xsl:value-of select="node()"/></xsl:variable>
<xsl:choose>
<xsl:when test="position()=1"><xsl:attribute name="id">intro</xsl:attribute></xsl:when>
<xsl:otherwise><xsl:attribute name="id"><xsl:value-of select="$currNode"/></xsl:attribute></xsl:otherwise>
</xsl:choose>
<h1><xsl:value-of select="$currNode"/></h1>
<xsl:for-each select="following-sibling::par">
<p><xsl:apply-templates/></p>
</xsl:for-each>
</xsl:element>
</xsl:template>
<!-- Paragraphs and Lists -->
<xsl:template match="par">
<!-- <p><xsl:apply-templates/></p> -->
</xsl:template>
<xsl:template match="list">
<ul>
<xsl:apply-templates/>
</ul>
</xsl:template>
<xsl:template match="item">
<li>
<xsl:value-of select="."/>
</li>
</xsl:template>
</xsl:stylesheet>

Unfortunately, I call only get so far:

<?xml version="1.0" encoding="UTF-8"?>
<section id="Some heading 1">
<page id="Some heading 1">
<h1>Some heading 1</h1>
<p>Some text</p>
<p>Some text</p>
</page>
<section id="Some heading 2a">
<page id="Some heading 2a">
<h1>Some heading 2a</h1>
<p>Some text</p>
<p>Some text</p>
</page>
<page>
<page id="Some heading 3a">
<h1>Some heading 3a</h1>
<p>Some text</p>
<p>Some text</p>
<p>Some text</p>
</page>
<ul>
<li>
Some text
</li>
<li>
Some text
</li>
</ul>
</page>
<page>
<page id="Some heading 3b">
<h1>Some heading 3b</h1>
<p>Some text</p>
</page>
</page>
</section>
<section id="Some heading 2b">
<page id="Some heading 2b">
<h1>Some heading 2b</h1>
<p>Some text</p>
<p>Some text</p>
</page>
</section>
</section>

irnbru

3:46 pm on Jul 11, 2005 (gmt 0)

10+ Year Member



You have two locations where a page element is created. Create it only in your heading template.

Replace the choose in your heading template with

<xsl:choose>
<xsl:when test="../@level=3">
<xsl:if test="position()=2">
<xsl:attribute name="id"><xsl:value-of select="$currNode"/></xsl:attribute>
</xsl:if>
</xsl:when>
<xsl:otherwise>
<xsl:choose>
<xsl:when test="position()=2"><xsl:attribute name="id">intro</xsl:attribute></xsl:when>
<xsl:otherwise>
<xsl:attribute name="id">
<xsl:value-of select="$currNode"/>
</xsl:attribute>
</xsl:otherwise>
</xsl:choose>
</xsl:otherwise>
</xsl:choose>

AFAIC that'll get you a step closer to the target output.

skube

4:34 pm on Jul 11, 2005 (gmt 0)

10+ Year Member



Well, that does take it a step closer, but I think there are still some fundamental issues with the transformation. I think there are only 3 of the now tho...

They are:
1) Level 3 pages are created inside a page node, there should never be a page with a child page.
2) The ul list is created outside of the page, after the page node is close.
3) If a section does not contain any section children (i.e. the Section 2b), it should be a page rather than a section containing only 1 page.

Anyway, I really appreciate the time and effort you took to respond irnbru. It's so frustating cause it seems so close...but I've been strugling for almost 2 weeks now...

skube

8:35 pm on Jul 11, 2005 (gmt 0)

10+ Year Member



For those that care, I found a solution by re-thinking my transformation. Basically, I did it by having more specific (almost "pull" like) template matches. Probably not the most refined, nor extensible solution, but at least it should suffice for my purposes.

Transformation below:


<xsl:template match="section[@level=1]">
<xsl:element name="section">
<xsl:attribute name="id"><xsl:value-of select="heading"/></xsl:attribute>
<page>
<xsl:attribute name="id">intro</xsl:attribute>
<xsl:apply-templates select="*[not(self::section)]"/>
</page>
<xsl:apply-templates select="section"/>
</xsl:element>
</xsl:template>
<xsl:template match="section[@level=2]">
<!-- If there are no child sections, then there should only be one page -->
<xsl:choose>
<xsl:when test="not(child::section)">
<xsl:element name="page">
<xsl:attribute name="id"><xsl:value-of select="heading"/></xsl:attribute>
<xsl:apply-templates select="*[not(self::section)]"/>
</xsl:element>
</xsl:when>
<xsl:otherwise>
<xsl:element name="section">
<xsl:attribute name="id"><xsl:value-of select="heading"/></xsl:attribute>
<page>
<xsl:attribute name="id">intro</xsl:attribute>
<xsl:apply-templates select="*[not(self::section)]"/>
</page>
<xsl:apply-templates select="section"/>
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="section[@level=3]">
<xsl:element name="page">
<xsl:attribute name="id"><xsl:value-of select="heading"/></xsl:attribute>
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
<xsl:template match="heading">
<h1><xsl:apply-templates/></h1>
</xsl:template>
<xsl:template match="par">
<p><xsl:apply-templates/></p>
</xsl:template>
<xsl:template match="list">
<ul>
<xsl:apply-templates/>
</ul>
</xsl:template>
<xsl:template match="item">
<li><xsl:value-of select="."/></li>
</xsl:template>