簡體   English   中英

如何使用模式驗證我的 XML,JAXB 的 XMLStreamReader 一次只讀取一個對象/元素?

[英]How can I validate my XML using a schema, reading only one object/element at a time by JAXB's XMLStreamReader?

下面的代碼可以正確地從 stream 一次解組 XML 一個 object。

但是當我取消注釋unmarshaller.setSchema(schema)行時,程序會拋出異常:

[org.xml.sax.SAXParseException:cvc-elt.1:找不到元素“訂閱者”的聲明。]

我已經使用javax.xml.validation.Validator class 驗證了 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();
    }
}

我的模式訂閱者的摘錄。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 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的 class 。 如果你給它一個帶有<Subscribers>根元素的 XML 文檔,它知道它必須解組到SubscriberType的 class 。 但是,如果您給它一個帶有<Subscriber>根元素的 XML 文檔,它通常不會在 XJC 生成的ObjectFactory class 中找到此元素定義。 但是,由於您使用了帶有第二個參數的unmarshal組方法,即您期望的 class,因此您告訴解組器它應該將其輸入解釋為SubscriberType 結果將是一個空的SubscriberType實例。

現在,由於您正在逐一迭代<Subscriber>元素(至少我認為這是您的意思),對於解組器來說,它似乎正在接收 XML 文檔,並將其作為根元素。 它不會抱怨找不到該定義,因為您已經完成了使用 class 參數找出類型的任務。 但是,當您附加一個模式進行驗證時,事情就會崩潰。 驗證器不知道您在<Subscribers>元素中。 它期待完整的 XML 文檔。 因此它會為<Subscriber>尋找元素聲明,但結果為空,因為該元素僅在復雜類型中定義。 它不是一個全局元素定義(即模式根下的一個)。

所以,這里有兩件事要做。 一種是定義元素<Subscriber>如上所示,然后在您的復雜類型中引用它。 另一種是將您的解組調用更改為unmarshal(streamReader, SubscriberInformation.class)以獲取 object 的正確類型。 還要注意無限循環或不正確的解組,因為您對streamReader.next()的調用處於條件並且可能不會觸發。

編寫帶有 JAXB 的模式需要一定的風格。 一般來說,最好全局定義元素,然后引用它們。 如果元素絕對必須保持封裝在那里,則僅在復雜類型中本地定義元素。

對不起,冗長的回答,我不是很清醒:)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM