使用XSLT删除具有不同值/属性的重复节点

时间:2015-11-15 18:23:51

标签: xml xslt

我正在尝试对导出的一组XML文件执行XSL 1.0转换,并在其他地方转换具有重复节点的文件 - 我能够删除相同的重复节点,但不能删除具有不同的值/属性。 我想要实现的只是保留第二组错误节点。感谢任何有助于理解我出错的地方!

一组XML文件包含如下数据:

<row xmlns="http://www.example.com/abc/xyz" xmlns:dg="http://www.example.com/abc/def" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <data>
    <status>Y</status>
    <product>48530</product>
    <id>12312343</id>
    <error xmlns="">true</error>
    <errorReason xmlns="">Detailed error message</errorReason>
    <error xmlns="">true</error>
    <errorReason xmlns="">Detailed error message</errorReason>
  </data>
</row>

使用以下XSL时,将删除重复项:

<xsl:stylesheet version="1.0" exclude-result-prefixes="xsi d dg" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:d="http://www.example.com/abc/xyz" 
xmlns:dg="http://www.example.com/abc/def" >
<xsl:output omit-xml-declaration="yes" method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

  <xsl:template match="node()|@*">
    <xsl:copy>
      <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="comment()"/>

  <!-- Drill down into the export XML and extract only the main table row data -->
  <xsl:template match="d:row">
    <xsl:apply-templates select="d:data"/>
  </xsl:template>

  <xsl:template match="error[preceding::error]"/>
  <xsl:template match="errorReason[preceding::errorReason]"/>

</xsl:stylesheet>

但是,当我为一组XML文件尝试相同的XSL时,如下所示:

<row xmlns="http://www.example.com/abc/xyz" xmlns:dg="http://www.example.com/abc/def" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <data>
    <status>Y</status>
    <product>130160072014</product>
    <dob>11/11/1911</dob>
    <id>12312312</id>
    <error>false</error>
    <errorReason />
    <error xmlns="">true</error>
    <errorReason xmlns="">Detailed error message</errorReason>
  </data>
</row>
什么都没发生。

我怀疑空 xmlns 可能是原因,但我不太确定。

1 个答案:

答案 0 :(得分:1)

这是因为命名空间。 xmlns是名称空间声明。在您的第一个XML中,errorerrorreason元素都声明了xmlns="",这意味着它们都没有名称空间。

但是,在第二个XML中,您可以执行此操作:

<error>false</error>
<errorReason />
<error xmlns="">true</error>
<errorReason xmlns="">Detailed error message</errorReason>

第一个errorerrorReason没有明确的xmlns,这意味着它们位于row元素<上定义的默认命名空间中/ p>

 <row xmlns="http://www.example.com/abc/xyz" 

该声明不仅适用于row元素,也适用于其后代,除非被覆盖。

这意味着第一个errorerrorReason与另外两个名称空间不同(实际上并不在命名空间中),因此它们实际上是不同的。它们与您的XSLT模板不匹配,因为模板仅匹配无命名空间中的元素。

您还没有说过要保留哪一对元素。命名空间中的那些,或没有命名空间的那些。但是,如果你真的想要删除“重复”而不管命名空间如何,你可以使用这两个模板,它们只是完全忽略命名空间(因此将保留第一个元素,在你的例子中位于命名空间中)。 p>

<xsl:template match="*[local-name() = 'error'][preceding::*[local-name() = 'error']]"/>
<xsl:template match="*[local-name() = 'errorReason'][preceding::*[local-name() = 'errorReason']]"/>