3

下面的代码可以正确地一次从流中解组一个对象的 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>
4

1 回答 1

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 上下文知道SubscriberTypeand的类SubscriberInformation。如果您要给它一个带有<Subscribers>根元素的 XML 文档,它知道它必须解组到SubscriberType. 然而,如果你给它一个带有<Subscriber>根元素的 XML 文档,它通常不会在ObjectFactoryXJC 生成的类中找到这个元素定义。但是由于您使用了unmarshal接受第二个参数的方法,即您期望的类,您已经告诉解组器它应该将其输入解释为SubscriberType. 结果将是一个空SubscriberType实例。

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

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

考虑到 JAXB 编写模式需要一定的风格。一般来说,最好全局定义元素,然后引用它们。如果元素绝对必须保持封装在那里,则仅在复杂类型中本地定义元素。

对不起,冗长的回答,我不太清醒:)

于 2011-08-18T12:05:44.810 回答