2

我们有一大套风格的配置文件

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

通用实现类都使用 Jaxb 本身进行映射。

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

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

其他想法?

4

2 回答 2

3

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

演示

StAXXMLStreamReader可用于解析 XML 文档。您可以使用它前进到一个bar元素,然后您可以读取class属性并从ClassLoader. 然后,您可以利用其中一种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类:

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 + ")";
    }

}

输入.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)
于 2012-09-13T09:00:59.473 回答
2

如果结构真的那么简单,我会很想自己使用 an 解析前两个级别(foo 和 bar 的类属性)XMLStreamReader,然后将阅读器交给 JAXB 解组器来解析每个 bar,将结果组装成列表。我不会费心尝试直接使用 JAXB 解析外部信封层。

于 2012-09-13T08:55:53.847 回答