我有一个有趣的情况,我的XML编辑器(Oxygen,它使用Xerces XML处理器)需要在根标记上有一个前缀,但我的JAXB XML Marshaller(也基于Xercies)不需要根标记上的前缀。我试图了解这种情况。
首先是 2 个架构文件:
ns1.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.ns1.com"
xmlns="http://www.ns1.com"
xmlns:ns2="http://www.ns2.com"
elementFormDefault="unqualified"
attributeFormDefault="unqualified"
version="1.0" >
<xs:import namespace="http://www.ns2.com" schemaLocation="ns2.xsd"/>
<xs:element name="root">
<xs:complexType>
<xs:all>
<xs:element name="element1">
<xs:complexType>
<xs:all>
<xs:element name="element1a" type="NS1Type"/>
<xs:element name="element1b" type="ns2:NS2Type"/>
</xs:all>
</xs:complexType>
</xs:element>
</xs:all>
</xs:complexType>
</xs:element>
<xs:simpleType name="NS1Type">
<xs:restriction base="xs:string">
<xs:enumeration value="VALUE_1"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>
ns2.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.ns2.com"
xmlns="http://www.ns2.com"
elementFormDefault="unqualified"
attributeFormDefault="unqualified"
version="1.0" >
<xs:complexType name="NS2Type">
<xs:all>
<xs:element name="value" type="xs:float" minOccurs="0"/>
</xs:all>
</xs:complexType>
</xs:schema>
当前版本的 Oxygen (16.1) 需要什么,我将称之为"版本 1"
版本 1
<?xml version="1.0" encoding="UTF-8"?>
<ns1:root
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ns1="http://www.ns1.com"
xsi:schemaLocation="http://www.ns1.com ../schema/ns1.xsd">
<element1>
<element1a>VALUE_1</element1a>
<element1b>
<value>4.5</value>
</element1b>
</element1>
</ns1:root>
相反,如果我删除前缀,如以下示例(版本 1):
版本 2
<?xml version="1.0" encoding="UTF-8"?>
<root
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ns1="http://www.ns1.com"
xsi:schemaLocation="http://www.ns1.com ../schema/ns1.xsd">
<element1>
<element1a>VALUE_1</element1a>
<element1b>
<value>4.5</value>
</element1b>
</element1>
</root>
氧气抱怨:
"[Xerces] cvc-elt.1.a:找不到元素'root'的声明。
另一方面,JAXB 将只提供版本 2 之外的版本。如果我提供版本 1,则会收到此错误:
javax.xml.bind.UnmarshalException: unexpected element (uri:"http://www.ns1.com", local:"root")。预期的元素是<{}根>
完整的堆栈跟踪为:
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.handleEvent(UnmarshallingContext.java:662)
at com.sun.xml.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:258)
at com.sun.xml.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:253)
at com.sun.xml.bind.v2.runtime.unmarshaller.Loader.reportUnexpectedChildElement(Loader.java:120)
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext$DefaultRootLoader.childElement(UnmarshallingContext.java:1063)
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext._startElement(UnmarshallingContext.java:498)
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.startElement(UnmarshallingContext.java:480)
at com.sun.xml.bind.v2.runtime.unmarshaller.SAXConnector.startElement(SAXConnector.java:150)
at org.apache.xerces.parsers.AbstractSAXParser.startElement(Unknown Source)
at org.apache.xerces.impl.XMLNSDocumentScannerImpl.scanStartElement(Unknown Source)
at org.apache.xerces.impl.XMLNSDocumentScannerImpl$NSContentDispatcher.scanRootElementHook(Unknown Source)
at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(Unknown Source)
at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source)
at org.apache.xerces.parsers.DTDConfiguration.parse(Unknown Source)
at org.apache.xerces.parsers.XMLParser.parse(Unknown Source)
at org.apache.xerces.parsers.AbstractSAXParser.parse(Unknown Source)
现在 JAXB 编组器和解组器代码是:
JAXBContext context = JAXBContext.newInstance(object.getClass());
javax.xml.bind.Marshaller marshaller = context.createMarshaller();
JAXBContext jaxbContext = JAXBContext.newInstance(clazz);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
虽然我很快就会允许Swagger Core进行编组和取消编组,而Swagger使用Jackson XML。
我需要弄清楚如何构造这个XML(或配置JAXB),使我的编辑器和JAXB解组器都接受它。
问题不在于前缀,而在于命名空间。
您的架构具有目标命名空间,但也具有elementFormDefault="unqualified"
(您确定要这样做吗?这意味着全局元素是限定的,但局部元素不是。
因此,您的root
元素是限定的,属于命名空间http://www.ns1.com
。因此,Xerces错误消息是正确的。
另一个问题是,为什么 JAXB 无法识别命名空间。A 你没有发布你的 Java 代码(请做)我有两个理论:
- 您已手动定义 JAXB 注释,但未正确定义名称空间。
- 您已经使用 XJC 或基于此的东西生成了代码,但不知何故错过了通常定义前缀
package-info.java
。
顺便说一下,我不会称任何JAXB实现为"基于Xerces"。