简体   繁体   中英

XSLT : Remove child nodes without repeating XPath

I have the following 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>

For sake of brevity I've left out several more children to the <ProductRq> tag, which contains 4 or 5 more child elements akin to <OrderInfo> and <CustomerInfo> , as well as the child nodes of the *Info elements.

I need to remove the children of the elements like Order and <CustomerInfo> while retaining the *Info tag. Out of the 7 tags, around 4 are to be put through this process. I can't think of how to do this without repeating:

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

for each child of <ProductRq> . Is there a way to leverage the context node( <ProductRq> ) and sort of loop through the children, removing their own child nodes aside from the above?

EDIT:
I added the remaining child tags of <ProductRq> . All tags except <AuditInfo> and <ContactInfo> must have their child nodes removed.

One solution is applying the following 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>

Output:

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

I need to remove the children of the elements like Order and <CustomerInfo> while retaining the *Info tag.

The template you are looking for is

<!-- 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') = ''
]/*" />

Write a template matching ProductRq :

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

As you see, the select clause contains all child nodes, which are to be included. By default it performs a deep copy (with child nodes).

But you wrote that some nodes (eg ContactInfo and OrderInfo ) are to be copied only in the shallow mode. (I assume that this mode should involve copying only child text nodes but nothing more. Copying of "empty" tags seems a weird concept.)

In order to have only shallow copy of these nodes, write another tempate:

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

To sum up, you write names of nodes involved (separated with "|") in 2 places:

  • all names is the first template,
  • names of nodes to be shallow copied in the second template.

Somewhere you have to write these names anyway.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM