简体   繁体   中英

XSD for use with Spring, can't get it to match WSDL

For the project I'm working on we need to create a SOAP web service (using Spring boot). The actual interface and message format is defined by a WSDL. The problem is that from what I understand from the documentation (eg https://www.baeldung.com/spring-boot-soap-web-service ), I actually need an XSD (the WSDL will be generated from that).

Since there is only the WSDL, I tried to create the XSD myself for use in the application. Here I have run in to a couple of problems, the biggest problem being that the request messages it accepts aren't the ones that are accepted by the WSDL.

The WSDL accepts requests which simply are named payment where mine require paymentRequest as the name of the body element. This is probably something simple, but I can't find how to fix this…

Simplified wsdl:

<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions targetNamespace="http://xxx.yyy.com" 
                  xmlns:impl="http://xxx.yyy.com" 
                  xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
                  xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" 
                  xmlns:xsd="http://www.w3.org/2001/XMLSchema">
 <wsdl:types>
  <schema targetNamespace="http://xxx.yyy.com" xmlns="http://www.w3.org/2001/XMLSchema">
   <import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>
   <complexType name="XxxTxnResponse">
    <sequence>
     <element name="resultCode" type="xsd:int"/>
    </sequence>
   </complexType>
   <complexType name="XxxToken">
    <sequence>
     <element name="tokenId" nillable="true" type="xsd:string"/>
    </sequence>
   </complexType>
   <complexType name="PaymentTxnResponse">
    <complexContent>
     <extension base="impl:XxxTxnResponse">
      <sequence>
       <element name="transactionRef" type="xsd:int"/>
       </sequence>
      </extension>
    </complexContent>
   </complexType>
  </schema>
 </wsdl:types>
    <wsdl:message name="paymentRequest">
      <wsdl:part name="posId" type="xsd:string"/>
      <wsdl:part name="amountCents" type="xsd:int"/>
      <wsdl:part name="token" type="impl:XxxToken"/>
    </wsdl:message>
    <wsdl:message name="paymentResponse">
      <wsdl:part name="paymentReturn" type="impl:PaymentTxnResponse"/>
    </wsdl:message>  
   <wsdl:portType name="XxxTxnHost">
      <wsdl:operation name="payment" parameterOrder="posId amountCents token">
         <wsdl:input message="impl:paymentRequest" name="paymentRequest"/>
         <wsdl:output message="impl:paymentResponse" name="paymentResponse"/>
      </wsdl:operation>     
   </wsdl:portType>
   <wsdl:binding name="XxxTxnHostSoapBinding" type="impl:XxxTxnHost">
      <wsdlsoap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>    
     <wsdl:operation name="payment">
       <wsdlsoap:operation soapAction=""/>
       <wsdl:input name="paymentRequest">
         <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://xxx.yyy.com" use="encoded"/>
       </wsdl:input>
       <wsdl:output name="paymentResponse">
         <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://xxx.yyy.com" use="encoded"/>
       </wsdl:output>
     </wsdl:operation>     
   </wsdl:binding>
   <wsdl:service name="XxxTxnHostService">
      <wsdl:port binding="impl:XxxTxnHostSoapBinding" name="XxxTxnHost">
         <wsdlsoap:address location="wp.wsdl"/>
      </wsdl:port>
   </wsdl:service>   
</wsdl:definitions>

Example request:

<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xxx="http://xxx.yyy.com">
   <soapenv:Header/>
   <soapenv:Body>
      <xxx:payment soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
         <posId xsi:type="xsd:string">?</posId>
         <amountCents xsi:type="xsd:int">?</amountCents>
         <token xsi:type="xxx:XxxToken">
            <tokenId xsi:type="xsd:string">?</tokenId>
         </token>
      </xxx:payment>
   </soapenv:Body>
</soapenv:Envelope>

My simplified xsd:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           targetNamespace="http://xxx.yyy.com"
           xmlns:tns="http://xxx.yyy.com">
    <xs:import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>
    <xs:complexType name="XxxTxnResponse">
        <xs:sequence>
            <xs:element name="resultCode" type="xs:int"/>
        </xs:sequence>
    </xs:complexType>

    <xs:complexType name="XxxToken">
        <xs:sequence>
            <xs:element name="tokenId" nillable="true" type="xs:string"/>
        </xs:sequence>
    </xs:complexType>

    <xs:complexType name="PaymentTxnResponse">
        <xs:complexContent>
            <xs:extension base="tns:XxxTxnResponse">
                <xs:sequence>
                    <xs:element name="transactionRef" type="xs:int"/>
                </xs:sequence>
            </xs:extension>
        </xs:complexContent>
    </xs:complexType>

    <xs:element name="paymentRequest">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="posId" type="xs:string"/>
                <xs:element name="amountCents" type="xs:int"/>
                <xs:element name="token" type="tns:XxxToken"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:element name="paymentResponse">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="paymentReturn" type="tns:PaymentTxnResponse"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

</xs:schema>

Generated wsdl:

<?xml version="1.0" encoding="UTF-8" standalone="no"?><wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:sch="http://xxx.yyy.com" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://xxx.yyy.com" targetNamespace="http://xxx.yyy.com">
  <wsdl:types>
    <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://xxx.yyy.com">
    <xs:import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>
    <xs:complexType name="XxxTxnResponse">
        <xs:sequence>
            <xs:element name="resultCode" type="xs:int"/>
        </xs:sequence>
    </xs:complexType>

    <xs:complexType name="XxxToken">
        <xs:sequence>
            <xs:element name="tokenId" nillable="true" type="xs:string"/>
        </xs:sequence>
    </xs:complexType>

    <xs:complexType name="PaymentTxnResponse">
        <xs:complexContent>
            <xs:extension base="tns:XxxTxnResponse">
                <xs:sequence>
                    <xs:element name="transactionRef" type="xs:int"/>
                </xs:sequence>
            </xs:extension>
        </xs:complexContent>
    </xs:complexType>

    <xs:element name="paymentRequest">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="posId" type="xs:string"/>
                <xs:element name="amountCents" type="xs:int"/>
                <xs:element name="token" type="tns:XxxToken"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:element name="paymentResponse">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="paymentReturn" type="tns:PaymentTxnResponse"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

</xs:schema>
  </wsdl:types>
  <wsdl:message name="paymentResponse">
    <wsdl:part element="tns:paymentResponse" name="paymentResponse">
    </wsdl:part>
  </wsdl:message>
  <wsdl:message name="paymentRequest">
    <wsdl:part element="tns:paymentRequest" name="paymentRequest">
    </wsdl:part>
  </wsdl:message>
  <wsdl:portType name="yyy">
    <wsdl:operation name="payment">
      <wsdl:input message="tns:paymentRequest" name="paymentRequest">
    </wsdl:input>
      <wsdl:output message="tns:paymentResponse" name="paymentResponse">
    </wsdl:output>
    </wsdl:operation>
  </wsdl:portType>
  <wsdl:binding name="yyySoap11" type="tns:yyy">
    <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
    <wsdl:operation name="payment">
      <soap:operation soapAction=""/>
      <wsdl:input name="paymentRequest">
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output name="paymentResponse">
        <soap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>
  <wsdl:service name="yyyService">
    <wsdl:port binding="tns:yyySoap11" name="yyySoap11">
      <soap:address location="http://localhost:8206/yyyservice/ws"/>
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>

There are a number of differences which I hope to solve in the end (no use of encoded is one), but the biggest problem is the fact that my wsdl requires paymentRequest in the request body, whereas the original message uses just payment . The response actually looked similar to what is expected.

I'm sure there something simple I have forgotten to do/specify, so hopefully one of you is able to point me in the right direction.

There is a difference in your bindings definitions. In the given wsdl there is specified that rpc/encoded is used while in your generated wsdl document/literal is used. Most likely you can set these settings before generating the wsdl.

If you alter the generated wsdl so it uses the prc/encoded the request looks like:

    <SOAP-ENV:Body>
        <m:payment xmlns:m="http://xxx.yyy.com">
            <m:payment>
                <posId xsi:type="xsd:string">String</posId>
                <amountCents xsi:type="xsd:int">0</amountCents>
                <token xsi:type="m:XxxToken">
                    <tokenId xsi:type="xsd:string">String</tokenId>
                </token>
            </m:payment>
        </m:payment>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

see https://docs.microsoft.com/en-us/previous-versions/dotnet/articles/ms996486(v=msdn.10)?redirectedfrom=MSDN#understand_topic6

OK, after loads of trial and error, I managed to find a different solution with which I was able to consume the messages.

I didn't like my earlier attempt where I renamed paymentRequest to just payment since when looking at the wsdl, I saw all the “input” parts missing from the operations. This didn't feel good.

However, by simply specifying the type

<xs:complexType name="PaymentRequest">
    <xs:sequence>
        <xs:element name="posId" type="xs:string"/>
        <xs:element name="amountCents" type="xs:int"/>
        <xs:element name="token" type="tns:XxxToken"/>
    </xs:sequence>
</xs:complexType>

and the element

<xs:element name="paymentRequest" type ="PaymentRequest">

separately, it worked, and now with the input parts showing properly again in the WSDL.

Digging around a little more, it follows the main issue is actually (fully) caused by the original WSDL using RPC/encoded instead of Document/Literal (as already suggested by @martijn in his answer). As it turns out RPC/encoded is actually deprecated (quite a number of years now…) and doesn't seem to be supported by Spring.

So unless someone knows how to get Spring to use RPC/encoded, I guess I need to go back to the company that is asking me to develop a server to communicate with their hardware and make them allow Document/literal responses (at least).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM