Home > Blockchain >  XSLT : Unable to remove entire parent node content when child node is equal to some value. Has 2 dif
XSLT : Unable to remove entire parent node content when child node is equal to some value. Has 2 dif

Time:07-02

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.

  • Related