Gar*_*owe 5 java xml jaxb marshalling
我想修改JAXB编组操作的输出流以包含一些任意XML.这是一个澄清情况的例子.
我有一个Product带有JAXB注释的任意域对象,目前看起来像这样:
@XmlRootElement(name="Product")
public class Product {
@XmlElement(name="CommonProperty")
private String commonProperty="Something";
@XmlElement(name="ExtraXml")
private String extraXml="Something extra";
}
Run Code Online (Sandbox Code Playgroud)
通常会编组进行此操作:
<Product>
<CommonProperty>Something</CommonProperty>
<ExtraXml>Something else</ExtraXml>
</Product>
Run Code Online (Sandbox Code Playgroud)
现在,如果该extraXml字段包含一些额外的XML(任意复杂性),并将其与最终的编组结果一起包含,该怎么办?
说,extraXml包含" <abc><def>Something extra</def></abc>",我真的想要一个能让我Product像这样编组的解决方案(格式化可选):
<Product>
<CommonProperty>Something</CommonProperty>
<abc>
<def>Something extra</def>
</abc>
</Product>
Run Code Online (Sandbox Code Playgroud)
我已经看过这个相关的问题,但它并没有完全产生我所追求的结果,因为它似乎更倾向于整体格式更改而不是DOM插入.
该extraXml属性只是为了说明,它可以标记为@XmlTransient或单个专门的类.唯一的标准是它可以以某种方式获得String包含完全任意的XML内容以附加到单独的Product编组输出.
我还应该提到,由此产生的输出的消费者能够以适合他们的方式解析任意内容.这里的目的是简化服务器端的处理.
提前感谢您提供的任何帮助.
您可以将额外的XML表示为DOM节点而不是String.
将extraXML属性更改为org.w3c.dom.Node而不是String,并使用@XmlAnyElement对其进行批注.
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAnyElement;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import org.w3c.dom.Node;
@XmlRootElement(name="Product")
@XmlAccessorType(XmlAccessType.FIELD)
public class Product {
@XmlElement(name="CommonProperty")
private String commonProperty="Something";
@XmlAnyElement
private Node extraXml;
}
Run Code Online (Sandbox Code Playgroud)
然后,当您解组XML文档时,例如:
<Product>
<CommonProperty>Something</CommonProperty>
<abc>
<def>Something extra</def>
</abc>
</Product>
Run Code Online (Sandbox Code Playgroud)
使用以下代码:
import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Product.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("input.xml");
Product product = (Product) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(product, System.out);
}
}
Run Code Online (Sandbox Code Playgroud)
"额外XML"将保留为DOM节点.
在这里,Blaise Doughan的帮助是我最终解决的问题.这包括一些额外的演示代码,以帮助可能发现自己处于这种情况的其他人.
课程
ProductList(一个新的包装类,用于显示多个Product条目的工作原理)
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import java.util.ArrayList;
import java.util.List;
@XmlRootElement(name="ProductList")
public class ProductList {
@XmlElementWrapper(name="Products")
@XmlElement(name="Product")
public List<Product> products = new ArrayList<Product>();
}
Run Code Online (Sandbox Code Playgroud)
产品(Blaise的修改)
import org.w3c.dom.Node;
import javax.xml.bind.annotation.*;
@XmlRootElement(name="Product")
@XmlAccessorType(XmlAccessType.FIELD)
public class Product {
@XmlElement(name="CommonProperty")
public String commonProperty="Something";
@XmlAnyElement
public Node extraXml;
}
Run Code Online (Sandbox Code Playgroud)
主要(一些演示代码)
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.StringReader;
public class Main {
public static void main(String[] args) throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
// Build some arbitrary extra XML and prepare an InputStream
String fragment1 = "<abc><def>Some extra 1</def></abc>";
String fragment2 = "<ghi><jkl>Some extra 2</jkl></ghi>";
Document document1 = factory.newDocumentBuilder().parse(new InputSource(new StringReader(fragment1)));
Document document2 = factory.newDocumentBuilder().parse(new InputSource(new StringReader(fragment2)));
Product product1 = new Product();
product1.commonProperty = "Hello 1";
product1.extraXml=document1.getFirstChild();
Product product2 = new Product();
product2.commonProperty = "Hello 2";
product2.extraXml=document2.getFirstChild();
ProductList productList = new ProductList();
productList.products.add(product1);
productList.products.add(product2);
JAXBContext jc = JAXBContext.newInstance(ProductList.class, Product.class);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(productList, System.out);
}
}
Run Code Online (Sandbox Code Playgroud)
最终输出:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ProductList>
<Products>
<Product>
<CommonProperty>Hello 1</CommonProperty>
<abc>
<def>Some extra 1</def>
</abc>
</Product>
<Product>
<CommonProperty>Hello 2</CommonProperty>
<ghi>
<jkl>Some extra 2</jkl>
</ghi>
</Product>
</Products>
</ProductList>
Run Code Online (Sandbox Code Playgroud)
结果!
但它在JBoss中不起作用......
如果你在JBoss 4.2.3.GA或4.3中尝试上述内容,你可能会发现你得到了一个
class com.sun.org.apache.xerces.internal.dom.DocumentFragmentImpl nor any of its super class is known to this context.
Run Code Online (Sandbox Code Playgroud)
报告例外情况.这可能(可能)是由于xercesImpl.jarJBoss lib和/lib/endorsed使用Java META-INF/Services覆盖工具的文件夹阻止JDK使用内部类进行编组.您可能需要DocumentBuilderFactory使用以下方法直接指定替代方法:
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance("oracle.xml.jaxp.JXDocumentBuilderFactory", this
.getClass().getClassLoader());
Run Code Online (Sandbox Code Playgroud)
Oracle实现似乎缓解了这些问题,可能是因为它在JAXB上下文中保持对DOM Node类的了解.这些类可以在Oracle客户端附带的xdb.jar和xmlparserv2.jar中找到.
希望能帮助到你.
| 归档时间: |
|
| 查看次数: |
6347 次 |
| 最近记录: |