JAXB解组“通用”真实世界文档

时间:2012-09-13 08:25:03

标签: java jaxb unmarshalling

我们有一大堆风格的配置文档

<foo>
  <bar class="com.diedel.Gnarf">
    ...more content
  </bar>
  <bar class="de.doedel.Bork">
    ..more content
  </bar>
  ...
</foo>

通用实现类都是使用Jaxb自己映射的。

在我最终回归到Xstream之前,向社区提出一个问题:是否有一种(非黑客)方式可以在Jaxb中解组。到目前为止我们尝试使用@XMLAdapter进行“嵌套”解组,其中“bar”字段获取Element,获取目标类并调用另一个“unmarshall”循环。这种方法已经a)非常慢并且b)在切换到Java 7时被破坏,其中一些神奇的ThreadLocal在从内部unmarshall返回时破坏了上下文。

我发现MOXy可以使用@XmlDiscriminatorNode支持这个 - 这看起来是一个很好的解决方案,我非常喜欢Blaise的非常好的输入 - 但是为了好玩添加一个&gt; 7MB的lib不是一种选择。

其他想法?

2 个答案:

答案 0 :(得分:3)

您可以使用JAXB (JSR-222)StAX (JSR-173)执行以下操作:

<强>演示

StAX XMLStreamReader可用于解析XML文档。您可以使用它前进到bar元素,然后您可以阅读class属性并从ClassLoader加载适当的Java类。然后,您可以利用带有类参数的unmarshal方法之一。

package forum12402215;

import javax.xml.bind.*;
import javax.xml.stream.*;
import javax.xml.transform.stream.StreamSource;

public class Demo {

    public static void main(String[] args) throws Exception {
        ClassLoader classLoader = Bork.class.getClassLoader();
        JAXBContext jc = JAXBContext.newInstance(Bork.class, Gnarf.class);
        Unmarshaller unmarshaller = jc.createUnmarshaller();

        StreamSource source = new StreamSource("src/forum12402215/input.xml");
        XMLInputFactory xif = XMLInputFactory.newFactory();
        XMLStreamReader xsr = xif.createXMLStreamReader(source);
        xsr.nextTag(); // Advance to "foo" element
        xsr.nextTag(); // Advance to "bar" element

        while(xsr.getLocalName().equals("bar")) {
             String className = xsr.getAttributeValue("", "class");
             Class<?> clazz = classLoader.loadClass(className);
             Object object = unmarshaller.unmarshal(xsr, clazz).getValue();
             System.out.println(object);
             xsr.nextTag();
        }
    }

}

<强>博克

以下是示例Bork类。

package forum12402215;

public class Bork {

    private String b;

    public String getB() {
        return b;
    }

    public void setB(String b) {
        this.b = b;
    }

    @Override
    public String toString() {
        return "Bork(b=" + b + ")";
    }

}

<强> Gnarf

以下是Gnarf类示例:

package forum12402215;

public class Gnarf {

    private int a;

    public int getA() {
        return a;
    }

    public void setA(int a) {
        this.a = a;
    }

    @Override
    public String toString() {
        return "Gnarf(a=" + a + ")";
    }

}

<强> input.xml中

以下是我根据您的问题使用的示例文档。我更改了包名。

<?xml version="1.0" encoding="UTF-8"?>
<foo>
    <bar class="forum12402215.Gnarf">
        <a>123</a>
    </bar>
    <bar class="forum12402215.Bork">
        <b>Hello World</b>
    </bar>
</foo>

<强>输出

以下是运行演示代码的输出。

Gnarf(a=123)
Bork(b=Hello World)

答案 1 :(得分:2)

如果结构真的那么简单,我很想用XMLStreamReader自己解析前两个级别(foo和bar的class属性),然后将读者移到JAXB unmarshaller来解析每个栏,将结果汇总到一个列表中。我不打算尝试直接使用JAXB解析外包层。