根据从WSDL中提取的多个模式验证XML

时间:2014-01-20 16:01:59

标签: java xsd wsdl schema wsdl4j

我正在尝试使用SAAJ手动处理Web Service请求,但仍然根据Web服务的WSDL架构验证收到的请求。这个特定的WSDL包含多个元素,我使用wsdl4j提取,当我到达尝试创建新的Validator时,我收到一条关于Validator无法解析一个模式内的引用的错误消息另一个中定义的元素:

org.xml.sax.SAXParseException; src-resolve: Cannot resolve the name 'ns0:CustomerNumber' to a(n) 'element declaration' component.

我已经将实际的WSDL和代码编写成了一些小的东西来创建可重现的东西。 “simple.wsdl”也在Soap-UI中正确加载。这是在Windows 7上使用jdk1.7.0_51。

请注意,我注意到此问题的原始WSDL是由TIBCO BusinessWorks生成的,因此我不认为这是无效WSDL的问题。

我在SO上看到过与此类似的其他问题,但提供的解决方案似乎并不完全符合我的情况,所以我想我会再问一次。

有没有人知道发生了什么以及如何让它发挥作用?

测试代码:

import java.util.ArrayList;

import javax.wsdl.Definition;
import javax.wsdl.extensions.schema.Schema;
import javax.wsdl.factory.WSDLFactory;
import javax.wsdl.xml.WSDLReader;
import javax.xml.XMLConstants;
import javax.xml.transform.dom.DOMSource;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;

import org.junit.Test;
import org.w3c.dom.Element;

public class TestIt {
    @Test
    public void testWSDLSchema() throws Exception {
        WSDLFactory wsdlFactory    = WSDLFactory.newInstance();
        WSDLReader reader         = wsdlFactory.newWSDLReader();
        Definition wsdlDefinition = reader.readWSDL("test/resources/simple.wsdl");

        ArrayList<Element> wsdlSchemas = new ArrayList<Element>();

        for (Object o : wsdlDefinition.getTypes().getExtensibilityElements()) {
            if (o instanceof Schema) {
                wsdlSchemas.add(((Schema) o).getElement());
            }
        }

        SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
        ArrayList<DOMSource> asrcs   = new ArrayList<DOMSource>();

        for (Element e : wsdlSchemas) {
            asrcs.add(new DOMSource(e));
        }
        DOMSource sources[] = asrcs.toArray(new DOMSource[0]);
        javax.xml.validation.Schema schema  = factory.newSchema(sources);

        Validator schemaValidator = schema.newValidator();
    }
}

完整堆栈跟踪:

Retrieving document at 'test/resources/simple.wsdl'.

org.xml.sax.SAXParseException; src-resolve: Cannot resolve the name 'ns0:CustomerNumber' to a(n) 'element declaration' component.
    at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:198)
    at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.error(ErrorHandlerWrapper.java:134)
    at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:437)
    at com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:347)
    at com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.reportSchemaErr(XSDHandler.java:4166)
    at com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.reportSchemaError(XSDHandler.java:4145)
    at com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.getGlobalDecl(XSDHandler.java:1678)
    at com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDElementTraverser.traverseLocal(XSDElementTraverser.java:170)
    at com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.traverseLocalElements(XSDHandler.java:3618)
    at com.sun.org.apache.xerces.internal.impl.xs.traversers.XSDHandler.parseSchema(XSDHandler.java:633)
    at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaLoader.loadSchema(XMLSchemaLoader.java:616)
    at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaLoader.loadGrammar(XMLSchemaLoader.java:574)
    at com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaLoader.loadGrammar(XMLSchemaLoader.java:540)
    at com.sun.org.apache.xerces.internal.jaxp.validation.XMLSchemaFactory.newSchema(XMLSchemaFactory.java:252)
    at TestIt.testWSDLSchema(TestIt.java:37)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:74)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:202)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:65)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)

WSDL:

<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions xmlns:ns10="http://www.abc.com/ServiceA"
                  xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
                  xmlns:ns13="http://www.abc.com/Common"
                  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
                  xmlns:ns2="http://www.abc.com/DetailsResponse"
                  xmlns:ns3="http://www.abc.com/ErrorSchema"
                  xmlns:ns1="http://www.abc.com/DetailsRequest"
                  xmlns:tns="http://www.abc.com/Service"
                  name="Untitled"
                  targetNamespace="http://www.abc.com/Service">
    <wsdl:types>
        <xs:schema
                xmlns="http://www.abc.com/DetailsRequest"
                xmlns:ns0="http://www.abc.com/Common"
                xmlns:xs="http://www.w3.org/2001/XMLSchema"
                targetNamespace="http://www.abc.com/DetailsRequest"
                elementFormDefault="qualified"
                attributeFormDefault="unqualified">
            <xs:import namespace="http://www.w3.org/XML/1998/namespace"/>
            <xs:import namespace="http://www.abc.com/Common"/>
            <xs:element name="DetailsRequest">
                <xs:complexType>
                    <xs:sequence>
                        <xs:element ref="ns1:RequestBody"/>
                    </xs:sequence>
                </xs:complexType>
            </xs:element>
            <xs:element name="RequestBody">
                <xs:complexType>
                    <xs:sequence>
                        <xs:element ref="ns0:CustomerNumber"/>
                    </xs:sequence>
                </xs:complexType>
            </xs:element>
        </xs:schema>
        <xs:schema
                xmlns="http://www.abc.com/DetailsResponse"
                xmlns:ns0="http://www.abc.com/Common"
                xmlns:xs="http://www.w3.org/2001/XMLSchema"
                targetNamespace="http://www.abc.com/DetailsResponse"
                elementFormDefault="qualified"
                attributeFormDefault="unqualified">
            <xs:import namespace="http://www.abc.com/Common"/>
            <xs:element name="DetailsResponse">
                <xs:complexType>
                    <xs:sequence>
                        <xs:element ref="ns0:AccountNumber"/>
                    </xs:sequence>
                </xs:complexType>
            </xs:element>
        </xs:schema>
        <xs:schema
                xmlns="http://www.abc.com/Common"
                xmlns:xs="http://www.w3.org/2001/XMLSchema"
                targetNamespace="http://www.abc.com/Common"
                elementFormDefault="qualified"
                attributeFormDefault="unqualified">
            <xs:element name="CustomerNumber">
                <xs:simpleType>
                    <xs:restriction base="xs:string">
                        <xs:maxLength value="20"/>
                    </xs:restriction>
                </xs:simpleType>
            </xs:element>
            <xs:element name="AccountNumber">
                <xs:simpleType>
                    <xs:restriction base="xs:string">
                        <xs:maxLength value="20"/>
                    </xs:restriction>
                </xs:simpleType>
            </xs:element>
        </xs:schema>
        <xs:schema
                xmlns="http://www.abc.com/ErrorSchema"
                xmlns:xs="http://www.w3.org/2001/XMLSchema"
                targetNamespace="http://www.abc.com/ErrorSchema"
                elementFormDefault="qualified"
                attributeFormDefault="unqualified">
            <xs:element name="ErrorSchema">
                <xs:complexType>
                    <xs:sequence>
                        <xs:element name="ErrorResponseBody" type="xs:string"/>
                    </xs:sequence>
                </xs:complexType>
            </xs:element>
        </xs:schema>
    </wsdl:types>
    <wsdl:service name="ServiceA">
        <wsdl:port name="ServiceAEndpoint" binding="tns:ServiceABinding">
            <soap:address location="http://localhost:7232/ServiceA/ServiceAEndpoint"/>
        </wsdl:port>
    </wsdl:service>
    <wsdl:portType name="ServiceA">
        <wsdl:operation name="GetDetails">
            <wsdl:input message="tns:DetailsRequest"/>
            <wsdl:output message="tns:DetailsResponse"/>
            <wsdl:fault name="fault1" message="tns:DetailsErrorResponse"/>
        </wsdl:operation>
    </wsdl:portType>
    <wsdl:binding name="ServiceABinding" type="tns:ServiceA">
        <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
        <wsdl:operation name="GetDetails">
            <soap:operation style="document" soapAction="/ServiceA/ServiceAEndpoint/GetDetails"/>
            <wsdl:input>
                <soap:body use="literal" parts="DetailsRequest"/>
            </wsdl:input>
            <wsdl:output>
                <soap:body use="literal" parts="DetailsResponse"/>
            </wsdl:output>
            <wsdl:fault name="fault1">
                <soap:fault use="literal" name="fault1"/>
            </wsdl:fault>
        </wsdl:operation>
    </wsdl:binding>
    <wsdl:message name="DetailsRequest">
        <wsdl:part name="DetailsRequest" element="ns1:DetailsRequest"/>
    </wsdl:message>
    <wsdl:message name="DetailsResponse">
        <wsdl:part name="DetailsResponse" element="ns2:DetailsResponse"/>
    </wsdl:message>
    <wsdl:message name="DetailsErrorResponse">
        <wsdl:part name="DetailsErrorResponse" element="ns3:ErrorSchema"/>
    </wsdl:message>
</wsdl:definitions>

2 个答案:

答案 0 :(得分:1)

我必须既使用LSResourceResolver,又将名称空间声明从wsdl文档复制到架构元素,以完成此工作。这是代码:

\b

这里也回答相同: Java, Validate XML against an embedded schema in WSDL

答案 1 :(得分:0)

我认为SchemaFactory对于如何导致进口感到“愚蠢”。我相信如果你以相反的顺序(最低级别到最高级别)提供模式,那应该有效。在您有更复杂的依赖项(或同一名称空间的多个模式)的情况下,您可能需要实现自定义LSResourceResolver并将其设置在SchemaFactory上。