6

我有一个org.w3c.dom.Element我从我XmlAdapter的自定义返回的@XmlElement,我想将它作为 JAXB 对象的一部分包含为任意 XML(我知道我必须手工制作 XSD)。但是,JAXB 抱怨

org.w3c.dom.Element is an interface, and JAXB can't handle interfaces.

显然 w3c XML 类型不支持作为 Java 类型,这是一种耻辱。但除此之外,当我使用javax.xml.transform.Result显然受支持的时,我也会遇到同样的错误。

如何在 JAXB 中包含任意 XML 元素作为元素?

注意:根据https://forums.oracle.com/thread/1668210我也试过

MessageFactory factory = MessageFactory.newInstance();
message = factory.createMessage();          
SOAPElement element = message.getSOAPBody().addDocument(doc);

但这也给出了同样的错误。

4

1 回答 1

12

TL;博士

只要您将值类型指定为(not ) ,您就可以XmlAdapter将域对象转换为实例。org.w3c.dom.ElementObjectElement


下面是一个完整的例子。

xml适配器

类型的字段/属性java.lang.Object会将未知内容保留为 DOM 节点。XmlAdapter您可以通过在as中指定值类型来在您的用例中利用这一点Object。您需要确保从该方法返回的根元素与注释marshal定义的字段/属性相匹配。@XmlElement

import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.parsers.*;
import org.w3c.dom.*;

public class BarAdapter extends XmlAdapter<Object, Bar>{

    private DocumentBuilder documentBuilder;

    public BarAdapter() {
        try {
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            documentBuilder = dbf.newDocumentBuilder();
        } catch(Exception e) {
            // TODO - Handle Exception
        }
    }

    @Override
    public Bar unmarshal(Object v) throws Exception {
        Bar bar = new Bar();
        Element element = (Element) v;
        bar.value = element.getTextContent();
        return bar;
    }

    @Override
    public Object marshal(Bar v) throws Exception {
        Document document = documentBuilder.newDocument();
        Element root = document.createElement("bar");
        root.setTextContent(v.value);
        return root;
    }

}

Java 模型

@XmlJavaTypeAdapter注释用于XmlAdapter引用.

import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Foo {

    @XmlJavaTypeAdapter(BarAdapter.class)
    private Bar bar;

}

酒吧

import javax.xml.bind.annotation.*;

@XmlAccessorType(XmlAccessType.FIELD)
public class Bar {

    String value;

}

演示代码

演示

由于创建 DocumentBuilderFactory 是有成本的,我们可以通过在 Marshaller 上设置一个实例来利用 JAXB 处理 XmlAdapter 的有状态实例的能力。

import java.io.File;
import javax.xml.bind.*;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Foo.class);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        File xml = new File("src/forum18272059/input.xml");
        Foo foo = (Foo) unmarshaller.unmarshal(xml);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setAdapter(new BarAdapter());
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(foo, System.out);
    }

}

输入.xml/输出

<?xml version="1.0" encoding="UTF-8"?>
<foo>
    <bar>Hello World</bar>
</foo>
于 2013-08-20T17:45:15.043 回答