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:

  

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



    
    This is child 2

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



    
    This is child 2

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


 
       This is child 1
       This is child 2
 

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 + "]";
		}

	}

}


Leave a Comment