Larry
Larry

Reputation: 11899

Swap elements attribute-values in XML (WSDL) file?

Consider I’ve got any standard WSDL file (represented in XML):

<wsdl:definitions>

      <wsdl:types>
        ...
      </wsdl:types>

      <wsdl:message>
        ...
      </wsdl:message>

      <wsdl:portType name="countrySoap”>
         <wsdl:operation name="GetCountryByCountryCode">
             <wsdl:documentation>Get country name by country code</wsdl:documentation>
             <wsdl:input message="tns:GetCountryByCountryCodeSoapIn" />
             <wsdl:output message="tns:GetCountryByCountryCodeSoapOut" />
         </wsdl:operation>
        <wsdl:operation name="GetISD">
            <wsdl:documentation>Get International Dialing Code </wsdl:documentation>
            <wsdl:input message="tns:GetISDSoapIn" />
            <wsdl:output message="tns:GetISDSoapOut" />
        </wsdl:operation>
        ...
      <wsdl:portType name="countrySoap”>

  ....
</wsdl:definitions>

What I would like to do is have a simple/efficient way of swapping the input and output messages for every message.

So for instance, I want:

         <wsdl:operation name="GetCountryByCountryCode">
             <wsdl:documentation>Get country name by country code</wsdl:documentation>
             <wsdl:input message="tns:GetCountryByCountryCodeSoapOut" />
             <wsdl:output message="tns:GetCountryByCountryCodeSoapIn" />
         </wsdl:operation>

The example wsdl file I’ve been working with can be found here: http://www.webservicex.net/country.asmx?WSDL

Further notes:

Upvotes: 3

Views: 1205

Answers (2)

Dimitre Novatchev
Dimitre Novatchev

Reputation: 243459

This XSLT (both 1.0 and 2.0) transformation:

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

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

 <xsl:template match="x:input/@message">
  <xsl:attribute name="message">
    <xsl:value-of select="../../x:output/@message"/>
  </xsl:attribute>
 </xsl:template>

 <xsl:template match="x:output/@message">
  <xsl:attribute name="message">
    <xsl:value-of select="../../x:input/@message"/>
  </xsl:attribute>
 </xsl:template>
</xsl:stylesheet>

when applied on the following XML document (obtained from the provided, severely malformed one):

<wsdl:definitions xmlns:wsdl="some:wsdl">

          <wsdl:types>
            ...
          </wsdl:types>

          <wsdl:message>
            ...
          </wsdl:message>

          <wsdl:portType name="countrySoap">
             <wsdl:operation name="GetCountryByCountryCode">
                 <wsdl:documentation>Get country name by country code</wsdl:documentation>
                 <wsdl:input message="tns:GetCountryByCountryCodeSoapIn" />
                 <wsdl:output message="tns:GetCountryByCountryCodeSoapOut" />
             </wsdl:operation>
            <wsdl:operation name="GetISD">
                <wsdl:documentation>Get International Dialing Code </wsdl:documentation>
                <wsdl:input message="tns:GetISDSoapIn" />
                <wsdl:output message="tns:GetISDSoapOut" />
            </wsdl:operation>
            ...
          </wsdl:portType>

      ....
</wsdl:definitions>

produces the wanted, correct result:

<wsdl:definitions xmlns:wsdl="some:wsdl">
   <wsdl:types>
            ...
          </wsdl:types>
   <wsdl:message>
            ...
          </wsdl:message>
   <wsdl:portType name="countrySoap">
      <wsdl:operation name="GetCountryByCountryCode">
         <wsdl:documentation>Get country name by country code</wsdl:documentation>
         <wsdl:input message="tns:GetCountryByCountryCodeSoapOut"/>
         <wsdl:output message="tns:GetCountryByCountryCodeSoapIn"/>
      </wsdl:operation>
      <wsdl:operation name="GetISD">
         <wsdl:documentation>Get International Dialing Code </wsdl:documentation>
         <wsdl:input message="tns:GetISDSoapOut"/>
         <wsdl:output message="tns:GetISDSoapIn"/>
      </wsdl:operation>
            ...
          </wsdl:portType>

      ....
</wsdl:definitions>

Upvotes: 1

grtjn
grtjn

Reputation: 20414

You don't need to worry about the namespace prefix, it doesn't really matter as long as the namespace uri matches.

Both XSLT and XQuery can give you a compact solution. The output indentation might be a little easier to tweak in XSLT though.

Here an XSLT 2.0 solution:

<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/">

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

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

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

</xsl:stylesheet> 

And here an XQuery 1.0 solution:

xquery version "1.0";

declare namespace wsdl = "http://schemas.xmlsoap.org/wsdl/";

declare function local:recurse-nodes($nodes) {
    for $node in $nodes
    return typeswitch ($node)
        case $node as element (wsdl:input) return
            element { node-name($node) } { $node/../wsdl:output/local:recurse-nodes(@*|node()) }
        case $node as element (wsdl:output) return
            element { node-name($node) } { $node/../wsdl:input/local:recurse-nodes(@*|node()) }
        case $node as element () return
            element { node-name($node) } { $node/local:recurse-nodes(@*|node()) }
        case $node as document-node () return
            document { local:recurse-nodes($node/node()) }
        default return $node
};

local:recurse-nodes(doc("country.xml"))

HTH!

Upvotes: 1

Related Questions