分组/移动具有相同属性的节点

时间:2013-12-05 00:36:17

标签: xml xslt

在stackoverflow和其他网站上阅读了5个小时后,我无法为我的问题创建解决方案。很多描述的问题解决方案听起来很熟悉我的问题。但不幸的是,我无法满足我的需求。

我的初始xml文件如下所示:

<document>
  <page>
    <block>
      <line>
        <span string="String1" bottom="12" />
      </line>
    </block>
    <block>
      <line>
        <span string="String2" bottom="12" />
      </line>
    </block>
    <block>
      <line>
        <span string="String3" bottom="12" />
      </line>
    </block>
    <block>
      <line>
        <span string="String4" bottom="20" />
      </line>
    </block>
    <block>
      <line>
        <span string="String5" bottom="20" />
      </line>
    </block>
    <block>
      <line>
        <span string="String6" bottom="30" />
      </line>
    </block>
  </page>
  <page>
    <block>
      <line>
        <span string="String10" bottom="20" />
      </line>
    </block>
    <block>
      <line>
        <span string="String11" bottom="20" />
      </line>
    </block>
    <block>
      <line>
        <span string="String12" bottom="25" />
      </line>
    </block>
  </page>
</document>

我尝试使用xslt达到的结果如下所示:

<document>
  <page>
    <block>
      <line>
        <span string="String1" bottom="12" />
        <span string="String2" bottom="12" />
        <span string="String3" bottom="12" />
      </line>
    </block>
    <block>
      <line>
        <span string="String4" bottom="20" />
        <span string="String5" bottom="20" />
      </line>
    </block>
    <block>
      <line>
        <span string="String6" bottom="30" />
      </line>
    </block>
  </page>
  <page>
    <block>
      <line>
        <span string="String10" bottom="20" />
        <span string="String11" bottom="20" />
      </line>
    </block>
    <block>
      <line>
        <span string="String12" bottom="25" />
      </line>
    </block>
  </page>
</document>

现在我自然而然地说道:

  • 识别块元素
  • 比较:

    following-sibling::*[1]/line/span/@bottom = self::line/span[last()]/@bottom"
    
  • 如果相等 - 将span从“楼下”复制为实际block/line节点下的最后一个节点
  • 删除“旧”span节点
  • 删除整个兄弟,仅由//block/line组成,不再有span

这是寻找有效xslt的一个不好的尝试:

<?xml version="1.0" encoding="UTF8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:output method="xml" indent="yes"/>

    <!-- Identity - copy all other data-->
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>


    <xsl:template match="//block/line">
      <line>
        <xsl:apply-templates select="node()|@*" />
        <xsl:if test="parent::block/following-sibling::*[1]/line/span/@bottom = span[last()]/@bottom">
            <xsl:copy-of select="parent::block/following-sibling::*[1]/line/span" />
            <xsl:apply-templates select="parent::block/following-sibling::*[1]/*" />
        </xsl:if>
      </line>
    </xsl:template>


</xsl:stylesheet>

希望任何人都可以提供帮助! : - )

1 个答案:

答案 0 :(得分:1)

在XSLT2(或3)中,您使用xsl:for-each-group,但在XSLT1中,您可以使用“Muenchian Grouping”执行相同的操作(使用密钥可以避免在每次迭代时检查兄弟姐妹的性能成本)

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:strip-space elements="*"/>
<xsl:output indent="yes"/>

<xsl:key name="b" match="page//span" 
     use="concat(generate-id(ancestor::page[1]),' ',@bottom)"/>

<xsl:template match="*">
 <xsl:copy>
  <xsl:copy-of select="@*"/>
  <xsl:apply-templates/>
 </xsl:copy>
</xsl:template>

<xsl:template match="page">
 <page>
  <xsl:for-each select=".//span[generate-id()=
            generate-id(key('b',
            concat(generate-id(ancestor::page[1]),' ',@bottom))[1])]">
   <block>
    <line>
     <xsl:apply-templates select="key('b',
                  concat(generate-id(ancestor::page[1]),' ',@bottom))"/>
    </line>
   </block>
  </xsl:for-each>
 </page>
</xsl:template>

</xsl:stylesheet>