检查OUTPUT中的重复元素

时间:2008-10-01 13:55:12

标签: xml xslt xslt-1.0

我有一些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:元素进行某种检查,但是我不确定如何查询输出文档以查看元素是否已经存在。

编辑:忘记预标记,代码现在应该可见了!

3 个答案:

答案 0 :(得分:7)

这取决于你想要的系统范围。

即。您是否只关注同一父级的子元素,或同一级别的所有元素(如果您愿意,可以使用“堂兄弟”)或文档中任何位置的元素......

在第一种情况下,您可以检查前一个兄弟轴,看看是否存在同名的任何其他元素。

<xsl:if test="count(preceding-sibling::node()[name()=name(current())])=0">
  ... do stuff in here.
</xsl:if>

答案 1 :(得分:1)

要仅检查(并警告您重复),您可能会找到example here

有些事情:

<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>

要修改以选择“root”元素中的所有节点。

至于删除重复的行,您还有另一个example here

这看起来像是:

<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)或任何你想要的。

现在我不确定这两个例子是否可以很容易地适应你的情况,但我只是想指出这两个来源,万一它有所帮助。

答案 2 :(得分:1)

无法询问转换的输出。也无法跟踪转换的当前状态(即跟踪您在变量中发出的节点)。从根本上说,这不是XSLT的工作原理。无副作用的编程环境的成本之一是你不能做有副作用的事情。哦,好吧。

在您的情况下,实现此目的的一种方法是构建一个变量,该变量包含可以转换为您只想发出一次的输出元素的所有源元素的列表。然后检查您正在针对此列表进行转换的每个节点。如果它不在列表中,则发出它。如果它是列表中的第一个项目,则将其发出。否则,不要。