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:
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.