I am struggling a bit of XSLT. My (extremely simplified) input looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<doc>
<p>
A <note>a</note>
B <note>b</note>
</p>
<p>
C <note>c</note>
<!-- note the sneaky quote element -->
<q>
D <note>d</note>
</q>
</p>
<p>
E <note>e</note>
</p>
</doc>
I would like to convert this to something like:
<body>
<p>
A <span >1</span>
<span >
<span >1</span>a</span>
B <span >2</span>
<span >
<span >2</span>b</span>
</p>
<p>
C <span >3</span>
<span >
<span >3</span>c</span>
<q>D <span >4</span>
<span >
<span >4</span>d</span>
</q>
</p>
<p>
E <span >5</span>
<span >
<span >5</span>e</span>
</p>
</body>
i.e. the notes are numbered with the order they occur in the document.
The (extremely simplified) code I was using for this is as follows:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" omit-xml-declaration="yes" encoding="utf-8" method="xml"/>
<xsl:template match="p">
<p>
<xsl:apply-templates/>
</p>
</xsl:template>
<xsl:template match="q">
<q>
<xsl:apply-templates />
</q>
</xsl:template>
<xsl:template match="note">
<xsl:variable name="num" select="count(ancestor::p/preceding-sibling::*//note) count(preceding-sibling::note) 1"/>
<span ><xsl:value-of select="$num"/></span>
<span >
<span ><xsl:value-of select="$num"/></span>
<xsl:value-of select="."/>
</span>
</xsl:template>
<xsl:template match="/">
<body>
<xsl:apply-templates/>
</body>
</xsl:template>
</xsl:stylesheet>
That worked okay until someone rudely put a <note>
tag inside a <q>
tag, at which put the numbering was reset, because I can't figure out how to count the preceding things that might be at a different level from the focus node.
As far as I see it I need to do two things:
- count all the notes in preceding paragraphs
- count all prior notes in the current paragraph
Step 1 seems to work okay with count(ancestor::p/preceding-sibling::*//note)
. Step 2 is what I can't figure out.
I'm vaguely aware that position()
will give the count of an element within a particular selection, but I can't see how that will work in the context of my document transformation.
CodePudding user response:
In your template matching note
, use <xsl:number level="any"/>
to get the number you want.