How to deserialize xml into a map of custom attributes (and their values) with SimpleXml?

ぐ巨炮叔叔 提交于 2019-12-12 17:18:47

问题


I am using SimpleXml.

The xml I am deserializing looks roughly like so:

<?xml version="1.0" encoding="UTF-8"?> 
<test a="1" e="2" f="5"/>

That the attributes happen to be a, e and f is not known at runtime - could be q and z just as well.

The class definition:

@Root (strict = false)
public class Test {
   @ElementMap (entry = "test", attribute = true)
   public HashMap<String, Integer> map;
}

I expect Test.map to contain "a" -> 1, "b" -> 2 and "f" -> 5 after deserialization.

Instead, I keep on getting an exception: unnable to satisfy @org.simpleframework.xml.ElementMap ... on field 'map' ... for class Test ... (fluff removed - exception message doesn't contain any further clarification).

I tried to fiddle with various attributes of ElementMap (inlining, not inlining etc.), but to no success so far.

(It is actually the case that the values happen to be numeric, although that's circumstantial and I'd be fine going with string values to parse them on my own if that's necessary - not sure if it matters at all here though.)

What's the solution?

And if SimpleXml doesn't offer any out of the box, what's the suggested workaround?


回答1:


I solved it with the use of a Converter, which allows to perform the deserialization manually.

So now the model is:

public class Test {
   @Convert (MapConverter.class)
   @Element (name = "test")
   public HashMap<String, Integer> test;
}

And MapConverter:

public class MapConverter implements Converter<HashMap<String, Integer>> {
   @Override
   public HashMap<String, Integer> read(InputNode inputNode) throws Exception {
      final HashMap<String, Integer> result = new HashMap<String, Integer>();

      for (final String attributeName : inputNode.getAttributes()) {
         final String value = inputNode.getAttribute(attributeName).getValue();
         result.put(attributeName, Integer.parseInt(value));
      }

      return result;
   }

   @Override
   public void write(OutputNode outputNode, HashMap<String, Integer> stringIntegerHashMap)
         throws Exception {
      // not used
   }
}

Note that for this to work you have to pass an instance of AnnotationStrategy to Persister:

// instead of new Persister()
Persister persister = new Persister(new AnnotationStrategy()); 

I'm not that keen on this solution, because

  1. I suspect it could be an overkill

  2. Initializing a Persister is done deep inside a preexisting library that I have to be using, so it required me to crack the code open in order to get it to work at all.

The fact that Persister ignores one of the framework's native annotation by default makes for a confusing API (even though this behaviour is documented). But that's a different story.

I wonder if someone comes up with something better.



来源:https://stackoverflow.com/questions/25962033/how-to-deserialize-xml-into-a-map-of-custom-attributes-and-their-values-with-s

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!