Search code examples
javaxmlxstreamxml-deserialization

Deserialising to a map key-value pairs provided as XML attributes (Java)


I would like this XML

<root>

  <firstTag>
    <property key="foo" value="One"/>
    <property key="bar" value="Two"/>
  </firstTag>

  <secondTag>
    <property key="foo" value="1"/>
    <property key="bar" value="2"/>
  </secondTag>

</root>

to be deserialised into a Map<String, String>such that only the keys and values that are provided via attributes inside the <firstTag/> are taken into account. Here is the desired output map:

{foo=One, bar=Two}

And this using XStream, jackson-dataformat-xml, or any popular unmarshalling library.


Solution

  • I needed to implement a Converter for this:

    public class MyConverter implements Converter {
    
        public boolean canConvert(Class clazz) {
            return AbstractMap.class.isAssignableFrom(clazz);
        }
    
        @Override
        public void marshal(Object arg0, HierarchicalStreamWriter writer, MarshallingContext context) {}
    
        @Override
        public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
    
            Map<String, String> map = new HashMap<String, String>();
            reader.moveDown();  // Get down to the firstTag and secondTag level.
    
            while(reader.hasMoreChildren()) {
                if(reader.getNodeName().equals("firstTag")) {
                    while(reader.hasMoreChildren()) {
                        reader.moveDown();
                        String key = reader.getAttribute("key");
                        String value = reader.getAttribute("value");
                        map.put(key, value);
                        reader.moveUp();
                    }
                }
            }
            return map;
        }
    }
    

    Then use it:

    XStream xstream = new XStream();
    xstream.alias("root", java.util.Map.class);
    xstream.registerConverter(new MyConverter());
    
    String xml = ...
    Map<String, String> map = (Map<String, String>) xstream.fromXML(xml);