0

I saw many examples using multiple classes to define attributes at different levels. I have a lot of elements that need an additional entry in the XML, so it would make sense to have many files for this. My overall main goal is to add more data to an existing class.

I am trying to change this

<definition>
  <rows>
    <row>1</row>
  </rows>
  <columns>
    <column>2</column>
  </columns>

to either modify (change) or add attributes to each entry. I have these values in a map (1=Test1). I am trying to do something like this.

<definition>
<rows>
    <row name="Test1">1</row>
</rows>
<columns>
    <column name="Test2">2</column>
</columns>

or this (The only problem with this is that I have these rows/cols stored as Integers in the source, and putting names would be in a string format)

<definition>
<rows>
    <row>Test1</row>
</rows>
<columns>
    <column>Test2</column>
</columns>

Here is what I currently have in java.

public class Definition{    
    @XmlElementWrapper(name="rows")
    @XmlElement(name="row")
    @XmlElement (name="row_names")
    ...
    @XmlElementWrapper(name="cols")
    @XmlElement(name="col")
    @XmlElement (name="col_names")
blackpearl
  • 51
  • 1
  • 5
  • Can you show more of your Java Class? – W Almir Sep 28 '13 at 18:38
  • What else are you looking for? I have @XmlRootElement (name="definition") @XmlAccessorType(XmlAccessType.FIELD) before the class. I am trying to get multiple attributes in the same class – blackpearl Sep 29 '13 at 19:23

1 Answers1

0

I think your best approach would be to use an XmlAdapter. Here's a test I did based on a modification on this tutorial.

Definition Class

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Definition {

    @XmlJavaTypeAdapter(MapAdapter.class)
    private Map<String,String> columns;

    @XmlJavaTypeAdapter(MapAdapter.class)
    private Map<String,String> rows;

    public Map<String,String> getColumns() {
        if (columns == null)
            columns = new HashMap<String,String>();
        return columns;
    }

    public Map<String,String> getRows() {
        if (rows == null)
            rows = new HashMap<String,String>();
        return rows;
    }

}

Map Adapter

public class MapAdapter extends XmlAdapter<MapAdapter.AdaptedMap, Map<String, String>> {

    public static class AdaptedMap {
        public List<Entry> entry = new ArrayList<Entry>();
    }

    public static class Entry {

        @XmlAttribute
        public String name;

        @XmlValue
        public String value;

    }

    @Override
    public Map<String, String> unmarshal(AdaptedMap adaptedMap) throws Exception {
        Map<String, String> map = new HashMap<String, String>();
        for(Entry entry : adaptedMap.entry) {
            map.put(entry.name, entry.value);
        }
        return map;
    }

    @Override
    public AdaptedMap marshal(Map<String, String> map) throws Exception {
        AdaptedMap adaptedMap = new AdaptedMap();
        for(Map.Entry<String, String> mapEntry : map.entrySet()) {
            Entry entry = new Entry();
            entry.name = mapEntry.getKey();
            entry.value = mapEntry.getValue();
            adaptedMap.entry.add(entry);
        }
        return adaptedMap;
    }

}

Basically this Adapter, converts your Map to a List<Entry>. Notice the annotations in the Entry class, this help you create the structure you want.

The Main method for the test

public static void main(String[] args) throws JAXBException {
    JAXBContext context = JAXBContext.newInstance(Definition.class);

    Definition d = new Definition();
    d.getColumns().put("Test1","1");
    d.getRows().put("Test2", "2");

    Marshaller m = context.createMarshaller();
    m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
    m.marshal(d, System.out);

}

The result

<definition>
    <columns>
        <entry name="Test1">1</entry>
    </columns>
    <rows>
        <entry name="Test2">2</entry>
    </rows>
</definition>

The only problem now is that the elements are not called rows or columns but entry! To change that I think you will need to create to two adapters.

Hope you find this helpful.

W Almir
  • 656
  • 8
  • 19