9

I'm serializing Objects to XML with the help of XStream. How do I tell XStream to insert an xmlns to the XML output of my object?

As an example, I have this simple object I want to serialize:

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

    private String os;

    (...)
}

How do I achieve exactly the following output with XStream?

<domain type="kvm" xmlns:qemu="http://libvirt.org/schemas/domain/qemu/1.0">
  <os>linux</os>
</domain>
skaffman
  • 398,947
  • 96
  • 818
  • 769
Wolkenarchitekt
  • 20,170
  • 29
  • 111
  • 174

3 Answers3

16

XStream doesn't support namespaces but the StaxDriver it uses, does. You need to set the details of your namespace into a QNameMap and pass that into the 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);

Output:

<qemu:domain type="kvm" xmlns:qemu="http://libvirt.org/schemas/domain/qemu/1.0">
  <qemu:os>linux</qemu:os>
</qemu:domain>
dogbane
  • 266,786
  • 75
  • 396
  • 414
  • Nice, thanks! Ok but there is still one problem: I don't want that qemu prefix as default prefix for all nodes. It should just be defined inside the root node, so that the resulting XML looks exactly like in my question. Do you have any hints how to achieve that? – Wolkenarchitekt May 25 '11 at 08:16
  • @ifischer I don't think there is a way to get your exact output. You can try removing the `setDefaultPrefix` statement, but that will also remove qemu from the xmlns declaration. Why do you need qemu in your output if you are not going to be using it to prefix your elements? – dogbane May 25 '11 at 08:29
  • because not all child nodes are using the qemu-namespace. Also, maybe I want to add more XML namespaces later. BTW, the generated XML needs to be in a very specific format, as It's been sent to Libvirt, which is very strict. – Wolkenarchitekt May 25 '11 at 08:35
5

Alternatively, this use case could be handled quite easily with a JAXB implementation (Metro, EclipseLink MOXy, Apache JaxMe, etc):

Domain

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;
    }

}

package-info

@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;

Demo

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


}

Output

<?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>

For More Information

bdoughan
  • 147,609
  • 23
  • 300
  • 400
4

This is a bit of a hack, but it's quick and easy: add a field to your class called xmlns, and only have it non-null during serialisation. To continue your example:

@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;
    }
}

To be complete, setting xmlns = null should be in a finally clause. Using a PrintWriter also allows you to insert an XML declaration at the start of the output, if you like.

z0r
  • 8,185
  • 4
  • 64
  • 83