2010-03-08 75 views
1

在使用XSLT实现此需求时需要一些帮助,我已经使用SAX解析器实现了此代码的Java代码,但由于客户请求改变了某些内容。XSLT:分割无继续元素/分组继续元素

所以我们现在正在使用XSLT进行编译,并且不需要编译并部署到Web服务器。我有如下的XML。

实施例1:

<ShotRows> 
    <ShotRow row="3" col="3" bit="1" position="1"/> 
    <ShotRow row="3" col="4" bit="1" position="2"/> 
    <ShotRow row="3" col="5" bit="1" position="3"/> 
    <ShotRow row="3" col="6" bit="1" position="4"/> 
    <ShotRow row="3" col="7" bit="1" position="5"/> 
    <ShotRow row="3" col="8" bit="1" position="6"/> 
    <ShotRow row="3" col="9" bit="1" position="7"/> 
    <ShotRow row="3" col="10" bit="1" position="8"/> 
    <ShotRow row="3" col="11" bit="1" position="9"/> 
</ShotRows> 

输出1:

<ShotRows> 
    <ShotRow row="3" colStart="3" colEnd="11" /> 
</ShotRows> 
<!-- because the col is continuous from 3 to 11 --> 

实施例2:

<ShotRows> 
    <ShotRow row="3" col="3" bit="1" position="1"/> 
    <ShotRow row="3" col="4" bit="1" position="2"/> 
    <ShotRow row="3" col="6" bit="1" position="3"/> 
    <ShotRow row="3" col="7" bit="1" position="4"/> 
    <ShotRow row="3" col="8" bit="1" position="5"/> 
    <ShotRow row="3" col="10" bit="1" position="6"/> 
    <ShotRow row="3" col="11" bit="1" position="7"/> 
    <ShotRow row="3" col="15" bit="1" position="8"/> 
    <ShotRow row="3" col="19" bit="1" position="9"/> 
</ShotRows> 

输出2:

<ShotRows> 
    <ShotRow row="3" colStart="3" colEnd="4" /> 
    <ShotRow row="3" colStart="6" colEnd="8" /> 
    <ShotRow row="3" colStart="10" colEnd="11" /> 
    <ShotRow row="3" colStart="15" colEnd="15" /> 
    <ShotRow row="3" colStart="19" colEnd="19" /> 
</ShotRows> 

其基本思想是将任何连续的列组合到一个元素中,例如col 3到4,col 6到8,col 10到11,col 15只有一个,col 19只有一个。提前致谢。

回答

2

使用Java,你可以使用Saxon 9和XSLT 2.0如下:

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

    <xsl:output indent="yes"/> 

    <xsl:template match="ShotRows"> 
    <xsl:copy> 
     <xsl:for-each-group select="ShotRow" group-adjacent="number(@col) - position()"> 
     <ShotRow row="{@row}" colStart="{@col}" colEnd="{@col + count(current-group()) - 1}"/> 
     </xsl:for-each-group> 
    </xsl:copy> 
    </xsl:template> 

</xsl:stylesheet> 
+0

简单而优雅,+1。:) – Tomalak 2010-03-08 12:34:52

+0

XSLT 2.0也可以通过Saxon.NET在.NET中使用。 – 2010-03-08 13:40:49

+0

我们在java中使用Saxon 9.1 – Gerald 2010-03-08 14:51:43

0

这感觉有点混乱,因为迭代处理通常在XSLT中执行。

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

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

    <xsl:template match="ShotRows"> 
     <xsl:copy> 
      <xsl:apply-templates select="ShotRow[1]" /> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="ShotRow"> 
     <xsl:call-template name="ShotRow"> 
      <xsl:with-param name="start" select="@col" /> 
      <xsl:with-param name="shotrow" select="." /> 
     </xsl:call-template> 
    </xsl:template> 

    <xsl:template name="ShotRow"> 
     <xsl:param name="start" /> 
     <xsl:param name="shotrow" /> 

     <xsl:choose> 
      <xsl:when test="$shotrow/@row = $shotrow/following-sibling::ShotRow[1]/@row and 1 + number($shotrow/@col) = number($shotrow/following-sibling::ShotRow[1]/@col)"> 
       <xsl:call-template name="ShotRow"> 
        <xsl:with-param name="start" select="$start" /> 
        <xsl:with-param name="shotrow" select="$shotrow/following-sibling::ShotRow[1]" /> 
       </xsl:call-template> 

      </xsl:when> 
      <xsl:otherwise> 
       <ShotRow row="{$shotrow/@row}" colStart="{$start}" colEnd="{$shotrow/@col}" /> 
       <xsl:apply-templates select="$shotrow/following-sibling::ShotRow[1]" /> 

      </xsl:otherwise> 
     </xsl:choose> 

    </xsl:template> 

</xsl:stylesheet> 
+0

@Gerald:有一个在我张贴的替代品。 – Tomalak 2010-03-08 11:53:46

1

通过精心设计的XPath表达式,这是一个简单的选择和复制操作。

<xsl:stylesheet 
    version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
> 
    <xsl:template match="ShotRows"> 
    <xsl:copy> 
     <xsl:apply-templates select="ShotRow[ 
     not(preceding-sibling::ShotRow) 
     or 
     not(@col = preceding-sibling::ShotRow[1]/@col + 1) 
     ]" /> 
    </xsl:copy> 
    </xsl:template> 

    <xsl:template match="ShotRow"> 
    <xsl:copy> 
     <xsl:copy-of select="@row" /> 
     <xsl:attribute name="colStart"> 
     <xsl:value-of select="@col" /> 
     </xsl:attribute> 
     <xsl:attribute name="colEnd"> 
     <xsl:value-of select="(. | following-sibling::ShotRow)[ 
      not(@col = following-sibling::ShotRow[1]/@col - 1) 
     ][1]/@col" /> 
     </xsl:attribute> 
    </xsl:copy> 
    </xsl:template> 

</xsl:stylesheet> 

产生您要求的完全相同的输出。第一XPath表达式是:

ShotRow[ 
    not(preceding-sibling::ShotRow) 
    or 
    not(@col = preceding-sibling::ShotRow[1]/@col + 1) 
] 

和它选择所有<ShotRow>节点即

  • 要么没有前身,即在一组
  • 或他们@col第一(或唯一的)一个不完全是一个比他们各自的前任的
  • ERGO更多:这些条件表示一个连续范围的开始
  • 我已经打上所有位置对他们来说,这是#s低于

第二个表达真实更是一点点微妙:

(. | following-sibling::ShotRow)[ 
    not(@col = following-sibling::ShotRow[1]/@col - 1) 
][1]/@col 
  • (. | following-sibling::ShotRow)是当前节点的并集和所有下面的兄弟姐妹—我会使用“以下同胞或自身”,但不幸的是这样的轴不存在;)这些节点的
  • ,它选择其@col的那些不是一个小于各自的继任者的
  • 麦角:该条件表示连续范围的(请注意,此选择提前任何连续范围的所有端)
  • 这些节点
  • ,需要第一个(这是合乎逻辑的,我们感兴趣的是“一个连续范围的第一端”,或者离我们最近的一个)
  • 我已标记为他们这一切职务与#e低于

你的榜样真:

<ShotRows> 
    <ShotRow row="3" col="3" bit="1" position="1"/><!-- #s --> 
    <ShotRow row="3" col="4" bit="1" position="2"/><!-- #e --> 
    <ShotRow row="3" col="6" bit="1" position="3"/><!-- #s --> 
    <ShotRow row="3" col="7" bit="1" position="4"/> 
    <ShotRow row="3" col="8" bit="1" position="5"/><!-- #e --> 
    <ShotRow row="3" col="10" bit="1" position="6"/><!-- #s --> 
    <ShotRow row="3" col="11" bit="1" position="7"/><!-- #e --> 
    <ShotRow row="3" col="15" bit="1" position="8"/><!-- #s #e --> 
    <ShotRow row="3" col="19" bit="1" position="9"/><!-- #s #e --> 
</ShotRows> 

输出:

<ShotRows> 
    <ShotRow row="3" colStart="3" colEnd="4" /> 
    <ShotRow row="3" colStart="6" colEnd="8" /> 
    <ShotRow row="3" colStart="10" colEnd="11" /> 
    <ShotRow row="3" colStart="15" colEnd="15" /> 
    <ShotRow row="3" colStart="19" colEnd="19" /> 
</ShotRows> 

编辑 - 上述修改版本使用XSL密钥。对于大型输入文档,性能增益应该变得明显,主要是因为'kEnd'减少了处理时间。 'kStart'没有太大的影响,我只将它包含在代码对称中。

<xsl:stylesheet 
    version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
> 
    <xsl:key 
    name="kStart" 
    match="ShotRow[ 
     not(preceding-sibling::ShotRow) 
     or 
     not(@col = preceding-sibling::ShotRow[1]/@col + 1) 
    ]" 
    use="generate-id(..)" 
    /> 
    <xsl:key 
    name="kEnd" 
    match="ShotRow[ 
     (. | following-sibling::ShotRow)[ 
     not(@col = following-sibling::ShotRow[1]/@col - 1) 
     ] 
    ]" 
    use="concat(generate-id(..), ':', generate-id())" 
    /> 

    <xsl:template match="ShotRows"> 
    <xsl:copy> 
     <xsl:apply-templates select="key('kStart', generate-id(.))" /> 
    </xsl:copy> 
    </xsl:template> 

    <xsl:template match="ShotRow"> 
    <xsl:copy> 
     <xsl:copy-of select="@row" /> 
     <xsl:attribute name="colStart"> 
     <xsl:value-of select="@col" /> 
     </xsl:attribute> 
     <xsl:attribute name="colEnd">   
     <xsl:value-of select="key('kEnd', 
      concat(generate-id(..), ':', generate-id()) 
     )[1]/@col" /> 
     </xsl:attribute> 
    </xsl:copy> 
    </xsl:template> 

</xsl:stylesheet> 

该逻辑与上面解释的完全相同。

+0

男士感谢您的答案,我们非常感谢。这里有一个问题,我发布的XML只是实际XML的一小部分。我们预计约有1000行和1000列。在性能方面我们应该考虑什么? – Gerald 2010-03-08 12:09:13

+0

@杰拉德:只需测试一下。我的猜测是我的解决方案比@ Lachlan更快,更稳定。此解决方案不使用递归,所以你将永远不会遇到“堆栈溢出”错误(无双关语意)。我可以稍微考虑一下用XSL键改进这个解决方案。 – Tomalak 2010-03-08 12:14:04

+0

@Gerald:如果你发布了一些真实的数字和每个解决方案的性能,我将不胜感激。 – Tomalak 2010-03-08 12:33:35