JAXB 解组未知 XML 内容的子集

Posted

技术标签:

【中文标题】JAXB 解组未知 XML 内容的子集【英文标题】:JAXB Unmarshalling an subset of Unknown XML content 【发布时间】:2013-05-23 16:22:20 【问题描述】:

我需要 unmarshall 未知 XML 内容的子集,使用该未编组的对象,我需要修改一些内容并将相同的 XML 内容(子集)与原始 XML 重新绑定。

输入 XML 示例:

<Message>
    <x>
    </x>
    <y>
    </y>
    <z>
    </z>
    <!-- Need to unmarshall this content to "Content" - java Object -->
    <Content>
        <Name>Robin</Name>
        <Role>SM</Role>
        <Status>Active</Status>
    </Content>
.....
</Message>

需要单独解组 &lt;Content&gt; 标记,保持其他 XML 部分相同。需要修改&lt;Content&gt;标签中的元素,并将修改后的XML部分与原文绑定如下:

预期输出 XML:

<Message>
    <x>
    </x>
    <y>
    </y>
    <z>
    </z>
    <!-- Need to unmarshall this content to "Content" - java Object -->
    <Content>
        <Name>Robin_123</Name>
        <Role>Senior Member</Role>
        <Status>1</Status>
    </Content>
.....
</Message>

我的问题:

    此要求的可能解决方案是什么? DOM 解析除外 - 因为 XML 网络非常庞大)

    JAXB2.0 中是否有任何选项可以执行此操作?

请就此提出您的建议。

【问题讨论】:

【参考方案1】:

考虑使用StAX API 将源文档缩小。

对于给定的示例,此代码创建一个根元素为 Content 元素的 DOM 文档:

class ContentFinder implements StreamFilter 
  private boolean capture = false;

  @Override public boolean accept(XMLStreamReader xml) 
    if (xml.isStartElement() && "Content".equals(xml.getLocalName())) 
      capture = true;
     else if (xml.isEndElement() && "Content".equals(xml.getLocalName())) 
      capture = false;
      return true;
    
    return capture;
  


XMLInputFactory inFactory = XMLInputFactory.newFactory();
XMLStreamReader reader = inFactory.createXMLStreamReader(inputStream);
reader = inFactory.createFilteredReader(reader, new ContentFinder());
Source src = new StAXSource(reader);
DOMResult res = new DOMResult();
TransformerFactory.newInstance().newTransformer().transform(src, res);
Document doc = (Document) res.getNode();

这可以是passed to JAXB 作为DOMSource。

在输出时重写 XML 时可以使用类似的技术。

JAXB 似乎不直接接受 StreamSource,至少在 Oracle 1.7 实现中是这样。

【讨论】:

是否可以以流方式迭代多个 节点?我有一个巨大的 XML 文件,我想一个一个地提取节点,而不必将整个内容加载到内存中。 我相信是的。我可能会使用 StAX 事件来创建某种访问者模式。要求是不同的足以保证它自己的问题。如果您愿意同时在内存中拥有所有未编组的对象,您可能仍然可以使用过滤器方法。 谢谢,我创建了一个separate question。但是,我不能将所有对象都保存在内存中,因此我需要找出一种不同的方法。 Camel 的tokenizeXML 和我一模一样,所以我想我可以调查一下。【参考方案2】:

您可以使用 @XmlAnyElement 在您的类上注释 Object 属性,默认情况下,未映射的内容将被捕获为 DOM 节点。如果您在@XmlAnyElement 上指定DomHandler,那么您可以控制格式。这是一个示例的链接,其中内容保存为String

JAXB use String as it is

【讨论】:

以上是关于JAXB 解组未知 XML 内容的子集的主要内容,如果未能解决你的问题,请参考以下文章

使用 JAXB 解组多次出现的 XML 元素

Java/JAXB:根据属性将 Xml 解组为特定子类

JAXB:如何在解组 XML 文档期间忽略命名空间?

使用 Xpath 表达式和 jaxb 解组 XML

JAXB 继承,解组到编组类的子类

在将 XML 文件解组为对象后,如何让 JAXB 调用方法?