divideByZero
divideByZero

Reputation: 1188

add namespace prefix to element and subnodes with xslt

I'd like to copy only header element with all subnodes and add to every subnode prefix "v11"(including header element)

Source xml:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Body>
        <ns3:createReservationRequest xmlns:ns3="ns3URL" xmlns:ns2="ns2URL">
            <header>
                <language isoCountryCode="US" isoLanguageCode="en"/>
                <channel name="DT">
                    <subChannel name="WEBWB">
                        <subChannel name="WEBWB">
                            <subChannel name="Functester">
                                <subChannel name="ecom"/>
                            </subChannel>
                        </subChannel>
                    </subChannel>
                </channel>
            </header>
            <ns3:agentInfo>
                <ns2:agentDutyCode>PR</ns2:agentDutyCode>
            </ns3:agentInfo>
        </ns3:createReservationRequest>
    </soap:Body>
</soap:Envelope>

Desired result xml:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
              xmlns:v1="v1URL"
              xmlns:v11="v11URL">
    <soapenv:Body>
        <v1:createBookerEventRequest>
            <v11:header>
                <v11:channel name="DT">
                    <v11:subChannel name="WEBWB">
                        <v11:subChannel name="WEBWB">
                            <v11:subChannel name="Functester">
                                <v11:subChannel name="ecom"/>
                            </v11:subChannel>
                        </v11:subChannel>
                    </v11:subChannel>
                </v11:channel>
            </v11:header>
        </v1:createBookerEventRequest>
    </soapenv:Body>
</soapenv:Envelope>

I've tried to implement this using example from here . I've written the following xsl:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
            xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
            xmlns:v11="v11URL">
    <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>

    <xsl:template match="/">
        <xsl:copy>
            <xsl:apply-templates select="//*[local-name()='header']/*"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="//*[local-name()='header']/*">
        <xsl:element name="v11:{name()}" inherit-namespaces="no">
            <xsl:apply-templates select="node()|@*"/>
        </xsl:element>
    </xsl:template>

</xsl:stylesheet>

But it doesn't copy subchannels into result xml. And also adds unwanted "xmlns:v11="http://example.com/schema/common/ATPCommonServiceTypes/v1" attribute to header subnodes. Any help is appreciated

Upvotes: 1

Views: 3354

Answers (2)

helderdarocha
helderdarocha

Reputation: 23627

I added a xmlns declaration to agentDutyCode since it is missing a namespace declaration:

<ns2:agentDutyCode xmlns:ns2="ns2URL">PR</ns2:agentDutyCode>

Using the source with this stylesheet (templates explained in the comments):

<xsl:stylesheet version="2.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
    xmlns:v11="v11URL"
    xmlns:v1="v1URL"
    xmlns:ns3="ns3URL"
    exclude-result-prefixes="ns3">

    <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
    <xsl:strip-space elements="*"/>

    <!-- Copies Envelope and Body preserving their namespace -->
    <xsl:template match="soap:Envelope | soap:Body">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>

    <!-- Creates the createReservationRequest element -->
    <xsl:template match="ns3:createReservationRequest">
        <v1:createBookerEventRequest>
            <xsl:apply-templates/>
        </v1:createBookerEventRequest>
    </xsl:template>

    <!-- Ignores language and agentInfo subtrees -->
    <xsl:template match="language"/>
    <xsl:template match="ns3:agentInfo"/>

    <!-- Matches all other elements -->
    <xsl:template match="*">
        <xsl:element name="v11:{local-name()}" inherit-namespaces="no">
            <xsl:apply-templates select="node()|@*"/>
        </xsl:element>
    </xsl:template>

    <!-- Copies attributes -->
    <xsl:template match="@*">
        <xsl:copy>
            <xsl:value-of select="."/>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

You will have this result:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
   <soap:Body>
      <v1:createBookerEventRequest xmlns:v11="v11URL" xmlns:v1="v1URL">
         <v11:header>
            <v11:channel name="DT">
               <v11:subChannel name="WEBWB">
                  <v11:subChannel name="WEBWB">
                     <v11:subChannel name="Functester">
                        <v11:subChannel name="ecom"/>
                     </v11:subChannel>
                  </v11:subChannel>
               </v11:subChannel>
            </v11:channel>
         </v11:header>
      </v1:createBookerEventRequest>
   </soap:Body>
</soap:Envelope>

Here is an XSLT Fiddle where you can see the result.

Upvotes: 2

Martin Honnen
Martin Honnen

Reputation: 167726

Here is my (edited) suggestion:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
            xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
            xmlns:v1="v1URL"
            xmlns:v11="v11URL"
            xmlns:ns3="ns3URL"
            exclude-result-prefixes="soap ns3">

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

<xsl:template match="/*">
  <xsl:copy>
    <xsl:copy-of select="document('')/xsl:stylesheet/namespace::*[local-name() = ('v1', 'v11')]"/>
    <xsl:apply-templates select="@* , node()"/>
  </xsl:copy>
</xsl:template>

<xsl:template match="*[not(namespace-uri())]">
  <xsl:element name="v11:{local-name()}">
    <xsl:apply-templates select="@* , node()"/>
  </xsl:element>
</xsl:template>

<xsl:template match="ns3:createReservationRequest">
  <v1:createBookerEventRequest>
    <xsl:apply-templates select="@* , node()"/>
  </v1:createBookerEventRequest>
</xsl:template>

<xsl:template match="ns3:agentInfo"/>

</xsl:stylesheet>

Upvotes: 2

Related Questions