shitanshu
shitanshu

Reputation: 222

Convert XML to Json Array when only one object Java

I have one XML which i need to convert to JSON when in XML we have more than one element its creating proper jsonArray but when single element not creating the array can any one please help me how we can get array in case of single element

String TEST_XML_STRING = "<Items><Item><Name>Stack</Name><Name>OverFlow</Name></Item></Items>";
JSONObject xmlJSONObj = XML.toJSONObject(TEST_XML_STRING);
// output - {"Items":{"Item":{"Name":["Stack","OverFlow"]}}}

when

String TEST_XML_STRING = "<Items><Item><Name>Stack</Name></Item></Items>";
JSONObject xmlJSONObj = XML.toJSONObject(TEST_XML_STRING);
// output - {"Items":{"Item":{"Name":"Stack"}}}

but it should be {"Items":{"Item":[{"Name":"Stack"}]}}

Upvotes: 4

Views: 15014

Answers (7)

Based on Mario's solution, I made some changes, specially for nested children in the Json object. The xmlJSONObj is the same, but the obj param is a List that contains the path to the JSON child, and the index param is only required for the recursion (it should start at 0 in the first execution).

/**
       * Forces a JSON Object to be an Array. When converting from XML to JSON, There may be cases in
       * which we want a list of elements in the final JSON but there is only one element in the XML
       * file, so the XML.toJSONObject method will fail. This methods forces a JSON element to be an
       * array instead of just a JSON Object.
       * 
       * @param xmlJSONObj obtained by passing the XML through the method toJSONObject
       * @param obj list of String that contains the path to the JSON child to convert to Array
       * @param index required for recursion, starts at 0
       * @throws org.json.JSONException
       */
      public static void forceToJSONArray(JSONObject xmlJSONObj, List<String> obj, int index)
          throws org.json.JSONException {
        Object myObj = xmlJSONObj.opt(obj.get(index));
        if (myObj instanceof JSONObject && obj.size() == index + 1) {
          JSONObject myJSONObj = (JSONObject) myObj;
          JSONArray jsonArray = new JSONArray();
          jsonArray.add(myJSONObj);
          xmlJSONObj.put(obj.get(index), jsonArray);
        } else if (myObj instanceof JSONObject) {
          forceToJSONArray((JSONObject) myObj, obj, index + 1);
        }
      }

Example:

We have this JSON:

{
   "person":{
      "name":"Tony",
      "data":{
         "car":"Toyota"
      }
   }
}

And we want this JSON:

{
   "person":{
      "name":"Tony",
      "data":{
         "car":["Toyota"]
      }
   }
}

We should call the method like this:

forceToJSONArray(xmlJSONObj, Arrays.asList("person", "data", "car"), 0);

Upvotes: 1

krishna prasad
krishna prasad

Reputation: 1

It's very late to reply to this post but my solution might help someone.

Problem Description : Always convert a specific XML tag to JSON Array irrespective of number of instances.

Traditional Way : Single instance of XML tag will always converts into JSON object, We couldn't do anything here. Please find below for my solution.

My Approach : So take above point into consideration, if we always insert a dummy empty tag in the beginning just to make sure that we have more than one instance of same XML tag.

As we are adding a dummy in the beginning, If we convert this XML into JSON, we always have a null object in the 0th instance of our JSON array. So we have to remove this null object from our array using .remove(0) method of JSONArray Class.

Combining all together, Please find the sample java code for your reference.


    import org.json.JSONArray;
    import org.json.JSONException;
    import org.json.JSONObject;
    import org.json.XML;
    
    public class XMLtoJSONConverter {
    public static void main(String[] args) {
          String xmlData = "<Items><Item><Name>Stack</Name><Name>OverFlow</Name></Item></Items>";
          xmlData = xmlData.replaceFirst("<Item>","<Item/><Item>");
          try {
              JSONObject xmlJSONObj = XML.toJSONObject(xmlData);
              JSONArray jsonArray = xmlJSONObj.getJSONObject("Items").getJSONArray("Item");
              jsonArray.remove(0);
              System.out.println(xmlJSONObj);
          } catch (JSONException je) {
              System.out.println(je.toString());
          }
        }
    }

Output :

{
    "Items":{
       "Item":[{
          "Name":["Stack","OverFlow"]
        }]
     }
}

Note : "Item" tag in the given XML is actually a single instance but it turns out to be JSON array in the output.

Happy Coding!!!

Upvotes: 0

Mario
Mario

Reputation: 171

I'm late on this... but, using org.json:

public static void forceToJSONArray(JSONObject xmlJSONObj, String obj) throws org.json.JSONException 
{
    // where "JSONObject xmlJSONObj" is my JSONObject obtained by passing the XML throug the method toJSONObject 
    // and where "String obj" is the name of the JSONObject I want to force to JSONArray
    Object myObj = xmlJSONObj.opt(obj);
    if (myObj == null)
    {
        // if my obj doesn't exist inside my xmlJSONObj i create it empty
        JSONArray jsonArray = new JSONArray();
        xmlJSONObj.put(obj, jsonArray);
    }
    else if ( myObj instanceof JSONObject ) 
    {
        // if exist but is a JSONObject, I force it to JSONArray
        JSONObject myJSONObj = (JSONObject)myObj;
        JSONArray jsonArray = new JSONArray();
        jsonArray.put(myJSONObj);
        xmlJSONObj.put(obj, jsonArray);
     }
     else if ( myObj instanceof String || myObj instanceof Integer ) 
     {
        // if exist but is a primitive entry (like in your case), I force it to a "primitive" JSONArray
        JSONArray jsonArray = new JSONArray();
        jsonArray.put(myObj);
        xmlJSONObj.put(obj, jsonArray);
     }  
}

Hope this could help ;)

Upvotes: 2

Victor Costa
Victor Costa

Reputation: 81

I use these two methods, but you will have to identify which fields you want to wrap in a array. With javax.json.*:

private static JsonObject wrapFieldInArray(JsonObject object, String fieldKey) {
    JsonValue fieldValue = object.get(fieldKey);
    if(fieldValue instanceof JsonObject){
        JsonObjectBuilder builder = Json.createObjectBuilder(object);
        builder.remove(fieldKey);
        builder.add(fieldKey, wrapObjectInArray((JsonObject) fieldValue));
        object = builder.build();
    }
    return object;
}

public static JsonArray wrapObjectInArray(JsonObject obj){
    JsonArrayBuilder builder = Json.createArrayBuilder();
    builder.add(obj);
    return builder.build();
}

And with org.json:

private static JSONObject wrapFieldInArray(JSONObject object, String fieldKey) {
    Object fieldValueObj = object.get(fieldKey);
    if(fieldValueObj instanceof JSONObject){
        JSONObject fieldValue = (JSONObject) fieldValueObj;
        object.remove(fieldKey);
        object.put(fieldKey, wrapObjectInArray(fieldValue));
    }
    return object;
}

public static JSONArray wrapObjectInArray(JSONObject obj){
    return new JSONArray().put(new JSONObject(obj.toString()));
}

Upvotes: 0

tomaj
tomaj

Reputation: 1590

If you are using Java 8 or later, you should check out my open source library: unXml. unXml basically maps from Xpaths to Json-attributes.

It's available on Maven Central.

Example

import com.fasterxml.jackson.databind.node.ObjectNode;
import com.nerdforge.unxml.factory.ParsingFactory;
import com.nerdforge.unxml.parsers.Parser;
import org.w3c.dom.Document;

public class Parser {
  public ObjectNode parseXml(String xml){
    Parsing parsing = ParsingFactory.getInstance().create();
    Document document = parsing.xml().document(xml);

    Parser<ObjectNode> parser = parsing.obj("/Items/Item")
        .attribute("name", "Name")
        .build();

    ObjectNode result = parser.apply(document);
    return result;
  }
}

It will return a Jackson ObjectNode, with the following json:

{"name":"Stack"}

You can also create a parser that will return nested ObjectNodes or ArrayNodes to whatever JSON structure you desire.

Upvotes: 0

Daniel Przybylowski
Daniel Przybylowski

Reputation: 116

There doesn't seem to be out of the box way of doing that. If the json is processed in the code later on you could check whether it's JSONObject or JSONArray. In case you need to return json object in the correct format from let say spring mvc rest controller, you could also check what you dealing with (JSONArray or JSONObject). When it's JSONObject you will have to replace it with JSONArray with the same data.

Test if it is JSONObject or JSONArray

Upvotes: 0

Mykola Yashchenko
Mykola Yashchenko

Reputation: 5371

If XML tag has a single child, it will convert this child to an object instead of an array. But if XML tag has 2+ children of the same name, it returns an array.

You can do nothing with this. The only way is to use another library.

Upvotes: 0

Related Questions