Java 如何使用模式验证XML,通过JAXB'一次只读取一个对象/元素;XMLStreamReader?
下面的代码可以正确地从流中一次解组一个对象的XML 但是当我取消注释Java 如何使用模式验证XML,通过JAXB'一次只读取一个对象/元素;XMLStreamReader?,java,xml,jaxb,stax,Java,Xml,Jaxb,Stax,下面的代码可以正确地从流中一次解组一个对象的XML 但是当我取消注释unmarshaller.setSchema(schema)行时,程序会抛出一个异常: [org.xml.sax.SAXParseException:cvc elt.1:找不到元素'Subscriber'的声明。] 我已经使用javax.XML.validation.Validator类验证了XML,但我的目标是同时验证和解组,每次一个元素 这是我当前的代码: SchemaFactory sf = SchemaFactory.n
unmarshaller.setSchema(schema)
行时,程序会抛出一个异常:
[org.xml.sax.SAXParseException:cvc elt.1:找不到元素'Subscriber'的声明。]
我已经使用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();
}
}
SchemaFactory sf=SchemaFactory.newInstance(xmlstants.W3C\u XML\u SCHEMA\u NS\u URI);
Schema Schema=sf.newSchema(新文件(“/Path to xsd”);
XMLInputFactory inputFactory=XMLInputFactory.newInstance();
XMLStreamReader streamReader=inputFactory.createXMLStreamReader(新文件读取器(“/Path to xml”);
JAXBContext JAXBContext=JAXBContext.newInstance(SubscriberType.class);
Unmarshaller Unmarshaller=jaxbContext.createUnmarshaller();
//解组器。设置模式(模式);
streamReader.nextTag();
require(XMLStreamConstants.START_元素,null,“订阅者”);
streamReader.nextTag();
while(streamReader.getEventType()==XMLStreamConstants.START\u元素){
JAXBElement pt=unmarshaller.unmarshal(streamReader,SubscriberType.class);
//对解组对象pt…store to db ect执行一些操作。
if(streamReader.getEventType()==XMLStreamConstants.CHARACTERS){
streamReader.next();
}
}
my schema 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 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上下文知道SubscriberType
和SubscriberInformation
的类。如果要给它一个带有
根元素的XML文档,它知道它必须解组到SubscriberType
的类。但是,如果您给它一个带有
根元素的XML文档,它通常在XJC生成的对象工厂
类中找不到该元素定义。但是,由于您使用了unmarshal
方法,该方法接受第二个参数,即您所期望的类,因此您已经告诉unmarshaller它应该将其输入解释为SubscriberType
。结果将是一个空的SubscriberType
实例
现在,由于您正在逐个迭代
元素(至少我认为您的意思是这样做的),对于解组器来说,它似乎正在接收作为根元素的XML文档。它不会抱怨找不到那个定义,因为你已经用class参数把计算类型的任务去掉了。但是,当您附加一个用于验证的模式时,事情就崩溃了。验证器不知道您在
元素中。它需要一个完整的XML文档。因此,它将查找
的元素声明,但结果为空,因为该元素仅在复杂类型中定义。它不是全局元素定义(即模式根下的定义)
所以,这里有两件事要做。一种是如上所示定义元素
,然后在复杂类型中引用它。另一种方法是将unmarshal调用更改为unmarshal(streamReader,SubscriberInformation.class)
,以获取正确类型的对象。还要注意无限循环或不正确的解组,因为对streamReader.next()
的调用处于某种状态,可能不会触发
使用JAXB编写模式需要某种风格。通常,最好全局定义元素,然后引用它们。仅在复杂类型中本地定义一个元素,前提是它必须保持封装状态
对不起,我的回答太冗长了,我不是很清醒:)你能给我们看看模式文件吗?基本上只验证XML的摘录,而不是整个文档。您是否使用验证器验证了整个文档?如果模式中唯一的元素声明是针对根节点的,那么他找不到“订阅者”的声明是有意义的。您所说的有意义…我将编辑模式并尝试一下。