2010-10-21 38 views
2

我想将属于<line/>@page属性的值(<section type="cover"/>的后代)更改为<section type="contents"/>(max(@page) + 1)属性的最大值

基本上我需要封面部分的页码比内容部分的最后一个数字页码要高1。

注意:<line/>节点并不总是兄弟,它们可以嵌套在任何级别。

例如改变这个:

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

这样:

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

有没有一种简单的方法与PHP5,XSLT1.0,XPATH实现这一目标?

+0

好问题,+1。请参阅我的回答,以获取完整的解决方案,该解决方案使用XSLT 1.0中最快的已知方式查找最大值。 – 2010-10-21 13:35:06

回答

2

这种转变

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

时所提供的XML文档应用:

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

产生想要的,正确的结果

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

注意事项:所需最大值是使用对所有line元素的page属性进行排序并获取排序节点集中最后一个元素的page属性而生成的。

在XSLT 1.0中,对于所有实际目的,尽管存在O(N * log(N))的复杂度,但找到最大值或最小值的这种方法最快是,而O(N)算法。一切都是一个不变的问题...

+0

+1这样比较好:最多只能找到一次。 – 2010-10-21 13:38:45

+0

+1有用的答案。 “虽然有O(N)对数” - 你是指算法吗?否则我不明白...另外,我想知道是否会有性能优势,可能取决于XSLT处理器,使用''和'position()= 1' 。 – LarsH 2010-10-22 11:52:03

+0

@LarsH:感谢您注意这一点 - 修复。至于是否使用1或last() - 这取决于XSLT处理器的优化能力 - 对于非优化的它们是等效的。 – 2010-10-22 12:54:30

相关问题