Unnamed user
Unnamed user

Reputation: 181

XSLT to add prefix namespaces of all nodes except few

I Am trying to write XSLT code to add prefix namespaces to all nodes except few.

Sample XML:

    <BatchPrepareDeliverArchive xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="schema">
<BatchInformation>
    <RqUId>424000000071256187550913330</RqUId>
    <BatchFeedId>CMLTREXT4240</BatchFeedId>
    <BatchCount>7</BatchCount>
</BatchInformation>
<BatchDeliverArchive>
    <Transactions>
        <Transaction>
            <TransactionUUID>90022016-01-140000001</TransactionUUID>
            <CustomerData>
                <GBD_Transactions>
                    <GBD_Transaction>
                        <Common_Data>
                            <Transaction_ID>90022016-01-140000001</Transaction_ID>
                            </Common_Data>
                        <Templates>
                            <Template>
                                <Template_Name>A21_LETTER_FINAL_NOTICE_OF_CANCELLATION_TPA</Template_Name>
                                <Transaction_ID>90022016-01-140000001</Transaction_ID>
                                </Template>
                        </Templates>
                    </GBD_Transaction>
                </GBD_Transactions>
            </CustomerData>
            <DocInfo>
                <Name>OPERATION NAME</Name>
                </DocInfo>
            </Transaction>
            </Transactions>
            </BatchDeliverArchive>
    </BatchPrepareDeliverArchive>

I want to add urn prefix to all nodes except GBD_Transactions & its child elements.

I came up with this XSLT:

    <xsl:stylesheet version="1.0"  xmlns:urn="http://www.w3.org/2001/XMLSchema-instance"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="*">
    <xsl:element name="urn:{local-name()}">
    <xsl:apply-templates/>
    </xsl:element>
    </xsl:template>

    <xsl:template match="@*">
    <xsl:element name="urn:{local-name()}">
    <xsl:value-of select="."/>
    </xsl:element>
    </xsl:template>

    </xsl:stylesheet>

All nodes are getting transformed here, which is not the expected output. Would appreciate any help on this!

Upvotes: 2

Views: 514

Answers (2)

Tim C
Tim C

Reputation: 70648

If you want to ignore GBD_Transactions elements, and its descendants, just add a template to match the relevant nodes, and use the identity template to copy them as-is.

Try adding this template to the XSLT

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

Note that matching on a specific element name has a higher priority than matching on *, so this template should always be used ahead of the more generic one.

By the way, there is an issue with your template that matches "*". You probably change it to this...

<xsl:template match="*">
  <xsl:element name="urn:{local-name()}">
    <xsl:apply-templates select="@*|node()" />
   </xsl:element>
</xsl:template>

This is because <xsl:apply-templates /> is the same as doing <xsl:apply-templates select="node()" /> and so will not select attributes. Thus, your existing template that matches @* would not get called otherwise.

EDIT: If you want to stop the xsi:schemaLocation attribute becoming an element, add this template too (You will need to declare the xsi namespace in the XSLT)

<xsl:template match="@xsi:*">
    <xsl:copy />
</xsl:template>

Or perhaps you don't want any attributes changed to elements? Try this XSLT instead?

<xsl:stylesheet version="1.0"  xmlns:urn="http://www.w3.org/2001/XMLSchema-instance"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <xsl:output omit-xml-declaration="yes" indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="*">
    <xsl:element name="urn:{local-name()}">
    <xsl:apply-templates select="@*|node()" />
    </xsl:element>
    </xsl:template>

    <xsl:template match="@*">
        <xsl:copy />
    </xsl:template>

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

Upvotes: 1

Kim Homann
Kim Homann

Reputation: 3248

In your template matching "*", you should differentiate like this:

<xsl:template match="*">
    <xsl:choose>
        <xsl:when test="ancestor-or-self::GBD_Transactions">
            <xsl:copy>
                <xsl:apply-templates"/>
            </xsl:copy>
        </xsl:when>
        <xsl:otherwise>
            <xsl:element name="urn:{local-name()}">
                <xsl:apply-templates/>
            </xsl:element>
        </xsl:otherwise>
    </xsl:choose>
</xsl:template>

Output will look like this:

<urn:BatchPrepareDeliverArchive xmlns:urn="http://www.w3.org/2001/XMLSchema-instance">
    <urn:BatchInformation>
        <urn:RqUId>424000000071256187550913330</urn:RqUId>
        <urn:BatchFeedId>CMLTREXT4240</urn:BatchFeedId>
        <urn:BatchCount>7</urn:BatchCount>
    </urn:BatchInformation>
    <urn:BatchDeliverArchive>
        <urn:Transactions>
            <urn:Transaction>
                <urn:TransactionUUID>90022016-01-140000001</urn:TransactionUUID>
                <urn:CustomerData>
                    <GBD_Transactions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
                        <GBD_Transaction>
                            <Common_Data>
                                <Transaction_ID>90022016-01-140000001</Transaction_ID>
                            </Common_Data>
                            <Templates>
                                <Template>
                                    <Template_Name>A21_LETTER_FINAL_NOTICE_OF_CANCELLATION_TPA</Template_Name>
                                    <Transaction_ID>90022016-01-140000001</Transaction_ID>
                                </Template>
                            </Templates>
                        </GBD_Transaction>
                    </GBD_Transactions>
                </urn:CustomerData>
                <urn:DocInfo>
                    <urn:Name>OPERATION NAME</urn:Name>
                </urn:DocInfo>
            </urn:Transaction>
        </urn:Transactions>
    </urn:BatchDeliverArchive>
</urn:BatchPrepareDeliverArchive>

Is that what you want?

Upvotes: 0

Related Questions