XSLT删除具有特定属性值的祖先元素

时间:2016-08-03 18:36:57

标签: xml xslt

我正在尝试使用XSLT删除祖先标记(及其子代),因为它们具有空文本和特定属性值。我有XSLT检查每个节点的text(),当它是空的,祖先有属性deltaxml:deltaV2 =“A”我想删除祖先和子节点。

这是我要删除的xml标签(注意:祖先可以是任何不仅仅是'p')。在这种情况下,我想要删除最后一个p标签和子项:

<body>
  <p deltaxml:deltaV2="A=B">
    <t>This is the same</t>
  </p>
  <p deltaxml:deltaV2="B">
    <t>This is inserted</t>
  </p>
  <p deltaxml:deltaV2="A">
    <t>This is deleted</t>
  </p>
  <p deltaxml:deltaV2="A">
    <t> </t>
  </p>
</body>

这是我到目前为止的XSLT:

<xsl:template match="@* | * | processing-instruction() | comment()" mode="#all">
  <xsl:copy copy-namespaces="no">
    <xsl:apply-templates select="@*, node()" mode="#current"/>
  </xsl:copy>
</xsl:template> 
<xsl:template match="text()">
   <xsl:variable name="deltaV2" as="attribute()" select="ancestor::*[@deltaxml:deltaV2][1]/@deltaxml:deltaV2"/>
   <xsl:variable name="text" select="."/>
<xsl:choose>
  <xsl:when test="$deltaV2 eq 'A'">
    <xsl:choose>
      <xsl:when test="$text = ' '">

        <!-- need to remove ancestor tags-->

      </xsl:when>
      <xsl:otherwise>
        <xsl:element name="delete" namespace="{$root-ns}">
          <xsl:value-of select="."/>
        </xsl:element>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:when>
  <xsl:when test="$deltaV2 eq 'B'">
    <xsl:element name="insert" namespace="{$root-ns}">
      <xsl:value-of select="."/>
    </xsl:element>
  </xsl:when>
  <xsl:otherwise>
    <xsl:value-of select="."/>
  </xsl:otherwise>
</xsl:choose>

这是期望的输出:

<body>
  <p deltaxml:deltaV2="A=B">
    <t>This is the same</t>
  </p>
  <p deltaxml:deltaV2="B">
    <t><insert>This is inserted</insert></t>
  </p>
  <p deltaxml:deltaV2="A">
    <t><delete>This is deleted</delete></t>
  </p>
</body>

我需要这个的原因是因为这些属性显示在两个版本的XML之间是否插入或删除了某些内容,但是如果有一个空节点(即样本中的空t标签)我不想跟踪这是一个变化,因为没有文字发生变化,只是希望删除。 当文本为空时我需要放置什么才能删除这些标签?

2 个答案:

答案 0 :(得分:1)

  

当我们有空文本和特定属性值时,我试图使用XSLT删除[...]标签(及其子代)。

执行此操作的模板非常简单

<xsl:template match="*[@deltaxml:deltaV2 = 'A' and normalize-space() = '']" />

将其与身份转换一起使用。在这里阅读有关身份转换的信息:http://www.dpawson.co.uk/xsl/sect2/identity.html(您最喜欢的搜索引擎将提供的无数其他示例)。

此处关于SO的问题也为您所描述的同一问题提供了规范性答案:How to remove elements from xml using xslt with stylesheet and xsltproc?

答案 1 :(得分:0)

您无法删除处理后代的模板中的祖先。当样式表到达空text()节点时,p祖先已经处理并写入输出树 - 请参阅:https://www.w3.org/TR/xslt/#section-Processing-Model

如果您重申您的要求:删除满足两者的任何元素(及其所有后代):

  1. 有一个名为deltaxml:deltaV2的属性,其值为“A”;
  2. 至少有一个没有非空白文本节点的后代元素
  3. 然后您可以将其实现为:

    <xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:deltaxml="http://example.com/deltaxml">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    <xsl:strip-space elements="*"/>
    
    <!-- identity transform -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="*[@deltaxml:deltaV2='A'][.//*[not(normalize-space())]]" />
    
    </xsl:stylesheet>
    

    当然,您需要将deltaxml:前缀绑定到输入XML中使用的相同名称空间URI,而不是像我在此处所做的任意名称。