JSON

JSONObjectIterator

// EXAMPLE
SerialLogHandler logHandler;

void setup() {
    Particle.subscribe("jsonTest", subscriptionHandler);
}

void subscriptionHandler(const char *event, const char *data) {

    JSONValue outerObj = JSONValue::parseCopy(data);

    JSONObjectIterator iter(outerObj);
    while(iter.next()) {
        Log.info("key=%s value=%s", 
          (const char *) iter.name(), 
          (const char *) iter.value().toString());
    }
}

// TEST EVENT
$ particle publish jsonTest '{"a":123,"b":"testing"}'

// LOG
0000068831 [app] INFO: key=a value=123
0000068831 [app] INFO: key=b value=testing

In order to access key/value pairs in a JSON object, you just create a JSONObjectIterator from the JSONValue.

The basic flow is:

  • Create a JSONObjectIterator from a JSONValue.
  • Call iter.next(). This must be done before accessing the first value, and to access each subsequent value. When it returns false, there are no more elements. It's possible for next() return false on the first call for an empty object.
  • Use iter.name() and iter.value() to get the key name and value.

// EXAMPLE
JSONValue outerObj = JSONValue::parseCopy(
  "{\"a\":123,\"b\":\"test\",\"c\":true}");

JSONObjectIterator iter(outerObj);
while(iter.next()) {
    if (iter.name() == "a") {
        Log.trace("a=%d", 
          iter.value().toInt());
    }
    else
    if (iter.name() == "b") {
        Log.trace("b=%s", 
          (const char *) iter.value().toString());     
    }
    else
    if (iter.name() == "c") {
        Log.trace("c=%d", 
          iter.value().toBool());
    }
    else {
        Log.trace("unknown key %s", 
          (const char *)iter.name());
    }
}

// LOG
0000242555 [app] TRACE: a=123
0000242555 [app] TRACE: b=test
0000242555 [app] TRACE: c=1

Since there is no way to find an element by its key name, you typically iterate the object and compare the name like this:

You should not rely on the ordering of keys in a JSON object. While in this simple example, the keys will always be in the order a, b, c, when JSON objects are manipulated by server-based code, the keys can sometimes be reordered. The name-based check here assures compatibility even if reordered. Arrays will always stay in the same order.


JSONObjectIterator::JSONObjectIterator(const JSONValue &value)

// PROTOTYPE
explicit JSONObjectIterator(const JSONValue &value);

Construct an iterator from a JSONValue. This can be the whole object, or you can use it to iterate an object within the key of another object.

JSONObjectIterator::next()

// PROTOTYPE
bool next();

Call next() before accessing name() and value(). Then each subsequent call will get the next pair. When it returns false, there are no elements left. It's possible for next() to return false on the first call if the object has no key/value pairs.

There is no rewind function to go back to the beginning. To start over, construct a new JSONObjectIterator from the JSONValue again.

JSONObjectIterator::name()

// PROTOTYPE
JSONString name() const;

Returns the name of the current name/value pair in the object. The name must be 7-bit ASCII but can contain characters that require escaping (like double quotes and backslash). To get a const char * you can use iter.name().data().

JSONObjectIterator::value()

// PROTOTYPE
JSONValue value() const;

Returns the current value of the name/value pair in the object.

You will typically use methods of JSONValue like toInt(), toBool(), toDouble(), and toString() to get useful values. For example:

  • iter.value().toInt(): Returns a signed 32-bit int.
  • iter.value().toDouble(): Returns a 64-bit double.
  • iter.value().toString().data(): Returns a const char *. You can assign this to a String to copy the value, if desired.

JSONObjectIterator::count()

// PROTOTYPE
size_t count() const;

Returns the count of the number of remaining key/value pairs. As you call next() this value will decrease.