开发者

max value of attribute

开发者 https://www.devze.com 2023-01-20 14:29 出处:网络
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\"/>.

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 ...

0

精彩评论

暂无评论...
验证码 换一张
取 消