Forum Moderators: open
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>
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.
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...
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>