XStream: Handling Attributes in XML

In the previous tutorial we saw how to convert Java to XML and back. In this tutorial we look at different ways to handle XML attributes using XStream. However note that the attributes are only safe if you know that the written String values are not affected by the XML parser’s white space normalization. The XML specification requires that a parser does this and it means that an attribute value of:

<element attr="  foo\t\n   bar    ">
</element>

will always be normalized and passed this assertion:

assertEquals("foo bar", element.getAttr());
XStream has no influence about this behavior.

Case 1 : Element with attributes but no value - Using SingleValueConverter

<!--?xml version="1.0" encoding="UTF-8"?-->
<root>
    <child1 key1="value1"></child1>
    <child2>This is child 2</child2>
</root>

In this example we use a SingleValueConverter to convert the XML element containing an attribute. This method does not work if the element has a value

package com.studytrails.xml.xstream;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.converters.SingleValueConverter;

public class ElementWithAttribute {
    private String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + "<Root>" + "<child1 key1=\"value1\"></child1>"
            + "<child2>This is child 2</child2>" + "</Root>";

    public static void main(String[] args) {
        ElementWithAttribute unmarshaller = new ElementWithAttribute();
        unmarshaller.XMLToJavaObject();
    }

    public void XMLToJavaObject() {
        XStream xStream = new XStream();
        xStream.useAttributeFor(Child1.class, "key1");
        xStream.registerConverter(new Key1SingleValueConverter());
        xStream.alias("Root", Root.class);
        xStream.alias("child1", Child1.class);
        Root root = (Root) xStream.fromXML(xml);
        System.out.println(root);
        // prints Root [child1=Child1 [key1=Key1 [value=value1]], child2=This is child 2]
    }

    public class Root {
        public Child1 child1;

        public String child2;

        @Override
        public String toString() {
            return "Root [child1=" + child1 + ", child2=" + child2 + "]";
        }

    }

    public class Child1 {
        public Key1 key1;

        @Override
        public String toString() {
            return "Child1 [key1=" + key1 + "]";
        }

    }

    public class Key1 {
        String value;

        public Key1(String value) {
            this.value = value;
        }

        @Override
        public String toString() {
            return "Key1 [value=" + value + "]";
        }

    }

    public class Key1SingleValueConverter implements SingleValueConverter {
        @Override
        public boolean canConvert(Class type) {
            return (type.equals(Key1.class));
        }

        @Override
        public Object fromString(String str) {
            Key1 key = new Key1(str);
            return key;
        }

        @Override
        public String toString(Object obj) {
            return ((Key1) obj).value;
        }
    }
}

Case 2 : Element with attributes but no value - Using attribute alias

<!--?xml version="1.0" encoding="UTF-8"?-->
<root>
    <child1 key1="value1"></child1>
    <child2>This is child 2</child2>
</root>

The same result can be obtained by using an attribute alias.

package com.studytrails.xml.xstream;

import com.thoughtworks.xstream.XStream;

public class ElementWithAttribute2 {

    private String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + "<Root>" + "<child1 key1=\"value1\"></child1>"
            + "<child2>This is child 2</child2>" + "</Root>";

    public static void main(String[] args) {
        ElementWithAttribute2 unmarshaller = new ElementWithAttribute2();
        unmarshaller.XMLToJavaObject();
    }

    public void XMLToJavaObject() {
        XStream xStream = new XStream();
        xStream.alias("Root", Root.class);
        xStream.alias("child1", Child1.class);
        xStream.aliasAttribute(Child1.class, "key1", "key1");
        Root root = (Root) xStream.fromXML(xml);
        System.out.println(root);
        //prints Root [child1=Child1 [key1=value1], child2=This is child 2]
    }

    public class Root {
        public Child1 child1;

        public String child2;

        @Override
        public String toString() {
            return "Root [child1=" + child1 + ", child2=" + child2 + "]";
        }

    }

    public class Child1 {
        public String key1;

        @Override
        public String toString() {
            return "Child1 [key1=" + key1 + "]";
        }
    }

    public class Key1 {
        String value;

        public Key1(String value) {
            this.value = value;
        }

        @Override
        public String toString() {
            return "Key1 [value=" + value + "]";
        }

    }

}

Case 3 : Element with attributes and value

<!--?xml version="1.0" encoding="UTF-8"?-->
 <root>
       <child1 key1="value1">This is child 1</child1>
       <child2>This is child 2</child2>
 </root>

If the element has an attribute as well as a value then we use a special Converter called ToAttributedValueConverter

package com.studytrails.xml.xstream;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.converters.extended.ToAttributedValueConverter;

public class ElementWithValueAndAttributes1 {


    private String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + "<Root>" + "<child1 key1=\"value1\">This is child 1</child1>"
            + "<child2>This is child 2</child2>" + "</Root>";

    public static void main(String[] args) {
        ElementWithValueAndAttributes1 converter = new ElementWithValueAndAttributes1();
        converter.XmlToJavaObjects();
    }

    private void XmlToJavaObjects() {
        XStream xStream = new XStream();
        xStream.alias("Root", Root.class);
        xStream.registerConverter(new ToAttributedValueConverter(Child1.class, xStream.getMapper(), xStream.getReflectionProvider(), xStream
                .getConverterLookup(), "value"));
        Root test = (Root) xStream.fromXML(xml);
        System.out.println(test);
        /*- prints Root [child1=Child1 [value=This is child 1, key1=value1],child2=This is child 2] */

    }

    public class Root {
        public Child1 child1;

        public String child2;

        @Override
        public String toString() {
            return "Root [child1=" + child1 + ", child2=" + child2 + "]";
        }

    }

    public class Child1 {
        public String value;
        public String key1;

        @Override
        public String toString() {
            return "Child1 [value=" + value + ", key1=" + key1 + "]";
        }

    }

}

(Note: This article’s original links is here )

 XStream: Java to XML Using Annotation XStream: Referencing Objects 

Comments