在使用XSLT实现这个问题时需要一些帮助,我已经使用SAX解析器实现了这个问题的Java代码,但由于客户要求更改某些东西,这很麻烦。
所以我们现在正在使用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分组为一个元素,例如col 3到4,col 6到8,col 10到11,col 15只有一个,col 19只有一个。提前谢谢。
答案 0 :(得分: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>
答案 1 :(得分: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
并不比他们各自的前任#s
以下第二个表达更微妙一点:
(. | following-sibling::ShotRow)[
not(@col = following-sibling::ShotRow[1]/@col - 1)
][1]/@col
(. | following-sibling::ShotRow)
是当前节点和所有后续兄弟节点的联合 - 我会使用“follow-sibling-or-self”,但不幸的是这样的轴不存在;)@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>
逻辑与上面解释的完全相同。
答案 2 :(得分: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>