如果命名空间存在,则无法在JAXB中验证XML的特定部分

时间:2013-12-29 08:50:46

标签: validation namespaces jaxb stax

我正在使用XSD来验证JAXB中XML的特定部分,但由于XML命名空间而失败,您能建议吗?提前谢谢。

错误是“cvc-elt.1:找不到元素的声明'c:MessageDtl'”

XSD

parent.xsd

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema
   targetNamespace="ns.parent"
    elementFormDefault="qualified"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:c="ns.child"
    xmlns="ns.parent">
    <xs:import schemaLocation="child.xsd" namespace="ns.child"></xs:import>
    <xs:complexType name="MessageType">
    <xs:sequence>
        <xs:element name="Message" type="c:Document"></xs:element>
    </xs:sequence>
</xs:complexType>
<xs:element name="Message" type="MessageType"></xs:element>
</xs:schema>

child.xsd

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema
    xmlns="ns.child"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    targetNamespace="ns.child"
    elementFormDefault="qualified">
    <xs:element name="Document" type="Document"/>
    <xs:complexType name="Document">
        <xs:sequence>
            <xs:element name="MessageDtl" type="MessageDtl"/>
        </xs:sequence>
    </xs:complexType>

    <xs:complexType name="MessageDtl">
        <xs:sequence>
            <xs:element name="field1" type="xs:string"/>
            <xs:element name="field2" type="xs:string"/>
        </xs:sequence>
    </xs:complexType>
</xs:schema>

XML

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Message xmlns="ns.parent"
    xmlns:c="ns.child"
    xmlns:xs="http://www.w3.org/2001/XMLSchema-instance"
    xs:schemaLocation="ns.parent parent.xsd ns.child child.xsd">
    <Message>
        <c:MessageDtl>
            <c:field1>field 1</c:field1>
            <c:field2>field 2</c:field2>
        </c:MessageDtl>
    </Message>
</Message>

示例代码

public class TestXmlValidator {
    public static void main(String[] args) throws Exception {
        SchemaFactory SCHEMA_FACTORY = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
        Schema schema = SCHEMA_FACTORY.newSchema(new File("D:/researches/xmlvalidation/xsd/parent.xsd"));

        JAXBContext jaxbContext = JAXBContext.newInstance("com.test");
        SAXSource saxSource = new SAXSource(new InputSource(new FileInputStream("d:/researches/xmlvalidation/sample.xml")));

        InputFactoryImpl XML_INPUT_FACTORY; //fastxml
        XML_INPUT_FACTORY = new com.fasterxml.aalto.stax.InputFactoryImpl();
        XML_INPUT_FACTORY.setProperty(XML_INPUT_FACTORY.IS_NAMESPACE_AWARE, Boolean.TRUE);
        XML_INPUT_FACTORY.setProperty(XML_INPUT_FACTORY.IS_VALIDATING, Boolean.TRUE);
        XML_INPUT_FACTORY.configureForSpeed();

        XMLEventReader2 xmlEventReader = (XMLEventReader2) XML_INPUT_FACTORY.createXMLEventReader(saxSource);

        XMLEvent event;
        while ((event = xmlEventReader.peek()) != null) {
            if(event.isStartElement()){
                System.out.println("=====> " + event.asStartElement().getName().getLocalPart());
                if("MessageDtl".equals(event.asStartElement().getName().getLocalPart())){
                    break;
                }
            }
            xmlEventReader.nextEvent();
        }

        ParseValidationExceptionHandler validationHandler = new ParseValidationExceptionHandler();
        Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
        jaxbUnmarshaller.setEventHandler(validationHandler);
        jaxbUnmarshaller.setSchema(schema);
        JAXBElement<MessageDtl> result = jaxbUnmarshaller.unmarshal(xmlEventReader, MessageDtl.class);

        if(validationHandler.getEvents() != null && validationHandler.getEvents().length>0){
            for(ValidationEvent e : validationHandler.getEvents()){
                System.out.println("=====> " + e.getMessage());
            }
        }

        xmlEventReader.close();
        System.out.println("Completed.");
    }
}

class ParseValidationExceptionHandler implements ValidationEventHandler {
    private final List<ValidationEvent> events = new ArrayList<ValidationEvent>();

    public ValidationEvent[] getEvents() {
        return events.toArray(new ValidationEvent[events.size()]);
    }

    public boolean handleEvent( ValidationEvent event ) {
        events.add(event);
        return true;
    }
}

但是,如果我们尝试验证整个XML,那就是成功。以下是示例代码。

public class TestXmlValidator {
    public static void main(String[] args) throws Exception {
        SchemaFactory SCHEMA_FACTORY = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
        Schema schema = SCHEMA_FACTORY.newSchema(new File("D:/researches/xmlvalidation/xsd/parent.xsd"));
        Validator validator = schema.newValidator();
        SAXSource saxSource = new SAXSource(new InputSource(new FileInputStream("d:/researches/xmlvalidation/sample.xml")));
        validator.validate(saxSource);
        System.out.println("Completed.");
    }
}

1 个答案:

答案 0 :(得分:0)

由于您已在Schema上指定了Unmarshaller的实例,因此将在启用架构验证的情况下完成解组操作(请参阅:http://blog.bdoughan.com/2010/12/jaxb-and-marshalunmarshal-schema.html)。

    jaxbUnmarshaller.setSchema(schema);
    JAXBElement<MessageDtl> result = jaxbUnmarshaller.unmarshal(xmlEventReader, MessageDtl.class);

即使您已将XMLEventReader推进到c:MessageDetail这是一个嵌套元素,但JAXB会在启动解组时将其视为根元素。验证发生在unmarshal中,因此首先要做的是在XML模式中查找名为MessageDetail的根元素,因为这不存在,验证将失败。

<强>解决方案

  1. 更改XML架构,以便MessageDetail是一个全局元素。
  2. 查找并使用验证XMLEventReader