Jaxb:如何解组xs:任何XML字符串部分?

Pet*_*der 22 java xml jaxb

我有一个应用程序使用Jaxb进行XML < - >转换,并使用maven-jaxb2-plugin自动生成类.

在我的架构深处,我有可能输入"ANY"xml.

更新:这更好地描述了我的架构.一些已知的XML包含一个完全未知的部分("任何"部分).

<xs:complexType name="MessageType">
  <xs:sequence>
    <xs:element name="XmlAnyPayload" minOccurs="0">
        <xs:complexType>
            <xs:sequence>
                <xs:any namespace="##any"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:element name="OtherElements">
        ....
</xs:sequence>
Run Code Online (Sandbox Code Playgroud)

这将(通过jaxb)映射到这样的内部类.

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "any"
})
public static class XmlAnyPayload {

    @XmlAnyElement(lax = true)
    protected Object any;
Run Code Online (Sandbox Code Playgroud)

当我解开整个结构时,没问题."Object any"将呈现为org.apache.xerces.dom.ElementNSImpl.现在,我想手动重新创建Java对象,然后转到XML.我如何获取一些随机XML并放入any(org.apache.xerces.dom.ElementNSImpl)元素以构建Java对象?

另外,下一种情况是当我将这个元素作为java时,我想解组这个部分(为了能够提取这个元素的XML字符串).但这是不可能的.我得到一个关于根元素的例外.但是不可能注释ElementNSImpl.

unable to marshal type "com.sun.org.apache.xerces.internal.dom.ElementNSImpl" as an element because it is missing an @XmlRootElement annotation
Run Code Online (Sandbox Code Playgroud)

您对如何处理这些问题有什么建议吗?

lex*_*ore 42

@XmlAnyElement(lax = true) 用简单的英语表示:

亲爱的JAXB!如果您有此元素的映射,请将其解组为Java对象.如果您不知道此元素,请将其保留为DOM元素.

这正是您的案例中发生的事情.因此,如果您想要实际解组此lax的内容,请为JAXB上下文提供您要解组的元素的映射.最简单的方法是用你的课程注释@XmlRootElement

@XmlRootElement(name="foo", namespace="urn:bar")
public class MyClass { ... }
Run Code Online (Sandbox Code Playgroud)

现在,当您创建JAXB上下文时,请添加MyClass到其中:

JAXBContext context = JAXBContext.newInstance(A.class, B.class, ..., MyClass.class);
Run Code Online (Sandbox Code Playgroud)

在这种情况下,如果JAXB {urn:bar}foo在该位置遇到元素xs:any,它将知道该元素被映射到MyClass并将尝试解组MyClass.

如果您正在根据包名创建JAXB上下文(您可能会这样做),您仍然可以将类(例如com.acme.foo.MyClass)添加到它中.最简单的方法是创建com/acme/foo/jaxb.index资源:

com.acme.foo.MyClass
Run Code Online (Sandbox Code Playgroud)

并将您的包名称添加到上下文路径:

JAXBContext context = JAXBContext.newInstance("org.dar.gee.schema:com.acme.foo");
Run Code Online (Sandbox Code Playgroud)

还有其他方法ObjectFactory,但诀窍jaxb.index可能是最简单的.

或者,不是在一次运行中解组所有内容,而是可以将内容保留xs:any为DOM,并在第二次使用其他JAXB上下文(知道您的MyClass类)的解组时将其解组到目标对象中.就像是:

JAXBContext payloadContext = JAXBContext.newInstance(MyClass.class);
payloadContext.createUnmarshaller().unmarshal((Node) myPayload.getAny());
Run Code Online (Sandbox Code Playgroud)

这种方法有时更好,特别是当您拥有相对独立的容器/有效负载模式的组合时.取决于案件.

以上所述也适用于编组.这一切都是整齐的双向.

  • 这个答案是救命的.毋庸置疑,我赞成它,我很抱歉,我不能两次这样做.一个很好的解释加上一个很好的解决方案 - 谢谢你,lexicore! (2认同)
  • @Quantum欢迎你.拯救生命只是容易一点.:) (2认同)