XSL转换 - 条件删除空标记

时间:2017-04-17 19:01:18

标签: xml xslt

我有xsl删除所有空标记,但是如果该部分的所有标记都为空,我只想删除空标记。看看我的输入文件,例如:

<NEWORDER>
<ID>1</ID>
<HEADER>
   <NMP>NAME PLATE</NMP>
   <ORDER>
     <USER_ID>USER ID</USER_ID>
     <PARTNER_ID>PARTNER ID</PARTNER_ID>
     <USER_REFERENCE>5555-55555555-5555</USER_REFERENCE>
     <PO_HEADER>
        <PO_NUMBER>5555-55555555-5555</PO_NUMBER>
        <PO_DATE>20170322</PO_DATE>
        <PO_TYPE>BT</PO_TYPE>
        <RELEASE_NBR></RELEASE_NBR>
        <CUST_ORDER_NBR>5555555555</CUST_ORDER_NBR>
        <CONTACT_NAME></CONTACT_NAME>
        <CONTACT_PHONE></CONTACT_PHONE>
        <TRANS_METHOD></TRANS_METHOD>
        <SHIP_COMP>SC</SHIP_COMP>
        <CURR_CODE>USD</CURR_CODE>
        <INCO_TERMS>FOB</INCO_TERMS>
        <NAMED_PLACE></NAMED_PLACE>
        <PAYMENT_METHOD>BT</PAYMENT_METHOD>
        <TERM_TYPE>555</TERM_TYPE>
        <TERM_DESC>NET 10 DAYS</TERM_DESC>
        <DEST_BRANCH>5555</DEST_BRANCH>
    </PO_HEADER>
    <PO_HEADER_NOTES>
      <TEXT1_QUAL></TEXT1_QUAL>
      <TEXT1_MSG></TEXT1_MSG>
    </PO_HEADER_NOTES>
  </ORDER>
 </HEADER>
</NEWORDER>

在这个例子中,我希望输出只删除&#34; PO_HEADER_NOTES&#34;所有内部标签都是空的部分。预期产出的例子:

<NEWORDER>
<ID>1</ID>
<HEADER>
   <NMP>NAME PLATE</NMP>
   <ORDER>
     <USER_ID>USER ID</USER_ID>
     <PARTNER_ID>PARTNER ID</PARTNER_ID>
     <USER_REFERENCE>5555-55555555-5555</USER_REFERENCE>
     <PO_HEADER>
        <PO_NUMBER>5555-55555555-5555</PO_NUMBER>
        <PO_DATE>20170322</PO_DATE>
        <PO_TYPE>BT</PO_TYPE>
        <RELEASE_NBR></RELEASE_NBR>
        <CUST_ORDER_NBR>5555555555</CUST_ORDER_NBR>
        <CONTACT_NAME></CONTACT_NAME>
        <CONTACT_PHONE></CONTACT_PHONE>
        <TRANS_METHOD></TRANS_METHOD>
        <SHIP_COMP>SC</SHIP_COMP>
        <CURR_CODE>USD</CURR_CODE>
        <INCO_TERMS>FOB</INCO_TERMS>
        <NAMED_PLACE></NAMED_PLACE>
        <PAYMENT_METHOD>BT</PAYMENT_METHOD>
        <TERM_TYPE>555</TERM_TYPE>
        <TERM_DESC>NET 10 DAYS</TERM_DESC>
        <DEST_BRANCH>5555</DEST_BRANCH>
    </PO_HEADER>
  </ORDER>
 </HEADER>
</NEWORDER>

我用来删除所有空节点的xsl如下:

<?xml version="1.0" encoding="UTF-8"?>

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

    <xsl:template match="*">
    <xsl:if test=". != '' or ./@* != ''">
        <xsl:element name="{local-name()}">
            <xsl:apply-templates select="@* | node()" />
        </xsl:element>
    </xsl:if>
    </xsl:template>

   <xsl:template match="@*">
        <xsl:attribute name="{local-name()}">
            <xsl:value-of select="." />
        </xsl:attribute>
   </xsl:template>
       <xsl:template match="text() | comment() | processing-instruction()">
       <xsl:copy />
    </xsl:template>
</xsl:stylesheet>

请指教。任何帮助表示赞赏。

2 个答案:

答案 0 :(得分:0)

  

如果该部分的所有标签都是,我只想删除空标签   空。

这不是一个非常明确的要求。查看给定的示例,它看起来应该重述为:删除(a)有子节点的任何元素,但(b)不包含任何文本节点 - 作为直接子节点或其后代之一的子节点。这将实现为:

XSLT 1.0

x = 0 # empty
x |= 1<<19 # set bit 19
x &= ~(1<<19) # clear bit 19
x ^= 1<<19 # toggle bit 19
x = ~x # invert *all* bits, all the way to infinity
mask = ((1<<20)-1) # define a 20 bit wide mask
x &= mask # ensure bits 20 and higher are 0
x ^= mask # invert only bits 0 through 19

(x >> 19) & 1 # test bit 19
(x >> 16) & 0xf # get bits 16 through 20.

<强>结果

<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:strip-space elements="*"/>

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

<xsl:template match="*[* and not(descendant::text())]"/>

</xsl:stylesheet>

答案 1 :(得分:0)

根据您的要求,以下单个模板似乎符合要求:

  • 使用文本或属性复制元素。
  • 对于没有文字或属性的元素:
    • 如果他们没有自己的孩子,请复制他们。
    • 如果他们有孩子,则删除他们,但孩子也没有文字或属性。

请注意,这与您的示例XSLT略有不同 - 对于属性,仅检查元素的属性是否计算为'',即空字符串。根据我自己的经验,我(很少)遇到元素可能具有空字符串属性的情况,以及需要维护该属性的情况,因此下面的代码通过检查存在来解释属性的em>,而不仅仅是属性的。调整以符合您的要求。

<xsl:template match="*">
    <xsl:choose>
        <!-- Strip only if:
            1) Element has children.
            2) Nothing in the tree starting here contains any text or attributes. -->
        <xsl:when test="./* and not(descendant-or-self::*[text() or @*])"/>
        <!-- In all other cases, just copy over, and process children. -->
        <xsl:otherwise>
            <!-- Copies the element itself. -->
            <xsl:copy>
                <!-- Copies all attributes, if there are any. -->
                <xsl:copy-of select="@*"/>
                <!-- Sends any children along for further processing. -->
                <xsl:apply-templates/>
            </xsl:copy>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>