Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert XML with duplicate elements to JSON using jackson

I have some simple data in XML format which I need to convert to JSON and also be able to convert the JSON back into the same XML string. But I'm having problems with doing this using existing jackson (version 2.0.6) libraries.

Here's an example of XML data with similar structure

<channels>
  <channel>A</channel>
  <channel>B</channel>
  <channel>C</channel>
</channels>

To be able to convert this back to the original XML, I'd like the JSON to look something like this

{
  "channels": {
    "channel": [
      "A",
      "B",
      "C"
    ]
  }
}

However jackson gives me

{"channel":"C"}

The root element name is not preserved and instead og creating array of channels, the last one overwrites the previous ones.

Looking at the source code of com.fasterxml.jackson.databind.deser.std.BaseNodeDeserializer I found that the library doesn't support this, but allows for overriding and changing the behavior.

/**
 * Method called when there is a duplicate value for a field.
 * By default we don't care, and the last value is used.
 * Can be overridden to provide alternate handling, such as throwing
 * an exception, or choosing different strategy for combining values
 * or choosing which one to keep.
 *
 * @param fieldName Name of the field for which duplicate value was found
 * @param objectNode Object node that contains values
 * @param oldValue Value that existed for the object node before newValue
 *   was added
 * @param newValue Newly added value just added to the object node
 */
protected void _handleDuplicateField(String fieldName, ObjectNode objectNode,
                                     JsonNode oldValue, JsonNode newValue)
    throws JsonProcessingException
{
    // By default, we don't do anything
    ;
}

So my questions are

  1. Has anyone written a custom deserializer to support this feature? Or is there another way to work around this.
  2. How do I preserve the root element name?

Below is a test example

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
public class Test {
  public static void main(String[] args) throws Exception {
    String xml="<channels><channel>A</channel><channel>B</channel><channel>C</channel></channels>";

    XmlMapper xmlMapper = new XmlMapper();
    JsonNode node=xmlMapper.readValue(xml,JsonNode.class);
    System.out.println(node.toString());
  }
}
like image 763
alternative4 Avatar asked Sep 14 '12 15:09

alternative4


1 Answers

What really matters here are your classes -- just showing XML in itself does not give enough information to know what is going on.

I suspect that you will need Jackson 2.1 (once it gets released in a week or two), since it finally supports "unwrapped Lists" correectly. Prior to this, only "wrapped" Lists work correctly.

like image 97
StaxMan Avatar answered Sep 28 '22 00:09

StaxMan