#Chromium #JSON

As I’ve mentioned or will mention in other posts, Chromium itself is a very rich set of libraries. For example, if you use the Thread and GURL classes, you can easily create and manage threads, and you can also handle URLs as you like. There are many other useful classes (which do not need to be parsed to extract only the scheme), and they exist in Chromium’s base namespace.

Since Chromium is a web browser, of course, there will be a module for handling JSON (JavaScript Object Notation). No, it must exist. In fact, the JSONReader class exists under the base namespace. Of course, there is an option to use a library such as libjson-c or libjsoncpp, but if you are a Chromium developer, you do not need to use it. This post contains how to handle JSON in Chromium.

1. Open and read file

The object to be processed may exist in the form of a file, or it may exist in the form of a byte stream by receiving it from the network. The file format must also be converted into a byte stream format for processing, so let’s look at the former case.

Chromium even has a class that handles file paths. The class is FilePath. It may be questioned whether a class that handles file paths is necessary, but it is a very useful and important class that is more complex than you think, even if the rules for configuring file paths are different for each platform. If the file you want to process is test.json and the file path is “/path/to/file/test.json”, you can create a FilePath object as follows.

base::FilePath json_path("/path/to/file/test.json");

The above code creates a FilePath object called json_path. Now, you need to read test.json using this object and get the contents in the form of a byte stream. This operation can be performed as follows by using the ReadFileToString() function.

std::string json_string;
base::ReadFileToString(json_path, &json_string);

With the code above, the contents of test.json are saved in json_string, a string object.

2. Parse JSON and Ready to play with it

json_string is just a string object that stores the contents of test.json as a byte stream. This string should be parsed in an easy-to-handle form according to the JSON grammar. This cumbersome task can be easily handled with Read(), a member function of the JSONReader class in the base namespace. Since it is a static function, it can be used as follows.

std::unique_ptr<base::Value> json_structure;
json_structure = base::JSONReader::Read(json_str);

The above code creates a Value object called json_structure. You can use this to extract all key values in test.json.

3. Getting a dictionary from a JSON

JSON is structured based on the following two structures. [JSON Official Homepage] (https://www.json.org “JSON Official Homepage”) has a brief description of the two structures.

  • Collection - name/value pairs. In various languages this is realized as an object, record, struct, dictionary, hash table, keyed list, or associative array. - Ordered list of values - realized as an array, vector, list, or sequence.

JSON consists of Collection and Ordered list. Therefore, being able to derive these two structures from JSON means that JSON can be fully utilized. How to implement Collection and Ordered list depends on the language. In Chromium, they are expressed as Dictionary and List, respectively. And, in the base namespace, there are classes named DictionaryValue and ListValue that inherit Value class. Something is starting to come to mind. Before going any further, let’s assume that the contents of test.json are as follows:

{
   "key1" : {
      "key11" : "value11",
      "key12" : [ "element121",
                  "element122"
                ]
}

The entire JSON body is a Collection, ie a Dictionary. Therefore, it is necessary to obtain a DictionaryValue object from the json_structure, which is the Value object obtained by parsing earlier. Only then will it be possible to extract the values “element121” and “element122” that are included in “value11”, which is the value of key11, and “element121”, “element122”, which is the ‘Ordered list’. ` You can use a function, since it is a static function, it can be used as follows.

std::unique_ptr<base::DictionaryValue> json_dictionary;
json_dictionary = base::DictionaryValue::From(json_structure);

With the code above, you can get a DictionaryValue object called json_dictionary.

4. Getting a value which type is “string” from a dictionary

I don’t know if it’s only in Chromium, but you can use “.” to express the path of a specific key. For example, the address of Key11 is “key1.key11”. Using this path, you can extract the value of the corresponding key. Since the type of the value corresponding to key11 is a string, the GetString() function of the DictionaryValue class can be used as follows.

std::string key11_value;
json_dictionary->GetString("key1.key11", &key11_value);

5. Getting a list from a dictionary

key12 is an ordered list enclosed in square brackets, that is, a List. So this time we need to extract the ListValue object, not the std::string from the DictionaryValue object. For this, you can use the GetList() function of the DictionaryValue class as follows.

base::ListValue* key12_list;
json_dictionary->GetList("key1.key12", &key12_list);

6. Iterate and getting a value which type is “string” from a list

All elements of key12, an ordered list, can be extracted by traversing the elements of key12_list, the ListValue object obtained earlier. DictionaryValue, ListValue class inherits Value class. In the case of ListValue, elements are stored in ListStorage, a member variable defined by Value, the parent class. According to the chain substitution chain below,

// base/values.h
// https://cs.chromium.org/chromium/src/base/values.h?rcl=029daddc376494ee36c5d81cc51a5ade45002fb6&l=589
class ListValue : public Value {
using const_iterator = ListStorage::const_iterator;

}
// base/values.h
// https://cs.chromium.org/chromium/src/base/values.h?rcl=029daddc376494ee36c5d81cc51a5ade45002fb6&l=85
ListStorage = std::vector<Value>;

ListStorage is after all a std::vector object. That is, elements can be traversed using the same method of traversing std::vector objects.

ListValue::const_iterator == std::vector<Value>::const_iterator

What types of elements were visited during the traversal? You need to know the type to extract the value. As can be seen from the above equation, each element referenced by iterator or const_iterator is base::Value* or const base::Value*. On the other hand, the value of the Value object can be obtained with the member function GetString(). (If the type of the key value is a string) Below is an example.

for(base::ListValue::const_iterator it = key12_list->begin(); 
     it != key12_list->end(); ++it) {
   std::string key12_string() it->GetString();
}

Full example

The full example code to extract all values from test.json is as follows.

base::FilePath json_path("/path/to/file/test.json");
std::string json_string;
std::unique_ptr<base::Value> json_structure;
std::unique_ptr<base::DictionaryValue> json_dictionary;
std::string key11_value;
base::ListValue* key12_list;

base::ReadFileToString(json_path, &json_string);
json_structure = base::JSONReader::Read(json_str);
json_dictionary = base::DictionaryValue::From(json_structure);
json_dictionary->GetString("key1.key11", &key11_value);
json_dictionary->GetList("key1.key12", &key12_list);
for(base::ListValue::const_iterator it = key12_list->begin(); 
     it != key12_list->end(); ++it) {
   std::string key12_string() it->GetString();
}