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>
Related
I have a large number of html files with the following structure:
<html>
<head>
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />
<title>t</title>
</head>
<body>
<div class="a">
<div class="i">i</div>
<div class="b">b1
<div class="b1">b11</div>
<div class="b2">b12</div>
</div>
<div class="j">j</div>
<div class="b">b2
<div class="b1">b21</div>
<div class="b2">b22</div>
</div>
<div class="k">k</div>
</div>
<div class="x">
<div class="i">i3</div>
<div class="b">b3
<div class="b1">b31</div>
<div class="b2">b32</div>
</div>
<div class="j">j3</div>
</div>
</body>
</html>
I would like to:
move all siblings of b inside b
remove parent a but keep its content
Please notice that:
div class="a" has not text()
div class="b" can have other parents apart from div class="a", for instance div class="x"
div class="a" can contain 1:N div class="b"
The output should be like the following:
<html>
<head>
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />
<title>t</title>
</head>
<body>
<div class="b">b1
<div class="b1">b11</div>
<div class="b2">b12</div>
<div class="i">i</div>
<div class="j">j</div>
<div class="k">k</div>
</div>
<div class="b">b2
<div class="b1">b21</div>
<div class="b2">b22</div>
<div class="i">i</div>
<div class="j">j</div>
<div class="k">k</div>
</div>
<div class="x">
<div class="i">i3</div>
<div class="b">b3
<div class="b1">b31</div>
<div class="b2">b32</div>
</div>
<div class="j">j3</div>
</div>
</body>
</html>
I am using a shell script similar to the following:
xsltproc a.xslt a.html > b.html
where a.xslt is as follows:
<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:template match="node()|#*" name="identity">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="div[#class='a']/div[#class='b']">
<xsl:apply-templates select="#*|preceding-sibling()[not(self::div[#class='b'])]"/>
<xsl:apply-templates select="#*|following-sibling()[not(self::div[#class='b'])]"/>
<xsl:copy-of select="div[#class='b']"/>
</xsl:template>
</xsl:stylesheet>
However I get an error, probably because I am not using preceding-sibling and following-sibling correctly:
xmlXPathCompOpEval: function preceding-sibling not found
Could you advise me on how to untangle this xslt please?
I believe this follows your instructions:
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="*"/>
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<!-- remove parent a but keep its content -->
<xsl:template match="div[#class='a']">
<xsl:apply-templates/>
</xsl:template>
<!-- move all siblings of b inside b -->
<xsl:template match="div[#class='b']">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
<xsl:copy-of select="../node()[not(self::div[#class='b'])]"/>
</xsl:copy>
</xsl:template>
<!-- do not process siblings of b -->
<xsl:template match="node()[../div[#class='b']][not(self::div[#class='b'])]"/>
</xsl:stylesheet>
However, the result is not what you show:
<html>
<head>
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type"/>
<title>t</title>
</head>
<body>
<div class="b">b1
<div class="b1">b11</div>
<div class="b2">b12</div>
<div class="i">i</div>
<div class="j">j</div>
<div class="k">k</div>
</div>
<div class="b">b2
<div class="b1">b21</div>
<div class="b2">b22</div>
<div class="i">i</div>
<div class="j">j</div>
<div class="k">k</div>
</div>
<div class="x">
<div class="b">b3
<div class="b1">b31</div>
<div class="b2">b32</div>
<div class="i">i3</div>
<div class="j">j3</div>
</div>
</div>
</body>
</html>
I have a large number of html files like the following:
<html>
<head>
<title>t</title>
</head>
<body>
<div class="a">
<div class="b" type="t1">
b11<div class="x">x</div>
b12<div class="y">y</div>b13
</div>
<div class="c">c</div>
</div>
<div class="b" type="t2" region="r">b21
<div class="x">x</div>b22
<div class="y">y</div>
b23
</div>
</body>
</html>
At present the text for div class="b" is fragmented at the beginning, middle and end of the node.
I want to consolidate the text for div class="b" so that it appears at the beginning.
The file I want to obtain is like the following:
<html>
<head>
<title>t</title>
</head>
<body>
<div class="a">
<div class="b" type="t1">b11 b12 b13
<div class="x">x</div>
<div class="y">y</div>
</div>
<div class="c">c</div>
</div>
<div class="b" type="t2" region="r">b21 b22 b23
<div class="x">x</div>
<div class="y">y</div>
</div>
</body>
</html>
I run the following bash script a.sh:
xsltproc a.xslt a.html > b.html
where a.xslt is the following:
<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:template match="node()|#*" name="identity">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="//div[#class='b']">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
<xsl:for-each select="text()">
<xsl:if test="position() > 1"><xsl:text> </xsl:text></xsl:if>
<xsl:value-of select="normalize-space(.)"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Unfortunately my output is not what I want:
<html>
<head>
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />
<title>t</title>
</head>
<body>
<div class="a">
<div class="b" type="t1">b11
<div class="x">x</div>
b12
<div class="y">y</div>
b13</div>
b11 b12 b13
<div class="c">c</div>
</div>
<div class="b" region="r" type="t2">b21
<div class="x">x</div>
b22
<div class="y">y</div>
b23</div>
<p>b21 b22 b23</p>
</body>
</html>
Do you have any advice on how to proceed please?
Would this work for you?
<xsl:template match="div[#class='b']">
<xsl:copy>
<xsl:apply-templates select="#*"/>
<xsl:for-each select="text()">
<xsl:if test="position() > 1">
<xsl:text> </xsl:text>
</xsl:if>
<xsl:value-of select="normalize-space(.)"/>
</xsl:for-each>
<xsl:apply-templates select="*"/>
</xsl:copy>
</xsl:template>
I have the following source a.html:
<html>
<head>
<title>title</title>
</head>
<body>
<div class="a">a
<div class="a1">a1</div>
<div class="x" type="typea2">x
<div class="x1">x1</div>
</div>
<div class="a3">a3</div>
</div>
<div class="b">b_1
<div class="b1">b1_1</div>
<div class="b3">b3_11</div>
<div class="b3">b3_12</div>
<div class="b3">b3_13</div>
</div>
<div class="b">b_2
<div class="b1">b1_2</div>
<div class="b3">b3_21</div>
<div class="b3">b3_22</div>
<div class="b">b_3
<div class="b1">b1_3</div>
<div class="b3">b3_31</div>
<div class="b3">b3_32</div>
<div class="b3">b3_33</div>
<div class="b3">b3_34</div>
</div>
</body>
</html>
I want to:
copy the element div class="x" inside each div class="b" after its own text and any div class="b1"
remove the original div class="x" from div class="a"
The output should be:
<html>
<head>
<title>title</title>
</head>
<body>
<div class="a">a
<div class="a1">a1</div>
<div class="a3">a3</div>
</div>
<div class="b">b_1
<div class="b1">b1_1</div>
<div class="x" type="typea2">x
<div class="x1">x1</div>
</div>
<div class="b3">b3_11</div>
<div class="b3">b3_12</div>
<div class="b3">b3_13</div>
</div>
<div class="b">b_2
<div class="b1">b1_2</div>
<div class="x" type="typea2">x
<div class="x1">x1</div>
</div>
<div class="b3">b3_21</div>
<div class="b3">b3_22</div>
<div class="b">b_3
<div class="b1">b1_3</div>
<div class="x" type="typea2">x
<div class="x1">x1</div>
</div>
<div class="b3">b3_31</div>
<div class="b3">b3_32</div>
<div class="b3">b3_33</div>
<div class="b3">b3_34</div>
</div>
</body>
</html>
I have used the following shell script a.sh:
xsltproc --html a.xslt a.html > b.html
with the following a.xslt:
<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:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<!-- ignore x-inside-a -->
<xsl:template match="//div[#class='a']/div[#class='x']"/>
<!-- place the x-inside-a into each b after text() and b1 -->
<xsl:template match="div[#class='b']">
<xsl:copy>
<xsl:copy-of select="//div[#class='a']/div[#class='x']" />
<xsl:apply-templates />
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
However I am not getting the desired result?
Could I ask for your help please?
If the inner div is always present I would write a template for it:
<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:template match="node()|#*" name="identity">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<!-- ignore x-inside-a -->
<xsl:template match="div[#class='a']/div[#class='x']"/>
<!-- place the x-inside-a into each b after b1 -->
<xsl:template match="div[#class='b']/div[#class = 'b1']">
<xsl:call-template name="identity"/>
<xsl:copy-of select="//div[#class='a']/div[#class='x']" />
</xsl:template>
</xsl:stylesheet>
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.
I'm trying to do the following:
<body>
<div>
<p> text<note/>texttext<note/>text </p>
<p> text<note/>text </p>
</div>
<div>
text<note/>texttext<note/>text
</div>
</body>
should result in
<body>
<div>
<p> text<note n="1"/>texttext<note n="2"/>text </p>
<p> text<note n="3"/>text </p>
</div>
<div>
text<note n="1"/>texttext<note n="2"/>text
</div>
</body>
As you can see, I want to number all notes under div regardless of the parent node. So notes can be structured under div in any way.
However I can't figure out a solution by using xsl:number. Any help would be appreciated.
edit: Big thanks to DRCB for his solution. I've adapted it so that it can be also used for complex nesting by using an identity template.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="div//note">
<note>
<xsl:attribute name="n">
<xsl:value-of select="count(preceding::note) - count(preceding::div//note) + 1"/>
</xsl:attribute>
<xsl:value-of select="."/>
</note>
</xsl:template>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
tranforms:
<body>
<any>
<div>
<p>
<p> text<note/>texttext<note/>text </p>
</p>
<p> text<note/>text </p>
</div>
</any>
<div> text<note/>texttext<note/>text </div>
</body>
to:
<body>
<any>
<div>
<p>
<p> text<note n="1"/>texttext<note n="2"/>text </p>
</p>
<p> text<note n="3"/>text </p>
</div>
</any>
<div> text<note n="1"/>texttext<note n="2"/>text </div>
</body>
I believe there might be a better solution however this works for me.
A solution using xsl:number:
<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:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="note">
<xsl:variable name="vNum">
<xsl:number level="any" count="note" from="/*/div"/>
</xsl:variable>
<note n="{$vNum}">
<xsl:apply-templates/>
</note>
</xsl:template>
</xsl:stylesheet>
When this transformation is applied on the provided XML document:
<body>
<div>
<p> text<note/>texttext<note/>text </p>
<p> text<note/>text </p>
</div>
<div>
text<note/>texttext<note/>text
</div>
</body>
the wanted, correct result is produced:
<body>
<div>
<p> text<note n="1"/>texttext<note n="2"/>text </p>
<p> text<note n="3"/>text </p>
</div>
<div>
text<note n="1"/>texttext<note n="2"/>text
</div>
</body>
Explanation: Appropriate use of the from attribute of xsl:number.
I have found following quick workaround:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!-- Edited by http://www.w3schools.com/xsl/tryxslt.asp?xmlfile=cdcatalog&xsltfile=cdcatalogp -->
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="div">
[div <xsl:apply-templates/>]
</xsl:template>
<xsl:template match="note">
[note n=<xsl:value-of select="count(preceding::note) - count(preceding::div//note) + 1"/>]
</xsl:template>
</xsl:stylesheet>
It works however only with "plain" div structure without a complex nesting.
You can test it here: http://www.w3schools.com/xsl/tryxslt.asp?xmlfile=cdcatalog&xsltfile=cdcatalog with your source xml.