使用 xi:include 将 JAXB 导出到模块化 xml 文件
Posted
技术标签:
【中文标题】使用 xi:include 将 JAXB 导出到模块化 xml 文件【英文标题】:JAXB export to modular xml files with xi:include 【发布时间】:2012-12-21 20:37:35 【问题描述】:我有两个 XML 文件
树.xml
<tree>
<xi:include href="fruit.xml" xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:fallback>
<fruit/>
</xi:fallback>
</xi:include>
</tree>
水果.xml
<fruit>
...
</fruit>
我继承了解组文件的代码,它返回一个 java 对象。我现在需要将单个 java 对象编组回两个文件。我意识到还有其他解决方案(即使用两个对象而不是一个,这是一个选项)但我需要知道是否可以编组单个对象并维护 xi:include (或重新引入它)并导出到两个(或更多)xml文件。
这甚至可能吗?如果有,有什么提示/想法吗?
谢谢
更新:
我一直在研究这个(我在询问之前研究过)。我确实找到了这个教程http://tutorial.waycoolsearch.com/java/jaxb2.php,它似乎有我的答案,但是当我整理文件时,它需要两个并生成一个。
【问题讨论】:
【参考方案1】:下面我将演示如何使用XmlAdapter
来支持此用例的编组和解组。
XmlAdapter (IncludeFruitAdapter)
XmlAdapter
可用于此用例。
import java.io.File;
import javax.xml.bind.*;
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class IncludeFruitAdapter extends XmlAdapter<IncludeFruitAdapter.Include, Fruit>
private JAXBContext jc;
private String href = "fruit.xml";
public IncludeFruitAdapter()
try
jc = JAXBContext.newInstance(Fruit.class);
catch(Exception e)
throw new RuntimeException(e);
public static class Include
@XmlAttribute
public String href;
@XmlElement(namespace="http://www.w3.org/2001/XInclude")
public Fallback fallback;
public static class Fallback
@XmlElementRef
public Fruit value;
@Override
public Include marshal(Fruit fruit) throws Exception
File xml = new File(href);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(fruit, xml);
Include include = new Include();
include.href = href;
include.fallback = new Fallback();
include.fallback.value = new Fruit();
return include;
@Override
public Fruit unmarshal(Include include) throws Exception
File xml = new File(include.href);
Unmarshaller unmarshaller = jc.createUnmarshaller();
try
return (Fruit) unmarshaller.unmarshal(xml);
catch(Exception e)
return include.fallback.value;
树
@XmlJavaTypeAdapter
用于引用XmlAdapter
。
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Tree
@XmlJavaTypeAdapter(IncludeFruitAdapter.class)
@XmlElement(name="include", namespace="http://www.w3.org/2001/XInclude")
private Fruit fruit;
水果
import javax.xml.bind.annotation.*;
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Fruit
private String name;
演示
下面是一些演示代码,您可以运行它来证明一切正常:
import java.io.File;
import javax.xml.bind.*;
public class Demo
public static void main(String[] args) throws Exception
JAXBContext jc = JAXBContext.newInstance(Tree.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("input.xml");
Tree tree = (Tree) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(tree, System.out);
【讨论】:
【参考方案2】:我想出了一个答案,至少可以解决。我想这可能是这样做的方法。
我希望 JAXB 有某种方法可以将对象的一部分定义为用于编组的包含,但我找不到任何东西。
注意:我有一个额外的技巧,我将在下面解释,我想你可以不用但我无法让它工作,并且在其他人需要这样做的情况下,至少他们会知道。
流程如下。
-
一个带有 XI:Include 的 XML 文件被解组为一个 java 对象。此对象包含 2 个文件(父文件和包含文件)的内容。
对象已更新。
对象被编组回单个临时文件(这是 hack)。
单个临时文件被编组到一个 DOM 文档。 (我想直接编组到一个 DOM 文档,但我总是得到一个空的 DOM 文档,没有例外)。
然后我操作 DOM 文档,首先删除需要进入 XI:Include 的节点,然后插入一个新的 XI:include 文件。
将 DOM 文档转换为 xml 文件。请注意,在我的情况下,XI:include 的内容不会改变,但我认为该节点可以放入新文档并进行转换。
我会尽快更新代码。
还有其他方法可以解决这个问题吗?
谢谢, 特拉维斯
【讨论】:
以上是关于使用 xi:include 将 JAXB 导出到模块化 xml 文件的主要内容,如果未能解决你的问题,请参考以下文章