XSLT:删除子节点而不重复XPath

时间:2017-01-30 17:33:38

标签: xml xslt xpath

我有以下XML:

<?xml version="1.0"?>
<Transaction>
    <Product>
        <ProductRq>
            <ContactInfo>
                <!-- several child elements -->
            </ContactInfo>
            <OrderInfo>
                <!-- several child elements -->
            </OrderInfo>
            <ProductInfo>
                <!-- several child elements -->
            </ProductInfo>
            <AddressInfo>
                <!-- several child elements -->
            </AddressInfo>
            <AuditInfo>
                <!-- several child elements -->
            </AuditInfo>
            <DeliveryInfo>
                <!-- several child elements -->
            </DeliveryInfo>
        </ProductRq>
    </Product>
</Transaction>

为了简洁起见,我在<ProductRq>标记中遗漏了几个孩子,其中包含4或5个类似于<OrderInfo><CustomerInfo>的子元素,以及* Info元素的子节点。

我需要在保留* Info标记的同时删除Order和<CustomerInfo>等元素的子元素。在7个标签中,大约4个标签将通过此过程。我想不出怎么做而不重复:

<xsl:template match="Transcation/Product/ProductRq/<tag name here>/*" />

<ProductRq>的每个孩子。有没有办法利用上下文节点(<ProductRq>)并循环遍历子节点,除了上面的内容之外删除自己的子节点?

编辑:
我添加了<ProductRq>的剩余子标记。除<AuditInfo><ContactInfo>之外的所有代码都必须删除其子节点。

3 个答案:

答案 0 :(得分:1)

一种解决方案是应用以下XSLT:

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

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

  <!-- skip all child nodes of ProductRq except they are AuditInfo or ContactInfo -->
  <xsl:template match="ProductRq/*[not(self::AuditInfo | self::ContactInfo)]">       
    <xsl:element name="{name(.)}" />   <!-- so create an element with this name -->
  </xsl:template>

</xsl:stylesheet>

<强>输出:

<?xml version="1.0"?>
<Transaction>
    <Product>
        <ProductRq>
            <ContactInfo>
                <!-- several child elements -->
            </ContactInfo>
            <OrderInfo/>
            <ProductInfo/>
            <AddressInfo/>
            <AuditInfo>
                <!-- several child elements -->
            </AuditInfo>
            <DeliveryInfo/>
        </ProductRq>
    </Product>
</Transaction>

答案 1 :(得分:0)

  

我需要移除Order<CustomerInfo>等元素的子元素   <!-- XSLT 2.0 and up --> <xsl:template match="ProductRq/*[ends-with(name(), 'Info')]/*" /> <!-- XSLT 1.0 variant, as ends-with() does not exist here --> <xsl:template match="ProductRq/*[ substring-before(name(), 'Info') != '' and substring-after(name(), 'Info') = '' ]/*" /> 同时保留* Info标记。

您要找的模板是

to_csv

答案 2 :(得分:0)

撰写与ProductRq匹配的模板:

<xsl:template match="ProductRq">
  <xsl:copy>
    <xsl:apply-templates select="ContactInfo | OrderInfo | ProductInfo | AddressInfo"/>
  </xsl:copy>
</xsl:template>

如您所见,select子句包含要包含的所有子节点。 默认情况下,它执行深层复制(带子节点)。

但您写道,某些节点(例如ContactInfoOrderInfo)只能在浅层模式下复制。 (我假设这种模式应该只涉及复制子文本节点 但仅此而已。复制&#34;空&#34;标签似乎是一个奇怪的概念。)

为了只拥有这些节点的浅层副本,请写另一个tempate:

<xsl:template match="ContactInfo | OrderInfo">
  <xsl:copy><xsl:apply-templates select="text()"/></xsl:copy>
</xsl:template>

总而言之,您在2个地方写下所涉及的节点名称(用&#34; |&#34;分隔):

  • 所有名称都是第一个模板,
  • 要在第二个模板中复制的节点的名称。

无论如何你必须写这些名字。