Reputation: 11899
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:
wsdl:definitions
, wsdl:portType
, wsdl:operation
- while others might just be definitions
, portType
, operation
, etc.Upvotes: 3
Views: 1205
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
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