I'm trying to parse some XML with EclipseLink MOXy, and it's failing on the line with the xsi
attribute. If I remove this, it parses fine. However, I've got 100GiB of XML to wade through and changing the source files is not an option.
我正在尝试使用EclipseLink MOXy解析一些XML,并且它在使用xsi属性时失败了。如果我删除它,它解析很好。但是,我已经获得了100GiB的XML,并且不能更改源文件。
It's been suggested that if I can set XmlParser.setNamespaceAware(false)
then it should work - but I've got no idea how to configure this, without breaking right into the guts of MOXy.
有人建议,如果我可以设置XmlParser.setNamespaceAware(false)那么它应该可以工作 - 但是我不知道如何配置它,而没有直接进入MOXy的内部。
<record>
<header>
<!-- citation-id: 14404534; type: journal_article; -->
<identifier>info:doi/10.1007/s10973-004-0435-2</identifier>
<datestamp>2009-04-28</datestamp>
<setSpec>J</setSpec>
<setSpec>J:1007</setSpec>
<setSpec>J:1007:2777</setSpec>
</header>
<metadata>
<crossref xmlns="http://www.crossref.org/xschema/1.0"
xsi:schemaLocation="http://www.crossref.org/xschema/1.0 http://www.crossref.org/schema/unixref1.0.xsd">
<journal>
<journal_metadata language="en">
[...]
The exception I get when the xsi:
prefix is present is:
当xsi:前缀出现时我得到的例外是:
org.springframework.oxm.UnmarshallingFailureException: JAXB unmarshalling exception; nested exception is javax.xml.bind.UnmarshalException
- with linked exception:
[Exception [EclipseLink-25004] (Eclipse Persistence Services - 2.4.0.v20120608-r11652): org.eclipse.persistence.exceptions.XMLMarshalException
Exception Description: An error occurred unmarshalling the document
Internal Exception: javax.xml.stream.XMLStreamException: ParseError at [row,col]:[13,107]
Message: http://www.w3.org/TR/1999/REC-xml-names-19990114#AttributePrefixUnbound?crossref&xsi:schemaLocation&xsi]
2 个解决方案
#1
8
There currently isn't an option in EclipseLink JAXB (MOXy) to tell it to ignore namespaces. But there is an approach you can use by leveraging a StAX parser.
EclipseLink JAXB(MOXy)中目前没有一个选项可以告诉它忽略名称空间。但是有一种方法可以通过利用StAX解析器来使用。
Demo
演示
You can create a StAX XMLStreamReader
on the XML input that is not namespace aware and then have MOXy unmarshal from that.
您可以在XML输入上创建一个不支持名称空间的StAX XMLStreamReader,然后让MOXy解组。
package forum13416681;
import javax.xml.bind.*;
import javax.xml.stream.*;
import javax.xml.transform.stream.StreamSource;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Foo.class);
XMLInputFactory xif = XMLInputFactory.newFactory();
xif.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, false);
StreamSource source = new StreamSource("src/forum13416681/input.xml");
XMLStreamReader xsr = xif.createXMLStreamReader(source);
Unmarshaller unmarshaller = jc.createUnmarshaller();
Foo root = (Foo) unmarshaller.unmarshal(xsr);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(root, System.out);
}
}
Java Model (Foo)
Java模型(Foo)
package forum13416681;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class Foo {
private String bar;
public String getBar() {
return bar;
}
public void setBar(String bar) {
this.bar = bar;
}
}
Input (input.xml)
输入(input.xml)
Below is a simplified version of the XML from your question. Note that this XML is not properly namespace qualified since it is missing the namespace declaration for the xsi prefix.
以下是您问题中XML的简化版本。请注意,此XML未正确命名空间限定,因为它缺少xsi前缀的名称空间声明。
<?xml version="1.0" encoding="UTF-8"?>
<foo xsi:schemaLocation="http://www.crossref.org/xschema/1.0 http://www.crossref.org/schema/unixref1.0.xsd">
<bar>Hello World</bar>
</foo>
Output
产量
Below is the output from running the demo code.
以下是运行演示代码的输出。
<?xml version="1.0" encoding="UTF-8"?>
<foo>
<bar>Hello World</bar>
</foo>
#2
2
Rather than disabling namespace awareness altogether, you may be able to use a StAX-implementation-specific mechanism to declare the xsi
prefix in advance, then parse with namespaces enabled. For example, with Woodstox you can say:
您可以使用特定于StAX实现的机制来提前声明xsi前缀,然后解析启用的命名空间,而不是完全禁用命名空间感知。例如,使用Woodstox,您可以说:
import javax.xml.bind.*;
import javax.xml.stream.*;
import javax.xml.transform.stream.StreamSource;
import com.ctc.wstx.sr.BasicStreamReader;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance("com.example");
XMLInputFactory xif = XMLInputFactory.newFactory();
StreamSource source = new StreamSource("input.xml");
XMLStreamReader xsr = xif.createXMLStreamReader(source);
((BasicStreamReader)xsr).getInputElementStack().addNsBinding(
"xsi", "http://www.w3.org/2001/XMLSchema-instance");
and then create the unmarshaller and unmarshal the xsr
as in Blaise's answer. While this obviously ties you to one specific StAX implementation, it means that you don't have to modify your existing JAXB model classes if they expect the <crossref>
element and its children to be in the http://www.crossref.org/xschema/1.0
namespace.
然后在Blaise的答案中创建unmarshaller并解组xsr。虽然这显然将您绑定到一个特定的StAX实现,但这意味着如果他们希望
#1
8
There currently isn't an option in EclipseLink JAXB (MOXy) to tell it to ignore namespaces. But there is an approach you can use by leveraging a StAX parser.
EclipseLink JAXB(MOXy)中目前没有一个选项可以告诉它忽略名称空间。但是有一种方法可以通过利用StAX解析器来使用。
Demo
演示
You can create a StAX XMLStreamReader
on the XML input that is not namespace aware and then have MOXy unmarshal from that.
您可以在XML输入上创建一个不支持名称空间的StAX XMLStreamReader,然后让MOXy解组。
package forum13416681;
import javax.xml.bind.*;
import javax.xml.stream.*;
import javax.xml.transform.stream.StreamSource;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Foo.class);
XMLInputFactory xif = XMLInputFactory.newFactory();
xif.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, false);
StreamSource source = new StreamSource("src/forum13416681/input.xml");
XMLStreamReader xsr = xif.createXMLStreamReader(source);
Unmarshaller unmarshaller = jc.createUnmarshaller();
Foo root = (Foo) unmarshaller.unmarshal(xsr);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(root, System.out);
}
}
Java Model (Foo)
Java模型(Foo)
package forum13416681;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class Foo {
private String bar;
public String getBar() {
return bar;
}
public void setBar(String bar) {
this.bar = bar;
}
}
Input (input.xml)
输入(input.xml)
Below is a simplified version of the XML from your question. Note that this XML is not properly namespace qualified since it is missing the namespace declaration for the xsi prefix.
以下是您问题中XML的简化版本。请注意,此XML未正确命名空间限定,因为它缺少xsi前缀的名称空间声明。
<?xml version="1.0" encoding="UTF-8"?>
<foo xsi:schemaLocation="http://www.crossref.org/xschema/1.0 http://www.crossref.org/schema/unixref1.0.xsd">
<bar>Hello World</bar>
</foo>
Output
产量
Below is the output from running the demo code.
以下是运行演示代码的输出。
<?xml version="1.0" encoding="UTF-8"?>
<foo>
<bar>Hello World</bar>
</foo>
#2
2
Rather than disabling namespace awareness altogether, you may be able to use a StAX-implementation-specific mechanism to declare the xsi
prefix in advance, then parse with namespaces enabled. For example, with Woodstox you can say:
您可以使用特定于StAX实现的机制来提前声明xsi前缀,然后解析启用的命名空间,而不是完全禁用命名空间感知。例如,使用Woodstox,您可以说:
import javax.xml.bind.*;
import javax.xml.stream.*;
import javax.xml.transform.stream.StreamSource;
import com.ctc.wstx.sr.BasicStreamReader;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance("com.example");
XMLInputFactory xif = XMLInputFactory.newFactory();
StreamSource source = new StreamSource("input.xml");
XMLStreamReader xsr = xif.createXMLStreamReader(source);
((BasicStreamReader)xsr).getInputElementStack().addNsBinding(
"xsi", "http://www.w3.org/2001/XMLSchema-instance");
and then create the unmarshaller and unmarshal the xsr
as in Blaise's answer. While this obviously ties you to one specific StAX implementation, it means that you don't have to modify your existing JAXB model classes if they expect the <crossref>
element and its children to be in the http://www.crossref.org/xschema/1.0
namespace.
然后在Blaise的答案中创建unmarshaller并解组xsr。虽然这显然将您绑定到一个特定的StAX实现,但这意味着如果他们希望