删除满足条件的节点,然后删除父节点(如果为空)

时间:2019-07-31 13:02:01

标签: xml xslt

我正在尝试删除所有满足条件的元素节点,然后删除父节点(如果仍然没有子节点)。

我成功删除了所有满足我条件的孩子,但不知道如何删除仍然为空的父母。

<root>
  <parent>
     <childA>
        <grandchildX>03</grandchildX>
        <grandchildY>02</grandchildY>
     </childA>
  </parent>
</root>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="childA[grandchildX[text()='03']][grandchildY[text()='02']]"/>

</xsl:stylesheet>

当XSLT样式表具有除<parent>以外的其他子项(例如<childA>)时,XSLT样式表必须输出<childB>(这已经有效)。

2 个答案:

答案 0 :(得分:2)

使用XSLT 3(并假设xsl:strip-space),可以在xsl:where-populated的模板中使用parent

  <xsl:template match="parent">
      <xsl:where-populated>
          <xsl:next-match/>
      </xsl:where-populated>
  </xsl:template>

完整的样式表应为

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="#all"
    version="3.0">

  <xsl:strip-space elements="*"/>
  <xsl:output indent="yes"/>

  <xsl:mode on-no-match="shallow-copy"/>

  <xsl:template match="childA[grandchildX[text()='03']][grandchildY[text()='02']]"/>

  <xsl:template match="parent">
      <xsl:where-populated>
          <xsl:next-match/>
      </xsl:where-populated>
  </xsl:template>

</xsl:stylesheet>

https://xsltfiddle.liberty-development.net/ej9EGdh使用Saxon 9.8 HE的在线示例。

对于XSLT 1,我认为您可以尝试使用空模板

<xsl:template match="parent[childA[grandchildX[. = '03']][grandchildY[. ='02']] and not(*[not(self::childA[grandchildX[. = '03']][grandchildY[. ='02']])])]"/>

即完整的代码将是

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

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

    <xsl:template match="childA[grandchildX[. = '03']][grandchildY[. ='02']]"/>

    <xsl:template match="parent[childA[grandchildX[. = '03']][grandchildY[. ='02']] and not(*[not(self::childA[grandchildX[. = '03']][grandchildY[. ='02']])])]"/>

</xsl:stylesheet>

https://xsltfiddle.liberty-development.net/ej9EGdh/1

答案 1 :(得分:2)

首先,我认为您可以简化与此匹配的childA的当前模板...

<xsl:template match="childA[grandchildX = '03' and grandchildY ='02']"/>

然后,要删除父元素,您需要一个模板来匹配所有符合该条件的所有子元素的parent元素:

<xsl:template match="parent[count(*) = count(childA[grandchildX = '03' and grandchildY ='02'])]" />

http://xsltfiddle.liberty-development.net/gWvjQgj/1上查看它的运行情况

这样做的缺点是在两个地方指定了相同的条件。另一种方法是做这样的事情...

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="parent">
        <xsl:variable name="children" select="childA[grandchildX = '03' and grandchildY ='02']" />
        <xsl:variable name="otherChildren" select="*[count(.|$children) = count($children) + 1]" />
        <xsl:if test="$otherChildren">
            <xsl:copy>
                <xsl:apply-templates select="$otherChildren" />
            </xsl:copy>
        </xsl:if>
    </xsl:template>
</xsl:stylesheet>