如何在将对象序列化为XML时添加XML名称空间(xmlns)

问题描述:

我使用XStream将对象序列化为XML。 如何让XStream将xmlns插入到对象的XML输出中?如何在将对象序列化为XML时添加XML名称空间(xmlns)

举个例子,我有这个简单的对象我想要序列:

@XStreamAlias(value="domain") 
public class Domain 
{ 
    @XStreamAsAttribute 
    private String type; 

    private String os; 

    (...) 
} 

如何实现正是使用XStream以下输出?

<domain type="kvm" xmlns:qemu="http://libvirt.org/schemas/domain/qemu/1.0"> 
    <os>linux</os> 
</domain> 

另外,这种使用情况下,可以很容易地用JAXB实现处理( MetroEclipseLink MOXyApache JaxMe等):

package com.example; 

import javax.xml.bind.annotation.XmlAttribute; 
import javax.xml.bind.annotation.XmlRootElement; 

@XmlRootElement 
public class Domain 
{ 
    private String type; 
    private String os; 

    @XmlAttribute 
    public String getType() { 
     return type; 
    } 

    public void setType(String type) { 
     this.type = type; 
    } 

    public String getOs() { 
     return os; 
    } 

    public void setOs(String os) { 
     this.os = os; 
    } 

} 

包信息

@XmlSchema(xmlns={ 
     @XmlNs(
      prefix="qemu", 
      namespaceURI="http://libvirt.org/schemas/domain/qemu/1.0") 
}) 
package com.example; 

import javax.xml.bind.annotation.XmlNs; 
import javax.xml.bind.annotation.XmlSchema; 

演示

package com.example; 

import javax.xml.bind.JAXBContext; 
import javax.xml.bind.JAXBException; 
import javax.xml.bind.Marshaller; 

public class Demo { 

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

     Domain domain = new Domain(); 
     domain.setType("kvm"); 
     domain.setOs("linux"); 

     Marshaller marshaller = jc.createMarshaller(); 
     marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); 
     marshaller.marshal(domain, System.out); 
    } 


} 

输出

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<domain xmlns:qemu="http://libvirt.org/schemas/domain/qemu/1.0" type="kvm"> 
    <os>linux</os> 
</domain> 

更多信息

XStream的不支持命名空间,但它使用的StaxDriver,确实。您需要将命名空间的细节设置成QNameMap并传递到StaxDriver

QNameMap qmap = new QNameMap(); 
qmap.setDefaultNamespace("http://libvirt.org/schemas/domain/qemu/1.0"); 
qmap.setDefaultPrefix("qemu"); 
StaxDriver staxDriver = new StaxDriver(qmap);  
XStream xstream = new XStream(staxDriver); 
xstream.autodetectAnnotations(true); 
xstream.alias("domain", Domain.class); 

Domain d = new Domain("kvm","linux"); 
String xml = xstream.toXML(d); 

输出:

<qemu:domain type="kvm" xmlns:qemu="http://libvirt.org/schemas/domain/qemu/1.0"> 
    <qemu:os>linux</qemu:os> 
</qemu:domain> 
+0

不错,谢谢!好的,但仍然有一个问题:我不希望该qemu前缀作为所有节点的默认前缀。它应该只在根节点内部定义,以便生成的XML看起来完全像我的问题。你有什么提示如何实现这一点? – ifischer 2011-05-25 08:16:21

+0

@ifischer我不认为有一种方法来获得您的确切输出。您可以尝试删除'setDefaultPrefix'语句,但这也会从xmlns声明中删除qemu。为什么你需要在你的输出中输入qemu,如果你不打算用它作为你的元素的前缀? – dogbane 2011-05-25 08:29:10

+0

,因为并非所有子节点都使用qemu名称空间。另外,也许我想稍后添加更多的XML名称空间。顺便说一句,生成的XML需要采用非常特定的格式,因为它已发送到非常严格的Libvirt。 – ifischer 2011-05-25 08:35:47

这是一个黑客位,但它的快速和容易:一个字段添加到您的类名为xmlns,只有拥有它序列化期间非空。要继续例如:

@XStreamAlias(value="domain") 
public class Domain 
{ 
    @XStreamAsAttribute 
    private String type; 

    private String os; 

    (...) 

    @XStreamAsAttribute 
    @XStreamAlias("xmlns:qemu") 
    String xmlns; 

    public void serialise(File path) { 
     XStream xstream = new XStream(new DomDriver()); 
     xstream.processAnnotations(Domain.class); 
     (...) 

     PrintWriter out = new PrintWriter(new FileWriter(path.toFile())); 
     xmlns = "http://libvirt.org/schemas/domain/qemu/1.0"; 
     xstream.toXML(this, out); 
     xmlns = null; 
    } 
} 

齐全,设置xmlns = null应在finally条款。如果你喜欢,使用PrintWriter也可以让你在输出的开头插入一个XML声明。