Skip to content

Implement opt/get methods for accumulated values #551

Description

@johnjaylward

Currently we have an accumulate method on JSONObject, however, we don't have an easy way to get back out a consistent value (i.e. JSONArray).

One area where this is most painful is in XML to JSON conversion where some XML documents may contain a single element, while other documents may contain many.

Example 1:

<Student>
  <name>jack</name>
  <subjects>
    <class>english</class><grade>98</grade>
  </subjects>
  <subjects>
    <class>english</class><grade>98</grade>
  </subjects>
</Student>

Example 2:

<Student>
  <name>jack</name>
  <subjects>
    <class>english</class><grade>98</grade>
  </subjects>
</Student>

This currently leads to very messy code that has to check the type of value parsed:

void someFunction() {
  JSONObject jo = XML.toJSONObject(someXmlSource);
  JSONObject student = jo.getJSONObject("Student");
  if ( student.optJSONArray("subjects") ==null ) {
      processSubject(student.optJSONObject("subjects"));
  } else {
      processSubjects(student.optJSONArray("subjects"));
  }
}

void processSubjects(JSONArray subjects) {
  if (subjects == null || subjects.length() == 0) return;
  for(int i=0; i<subjects.length; i++) {
    processSubject(subjects.getJSONObject(i));
  }
}

void processSubject(JSONObject subject) {
  // some implementation
}

It would be nice if there was a convenience function in the JSONObject to get values that are accumulated:

// In JSONObject

/**
* Always returns a JSONArray, If the key doesn't exist or the value is `null`, the array will be empty.
* If the key holds a non-array/non-collection value, then it is placed in a JSONArray
* before returning.
* If the value is a JSONArray, then a copy is returned.
* If the value is directly convertible to a JSONArray (i.e. a JAVA Array or Collection), then it is
* converted to a JSONArray.
* @param key The key in the JSONObject to fetch
* @returns a JSONArray regardless of the value of the key.
*/
public JSONArray optAccumulated(String key) {
  Object o = opt(key);
  if (JSONObject.NULL.equals(o)) {
    return new JSONArray();
  }
  if (o instanceof JSONArray) {
    return new JSONArray(((JSONArray)o).myArrayList); // maybe create a copy constructor and/or extend putAll
  }
  if (o instanceof Collection || o.getClass().isArray()) {
    return new JSONArray(o);
  }
  JSONArray ret = new JSONArray();
  ret.put(o);
  return ret;
}


/**
* Always returns a JSONArray, If the key value is `null`, the array will be empty.
* If the key holds a non-array/non-collection value, then it is placed in a JSONArray
* before returning.
* If the value is a JSONArray, then a copy is returned.
* If the value is directly convertible to a JSONArray (i.e. a JAVA Array or Collection), then it is
* converted to a JSONArray.
* @param key The key in the JSONObject to fetch
* @returns a JSONArray regardless of the value of the key.
* @throws JSONException Thrown when the key does not exist
*/
public JSONArray getAccumulated(String key) throws JSONException {
  Object o = get(key);
  if (JSONObject.NULL.equals(o)) {
    return new JSONArray();
  }
  if (o instanceof JSONArray) {
    return new JSONArray(((JSONArray)o).myArrayList); // maybe create a copy constructor and/or extend putAll
  }
  if (o instanceof Collection || o.getClass().isArray()) {
    return new JSONArray(o);
  }
  JSONArray ret = new JSONArray();
  ret.put(o);
  return ret;
}

See also #550

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions