【问题标题】:Jaxb: how to unmarshall xs:any XML-string part?Jaxb:如何解组 xs:任何 XML 字符串部分?
【发布时间】:2019-02-14 06:02:08
【问题描述】:

我有一个应用程序使用 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>

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

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

    @XmlAnyElement(lax = true)
    protected Object any;

当我解组整个结构时,没问题。 “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

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

【问题讨论】:

  • 感谢对该域的良好输入,我设法解决了这个问题。一种方法是,我坚持使用我的 Dom 节点。只是添加了一些简单的 XML 解析来从字符串中获取 dom。另一种方式,我求助于在 DOM 空间中使用 XML(XPATH 明智),因为它实际上为我节省了一些时间和上下文切换。 XPATH 实际上非常适合降低代码复杂度。

标签: java xml jaxb


【解决方案1】:

@XmlAnyElement(lax = true) 在简单的英语中的意思是:

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

这正是您的情况。因此,如果您想真正解组此 lax any 的内容,请为 JAXB 上下文提供您希望解组的元素的映射。最简单的方法是使用 @XmlRootElement 注释您的类

@XmlRootElement(name="foo", namespace="urn:bar")
public class MyClass { ... }

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

JAXBContext context = JAXBContext.newInstance(A.class, B.class, ..., MyClass.class);

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

如果您基于包名创建 JAXB 上下文(您可能会这样做),您仍然可以向其中添加您的类(例如,com.acme.foo.MyClass)。最简单的方法是创建一个com/acme/foo/jaxb.index 资源:

com.acme.foo.MyClass

然后将你的包名添加到上下文路径中:

JAXBContext context = JAXBContext.newInstance("org.dar.gee.schema:com.acme.foo");

ObjectFactory 等还有其他方法,但jaxb.index 的技巧可能是最简单的方法。

或者,您可以将 xs:any 的内容保留为 DOM,然后使用另一个 JAXB 上下文(知道您的 MyClass 类)在第二次解组中将其解组到目标对象中,而不是在一次运行中解组所有内容。比如:

JAXBContext payloadContext = JAXBContext.newInstance(MyClass.class);
payloadContext.createUnmarshaller().unmarshal((Node) myPayload.getAny());

这种方法有时会更好,尤其是当您组合了相对独立的容器/有效负载模式时。视情况而定。

上述所有内容也适用于编组。这一切都是双向的。

【讨论】:

  • 这个答案是救命稻草。不用说我赞成它,我很抱歉我不能做两次。一个很好的解释加上一个很好的解决方案 - 谢谢你,lexcore!
  • @Quantum 不客气。拯救生命变得更容易了。 :)
  • @lexicore 那么,如果 XmlAnyElement 设置为 false/省略,它会将其保留为 DOM 对象吗?
  • 不知道为什么,但我遇到了同样的问题,你或@Blaise-Doughan 没有提到任何工作。我在 JBoss EAP 7 上编写了一个 EJB Web 服务项目,并且收到的 WS 参数对于所有“Any”类型都为 null。相当令人沮丧!
  • @JGlass 很抱歉听到这个消息,但众所周知它可以工作。
【解决方案2】:

我认为您需要 XSD 用于“任何”部分并为它们生成类。

这里有更多信息:

http://jaxb.java.net/guide/Mapping_of__xs_any___.html

编辑:如果您要编组的对象没有 @XmlRootElement 注释(请参阅错误消息),那么我认为您必须用 JAXBElement 包装它。

【讨论】:

  • 感谢您的回复。但是,我永远不会知道这个“任何”消息的确切内容,我也不想知道。我只是希望能够将其作为一个块来处理。
  • 链接到的指南提供了该领域的一些不错的详细知识。
【解决方案3】:
<xs:any/>

需要将一些不直观的东西转换为 java 对象。如果没有区别,请尝试使用

<element name="any" type="xs:anyType"/>

【讨论】:

    猜你喜欢
    • 2015-07-10
    • 2020-08-04
    • 2018-01-06
    • 2017-04-28
    • 2016-02-05
    • 2014-11-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多