gpt4 book ai didi

java - 忽略命名空间的 JAXB 解码将元素属性转换为 null

转载 作者:太空狗 更新时间:2023-10-29 22:43:53 25 4
gpt4 key购买 nike

我正在尝试使用 JAXB 将 xml 文件解码为对象,但遇到了一些困难。实际项目在 xml 文件中有几千行,所以我在较小的范围内重现了错误,如下所示:

XML 文件:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<catalogue title="some catalogue title"
publisher="some publishing house"
xmlns="x-schema:TamsDataSchema.xml"/>

用于生成 JAXB 类的 XSD 文件

<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:element name="catalogue" type="catalogueType"/>

<xsd:complexType name="catalogueType">
<xsd:sequence>
<xsd:element ref="journal" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="title" type="xsd:string"/>
<xsd:attribute name="publisher" type="xsd:string"/>
</xsd:complexType>
</xsd:schema>

代码片段 1:

final JAXBContext context = JAXBContext.newInstance(CatalogueType.class);
um = context.createUnmarshaller();
CatalogueType ct = (CatalogueType)um.unmarshal(new File("file output address"));

抛出错误:

javax.xml.bind.UnmarshalException: unexpected element (uri:"x-schema:TamsDataSchema.xml", local:"catalogue"). Expected elements are <{}catalogue>
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.handleEvent(UnmarshallingContext.java:642)
at com.sun.xml.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:247)
at com.sun.xml.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:242)
at com.sun.xml.bind.v2.runtime.unmarshaller.Loader.reportUnexpectedChildElement(Loader.java:116)
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext$DefaultRootLoader.childElement(UnmarshallingContext.java:1049)
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext._startElement(UnmarshallingContext.java:478)
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.startElement(UnmarshallingContext.java:459)
at com.sun.xml.bind.v2.runtime.unmarshaller.SAXConnector.startElement(SAXConnector.java:148)
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.startElement(Unknown Source)
at com.sun.org.apache.xerces.internal.parsers.AbstractXMLDocumentParser.emptyElement(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.scanStartElement(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl$NSContentDispatcher.scanRootElementHook(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(Unknown Source)
...etc

所以 XML 文档中的命名空间导致了问题,不幸的是,如果它被删除它就可以正常工作,但是由于文件是由客户端提供的,我们无法解决这个问题。我尝试了多种在 XSD 中指定它的方法,但似乎没有一种排列有效。

我还尝试使用以下代码解码忽略命名空间:

Unmarshaller um = context.createUnmarshaller();
final SAXParserFactory sax = SAXParserFactory.newInstance();
sax.setNamespaceAware(false);
final XMLReader reader = sax.newSAXParser().getXMLReader();
final Source er = new SAXSource(reader, new InputSource(new FileReader("file location")));
CatalogueType ct = (CatalogueType)um.unmarshal(er);
System.out.println(ct.getPublisher());
System.out.println(ct.getTitle());

工作正常但无法解码元素属性和打印

null
null

由于我们无法控制的原因,我们仅限于使用 Java 1.5,而我们使用的是 JAXB 2.0,这很不幸,因为第二个代码块使用 Java 1.6 可以正常工作。

如有任何建议,我们将不胜感激,另一种方法是在解析文件之前将命名空间声明从文件中删除,这看起来并不优雅。

最佳答案

感谢您发表这篇文章和您的代码片段。它确实让我走上了正确的道路,因为我也疯狂地试图处理一些供应商提供的 XML,这些 XML 到处都是 xmlns="http://vendor.com/foo"

我的第一个解决方案(在阅读您的帖子之前)是将 XML 放入字符串中,然后是 xmlString.replaceAll("xmlns=", "ylmns=");(恐怖的是,恐怖)。除了冒犯我的敏感度之外,在处理来自 InputStream 的 XML 时还很痛苦。

我的第二个解决方案,在查看了您的代码片段之后:(我使用的是 Java7)

// given an InputStream inputStream:
String packageName = docClass.getPackage().getName();
JAXBContext jc = JAXBContext.newInstance(packageName);
Unmarshaller u = jc.createUnmarshaller();

InputSource is = new InputSource(inputStream);
final SAXParserFactory sax = SAXParserFactory.newInstance();
sax.setNamespaceAware(false);
final XMLReader reader;
try {
reader = sax.newSAXParser().getXMLReader();
} catch (SAXException | ParserConfigurationException e) {
throw new RuntimeException(e);
}
SAXSource source = new SAXSource(reader, is);
@SuppressWarnings("unchecked")
JAXBElement<T> doc = (JAXBElement<T>)u.unmarshal(source);
return doc.getValue();

但是现在,我找到了我更喜欢的第三种解决方案,希望它可能对其他人有用:How to define properly the expected namespace in the schema:

<xsd:schema jxb:version="2.0"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb"
xmlns="http://vendor.com/foo"
targetNamespace="http://vendor.com/foo"
elementFormDefault="unqualified"
attributeFormDefault="unqualified">

这样,我们现在可以删除 sax.setNamespaceAware(false); 行(更新:实际上,如果我们保留 unmarshal(SAXSource) 调用,那么我们需要 sax.setNamespaceAware(true)。但更简单的方法是不要理会 SAXSource 及其创建周围的代码,而是 unmarshal(InputStream) 默认情况下是命名空间感知的。而且 marshal() 的输出也有适当的命名空间。

是的。仅用了大约 4 个小时。

关于java - 忽略命名空间的 JAXB 解码将元素属性转换为 null,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1871060/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com