Auto increment inside template - xslt

I've the below XML.
<?xml version="1.0" encoding="UTF-8"?>
<uaeccc>
<nd>
<AN>-2-0001</AN>
<h2>Ttle2</h2>
</nd>
<nd>
<h1>Ttle1</h1>
<h2>Ttle2</h2>
<h3>Part 1 Contracts</h3>
<h4>par2 sub contractts</h4>
</nd>
<nd>
<h1>Ttle1</h1>
<h2>Ttle2 </h2>
<h3>Part 1 Contracts</h3>
<h4>Part 2 Sub contracts</h4>
</nd>
<nd>
<h1>Ttle1</h1>
<h2>Ttle2 </h2>
<h3>Part 1 Contracts</h3>
<h4>part 2 sub contracts</h4>
</nd>
</uaeccc>
Here i was trying to increment a number, but it is getting incremented only in that section.
Below is my XSLT.
<xsl:template match="uaeccc">
<xsl:for-each select="nd">
<xsl:apply-templates select="."/>
</xsl:for-each>
</xsl:template>
<xsl:template name="section" match="nd">
<xsl:apply-templates select="./node()[1][self::page]" mode="first"/>
<!-- Variables-->
<xsl:variable name="getChap">
<xsl:value-of select="substring-before(substring-after((//AN)[1],'-'),'-')"/>
</xsl:variable>
<xsl:variable name="count">
<xsl:number level="any"/>
</xsl:variable>
<xsl:variable name="classname">
<!--Get name attribute of current node -->
<xsl:value-of select="concat('section-sect','1')"/>
</xsl:variable>
<xsl:variable name="Chn">
<xsl:value-of select="format-number($getChap,'00')"/>
</xsl:variable>
<xsl:variable name="chapternumber">
<xsl:value-of select="$Chn"/>
</xsl:variable>
<xsl:variable name="sectnum">
<xsl:number level="any" count="section" format="1"/>
</xsl:variable>
<!--Create a string variable by concat string method -->
<xsl:variable name="sectionname">
<xsl:value-of select="concat('CH_',$chapternumber,'-SEC-', $count)"/>
</xsl:variable>
<!-- Template Content -->
<div class="{$classname}">
<a name="{$sectionname}"> </a>
<div class="section-title">
<xsl:apply-templates select="h3"/>
</div>
<xsl:if test="./h4">
<div class="{$classname}">
<a name="{$sectionname}"> </a>
<div class="section-title2">
<xsl:apply-templates select="h4"/>
</div>
</div>
</xsl:if>
<xsl:apply-templates select="child::node()[not(self::h4| self::h3)]"/>
</div>
</xsl:template>
<xsl:template match="AN"/>
<xsl:template match="h1"/>
<xsl:template match="h2"/>
My current output is
<div class="section-sect1">
<a name="CH_02-SEC-1"></a>
<div class="section-title"></div>
</div>
<div class="section-sect1">
<a name="CH_02-SEC-2"></a>
<div class="section-title">
<h3>Part 1 Contracts</h3>
</div>
<div class="section-sect1">
<a name="CH_02-SEC-2"></a>
<div class="section-title2">
<h4>par2 sub contractts</h4>
</div>
</div>
</div>
<div class="section-sect1">
<a name="CH_02-SEC-3"></a>
<div class="section-title">
<h3>Part 1 Contracts</h3>
</div>
<div class="section-sect1">
<a name="CH_02-SEC-3"></a>
<div class="section-title2">
<h4>Part 2 Sub contracts</h4>
</div>
</div>
</div>
<div class="section-sect1">
<a name="CH_02-SEC-4"></a>
<div class="section-title">
<h3>Part 1 Contracts</h3>
</div>
<div class="section-sect1">
<a name="CH_02-SEC-4"></a>
<div class="section-title2">
<h4>part 2 sub contracts</h4>
</div>
</div>
</div>
and expected output is
<div class="section-sect1">
<a name="CH_02-SEC-1"></a>
<div class="section-title"></div>
</div>
<div class="section-sect1">
<a name="CH_02-SEC-2"></a>
<div class="section-title">
<h3>Part 1 Contracts</h3>
</div>
<div class="section-sect1">
<a name="CH_02-SEC-3"></a>
<div class="section-title2">
<h4>par2 sub contractts</h4>
</div>
</div>
</div>
<div class="section-sect1">
<a name="CH_02-SEC-4"></a>
<div class="section-title">
<h3>Part 1 Contracts</h3>
</div>
<div class="section-sect1">
<a name="CH_02-SEC-5"></a>
<div class="section-title2">
<h4>Part 2 Sub contracts</h4>
</div>
</div>
</div>
<div class="section-sect1">
<a name="CH_02-SEC-6"></a>
<div class="section-title">
<h3>Part 1 Contracts</h3>
</div>
<div class="section-sect1">
<a name="CH_02-SEC-7"></a>
<div class="section-title2">
<h4>part 2 sub contracts</h4>
</div>
</div>
</div>
Here i want to increment the number after SEC- every time there is $classnamecalled.But here in my XSLT, the increment occurs but is same in case of subsection also.
please let me know how can i get it fixed.
Here is a Working Demo

I can't make heads or tails of your code. FWIW, the following stylesheet, when applied to your example input, will produce the required output (with the exception of wrapping the result in a single root element):
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/uaeccc">
<root>
<xsl:apply-templates/>
</root>
</xsl:template>
<xsl:template match="nd">
<div class="section-sect1">
<xsl:variable name="sectionnum">
<xsl:number count="nd|h4" level="any"/>
</xsl:variable>
<a name="CH_02-SEC-{$sectionnum}"/>
<div class="section-title">
<xsl:copy-of select="h3"/>
</div>
<xsl:apply-templates select="h4"/>
</div>
</xsl:template>
<xsl:template match="h4">
<div class="section-sect1">
<xsl:variable name="sectionnum">
<xsl:number count="nd|h4" level="any"/>
</xsl:variable>
<a name="CH_02-SEC-{$sectionnum}"/>
<div class="section-title2">
<xsl:copy-of select="."/>
</div>
</div>
</xsl:template>
</xsl:stylesheet>

Related

Conditionally grouping nodes using XSLT 1.0

I'm iterating through a node group using the following:
<xsl:for-each select="NewDataSet/VehicleDetail/Options/Option">
<xsl:choose>
<xsl:when test="string-length(.) > 40">
<div class="large">
<xsl:value-of select="."/>
</div>
</xsl:when>
<xsl:otherwise>
<div class="small">
<xsl:value-of select="."/>
</div>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
What I would like to be able to do is group the large items (40 chars +) and the small items (40 chars and less) something like this:
<div class="largeItems">
<div class="large">Large Item</div>
<div class="large">Large Item</div>
<div class="large">Large Item</div>
<div class="large">Large Item</div>
<div class="large">Large Item</div>
</div>
<div class="smallItems">
<div class="small">Small Item</div>
<div class="small">Small Item</div>
<div class="small">Small Item</div>
<div class="small">Small Item</div>
<div class="small">Small Item</div>
</div>
Thanks.
Try:
<div class="largeItems">
<xsl:for-each select="NewDataSet/VehicleDetail/Options/Option[string-length() > 40]">
<div class="large">
<xsl:value-of select="."/>
</div>
</xsl:for-each>
</div>
<div class="smallItems">
<xsl:for-each select="NewDataSet/VehicleDetail/Options/Option[string-length() <= 40]">
<div class="small">
<xsl:value-of select="."/>
</div>
</xsl:for-each>
</div>
Or, if you prefer less code duplication:
<div class="largeItems">
<xsl:apply-templates select="NewDataSet/VehicleDetail/Options/Option[string-length() > 40]">
<xsl:with-param name="class" select="'large'"/>
</xsl:apply-templates>
</div>
<div class="smallItems">
<xsl:apply-templates select="NewDataSet/VehicleDetail/Options/Option[string-length() > 40]">
<xsl:with-param name="class" select="'small'"/>
</xsl:apply-templates>
</div>
and then:
<xsl:template match="Option">
<xsl:param name="class"/>
<div class="{$class}">
<xsl:value-of select="."/>
</div>
</xsl:template>
Untested because neither input nor context have been provided.

xslt split 1 html into n html

I have a large number of files with a structure like the following a.html:
<html>
<body>
<div class="a">aaa
<div class="b">bbb</div>
<div class="c">ccc1
<div class="d">ddd11
<div class="e">eee11</div>
<div class="f">fff11
<div class="g">ggg111</div>
<div class="g">ggg112</div>
<div class="g">ggg113</div>
<div class="g">ggg114</div>
<div class="g">ggg115</div>
<div class="g">ggg116</div>
</div>
</div>
</div>
<div class="c">ccc2
<div class="d">ddd21
<div class="e">eee21</div>
<div class="f">fff21
<div class="g">ggg211</div>
<div class="g">ggg212</div>
<div class="g">ggg213</div>
<div class="g">ggg214</div>
</div>
</div>
</div>
</div>
</body>
</html>
The number of div class="c" is a known single-digit integer, in this case it is equal to 2.
I would like to generate the files a_1.html and a_2.html, where each file contains the 1st and the 2nd occurrence of the div class="c" respectively.
In this example, I would like to generate a_1.html and a_2.html as follows:
a_1.html
<html>
<body>
<div class="a">aaa
<div class="b">bbb</div>
<div class="c">ccc1
<div class="d">ddd11
<div class="e">eee11</div>
<div class="f">fff11
<div class="g">ggg111</div>
<div class="g">ggg112</div>
<div class="g">ggg113</div>
<div class="g">ggg114</div>
<div class="g">ggg115</div>
<div class="g">ggg116</div>
</div>
</div>
</div>
</div>
</body>
</html>
a_2.html
<html>
<body>
<div class="a">aaa
<div class="b">bbb</div>
<div class="c">ccc2
<div class="d">ddd21
<div class="e">eee21</div>
<div class="f">fff21
<div class="g">ggg211</div>
<div class="g">ggg212</div>
<div class="g">ggg213</div>
<div class="g">ggg214</div>
</div>
</div>
</div>
</div>
</body>
</html>
I have a shell script like the following:
#!/bin/bash
for i in {1..2}
do
xsltproc --param occurrence ${i} a.xslt a.html > a_${i}.html
done
My a.xslt however does not extract just the i-th (first or second in this case) occurrence of div class="c".
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="occurrence"/>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="div[#class='a']">
<xsl:copy>
<xsl:apply-templates select="div[#class='a']" />
<xsl:apply-templates select="#* | div[#class='b'] | text()" />
<xsl:apply-templates select="div[#class='c']" />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
How could I modify it to get the correct result?
Thank you in advance for you help.
If you need to stay with your current approach, you need only to change the call for select="div[#class='c'].
To:
<xsl:apply-templates select="div[#class='c'][position()=$occurrence]" />
But attention:
The <xsl:apply-templates select="div[#class='a']" /> before apply-templates for attributes (#*) is wrong.
Therefor try:
<xsl:template match="div[#class='a']">
<xsl:copy>
<xsl:apply-templates select="#* | div[#class='b'] | text()" />
<xsl:apply-templates select="div[#class='c'][position()=$occurrence]" />
</xsl:copy>
</xsl:template>
Use
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="occurrence"/>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="div[#class='c']">
<xsl:variable name="pos">
<xsl:number count="div[#class = 'c']"/>
</xsl:variable>
<xsl:if test="$pos = $occurrence">
<xsl:copy-of select="."/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>

count the nodes ignoring blank nodes

I've the below XML.
Case 1
<body>
<nd>
<pnn>1.1</pnn>
<h1>PART 54</h1>
<ti>Construction</ti>
</nd>
<nd>
<h1>PART 54</h1>
<h2>I INTRODUCT</h2>
<ti>Time</ti>
</nd>
<nd>
<h1>PART 54</h1>
<h2>I INTRODUCT</h2>
<ti>Power</ti>
</nd>
<nd>
<h1>PART 54</h1>
<h2>II APPLICATIONS</h2>
<ti>Filing</ti>
</nd>
</body>
Case 2
<body>
<nd>
<pnn>1.1</pnn>
<h1>PART 54</h1>
<h2>I INTRODUCT</h2>
<ti>Construction</ti>
</nd>
<nd>
<h1>PART 54</h1>
<h2>I INTRODUCT</h2>
<ti>Time</ti>
</nd>
<nd>
<h1>PART 54</h1>
<h2>II APPLICATIONS</h2>
<ti>Filing</ti>
</nd>
</body>
and the below XSLT
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="html" doctype-public="XSLT-compat" omit-xml-declaration="yes" encoding="UTF-8" indent="yes" />
<xsl:template match="/">
<hmtl>
<head>
<title>New Version!</title>
</head>
<xsl:apply-templates select="body"></xsl:apply-templates>
</hmtl>
</xsl:template>
<xsl:template match="body">
<xsl:for-each select="nd">
<xsl:apply-templates select = "."/>
</xsl:for-each>
</xsl:template>
<xsl:template match="pnn"/>
<xsl:template match="h1"/>
<xsl:template match="h2"/>
<xsl:template match="ti"/>
<xsl:variable name="FinalChap">
<xsl:value-of select="substring-before((//pnn)[1],'.')"/>
</xsl:variable>
<xsl:variable name="FinalChn">
<xsl:value-of select="$FinalChap"/>
</xsl:variable>
<xsl:variable name="Finalchapternumber">
<xsl:value-of select="format-number($FinalChn,'00')"/>
</xsl:variable>
<xsl:template name="section" match="nd">
<xsl:variable name="count">
<xsl:number count="nd" level="any"/>
</xsl:variable>
<xsl:variable name="classname">
<!--Get name attribute of current node -->
<xsl:value-of select="concat('section-sect','1')"/>
</xsl:variable>
<xsl:variable name="classname1">
<!--Get name attribute of current node -->
<xsl:value-of select="concat('section-sect','2')"/>
</xsl:variable>
<xsl:variable name="classname2">
<!--Get name attribute of current node -->
<xsl:value-of select="concat('section-sect','3')"/>
</xsl:variable>
<!--Create a string variable by concat string method -->
<xsl:variable name="sectionname">
<xsl:value-of select="concat('CH_',$Finalchapternumber,'-SEC-', $count)"/>
</xsl:variable>
<div class="{$classname}">
<xsl:if test="./h2 and not(preceding::h2[1]/text() = ./h2/text())">
<a name="{$sectionname}"> </a>
<div class="section-title">
<xsl:if test="not(preceding::h2[1]/text() = ./h2/text())">
<xsl:apply-templates select="h2" mode="section"/>
</xsl:if>
</div>
</xsl:if>
<xsl:if test="not(lower-case(./ti/text()) = lower-case(./h2/text()))">
<xsl:if test="./ti">
<div class="{$classname2}">
<xsl:apply-templates select="ti" mode="section"/>
</div>
</xsl:if>
</xsl:if>
<xsl:apply-templates select="child::node()[not(self::h2|self::ti)]"/>
</div>
</xsl:template>
<xsl:template match="ti" mode="section">
<xsl:apply-templates select="./node()[1][self::page]" mode="first"/>
<xsl:variable name="sectionnum">
<xsl:number count="nd" level="any"/>
</xsl:variable>
<a name="CH_{$Finalchapternumber}-SEC-{$sectionnum}"/>
<div class="section-title">
<xsl:apply-templates/>
</div>
</xsl:template>
<xsl:template match="h2" mode="section">
<div class="section-title">
<xsl:apply-templates select="child::node()[not(self::fnt)]"/>
</div>
</xsl:template>
</xsl:transform>
here I'm trying to increment the section number based on a condition. The count should be done, if there is no node(here h2) <a name="CH_01-SEC-XX"></a> should be ignored I'm able to do it using <xsl:if test="./h2 and not(preceding::h2[1]/text() = ./h2/text())">, but the challenge i'm facing is count is not ignoring it.
Current output. Case 1
<div class="section-sect1">
<a name="CH_01-SEC-1"/>
<div class="section-title">
<div class="section-title">I INTRODUCT</div>
</div>
<div class="section-sect3">
<a name="CH_01-SEC-1"/>
<div class="section-title">Construction</div>
</div>
</div>
<div class="section-sect1">
<div class="section-sect3">
<a name="CH_01-SEC-2"/>
<div class="section-title">Time</div>
</div>
</div>
<div class="section-sect1">
<div class="section-sect3">
<a name="CH_01-SEC-3"/>
<div class="section-title">Power</div>
</div>
</div>
<div class="section-sect1">
<a name="CH_01-SEC-4"/>
<div class="section-title">
<div class="section-title">II APPLICATIONS</div>
</div>
<div class="section-sect3">
<a name="CH_01-SEC-4"/>
<div class="section-title">Filing</div>
</div>
</div>
Expected output Case 1
<div class="section-sect1">
<a name="CH_01-SEC-1"/>
<div class="section-title">
<div class="section-title">I INTRODUCT</div>
</div>
<div class="section-sect3">
<a name="CH_01-SEC-2"/>
<div class="section-title">Construction</div>
</div>
</div>
<div class="section-sect1">
<div class="section-sect3">
<a name="CH_01-SEC-3"/>
<div class="section-title">Time</div>
</div>
</div>
<div class="section-sect1">
<div class="section-sect3">
<a name="CH_01-SEC-4"/>
<div class="section-title">Power</div>
</div>
</div>
<div class="section-sect1">
<a name="CH_01-SEC-5"/>
<div class="section-title">
<div class="section-title">II APPLICATIONS</div>
</div>
<div class="section-sect3">
<a name="CH_01-SEC-6"/>
<div class="section-title">Filing</div>
</div>
</div>
Current Output Case 2
<div class="section-sect1"><a name="CH_01-SEC-1"></a><div class="section-title">
<div class="section-title">I INTRODUCT</div>
</div>
<div class="section-sect3"><a name="CH_01-SEC-1"></a><div class="section-title">Construction</div>
</div>
</div>
<div class="section-sect1">
<div class="section-sect3"><a name="CH_01-SEC-2"></a><div class="section-title">Time</div>
</div>
</div>
<div class="section-sect1"><a name="CH_01-SEC-3"></a><div class="section-title">
<div class="section-title">II APPLICATIONS</div>
</div>
<div class="section-sect3"><a name="CH_01-SEC-3"></a><div class="section-title">Filing</div>
</div>
</div>
Expected output Case 2
<div class="section-sect1">
<a name="CH_01-SEC-1"/>
<div class="section-title">
<div class="section-title">I INTRODUCT</div>
</div>
<div class="section-sect3">
<a name="CH_01-SEC-2"/>
<div class="section-title">Construction</div>
</div>
</div>
<div class="section-sect1">
<div class="section-sect3">
<a name="CH_01-SEC-3"/>
<div class="section-title">Time</div>
</div>
</div>
<div class="section-sect1">
<a name="CH_01-SEC-4"/>
<div class="section-title">
<div class="section-title">II APPLICATIONS</div>
</div>
<div class="section-sect3">
<a name="CH_01-SEC-5"/>
<div class="section-title">Filing</div>
</div>
</div>
in current output there is duplicate CH_01-SEC-1 Can someone please let me know how to make it into a series of 1...n
Here is a working DEmo
Thanks
How about ....
<xsl:transform
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
version="2.0">
<xsl:output method="html" doctype-public="XSLT-compat" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*" />
<xsl:variable name="FinalChap">
<xsl:value-of select="format-number( xs:integer( substring-before((/body/nd/pnn)[1],'.')), '00')"/>
</xsl:variable>
<xsl:template match="/">
<html>
<head><title>New Version from Sean!</title></head>
<xsl:apply-templates />
</html>
</xsl:template>
<xsl:template match="*">
<xsl:apply-templates />
</xsl:template>
<xsl:template match="text()|processing-instruction()|comment()|#*" />
<xsl:template match="body">
<xsl:for-each-group select="nd" group-adjacent="h2/text()">
<xsl:variable name="group-position" select="position()" />
<xsl:for-each select="current-group()">
<xsl:call-template name="nd">
<xsl:with-param name="group-position" select="$group-position" />
<xsl:with-param name="is-head" select="position() eq 1" as="xs:boolean" />
</xsl:call-template>
</xsl:for-each>
</xsl:for-each-group>
</xsl:template>
<xsl:template name="nd">
<xsl:param name="group-position" select="1" as="xs:integer" />
<xsl:param name="is-head" select="true()" as="xs:boolean" />
<div class="section-sect1">
<xsl:if test="$is-head">
<xsl:call-template name="a-link">
<xsl:with-param name="group-position" select="$group-position" />
<xsl:with-param name="delta" select="0" as="xs:integer" />
</xsl:call-template>
<div class="section-title">
<div class="section-title"><xsl:value-of select="h2" /></div>
</div>
</xsl:if>
<div class="section-sect3">
<xsl:call-template name="a-link">
<xsl:with-param name="group-position" select="$group-position" />
<xsl:with-param name="delta" select="1" as="xs:integer" />
</xsl:call-template>
<div class="section-title"><xsl:value-of select="ti" /></div>
</div>
</div>
</xsl:template>
<xsl:template name="a-link">
<xsl:param name="group-position" select="1" as="xs:integer" />
<xsl:param name="delta" select="0" as="xs:integer" />
<a name="CH_{$FinalChap}-SEC-{$group-position + count(preceding-sibling::nd) + $delta}" />
</xsl:template>
</xsl:transform>
The above transform, when applied to input document ...
<body>
<nd>
<pnn>1.1</pnn>
<h1>PART 54</h1>
<h2>I INTRODUCT</h2>
<ti>Construction</ti>
</nd>
<nd>
<h1>PART 54</h1>
<h2>I INTRODUCT</h2>
<ti>Time</ti>
</nd>
<nd>
<h1>PART 54</h1>
<h2>I INTRODUCT</h2>
<ti>Power</ti>
</nd>
<nd>
<h1>PART 54</h1>
<h2>II APPLICATIONS</h2>
<ti>Filing</ti>
</nd>
</body>
... yields output document ...
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>New Version from Sean!</title>
</head>
<div class="section-sect1">
<a name="CH_01-SEC-1"/>
<div class="section-title">
<div class="section-title">I INTRODUCT</div>
</div>
<div class="section-sect3">
<a name="CH_01-SEC-2"/>
<div class="section-title">Construction</div>
</div>
</div>
<div class="section-sect1">
<div class="section-sect3">
<a name="CH_01-SEC-3"/>
<div class="section-title">Time</div>
</div>
</div>
<div class="section-sect1">
<div class="section-sect3">
<a name="CH_01-SEC-4"/>
<div class="section-title">Power</div>
</div>
</div>
<div class="section-sect1">
<a name="CH_01-SEC-5"/>
<div class="section-title">
<div class="section-title">II APPLICATIONS</div>
</div>
<div class="section-sect3">
<a name="CH_01-SEC-6"/>
<div class="section-title">Filing</div>
</div>
</div>
</html>
Explanation
The body template uses the xsl:for-each-group to group the nd elements by common adjacent h2 (h2 headings). The xsl:for-each-group sequence constructor invokes the nd template to process each nd element in order, passing to it the group number, and whether or not this nd is the first (the 'head') nd of the group.
I have inferred from your sample output, that the head nd of each group produces extra content being about the group, including an extra a-link.
The number of the a-link (for example 4 in CH_01-SEC-4) is equal to the count of preceding nd's, plus the group number, plus an extra 1 if we are not a head nd.
Alternative solutions
Just as there are many ways to skin a cat, there a quiet a few alternative solutions which would be equally valid. Instead of grouping, you could use a full push design. The extra content for head nodes (<div class="section-title">) could be achieved using a predicate on the template pattern, comparing this h2 with the previous h2. And the correcting number of the a-links could be achieved by micro-pipelining.

creating a wrapper element for multiple elements with different names and different #class attribute values

I'm have the following flat XML-Structure
<div class="section-level-1">
<!-- other elements -->
<p class="para">
<img src="..." alt="..." title="..." />
</p>
<p class="figure-caption-german">
<img src="..." alt="..." title="..." />
</p>
<p class="figure-caption-english">
<img src="..." alt="..." title="..." />
</p>
<!-- other elements -->
<p class="para">
<img src="..." alt="..." title="..." />
</p>
<p class="figure-caption-german">
<img src="..." alt="..." title="..." />
</p>
<misc-element>...</misc-element>
<p class="figure-caption-english">
<img src="..." alt="..." title="..." />
</p>
</div>
The order of the these elements is always the same (para -> figure-caption-german -> figure-caption-english), however I can't exclude that it will be interrupted by other elements (here the misc-element).
I want to wrap these three elements inside a single element
<div class="section-level-1">
<!-- other elements -->
<div class="figure">
<p class="para">
<img src="..." alt="..." title="..." />
</p>
<p class="figure-caption-german">
<img src="..." alt="..." title="..." />
</p>
<p class="figure-caption-english">
<img src="..." alt="..." title="..." />
</p>
</div>
<!-- other elements -->
<div class="figure">
<p class="para">
<img src="..." alt="..." title="..." />
</p>
<p class="figure-caption-german">
<img src="..." alt="..." title="..." />
</p>
<p class="figure-caption-english">
<img src="..." alt="..." title="..." />
</p>
</div>
</div>
The interrupting element(s) don't need to be preserved and can be deleted.
What I have so far
<xsl:template match="/">
<xsl:apply-templates />
</xsl:template>
<!-- Html Ninja Pattern -->
<xsl:template match="*">
<xsl:element name="{name()}">
<xsl:apply-templates select="* | #* | text()"/>
</xsl:element>
</xsl:template>
<xsl:template match="body//#*">
<xsl:attribute name="{name(.)}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>
<!-- Modify certain elements -->
<xsl:template match="" priority="1">
<!-- do something -->
</xsl:template>
As a basic pattern I draw on the "Html Ninja Technique" (http://getsymphony.com/learn/articles/view/html-ninja-technique/) since it allows me to tackle only those particular elements I need to transform while sending all other elements to the output tree unchanged.
So far everything worked fine, but now I really seemed to hit a road block. I'm not even sure I can accomplish the desired task by relying on the "Html Ninja Technique".
Any help or indication would be highly appreciated.
Best regards and thank you, Matthias Einbrodt
It's a little involved, but I think this should do it:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="*" name="Copy">
<xsl:element name="{name()}">
<xsl:apply-templates select="* | #* | text()"/>
</xsl:element>
</xsl:template>
<xsl:template match="#*">
<xsl:attribute name="{name(.)}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>
<xsl:template match="div[starts-with(#class, 'section-level')]">
<xsl:copy>
<xsl:apply-templates select="#*" />
<!-- Apply templates to paras and anything with no preceding sibling
or with a figure-caption-english preceding sibling-->
<xsl:apply-templates select="p[#class = 'para'] |
*[not(preceding-sibling::*) or
preceding-sibling::*[1][self::p]
[#class = 'figure-caption-english']
]"
mode="iter"/>
</xsl:copy>
</xsl:template>
<xsl:template match="p[#class = 'para']" mode="iter">
<div class="figure">
<xsl:call-template name="Copy" />
<!-- Apply templates to the next english and german figure captions -->
<xsl:apply-templates
select="following-sibling::p[#class = 'figure-caption-german'][1] |
following-sibling::p[#class = 'figure-caption-english'][1]" />
</div>
</xsl:template>
<xsl:template match="*" mode="iter">
<xsl:call-template name="Copy" />
<xsl:apply-templates
select="following-sibling::*[1]
[not(self::p[#class = 'para'])]"
mode="iter"/>
</xsl:template>
</xsl:stylesheet>
When applied to this sample data:
<div class="section-level-1">
<!-- other elements -->
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<p class="para">
<img src="..." alt="..." title="..." />
</p>
<p class="figure-caption-german">
<img src="..." alt="..." title="..." />
</p>
<p class="figure-caption-english">
<img src="..." alt="..." title="..." />
</p>
<!-- other elements -->
<div>hello</div>
<div>hello</div>
<div>hello</div>
<p class="para">
<img src="..." alt="..." title="..." />
</p>
<p class="figure-caption-german">
<img src="..." alt="..." title="..." />
</p>
<misc-element>...</misc-element>
<p class="figure-caption-english">
<img src="..." alt="..." title="..." />
</p>
<div>hello</div>
<div>hello</div>
<div>hello</div>
</div>
It produces:
<div class="section-level-1">
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div class="figure">
<p class="para">
<img src="..." alt="..." title="..." />
</p>
<p class="figure-caption-german">
<img src="..." alt="..." title="..." />
</p>
<p class="figure-caption-english">
<img src="..." alt="..." title="..." />
</p>
</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
<div class="figure">
<p class="para">
<img src="..." alt="..." title="..." />
</p>
<p class="figure-caption-german">
<img src="..." alt="..." title="..." />
</p>
<p class="figure-caption-english">
<img src="..." alt="..." title="..." />
</p>
</div>
<div>hello</div>
<div>hello</div>
<div>hello</div>
</div>
Here's another approach. This one does involve iterating over the child elements of the div, but also makes use of an xsl:key to group the relevant p elements.
Firstly, define a key to group your 'figure-caption' elements by the first most preceding 'para' element:
<xsl:key name="para"
match="p[starts-with(#class, 'figure-caption')]"
use="generate-id(preceding-sibling::p[#class='para'][1])"/>
Then, you start off by matching the div element, and selecting the first element
<xsl:template match="div">
<div>
<xsl:apply-templates select="node()[1]" mode="iterate"/>
</div>
</xsl:template>
The mode iterate is used to indicate the templates that will recursively match their following sibling. You would need firstly need a template to match the 'para' element, where you can use the key to group the relevant elements
<xsl:template match="p[#class='para']" mode="iterate">
<div class="figure">
<xsl:apply-templates select=".|key('para', generate-id())" mode="group"/>
</div>
(The mode group here will be used to indicate that for the grouped elements the matching template will just output them, but not carry on processing at the next sibling. You could use xsl:copy-of here alternatively)
And within this template, you then carry on the iteration by selecting the node after the last element in the group
<xsl:apply-templates
select="key('para', generate-id())[last()]/following-sibling::node()[1]" mode="iterate"/>
Other elements within the iteration can then be matched with a more generic template to copy them, and continue at the next sibling
<xsl:template match="node()" mode="iterate">
<xsl:call-template name="identity"/>
<xsl:apply-templates select="following-sibling::node()[1]" mode="iterate"/>
</xsl:template>
identity here will call the identity template.
Here is the full XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:key name="para" match="p[starts-with(#class, 'figure-caption')]" use="generate-id(preceding-sibling::p[#class='para'][1])"/>
<xsl:template match="div">
<div>
<xsl:copy-of select="#*"/>
<xsl:apply-templates select="node()[1]" mode="iterate"/>
</div>
</xsl:template>
<xsl:template match="p[#class='para']" mode="iterate">
<div class="figure">
<xsl:apply-templates select=".|key('para', generate-id())" mode="group"/>
</div>
<xsl:apply-templates select="key('para', generate-id())[last()]/following-sibling::node()[1]" mode="iterate"/>
</xsl:template>
<xsl:template match="node()" mode="group">
<xsl:call-template name="identity"/>
</xsl:template>
<xsl:template match="node()" mode="iterate">
<xsl:call-template name="identity"/>
<xsl:apply-templates select="following-sibling::node()[1]" mode="iterate"/>
</xsl:template>
<xsl:template match="#*|node()" name="identity">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
When applied to your sample XML, the following is output
<div class="section-level-1">
<!-- other elements -->
<div class="figure">
<p class="para">
<img src="..." alt="..." title="..."/>
</p>
<p class="figure-caption-german">
<img src="..." alt="..." title="..."/>
</p>
<p class="figure-caption-english">
<img src="..." alt="..." title="..."/>
</p>
</div>
<!-- other elements -->
<div class="figure">
<p class="para">
<img src="..." alt="..." title="..."/>
</p>
<p class="figure-caption-german">
<img src="..." alt="..." title="..."/>
</p>
<p class="figure-caption-english">
<img src="..." alt="..." title="..."/>
</p>
</div>
</div>
One advantage of this approach is that you can throw other languages, other than english and german into the mix, and it should still work, and the order of the languages would not matter either. (Of course, you might want to ignore other languages, in which case it wouldn't work!)
A simple XSLT 2.0 solution:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="pClasses" select=
"'para', 'figure-caption-german', 'figure-caption-english'"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*">
<xsl:copy>
<xsl:apply-templates select="#*"/>
<xsl:for-each-group select="p[#class=$pClasses]"
group-starting-with="p[#class eq $pClasses[1]]">
<div class="figure">
<xsl:apply-templates select="current-group()"/>
</div>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the provided XML document:
<div class="section-level-1">
<!-- other elements -->
<p class="para">
<img src="..." alt="..." title="..." />
</p>
<p class="figure-caption-german">
<img src="..." alt="..." title="..." />
</p>
<p class="figure-caption-english">
<img src="..." alt="..." title="..." />
</p>
<!-- other elements -->
<p class="para">
<img src="..." alt="..." title="..." />
</p>
<p class="figure-caption-german">
<img src="..." alt="..." title="..." />
</p>
<misc-element>...</misc-element>
<p class="figure-caption-english">
<img src="..." alt="..." title="..." />
</p>
</div>
the wanted, correct result is produced:
<div class="section-level-1">
<div class="figure">
<p class="para">
<img src="..." alt="..." title="..."/>
</p>
<p class="figure-caption-german">
<img src="..." alt="..." title="..."/>
</p>
<p class="figure-caption-english">
<img src="..." alt="..." title="..."/>
</p>
</div>
<div class="figure">
<p class="para">
<img src="..." alt="..." title="..."/>
</p>
<p class="figure-caption-german">
<img src="..." alt="..." title="..."/>
</p>
<p class="figure-caption-english">
<img src="..." alt="..." title="..."/>
</p>
</div>
</div>
Based upon the solution of JLRishe I got inspired to implement a multi-pass solution to the problem using different template-modes.
Given the following flat XML-Structure
<div class="section-level-1">
<!-- other elements -->
<p class="para">
<img src="..." alt="..." title="..." />
</p>
<p class="figure-caption-german">
<img src="..." alt="..." title="..." />
</p>
<p class="figure-caption-english">
<img src="..." alt="..." title="..." />
</p>
<!-- other elements -->
<p class="para">
<img src="..." alt="..." title="..." />
</p>
<p class="figure-caption-german">
<img src="..." alt="..." title="..." />
</p>
<misc-element>...</misc-element>
<p class="figure-caption-english">
<img src="..." alt="..." title="..." />
</p>
</div>
I applied the following approach.
<xsl:template match="/">
<xsl:variable name="pass0">
<xsl:apply-templates mode="pass0" />
</xsl:variable>
<xsl:variable name="pass1">
<xsl:for-each select="$pass0">
<xsl:apply-templates mode="pass1" />
</xsl:for-each>
</xsl:variable>
<xsl:copy-of select="$pass1" />
</xsl:template>
<!--###############
### Pass 0 ####
###############-->
<xsl:template match="*" mode="pass0">
<xsl:element name="{name()}">
<xsl:apply-templates select="* | #* | text()" mode="pass0"/>
</xsl:element>
</xsl:template>
<xsl:template match="#*" mode="pass0">
<xsl:attribute name="{name(.)}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>
<!-- wraps figures and their associated captions within <div class="figure"> element -->
<xsl:template match="p[#class = 'para'][img]" mode="pass0" priority="1">
<div class="figure">
<xsl:copy-of select="./img" />
<xsl:apply-templates
select="following-sibling::p[#class = 'figure-caption-german'][1] |
following-sibling::p[#class = 'figure-caption-english'][1]"
mode="fig- captions-pass0" />
</div>
</xsl:template>
<xsl:template match="*" mode="fig-captions-pass0" priority="1">
<xsl:copy-of select="." />
</xsl:template>
<!--###############
### Pass 1 ####
###############-->
<xsl:template match="*" mode="pass1">
<xsl:element name="{name()}">
<xsl:apply-templates select="* | #* | text()" mode="pass1"/>
</xsl:element>
</xsl:template>
<xsl:template match="#*" mode="pass1">
<xsl:attribute name="{name(.)}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:template>
<!-- removes all elements with figure captions that don't reside within <div class="figure"> element and all other unnecessary elements -->
<xsl:template match="
p[#class = 'figure-caption-german'][not(parent::div[#class = 'figure'])] |
p[#class = 'figure-caption-english'][not(parent::div[#class = 'figure'])] |
misc-element"
mode="pass1" priority="1" />
As a result I get the desired output
<div class="section-level-1">
<p class="para">normal paragraph etc.</p>
<p class="para">normal paragraph etc.</p>
<p class="para">normal paragraph etc.</p>
<div class="figure">
<img src="..." alt="..." title="..."></img>
<p class="figure-caption-german">
figure caption in german
</p>
<p class="figure-caption-english">
figure caption in english
</p>
</div>
<p class="para">normal paragraph etc.</p>
<p class="para">normal paragraph etc.</p>
<p class="para">normal paragraph etc.</p>
<div class="figure">
<img src="..." alt="..." title="..."></img>
<p class="figure-caption-german">
figure caption in german
</p>
<p class="figure-caption-english">
figure caption in english
</p>
</div>
</div>

XSL apply templates not working...could be XPath error

I have converted mny stylesheet to use apply templates instead of call templates and it worked fine for my other styesheet, which was more complicated, but this one doesn't seem to work even thought it is a much simpler template.
All that it outputs is the sex node and the userlevel node. I think it has to do with my Xpath.
All i want is to output the < user > information, nothing else
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template name="hoo" match="/">
<html>
<head>
<title>Registered Members</title>
<link rel="stylesheet" type="text/css" href="user.css" />
</head>
<body>
<h1>Registered Members</h1>
<xsl:for-each select="folktask/member/user">
<div class="userdiv">
<xsl:apply-templates/>
</div>
</xsl:for-each>
</body>
</html>
</xsl:template>
<xsl:template match="folktask/member/user">
<xsl:apply-templates select="#id"/>
<xsl:apply-templates select="personal/name"/>
<xsl:apply-templates select="personal/address1"/>
<xsl:apply-templates select="personal/city"/>
<xsl:apply-templates select="personal/county"/>
<xsl:apply-templates select="personal/postcode"/>
<xsl:apply-templates select="personal/telephone"/>
<xsl:apply-templates select="personal/mobile"/>
<xsl:apply-templates select="personal/email"/>
<xsl:apply-templates select="personal"/>
<xsl:apply-templates select="account/username"/>
<xsl:apply-templates select="account"/>
</xsl:template>
<xsl:template match="#id">
<div class="heading bold"><h2>USER ID: <xsl:value-of select="." /></h2></div>
</xsl:template>
<xsl:template match="personal/name">
<div class="small bold">NAME:</div>
<div class="large"><xsl:value-of select="." /></div>
</xsl:template>
<xsl:template match="personal/address1">
<div class="small bold">ADDRESS:</div>
<div class="large"><xsl:value-of select="." /></div>
</xsl:template>
<xsl:template match="personal/city">
<div class="small bold">CITY:</div>
<div class="large"><xsl:value-of select="." /></div>
</xsl:template>
<xsl:template match="personal/county">
<div class="small bold">COUNTY:</div>
<div class="large"><xsl:value-of select="." /></div>
</xsl:template>
<xsl:template match="personal/postcode">
<div class="small bold">POSTCODE:</div>
<div class="large"><xsl:value-of select="." /></div>
</xsl:template>
<xsl:template match="personal/telephone">
<div class="small bold">TELEPHONE:</div>
<div class="large"><xsl:value-of select="." /></div>
</xsl:template>
<xsl:template match="personal/mobile">
<div class="small bold">MOBILE:</div>
<div class="large"><xsl:value-of select="." />
</div>
</xsl:template>
<xsl:template match="personal/email">
<div class="small bold">EMAIL:</div>
<div class="large">
<xsl:element name="a">
<xsl:attribute name="href">
<xsl:text>mailto:</xsl:text>
<xsl:value-of select="." />
</xsl:attribute>
<xsl:value-of select="." />
</xsl:element>
</div>
</xsl:template>
<xsl:template match="personal">
<div class="small bold">SEX:</div>
<div class="colored bold">
<xsl:choose>
<xsl:when test="sex='Male'">
<div class="sex male"><xsl:value-of select="sex/."/></div>
</xsl:when>
<xsl:otherwise>
<div class="sex female"><xsl:value-of select="sex/."/></div>
</xsl:otherwise>
</xsl:choose>
</div>
</xsl:template>
<xsl:template match="account/username">
<div class="small bold">USERNAME:</div>
<div class="large"><xsl:value-of select="." /></div>
</xsl:template>
<xsl:template match="account">
<div class="small bold">ACCOUNT TYPE:</div>
<div class="colored ">
<xsl:choose>
<xsl:when test="userlevel='1'">
<div class="nml bold">Normal User</div>
</xsl:when>
<xsl:when test="userlevel='2'">
<div class="vol bold">Volunteer</div>
</xsl:when>
<xsl:when test="userlevel='3'">
<div class="org bold">Organiser</div>
</xsl:when>
<xsl:otherwise>
<div class="name adm bold">Administrator</div>
</xsl:otherwise>
</xsl:choose>
</div>
</xsl:template>
</xsl:stylesheet>
and some of my xml
<?xml version="1.0" encoding="ISO-8859-1" ?>
<?xml-stylesheet type="text/xsl" href="users.xsl"?>
<folktask xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xs:noNamespaceSchemaLocation="folktask.xsd">
<member>
<user id="1">
<personal>
<name>Abbie Hunt</name>
<sex>Female</sex>
<address1>108 Access Road</address1>
<address2></address2>
<city>Wells</city>
<county>Somerset</county>
<postcode>BA5 8GH</postcode>
<telephone>01528927616</telephone>
<mobile>07085252492</mobile>
<email>adrock#gmail.com</email>
</personal>
<account>
<username>AdRock</username>
<password>269eb625e2f0cf6fae9a29434c12a89f</password>
<userlevel>4</userlevel>
<signupdate>2010-03-26T09:23:50</signupdate>
</account>
</user>
<volunteer id="1">
<roles></roles>
<region>South West</region>
</volunteer>
</member>
<member>
<user id="2">
<personal>
<name>Aidan Harris</name>
<sex>Male</sex>
<address1>103 Aiken Street</address1>
<address2></address2>
<city>Chichester</city>
<county>Sussex</county>
<postcode>PO19 4DS</postcode>
<telephone>01905149894</telephone>
<mobile>07784467941</mobile>
<email>ambientexpert#yahoo.co.uk</email>
</personal>
<account>
<username>AmbientExpert</username>
<password>8e64214160e9dd14ae2a6d9f700004a6</password>
<userlevel>2</userlevel>
<signupdate>2010-03-26T09:23:50</signupdate>
</account>
</user>
<volunteer id="2">
<roles>Van Driver,gas Fitter</roles>
<region>South Central</region>
</volunteer>
</member>
</folktask>
The problem is in this code:
<xsl:for-each select="folktask/member/user">
<div class="userdiv">
<xsl:apply-templates/>
</div>
</xsl:for-each>
This applies templates to all children of the current user element -- not to the user element.
As result, the template matching user is not selected.
The children of user are personal and account.
The templates matching these elements are selected and they produce their output.
Solution: Quite some cleanup is necessary, but the first obvious step is to replace the above code with:
<xsl:apply-templates select="folktask/member/user"/>
You'll also have to move the div from the deleted body of <xsl:for-each> into the template matching folktask/member/user.
The corrected XSLT code is:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template name="hoo" match="/">
<html>
<head>
<title>Registered Members</title>
<link rel="stylesheet" type="text/css" href="user.css" />
</head>
<body>
<h1>Registered Members</h1>
<xsl:apply-templates select="folktask/member/user"/>
</body>
</html>
</xsl:template>
<xsl:template match="folktask/member/user">
<div class="userdiv">
<xsl:apply-templates select="#id"/>
<xsl:apply-templates select="personal/name"/>
<xsl:apply-templates select="personal/address1"/>
<xsl:apply-templates select="personal/city"/>
<xsl:apply-templates select="personal/county"/>
<xsl:apply-templates select="personal/postcode"/>
<xsl:apply-templates select="personal/telephone"/>
<xsl:apply-templates select="personal/mobile"/>
<xsl:apply-templates select="personal/email"/>
<xsl:apply-templates select="personal"/>
<xsl:apply-templates select="account/username"/>
<xsl:apply-templates select="account"/>
</div>
</xsl:template>
<xsl:template match="#id">
<div class="heading bold"><h2>USER ID: <xsl:value-of select="." /></h2></div>
</xsl:template>
<xsl:template match="personal/name">
<div class="small bold">NAME:</div>
<div class="large"><xsl:value-of select="." /></div>
</xsl:template>
<xsl:template match="personal/address1">
<div class="small bold">ADDRESS:</div>
<div class="large"><xsl:value-of select="." /></div>
</xsl:template>
<xsl:template match="personal/city">
<div class="small bold">CITY:</div>
<div class="large"><xsl:value-of select="." /></div>
</xsl:template>
<xsl:template match="personal/county">
<div class="small bold">COUNTY:</div>
<div class="large"><xsl:value-of select="." /></div>
</xsl:template>
<xsl:template match="personal/postcode">
<div class="small bold">POSTCODE:</div>
<div class="large"><xsl:value-of select="." /></div>
</xsl:template>
<xsl:template match="personal/telephone">
<div class="small bold">TELEPHONE:</div>
<div class="large"><xsl:value-of select="." /></div>
</xsl:template>
<xsl:template match="personal/mobile">
<div class="small bold">MOBILE:</div>
<div class="large"><xsl:value-of select="." />
</div>
</xsl:template>
<xsl:template match="personal/email">
<div class="small bold">EMAIL:</div>
<div class="large">
<xsl:element name="a">
<xsl:attribute name="href">
<xsl:text>mailto:</xsl:text>
<xsl:value-of select="." />
</xsl:attribute>
<xsl:value-of select="." />
</xsl:element>
</div>
</xsl:template>
<xsl:template match="personal">
<div class="small bold">SEX:</div>
<div class="colored bold">
<xsl:choose>
<xsl:when test="sex='Male'">
<div class="sex male"><xsl:value-of select="sex/."/></div>
</xsl:when>
<xsl:otherwise>
<div class="sex female"><xsl:value-of select="sex/."/></div>
</xsl:otherwise>
</xsl:choose>
</div>
</xsl:template>
<xsl:template match="account/username">
<div class="small bold">USERNAME:</div>
<div class="large"><xsl:value-of select="." /></div>
</xsl:template>
<xsl:template match="account">
<div class="small bold">ACCOUNT TYPE:</div>
<div class="colored ">
<xsl:choose>
<xsl:when test="userlevel='1'">
<div class="nml bold">Normal User</div>
</xsl:when>
<xsl:when test="userlevel='2'">
<div class="vol bold">Volunteer</div>
</xsl:when>
<xsl:when test="userlevel='3'">
<div class="org bold">Organiser</div>
</xsl:when>
<xsl:otherwise>
<div class="name adm bold">Administrator</div>
</xsl:otherwise>
</xsl:choose>
</div>
</xsl:template>
</xsl:stylesheet>
Running the corrected transformation now produces the intended results:
<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=UTF-16">
<title>Registered Members</title>
<link rel="stylesheet" type="text/css" href="user.css">
</head>
<body>
<h1>Registered Members</h1>
<div class="userdiv">
<div class="heading bold"><h2>USER ID: 1</h2></div>
<div class="small bold">NAME:</div>
<div class="large">Abbie Hunt</div>
<div class="small bold">ADDRESS:</div>
<div class="large">108 Access Road</div>
<div class="small bold">CITY:</div>
<div class="large">Wells</div>
<div class="small bold">COUNTY:</div>
<div class="large">Somerset</div>
<div class="small bold">POSTCODE:</div>
<div class="large">BA5 8GH</div>
<div class="small bold">TELEPHONE:</div>
<div class="large">01528927616</div>
<div class="small bold">MOBILE:</div>
<div class="large">07085252492</div>
<div class="small bold">EMAIL:</div>
<div class="large">adrock#gmail.com</div>
<div class="small bold">SEX:</div>
<div class="colored bold">
<div class="sex female">Female</div>
</div>
<div class="small bold">USERNAME:</div>
<div class="large">AdRock</div>
<div class="small bold">ACCOUNT TYPE:</div>
<div class="colored ">
<div class="name adm bold">Administrator</div>
</div>
</div>
<div class="userdiv">
<div class="heading bold"><h2>USER ID: 2</h2></div>
<div class="small bold">NAME:</div>
<div class="large">Aidan Harris</div>
<div class="small bold">ADDRESS:</div>
<div class="large">103 Aiken Street</div>
<div class="small bold">CITY:</div>
<div class="large">Chichester</div>
<div class="small bold">COUNTY:</div>
<div class="large">Sussex</div>
<div class="small bold">POSTCODE:</div>
<div class="large">PO19 4DS</div>
<div class="small bold">TELEPHONE:</div>
<div class="large">01905149894</div>
<div class="small bold">MOBILE:</div>
<div class="large">07784467941</div>
<div class="small bold">EMAIL:</div>
<div class="large">ambientexpert#yahoo.co.uk</div>
<div class="small bold">SEX:</div>
<div class="colored bold">
<div class="sex male">Male</div>
</div>
<div class="small bold">USERNAME:</div>
<div class="large">AmbientExpert</div>
<div class="small bold">ACCOUNT TYPE:</div>
<div class="colored ">
<div class="vol bold">Volunteer</div>
</div>
</div>
</body>
</html>
There are many errors. The main are the following:
You cannot apply template to attribute
If you write <xsl:apply-templates select="personal/name"/>, you might write <xsl:template match="name"> to match it. (And also for other nodes)