I want to change the values of the @page
attributes of <line/>
that are descendants of <section type="cover"/>
to (max(@page) + 1)
of <section type="contents"/>
.
Basically I need the page number for the cover section to be 1 higher than the last numeric page number of the contents section.
Note: <line/>
nodes are not always siblings, they can be nested at any level.
For example transform this:
<root>
<section type="contents">
<line page="i">text</line>
<line page="ii">text</line>
<line page="1">text</line>
<line page="1">text</line>
<line page="2">text</line>
<block>
<line page="3">text</line>
<line page="4">text</line>
</block>
</section>
<section type="cover">
<line page="i">text</line>
&开发者_JAVA技巧lt;line page="i">text</line>
</section>
</root>
to this:
<root>
<section type="contents">
<line page="i">text</line>
<line page="ii">text</line>
<line page="1">text</line>
<line page="1">text</line>
<line page="2">text</line>
<block>
<line page="3">text</line>
<line page="4">text</line>
</block>
</section>
<section type="cover">
<line page="5">text</line> <!-- @page changes to max()+1 -->
<line page="5">text</line> <!-- @page changes to max()+1 -->
</section>
</root>
Is there an easy way to achieve this with PHP5, XSLT1.0, XPATH?
This transformation:
<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:variable name="vMax">
<xsl:for-each select="/*/*//line/@page">
<xsl:sort data-type="number"/>
<xsl:if test="position() = last()">
<xsl:value-of select="."/>
</xsl:if>
</xsl:for-each>
</xsl:variable>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="section[@type='cover']/line/@page">
<xsl:attribute name="page">
<xsl:value-of select="$vMax+1"/>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
when applied on the provided XML document:
<root>
<section type="contents">
<line page="i">text</line>
<line page="ii">text</line>
<line page="1">text</line>
<line page="1">text</line>
<line page="2">text</line>
<block>
<line page="3">text</line>
<line page="4">text</line>
</block>
</section>
<section type="cover">
<line page="i">text</line>
<line page="i">text</line>
</section>
</root>
produces the wanted, correct result:
<root>
<section type="contents">
<line page="i">text</line>
<line page="ii">text</line>
<line page="1">text</line>
<line page="1">text</line>
<line page="2">text</line>
<block>
<line page="3">text</line>
<line page="4">text</line>
</block>
</section>
<section type="cover">
<line page="5">text</line>
<line page="5">text</line>
</section>
</root>
Do note: The required maximum is produced using sorting on the page
attribute of all line
elements and taking the page
attribute of the last element in the sorted node-set.
In XSLT 1.0 for all practical purposes this way of finding a maximum or a minimum is the fastest, although it has a complexity of O(N*log(N)), while there are O(N) algorithms. Everything is a matter of a constant ...
精彩评论