hyde
hyde

Reputation: 2585

Validating XML documents against schemas nested inside wsdl:types

I have XML files that I need to validate against XSDs that are nested inside a <wsdl:types></wsdl:types> in a WSDL file retrieved from a web service.

Inside the <wsdl:types></wsdl:types> there are several <xs:schema>s. I am using the ruby gem nokogiri to load the XML files and validate them against said XSDs, however, I am getting following error when I run the program:

Element '{http://schemas.xmlsoap.org/soap/envelope/}Envelope': No 
matching global declaration available for the validation root.

So far I have extracted out the <xs:schema>s (all 4 of them) and copied them into a schema.xsd file.

Code:

require 'rubygems'
require 'nokogiri'

def validate(document_path, schema_path)
  schema = Nokogiri::XML::Schema(File.read(schema_path))
  document = Nokogiri::XML(File.read(document_path))
  schema.validate(document)
end


validate('data.xml', 'schema.xsd').each do |error|
  puts error.message
end

So basically my schema.xsd has multiple <xs:schema>s in there, which I do not think in and of itself is a problem because nokogiri didn't throw errors when I instantiated the schema object.

schema.xsd

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://schemas.microsoft.com/2003/10/Serialization/" attributeFormDefault="qualified" elementFormDefault="qualified" targetNamespace="http://schemas.microsoft.com/2003/10/Serialization/">
  <xs:element name="anyType" nillable="true" type="xs:anyType"/>
  <xs:element name="anyURI" nillable="true" type="xs:anyURI"/>
  <!-- data in here -->
</xs:schema>

<!-- three more xs:schema tags removed for brevity -->

data.xml

<?xml version='1.0' ?>
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
  <env:Header />
  <env:Body>
    <CreatePerson xmlns="https://person.example.com/">
      <oMessageType xmlns:epa="http://schemas.datacontract.org/2004/07/whatever" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:array="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
        <person:bodyField>
            <!-- data in here -->
        </person:bodyField>
        <!-- more data in here -->
      </oMessageType>
    </CreatePerson>
  </env:Body>
</env:Envelope>

Upvotes: 1

Views: 677

Answers (1)

Liping Huang
Liping Huang

Reputation: 4476

Yes, WSDL not the XSD scheam so you need to extract the schema partial manually or automatic by programming.

Here is the sample code, you need to refactor it and using in your codes.

str = <<EOF
    <definitions xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://www.examples.com/wsdl/HelloService.wsdl" xmlns:xsd="http://www.w3.org/2001/XMLSchema" name="HelloService" targetNamespace="http://www.examples.com/wsdl/HelloService.wsdl">
    <types>
        <schema xmlns="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://schemas.microsoft.com/2003/10/Serialization/" attributeFormDefault="qualified" elementFormDefault="qualified" targetNamespace="http://schemas.microsoft.com/2003/10/Serialization/">
          <element name="anyType" nillable="true" type="anyType"/>
          <element name="anyURI" nillable="true" type="anyURI"/>
          <!-- data in here -->
        </schema>
    </types>
    <message name="SayHelloRequest">
        <part name="firstName" type="xsd:string"/>
    </message>
    <message name="SayHelloResponse">
        <part name="greeting" type="xsd:string"/>
    </message>
    <portType name="Hello_PortType">
        <operation name="sayHello">
            <input message="tns:SayHelloRequest"/>
            <output message="tns:SayHelloResponse"/>
        </operation>
    </portType>
    <binding name="Hello_Binding" type="tns:Hello_PortType">
        <soap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http"/>
        <operation name="sayHello">
            <soap:operation soapAction="sayHello"/>
            <input>
                <soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:examples:helloservice"/>
            </input>
            <output>
                <soap:body use="encoded" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="urn:examples:helloservice"/>
            </output>
        </operation>
    </binding>
    <service name="Hello_Service">
        <documentation>WSDL File for HelloService</documentation>
        <port name="Hello_Port" binding="tns:Hello_Binding">
            <soap:address location="http://www.examples.com/SayHello/"/>
        </port>
    </service>
</definitions>

EOF

require 'rubygems'
require 'nokogiri'

doc = Nokogiri::XML(str)

doc.root.children.each do |child|
    if child.node_name == 'types'
        types = child 
        # p types.inner_html
        xsd_doc = Nokogiri::XML(types.inner_html)

        # p xsd_doc.root

        xsd = Nokogiri::XML::Schema.from_document xsd_doc.root
    end
end

Upvotes: 1

Related Questions