检查输出中的重复元素
时间:2020-03-06 14:58:36 来源:igfitidea点击:
我有一些XML,例如,它看起来像这样:
<root>
<field1>test</field1>
<f2>t2</f2>
<f2>t3</f2>
</root>
我想用XSLT对其进行转换,但是我想抑制输出中的第二个f2元素,当处理源中的第二个f2元素时,如何在模板内部检查输出中是否已经存在f2元素?我的XSLT目前看起来像这样:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="no" omit-xml-declaration="yes" standalone="no" />
<xsl:template match="/">
<xsl:for-each select="./root">
<output>
<xsl:apply-templates />
</output>
</xsl:for-each>
</xsl:template>
<xsl:template match="*" >
<xsl:element name="{name(.)}">
<xsl:value-of select="." />
</xsl:element>
</xsl:template>
</xsl:stylesheet>
我需要围绕模板中的xsl:element进行某种检查,但是我不确定如何查询输出文档以查看元素是否已存在。
编辑:忘记了pre标签,代码现在应该可见了!
解决方案
这取决于我们要达到的系统范围。
也就是说,我们是否只关注属于同一父元素的子元素,或者是同一级别的所有元素(如果愿意,可以使用'cousins')或者文档中任何位置的元素...
在第一种情况下,我们可以检查前一个同级轴,以查看是否存在其他具有相同名称的元素。
<xsl:if test="count(preceding-sibling::node()[name()=name(current())])=0"> ... do stuff in here. </xsl:if>
仅检查(并警告我们有重复),我们可以在此处找到示例
类似于以下内容:
<xsl:for-each-group select="collection(...)//@id" group-by=".">
<xsl:if test="count(current-group()) ne 1">
<xsl:message>Id value <xsl:value-of select="current-grouping-key()"/> is
duplicated in files
<xsl:value-of select="current-group()/document-uri(/)" separator=" and
"/></xsl:message>
</xsl:if>
</xsl:for-each-group>
要修改以选择"根"元素内的所有节点。
至于删除重复的行,我们在这里还有另一个示例
看起来像:
<xsl:stylesheet>
<xsl:key name="xyz" match="record[x/y/z]" use="x/y/z" />
<xsl:variable name="noxyzdups" select="/path/to/record[generate-id(.) = generate-id(key('xyz', x/y/z))]" />
...
<xsl:template ... >
<xsl:copy-of "exslt:node-set($noxyzdups)" />
</xsl:template>
</xsl:stylesheet>
x / y / z是我们要使其唯一的xpath表达式。它可以是concat(x,'-',@ y,'-',z)或者任何我们想要的。
现在,我不确定这两个示例是否可以轻松地适应情况,但我只是想指出这两个来源,以防万一。
无法询问转换的输出。也无法跟踪转换的当前状态(即跟踪变量中已发出的节点)。从根本上讲,这不是XSLT的工作方式。无副作用编程环境的代价之一是,我们不能做有副作用的事情。那好吧。
在情况下,完成此操作的一种方法是构建一个包含所有源元素列表的变量,这些源元素可以转换为只希望发出一次的输出元素。然后对照此列表检查要转换的每个节点。如果不在列表中,则发出它。如果它是列表中的第一项,请发出它。否则,请不要。

