I am trying to remove the entire content of an enclosing parent node. I want to remove entire <contactStanza>
when the value of its child node <ns2:contactTypeCode>
is NOT 'ABC' or 'DEF'
I have a long xslt script. But for simplicity, I have pasted here only the parts of code related to my question.
Input XML
<?xml version="1.0" encoding="UTF-8"?>
<accountEventNotify
xmlns="http://xmlns.example.com/eventNotify/v1"
xmlns:ns2="http://xmlns.example.com/cds/customer" schemaVersion="1">
<create>
<contactStanza>
<ns2:accountContact domain="customer" majorVersion="0" minorVersion="28">
<ns2:contactTypeCode>ABC</ns2:contactTypeCode>
</ns2:accountContact>
<ns2:contact domain="customer" majorVersion="0" minorVersion="28">
<ns2:companyName>Company A</ns2:companyName>
</ns2:contact>
</contactStanza>
<contactStanza>
<ns2:accountContact domain="customer" majorVersion="0" minorVersion="28">
<ns2:contactTypeCode>GHI</ns2:contactTypeCode>
</ns2:accountContact>
<ns2:contact domain="customer" majorVersion="0" minorVersion="28">
<ns2:companyName>Company B</ns2:companyName>
</ns2:contact>
</contactStanza>
</create>
</accountEventNotify>
XSLT
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://xmlns.example.com/eventNotify"
xmlns:v1="http://xmlns.example.com/eventNotify/v1"
xpath-default-namespace="http://xmlns.example.com/eventNotify/v1"
xmlns:ns2="http://xmlns.example.com/cds/customer"
exclude-result-prefixes="v1">
<!-- remove the empty lines with XSLT -->
<xsl:output method="xml" encoding="utf-8" indent="yes" />
<xsl:strip-space elements="*" />
<!-- Template #01 -->
<!-- replace the schema version value -->
<xsl:template match="/*/@schemaVersion">
<xsl:attribute name="{name()}">21.22.35</xsl:attribute>
</xsl:template>
<!-- Template #02 -->
<!-- Change namespace http://xmlns.example.com/eventNotify/v1 to http://xmlns.example.com/eventNotify -->
<xsl:template match="v1:*">
<xsl:element name="{local-name()}">
<xsl:copy-of
select="namespace::*[not(. = 'http://xmlns.example.com/eventNotify/v1')]" />
<xsl:apply-templates select="@* | node()" />
</xsl:element>
</xsl:template>
<!-- Template #03 -->
<xsl:template match="ns2:*">
<xsl:copy copy-namespaces="no">
<xsl:copy-of
select="namespace::*[not(. = 'http://xmlns.example.com/eventNotify/v1')]" />
<xsl:copy-of select="@*" />
<xsl:apply-templates select="node()" />
</xsl:copy>
</xsl:template>
<!-- Template #04 -->
<!-- Do not include <contactStanza> block if <ns2:contactTypeCode> is NOT 'ABC', 'DEF' -->
<xsl:template
match="contactStanza/ns2:accountContact[not(ns2:contactTypeCode = 'ABC' or ns2:contactTypeCode = 'DEF')]" />
</xsl:stylesheet>
Most of the existing code in XSL script are set and working for its own purpose which I prefer not to change since it's already in place.
In the xlst, the template we are interested is <!-- Template #04 -->
Current Output
<?xml version="1.0" encoding="UTF-8"?>
<accountEventNotify
xmlns="http://xmlns.example.com/eventNotify/v1"
xmlns:ns2="http://xmlns.example.com/cds/customer" schemaVersion="1">
<create>
<contactStanza>
<ns2:accountContact domain="customer" majorVersion="0" minorVersion="28">
<ns2:contactTypeCode>ABC</ns2:contactTypeCode>
</ns2:accountContact>
<ns2:contact domain="customer" majorVersion="0" minorVersion="28">
<ns2:companyName>Company A</ns2:companyName>
</ns2:contact>
</contactStanza>
<contactStanza>
<ns2:contact domain="customer" majorVersion="0" minorVersion="28">
<ns2:companyName>Company B</ns2:companyName>
</ns2:contact>
</contactStanza>
</create>
</accountEventNotify>
Problem
In the current output, the problem is it didn't entirely remove the 2nd <contactStanza>
I was expecting the <!-- Template #04 -->
code will be sufficient to remove entire <contactStanza>
<xsl:template
match="contactStanza/ns2:accountContact[not(ns2:contactTypeCode = 'ABC' or ns2:contactTypeCode = 'DEF')]" />
Desired output is :
<?xml version="1.0" encoding="UTF-8"?>
<accountEventNotify
xmlns="http://xmlns.example.com/eventNotify/v1"
xmlns:ns2="http://xmlns.example.com/cds/customer" schemaVersion="1">
<create>
<contactStanza>
<ns2:accountContact domain="customer" majorVersion="0" minorVersion="28">
<ns2:contactTypeCode>ABC</ns2:contactTypeCode>
</ns2:accountContact>
<ns2:contact domain="customer" majorVersion="0" minorVersion="28">
<ns2:companyName>Company A</ns2:companyName>
</ns2:contact>
</contactStanza>
</create>
</accountEventNotify>
Please note that <contactStanza>
will have multiple occurrences. For simplicity and to demonstrate, I just added 2 <contactStanza>
.
I am suspecting that the reason, it's not removing entire <contactStanza>
is because the xpath contactStanza/ns2:accountContact/ns2:contactTypeCode
is a combination of nodes from different namespaces
I'm still struggling on fixing this. I'd appreciate any recommendation.
Thank you.
CodePudding user response:
How about:
XSLT 2.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xpath-default-namespace="http://xmlns.example.com/eventNotify/v1"
xmlns:ns2="http://xmlns.example.com/cds/customer">
<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="create">
<xsl:copy>
<xsl:apply-templates select="contactStanza[ns2:accountContact/ns2:contactTypeCode=('ABC', 'DEF')]"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Or, if you prefer:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xpath-default-namespace="http://xmlns.example.com/eventNotify/v1"
xmlns:ns2="http://xmlns.example.com/cds/customer">
<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="contactStanza[not(ns2:accountContact/ns2:contactTypeCode=('ABC', 'DEF'))]"/>
</xsl:stylesheet>
CodePudding user response:
Please change this template
<xsl:template match="contactStanza/ns2:accountContact[not(ns2:contactTypeCode = 'ABC' or ns2:contactTypeCode = 'DEF')]" />
to
<xsl:template match="contactStanza[ns2:accountContact[not(ns2:contactTypeCode = 'ABC' or ns2:contactTypeCode = 'DEF')]]"/>
in this case you will match contactStanza element that has ns2:accountContact that doesn't have ns2:contactTypeCode = 'ABC' or ns2:contactTypeCode = 'DEF'.
Because now it matches ns2:accountContact with parent contactStanza.