Reputation: 125
sorry to ask this question again. i got some problem when i am using the answer for my previous question. suppose my xml like this,
<comp>
<section id="1">
<p>text</p>
<figure xml:id="c1-fig-002"/>
<p>text</p>
<figure xml:id="c1-fig-003"/>
</section>
<section id="2">
<p>text</p>
<figure xml:id="c1-fig-003"/>
<figure xml:id="c1-fig-004" resumeNumberingAt="7"/>
<figure xml:id="c1-fig-005"/>
<p>text</p>
</section>
<section id="3">
<p>text</p>
<figure xml:id="c1-fig-006"/>
<figure xml:id="c1-fig-007" resumeNumberingAt="18"/>
<p>text</p>
<figure xml:id="c1-fig-008"/>
<p>text</p>
<figure xml:id="c1-fig-009"/>
</section>
</comp>
i'm using xslt to get the following result,
<comp>
<section id="1">
<p>text</p>
<figure xml:id="c1-fig-002"/>
<fignum>2</fignum>
<p>text</p>
<figure xml:id="c1-fig-003"/>
<fignum>3</fignum>
</section>
<section id="2">
<p>text</p>
<figure xml:id="c1-fig-003"/>
<fignum>3</fignum>
<figure xml:id="c1-fig-004" resumeNumberingAt="7"/>
<fignum>7</fignum>
<figure xml:id="c1-fig-005"/>
<fignum>8</fignum>
<p>text</p>
</section>
<section id="3">
<p>text</p>
<figure xml:id="c1-fig-006"/>
<fignum>9</fignum>
<figure xml:id="c1-fig-007" resumeNumberingAt="18"/>
<fignum>18</fignum>
<p>text</p>
<figure xml:id="c1-fig-008"/>
<fignum>19</fignum>
<p>text</p>
<figure xml:id="c1-fig-009"/>
<fignum>20</fignum>
</section>
</comp>
i need to take value from the number that's come after fig that's 2
from c1-fig-002
.
if there's a attribute resumeNumberingAt then i need to use that value instead of the normal value and increment the value for the following node. i used the following xslt to do this but it's not working.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="figure[@resumeNumberingAt != '']">
<xsl:call-template name="fig">
<xsl:with-param name="sequence" select="@resumeNumberingAt"/>
</xsl:call-template>
</xsl:template>
<xsl:template match ="section">
<!--some operation-->
</xsl:template>
<xsl:template match ="p">
<!--some operation-->
</xsl:template>
<xsl:template match="figure" name="fig">
<xsl:param name="sequence" select="substring(@xml:id, 10, 1)"/>
<figure>
<xsl:apply-templates select="@*"/>
<fignum>
<xsl:value-of select="$sequence"/>
</fignum>
</figure>
<xsl:apply-templates select="following-sibling::figure[1]">
<xsl:with-param name="sequence" select="$sequence + 1"/>
</xsl:apply-templates>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Upvotes: 0
Views: 357
Reputation: 12729
This XSLT 1.0 style-sheet...
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="figure">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
<fignum>
<xsl:variable name="base-node" select="
((preceding::figure[@resumeNumberingAt] |
self ::figure[@resumeNumberingAt] )[last()] |
self ::figure)[1]" />
<xsl:variable name="base">
<xsl:apply-templates select="$base-node" mode="numbering" />
</xsl:variable>
<xsl:variable name="prev-figs" select="preceding::figure" />
<xsl:variable name="prev-fig-count" select="count($prev-figs)" />
<xsl:value-of select="$base +
count(($base-node/following::figure|$base-node)
[count(. | $prev-figs) = $prev-fig-count])" />
</fignum>
</xsl:template>
<xsl:template match="figure[@resumeNumberingAt]" mode="numbering">
<xsl:value-of select="@resumeNumberingAt" />
</xsl:template>
<xsl:template match="figure" mode="numbering">
<xsl:value-of select="substring(@xml:id, 8, 3)" />
</xsl:template>
</xsl:stylesheet>
... takes your sample input document and yields the stated expected output document. This solution was tested successfully on the Microsoft XslCompiledTransform XSLT engine
In the mode-less figure template, we will copy the input figure element and create the following fignum element. The variable $base-node will be the base node from which we base the figure number on. Looking at the detail, this expression ...
(preceding::figure[@resumeNumberingAt] |
self ::figure[@resumeNumberingAt] )[last()]
... will refer to the nearest previous figure element with an @resumeNumberingAt attribute, or this one (the focus node) if this one has an @resumeNumberingAt attribute. Generally, this will be our base for counting the fignum. However an exception is when the focus node is before the first @resumeNumberingAt. In this case we are going to base the counting off the context node (via the xml:id attribute). Thus we can find the base node, in all cases, without any awkward xsl:if statements with this expression...
((preceding::figure[@resumeNumberingAt] |
self ::figure[@resumeNumberingAt] )[last()] |
self ::figure)[1]
Now to calculate the base number. We have the base node. If it has a @resumeNumberingAt attribute, then that is the base number, otherwise it is based off the @xml:id attribute. Rather that doing an explicit test, we can simply leverage the template selection mechanism with a mode, to calculate the base number. For example, for node...
<figure xml:id="c1-fig-006"/>
... the base node is...
<figure xml:id="c1-fig-004" resumeNumberingAt="7"/>
... and therefore the base number is 7. Later will need to offset this by +2 to get the required fignum of 9. In contrast, for node...
<figure xml:id="c1-fig-003"/>
... the base node is itself and the base value is 3 ('003' converted to an integer). Later will need to offset this by +0 to get the required fignum of 3.
The variable $prev-figs is the set of figure elements previous to this one. So now we calculate the fignum by offsetting the base fignum by the count of figures inbetween the base node and the focus node (including base node, but excluding focus node). This offset is the intersection between two sets:
(1) the figures following (and including) the base node; and
(2) the figures previous to the focus node.
In XSLT 1.0, the general method for computing the intersection of two sets is ...
$node-set1[count(. | $node-set2) = count($node-set2)]
... and that's exactly what we do with this instruction...
<xsl:value-of select="$base +
count(($base-node/following::figure|$base-node)
[count(. | $prev-figs) = $prev-fig-count])" />
The following general principles were employed:
Upvotes: 1