如何使用XSD验证XML?

时间:2017-06-29 14:39:46

标签: java xml soap xsd

我犯了一个错误,但我看不出它是什么......

我正在尝试使用Java针对XSD验证一段XML(SOAP消息)。我认为应该是具有异常的有效XML /消息:

org.xml.sax.SAXParseException: cvc-elt.1: Cannot find the declaration of element 'tns:Envelope'.
at com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:203).

注1:我调试了xmlSource和xsdSource,它们包含具有预期字符串的预期读者。

注2:无法更改XML的内容。我只是消费者。

注3:由于XML是SOAP消息,我从Web上获取了XSD。因此可能不正确。

注4:为简洁起见,我简化了传入的消息,但在“实际”消息中出现了同样的错误。

爪哇

@Override
public boolean isMessageValid(final String xml) {
    try {
        final Source xmlSource = getStreamSource(xml);
        final Source xsdSource = getStreamSource(fileService.getResourceFileAsString("xsd/soap-envelope.xsd"));

        final SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
        final Schema schema = schemaFactory.newSchema(xsdSource);
        final Validator validator = schema.newValidator();
        validator.validate(xmlSource);
        return true;
    } catch (final Exception ex) {
        LOG.error("Exception whilst validating message", ex);
        return false;
    }
}

private StreamSource getStreamSource(final String xml) {
    return new StreamSource(new StringReader(xml));
}

XML

<?xml version="1.0" encoding="UTF-8"?>
<tns:Envelope xsi:schemaLocation="http://www.w3.org/2001/12/soap-envelope soap-envelope.xsd"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tns="http://www.w3.org/2001/12/soap-envelope">
    <tns:Body>
        <!-- snipped -->
        <someThing>else</someThing>
    </tns:Body>
</tns:Envelope>

XSD

<?xml version='1.0' encoding='UTF-8' ?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns:tns="http://schemas.xmlsoap.org/soap/envelope/"
           targetNamespace="http://schemas.xmlsoap.org/soap/envelope/" >


    <!-- Envelope, header and body -->
    <xs:element name="Envelope" type="tns:Envelope" />
    <xs:complexType name="Envelope" >
        <xs:sequence>
            <xs:element ref="tns:Header" minOccurs="0" />
            <xs:element ref="tns:Body" minOccurs="1" />
            <xs:any namespace="##other" minOccurs="0" maxOccurs="unbounded" processContents="lax" />
        </xs:sequence>
        <xs:anyAttribute namespace="##other" processContents="lax" />
    </xs:complexType>

    <xs:element name="Header" type="tns:Header" />
    <xs:complexType name="Header" >
        <xs:sequence>
            <xs:any namespace="##other" minOccurs="0" maxOccurs="unbounded" processContents="lax" />
        </xs:sequence>
        <xs:anyAttribute namespace="##other" processContents="lax" />
    </xs:complexType>

    <xs:element name="Body" type="tns:Body" />
    <xs:complexType name="Body" >
        <xs:sequence>
            <xs:any namespace="##any" minOccurs="0" maxOccurs="unbounded" processContents="lax" />
        </xs:sequence>
        <xs:anyAttribute namespace="##any" processContents="lax" >
            <xs:annotation>
                <xs:documentation>
                    Prose in the spec does not specify that attributes are allowed on the Body element
                </xs:documentation>
            </xs:annotation>
        </xs:anyAttribute>
    </xs:complexType>


    <!-- Global Attributes.  The following attributes are intended to be usable via qualified attribute names on any complex type referencing them.  -->
    <xs:attribute name="mustUnderstand" >
        <xs:simpleType>
            <xs:restriction base='xs:boolean'>
                <xs:pattern value='0|1' />
            </xs:restriction>
        </xs:simpleType>
    </xs:attribute>
    <xs:attribute name="actor" type="xs:anyURI" />

    <xs:simpleType name="encodingStyle" >
        <xs:annotation>
            <xs:documentation>
                'encodingStyle' indicates any canonicalization conventions followed in the contents of the containing element.  For example, the value 'http://schemas.xmlsoap.org/soap/encoding/' indicates the pattern described in SOAP specification
            </xs:documentation>
        </xs:annotation>
        <xs:list itemType="xs:anyURI" />
    </xs:simpleType>

    <xs:attribute name="encodingStyle" type="tns:encodingStyle" />
    <xs:attributeGroup name="encodingStyle" >
        <xs:attribute ref="tns:encodingStyle" />
    </xs:attributeGroup>

    <xs:element name="Fault" type="tns:Fault" />
    <xs:complexType name="Fault" final="extension" >
        <xs:annotation>
            <xs:documentation>
                Fault reporting structure
            </xs:documentation>
        </xs:annotation>
        <xs:sequence>
            <xs:element name="faultcode" type="xs:QName" />
            <xs:element name="faultstring" type="xs:string" />
            <xs:element name="faultactor" type="xs:anyURI" minOccurs="0" />
            <xs:element name="detail" type="tns:detail" minOccurs="0" />
        </xs:sequence>
    </xs:complexType>

    <xs:complexType name="detail">
        <xs:sequence>
            <xs:any namespace="##any" minOccurs="0" maxOccurs="unbounded" processContents="lax" />
        </xs:sequence>
        <xs:anyAttribute namespace="##any" processContents="lax" />
    </xs:complexType>

</xs:schema>

我估计我已经做了一些事情。

提前致谢

1 个答案:

答案 0 :(得分:1)

前缀“tns”绑定到源和架构中的不同命名空间。所以这不是源文档词汇表的模式。