70 votes

Comment convertir XML en java.util.Map et vice versa

Je suis à la recherche d'un léger API (préférable classe unique) pour convertir un

Map<String,String> map = new HashMap<String,String();

xml et vice versa, convertir XML en arrière à une Carte.

exemple:

Map<String,String> map = new HashMap<String,String();
map.put("name","chris");
map.put("island","faranga");

MagicAPI.toXML(map,"root");

résultat:

<root>
  <name>chris</chris>
  <island>faranga</island>
</root>

et à l'arrière:

Map<String,String> map = MagicAPI.fromXML("...");

Je ne veux pas utiliser JAXB ou JSON de conversion de l'API. Il n'a pas à prendre soin de imbriquée des cartes ou des attributs ou quoi que ce soit d'autre, juste que le cas simple. Toutes les suggestions?


Edit: j'ai créé un copier-coller de l'échantillon. Grâce à fvu et Michal Bernhard.

Télécharger la dernière XStream cadre de, "noyau seulement" suffit.

Map<String,Object> map = new HashMap<String,Object>();
map.put("name","chris");
map.put("island","faranga");

// convert to XML
XStream xStream = new XStream(new DomDriver());
xStream.alias("map", java.util.Map.class);
String xml = xStream.toXML(map);

// from XML, convert back to map
Map<String,Object> map2 = (Map<String,Object>) xStream.fromXML(xml);

Pas de convertisseurs ou n'importe quoi d'autre est nécessaire. Juste le xstream-x.y.z.jar est assez.

65voto

Michal Bernhard Points 2203

XStream!

Mise à jour : j'ai ajouté la partie unmarshal comme demandé dans les commentaires.

 import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;

import java.util.AbstractMap;
import java.util.HashMap;
import java.util.Map;

public class Test {

    public static void main(String[] args) {

        Map<String,String> map = new HashMap<String,String>();
        map.put("name","chris");
        map.put("island","faranga");

        XStream magicApi = new XStream();
        magicApi.registerConverter(new MapEntryConverter());
        magicApi.alias("root", Map.class);

        String xml = magicApi.toXML(map);
        System.out.println("Result of tweaked XStream toXml()");
        System.out.println(xml);

        Map<String, String> extractedMap = (Map<String, String>) magicApi.fromXML(xml);
        assert extractedMap.get("name").equals("chris");
        assert extractedMap.get("island").equals("faranga");

    }

    public static class MapEntryConverter implements Converter {

        public boolean canConvert(Class clazz) {
            return AbstractMap.class.isAssignableFrom(clazz);
        }

        public void marshal(Object value, HierarchicalStreamWriter writer, MarshallingContext context) {

            AbstractMap map = (AbstractMap) value;
            for (Object obj : map.entrySet()) {
                Map.Entry entry = (Map.Entry) obj;
                writer.startNode(entry.getKey().toString());
                writer.setValue(entry.getValue().toString());
                writer.endNode();
            }

        }

        public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {

            Map<String, String> map = new HashMap<String, String>();

            while(reader.hasMoreChildren()) {
                reader.moveDown();

                String key = reader.getNodeName(); // nodeName aka element's name
                String value = reader.getValue();
                map.put(key, value);

                reader.moveUp();
            }

            return map;
        }

    }

}
 

44voto

Vikas Gujjar Points 468

Voici le convertisseur pour XStream incluant unmarshall

 public class MapEntryConverter implements Converter{
public boolean canConvert(Class clazz) {
    return AbstractMap.class.isAssignableFrom(clazz);
}

public void marshal(Object value, HierarchicalStreamWriter writer, MarshallingContext context) {
    AbstractMap<String,String> map = (AbstractMap<String,String>) value;
    for (Entry<String,String> entry : map.entrySet()) {
        writer.startNode(entry.getKey().toString());
        writer.setValue(entry.getValue().toString());
        writer.endNode();
    }
}

public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
    Map<String, String> map = new HashMap<String, String>();

    while(reader.hasMoreChildren()) {
        reader.moveDown();
        map.put(reader.getNodeName(), reader.getValue());
        reader.moveUp();
    }
    return map;
}
 

8voto

fvu Points 21471

Qu'en est-il de XStream ? Pas une classe, mais deux bocaux pour de nombreux cas d'utilisation, y compris le vôtre, très simple à utiliser et pourtant assez puissant.

8voto

mlk Points 7270

Une option serait de rouler votre propre. Il serait assez simple à faire:

Document doc = getDocument();
Element root = doc.createElement(rootName);
doc.appendChild(root);
for (Map.Entry<String,String> element : map.entrySet() ) {
    Element e = doc.createElement(element.getKey());
    e.setTextContent(element.getValue());
    root.appendChild(e);
}
save(doc, file);

et la charge est tout aussi simplement, getChildNodes et une boucle. Sûr qu'il a un peu de chaudière assiette que le XML Dieux de la demande, mais il est au plus 1 heures de travail.

Ou vous pouvez regarder les Propriétés si vous n'êtes pas trop fondu sur le format XML.

6voto

Eva Troels Points 78

J'ai utilisé l'approche avec le convertisseur personnalisé:

 public static class MapEntryConverter implements Converter {

    public boolean canConvert(Class clazz) {
        return AbstractMap.class.isAssignableFrom(clazz);
    }

    public void marshal(Object value, HierarchicalStreamWriter writer, MarshallingContext context) {

        AbstractMap map = (AbstractMap) value;
        for (Object obj : map.entrySet()) {
            Entry entry = (Entry) obj;
            writer.startNode(entry.getKey().toString());
            context.convertAnother(entry.getValue());
            writer.endNode();
        }
    }

    public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) {
        // dunno, read manual and do it yourself ;)
    }

}
 

Mais j'ai changé la valeur de sérialisation de la carte pour déléguer à MarshallingContext. Cela devrait améliorer la solution afin qu'elle fonctionne également pour les valeurs de cartes composites et les cartes imbriquées.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X