检查输出中的重复元素
时间: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的工作方式。无副作用编程环境的代价之一是,我们不能做有副作用的事情。那好吧。
在情况下,完成此操作的一种方法是构建一个包含所有源元素列表的变量,这些源元素可以转换为只希望发出一次的输出元素。然后对照此列表检查要转换的每个节点。如果不在列表中,则发出它。如果它是列表中的第一项,请发出它。否则,请不要。