Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/xslt/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何使用XSLT递归删除一些xml元素_Xml_Xslt_Recursion - Fatal编程技术网

如何使用XSLT递归删除一些xml元素

如何使用XSLT递归删除一些xml元素,xml,xslt,recursion,Xml,Xslt,Recursion,所以我的处境很糟糕。我有一个这样的XML <table border="1" cols="200 100pt 200"> <tr> <td>isbn</td> <td>title</td> <td>price</td> </tr> <tr> <td /> <td /&

所以我的处境很糟糕。我有一个这样的XML


<table border="1" cols="200 100pt 200">
  <tr>
    <td>isbn</td>
    <td>title</td>
    <td>price</td>
  </tr>
  <tr>
    <td />
    <td />
    <td>
      <span type="champsimple" id="9b297fb5-d12b-46b1-8899-487a2df0104e" categorieid="a1c70692-0427-425b-983c-1a08b6585364" champcoderef="01f12b93-b4c5-401b-9da1-c9385d77e43f">
        [prénom]
      </span>
      <span type="champsimple" id="e103a6a5-d1be-4c34-8a54-d234179fb4ea" categorieid="a1c70692-0427-425b-983c-1a08b6585364" champcoderef="01f12b93-b4c5-401b-9da1-c9385d77e43f">[nom]</span>
      <span></span>
    </td>
  </tr>
  <tr></tr>
  <tr>
    <td></td>
    <td>Phill It in</td>
  </tr>
  <tr>
    <table id="cas1">
      <tr>
        <td ></td>
        <td >foo</td>
      </tr>
      <tr>
        <td >bar</td>
        <td >boo</td>
      </tr>
    </table>
  </tr>
  <tr>
    <table id="cas2">
      <tr>
        <td ></td>
        <td >foo</td>
      </tr>
      <tr>
        <td ></td>
        <td >boo</td>
      </tr>
    </table>
  </tr>
  <tr>
    <table id="cas3">
      <tr>
        <td >bar</td>
        <td ></td>
      </tr>
      <tr>
        <td >foo</td>
        <td >boo</td>
      </tr>
    </table>
  </tr>
  <tr>
    <table id="cas4">
      <tr>
        <td />
        <td />
      </tr>
      <tr>
        <td>foo</td>
        <td>boo</td>
      </tr>
    </table>
  </tr>
  <table id="cas4">
    <tr>
      <td />
      <td />
    </tr>
    <tr>
      <td>foo</td>
      <td>boo</td>
    </tr>
  </table>
  <tr>
    <td />
    <td />
  </tr>
</table>

isbn
标题
价格
[名称]
[名称]
菲勒
福
酒吧
喝倒采
福
喝倒采
酒吧
福
喝倒采
福
喝倒采
福
喝倒采
现在的问题是如何递归删除所有空的td、tr和table元素

现在我使用这个XSLT


<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output omit-xml-declaration="yes" indent="yes"/>
  <xsl:strip-space elements="*" />

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

  <xsl:template match="td[not(node())]" />
  <xsl:template match="tr[not(node())]" />
  <xsl:template match="table[not(node())]" />

</xsl:stylesheet>

但它做得不太好。删除td后,tr变为空,但它不能处理这个问题。太糟糕了。请参见带有“cas4”的元素


isbn
标题
价格
[名称]
[名称]
菲勒
福
酒吧
喝倒采
福
喝倒采
酒吧
福
喝倒采
福
喝倒采
福
喝倒采

您将如何解决此问题?您还可以使用类似的方法(未测试)筛选出任何只包含with empty的表和任何只包含with empty的表(除了其他筛选器之外):


听起来您对空的定义是“不包含文本或仅包含空白”。是这样吗?如果是这样的话,下面的转换应该可以做到这一点:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
  <xsl:output omit-xml-declaration="yes" indent="yes"/> 
  <xsl:strip-space elements="*" /> 

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

  <xsl:template match="td[not(normalize-space(.))]" /> 
  <xsl:template match="tr[not(normalize-space(.))]" /> 
  <xsl:template match="table[not(normalize-space(.))]" /> 
</xsl:stylesheet> 

这是您的解决方案:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>

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

    <xsl:template match="@* | text()">
        <xsl:copy />
    </xsl:template>

    <xsl:template match="table | tr | td">

        <!-- result of the transformation of descendants -->
        <xsl:variable name="content">
            <xsl:apply-templates select="node()" />
        </xsl:variable>

        <!-- if there are any children left then copy myself -->
        <xsl:if test="count($content/node()) > 0">
            <xsl:copy>
                <xsl:apply-templates select="@*" />
                <xsl:copy-of select="$content" />
            </xsl:copy>
        </xsl:if>

    </xsl:template>

</xsl:stylesheet>

这是因为
包含空元素
和其他元素的情况。然后你想删除
s,只剩下剩下剩下的部分。

+1这既干净又实用。请注意,
normalizespace(.)
相当于
normalize-space()
好问题!无论如何,删除所有空的
节点可能有点过头了-它们是保持合理的表结构所必需的。谢谢,足够好了,唯一要添加的是在验证节点数时使用msxls:node set($content)。我在XMLSpy中对其进行了测试,count($content/node())工作正常。
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
  <xsl:output omit-xml-declaration="yes" indent="yes"/> 
  <xsl:strip-space elements="*" /> 

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

  <xsl:template match="td[not(normalize-space(.))]" /> 
  <xsl:template match="tr[not(normalize-space(.))]" /> 
  <xsl:template match="table[not(normalize-space(.))]" /> 
</xsl:stylesheet> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>

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

    <xsl:template match="@* | text()">
        <xsl:copy />
    </xsl:template>

    <xsl:template match="table | tr | td">

        <!-- result of the transformation of descendants -->
        <xsl:variable name="content">
            <xsl:apply-templates select="node()" />
        </xsl:variable>

        <!-- if there are any children left then copy myself -->
        <xsl:if test="count($content/node()) > 0">
            <xsl:copy>
                <xsl:apply-templates select="@*" />
                <xsl:copy-of select="$content" />
            </xsl:copy>
        </xsl:if>

    </xsl:template>

</xsl:stylesheet>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>

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

    <xsl:template match="@* | text()">
        <xsl:copy />
    </xsl:template>

    <xsl:template match="table">

        <!-- result of the transformation of descendants -->
        <xsl:variable name="content">
            <xsl:apply-templates select="node()" />
        </xsl:variable>

        <!-- if there are any children left then copy myself -->
        <xsl:if test="count($content/node()) > 0">
            <xsl:copy>
                <xsl:apply-templates select="@*" />
                <xsl:copy-of select="$content" />
            </xsl:copy>
        </xsl:if>

    </xsl:template>

    <xsl:template match="tr">

        <!-- result of the transformation of descendants -->
        <xsl:variable name="content">
            <xsl:apply-templates select="node()" />
        </xsl:variable>

        <!-- number of non-empty td elements -->
        <xsl:variable name="cellCount">
            <xsl:value-of select="count($content/td[node()])" />
        </xsl:variable>

        <!-- number of other elements -->
        <xsl:variable name="elementCount">
            <xsl:value-of select="count($content/node()[name() != 'td'])" />
        </xsl:variable>

        <xsl:if test="$cellCount > 0 or $elementCount > 0">
            <xsl:copy>                  
                <xsl:apply-templates select="@*" />
                <xsl:copy-of select="$content" />
            </xsl:copy>
        </xsl:if>

    </xsl:template>

</xsl:stylesheet>
<xsl:choose>
    <!-- if there are cells then copy the content -->
    <xsl:when test="$cellCount > 0">
        <xsl:copy>
            <xsl:apply-templates select="@*" />
            <xsl:copy-of select="$content" />
        </xsl:copy>
    </xsl:when>

    <!-- if there are only other elements copy them -->
    <xsl:when test="$elementCount > 0">
        <xsl:copy>
            <xsl:apply-templates select="@*" />
            <xsl:copy-of select="$content/node()[name() != 'td']" />
        </xsl:copy>
    </xsl:when>
</xsl:choose>