Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add an XML namespace (xmlns) when serializing an object to XML

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>
like image 870
Wolkenarchitekt Avatar asked May 25 '11 07:05

Wolkenarchitekt


People also ask

How do I include xmlns in XML?

XML Namespaces - The xmlns Attribute When using prefixes in XML, a namespace for the prefix must be defined. The namespace can be defined by an xmlns attribute in the start tag of an element. The namespace declaration has the following syntax. xmlns:prefix="URI".

How do you add a namespace to an XML element in Java?

Add name space to document root element as attribute. Transform the document to XML string. The purpose of this step is to make the child element in the XML string inherit parent element namespace. Now the xml string have name space.

What is a namespace for XML serialization?

Xml. Serialization namespace contains several Attribute classes that can be applied to members of a class. For example, if a class contains a member that will be serialized as an XML element, you can apply the XmlElementAttribute attribute to the member.

Which keyword is used to declare a namespace in XML?

The xmlns attribute is an XML keyword for a namespace declaration.


3 Answers

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>
like image 144
dogbane Avatar answered Nov 09 '22 23:11

dogbane


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.

like image 31
z0r Avatar answered Nov 09 '22 21:11

z0r


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

  • http://bdoughan.blogspot.com/2010/08/jaxb-namespaces.html
  • http://bdoughan.blogspot.com/2010/10/how-does-jaxb-compare-to-xstream.html
like image 45
bdoughan Avatar answered Nov 09 '22 23:11

bdoughan