【问题标题】:How can I validate my XML using a schema, reading only one object/element at a time by JAXB's XMLStreamReader?如何使用模式验证我的 XML,通过 JAXB 的 XMLStreamReader 一次只读取一个对象/元素?
【发布时间】:2011-08-17 16:56:43
【问题描述】:

下面的代码可以正确地从流中一次解组一个对象的 XML。

但是当我取消注释 unmarshaller.setSchema(schema) 行时,程序会抛出异常:

[org.xml.sax.SAXParseException: cvc-elt.1: 找不到元素“订阅者”的声明。]

我已经使用 javax.xml.validation.Validator 类验证了 XML,但我的目标是同时验证和解组,一次一个元素。

这是我当前的代码:

SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); 
Schema schema = sf.newSchema(new File("/Path to xsd"));

XMLInputFactory inputFactory = XMLInputFactory.newInstance();
XMLStreamReader streamReader = inputFactory.createXMLStreamReader(new FileReader("/Path to xml"));

JAXBContext jaxbContext = JAXBContext.newInstance(SubscriberType.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
//unmarshaller.setSchema(schema);

streamReader.nextTag();
streamReader.require(XMLStreamConstants.START_ELEMENT, null, "Subscribers");
streamReader.nextTag();    
while (streamReader.getEventType() == XMLStreamConstants.START_ELEMENT) {

    JAXBElement<SubscriberType> pt = unmarshaller.unmarshal(streamReader, SubscriberType.class);
    //do something with the unmarshalled object pt...store to db ect.

    if (streamReader.getEventType() == XMLStreamConstants.CHARACTERS) {
        streamReader.next();
    }
}

我的架构subscriber.xsd 的摘录:

<?xml version="1.0" encoding="UTF-8" ?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
        elementFormDefault="unqualified" 
        attributeFormDefault="unqualified">

  <xsd:element name="Subscribers" type="SubscriberType" />

  <xsd:complexType name="SubscriberType">
    <xsd:sequence>
      <xsd:element name="Subscriber" 
              type="SubscriberInformation" 
              minOccurs="1" 
              maxOccurs="unbounded"/>
    </xsd:sequence>
  </xsd:complexType>

【问题讨论】:

  • 您能给我们看看架构文件吗?您基本上只验证 XML 的提取,而不是整个文档。您是否使用验证器验证了整个文档?如果架构中唯一的元素声明是针对根节点的,那么他找不到“订阅者”的声明是有道理的。
  • 你说的很有道理...我会编辑架构并试一试。

标签: java xml jaxb stax


【解决方案1】:

试试这样的架构:

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="unqualified" attributeFormDefault="unqualified">

    <xsd:element name="Subscribers" type="SubscriberType"/>

    <xsd:element name="Subscriber" type="SubscriberInformation" />

    <xsd:complexType name="SubscriberType">
        <xsd:sequence>
            <xsd:element ref="Subscriber" minOccurs="1" maxOccurs="unbounded"/>
        </xsd:sequence>
    </xsd:complexType>

我相信您的架构会发生以下情况:JAXB 上下文知道 SubscriberTypeSubscriberInformation 的类。如果您要给它一个带有&lt;Subscribers&gt; 根元素的XML 文档,它知道它必须解组到SubscriberType 的类。然而,如果你给它一个带有&lt;Subscriber&gt; 根元素的XML 文档,它通常不会在XJC 生成的ObjectFactory 类中找到这个元素定义。但是由于您使用了带有第二个参数的unmarshal 方法,即您期望的类,您已经告诉解组器它应该将其输入解释为SubscriberType。结果将是一个空的 SubscriberType 实例。

现在,由于您正在逐个迭代 &lt;Subscriber&gt; 元素(至少我认为您打算这样做),对于解组器来说,它似乎正在以 root 身份接收 XML 文档元素。它不会抱怨找不到该定义,因为您已经完成了使用 class 参数找出类型的任务。但是,当您附加一个模式进行验证时,事情就会崩溃。验证器不知道您在 &lt;Subscribers&gt; 元素内。它需要一个完整的 XML 文档。所以它会去寻找&lt;Subscriber&gt; 的元素声明,但结果为空,因为该元素仅在复杂类型中定义。它不是全局元素定义(即架构根下的一个)。

所以,这里有两件事要做。一种是定义元素&lt;Subscriber&gt;,如上所示,然后在您的复杂类型中引用它。另一种是将您的解组调用更改为unmarshal(streamReader, SubscriberInformation.class) 以获取正确类型的对象。还要注意无限循环或不正确的解组,因为您对 streamReader.next() 的调用处于状态,可能不会触发。

使用 JAXB 编写模式需要一定的风格。一般来说,最好全局定义元素,然后引用它们。只有在绝对必须保持封装的情况下,才在复杂类型中本地定义元素。

对不起,我的回答太啰嗦了,我不太清醒:)

【讨论】:

    猜你喜欢
    • 2014-09-05
    • 1970-01-01
    • 2014-11-28
    • 2016-12-05
    • 2014-06-10
    • 1970-01-01
    • 2018-02-09
    • 1970-01-01
    • 2015-09-11
    相关资源
    最近更新 更多