根据字符串递归进入Json对象

Recursively entering Json object based on string

我有以下 json 对象:

{
    "ESP_IN_PC_OUT":{
        "track":{
            "1":{
                "mute":{
                    "type":"LED",
                    "pins":[4]
                }
            },
            "2":{
                "mute":{
                    "type":"LED",
                    "pins":[5]
                }
            }
        }
    }
}

我要输入对象,取决于格式为“/index1/index2/index3 ...”的字符串(该字符串是OSC消息的地址)。例如,“/track/2/mute”应该 return 一个像这样的 Json 对象:

{
    "type":"LED",
    "pins":[5]
}

这样我就可以访问类型、引脚数组和一些稍后将实现的其他值。

我在 ESP8266 上使用 Arduino JSON library。这是我试过的代码:

#include <ArduinoJson.h>

char *jsonstr = "{\n    \"ESP_IN_PC_OUT\":{\n        \"track\":{\n            \"1\":{\n                \"mute\":{\n                    \"type\":\"LED\",\n                    \"pins\":[4]\n                }\n            },\n            \"2\":{\n                \"mute\":{\n                    \"type\":\"LED\",\n                    \"pins\":[5]\n                }\n            }\n        }\n    },\n\n\n    \"ESP_OUT_PC_IN\":{\n        \"analog\":{\n        },\n        \"digital\":{\n            \"16\":\"/track/1/mute\"\n        }\n    }\n}"; 

void setup() {
  Serial.begin(115200);

  DynamicJsonBuffer jsonBuffer;

  JsonObject& root = jsonBuffer.parseObject(jsonstr);
  if (!root.success()) {
    Serial.println("parseObject() failed");
    return;
  }

  Serial.println((const char*) root["ESP_IN_PC_OUT"]["track"]["2"]["mute"]["type"]); // prints "LED"
  Serial.println();

  char *address = "/track/2/mute";     // _____Interesting part_____
  char *tmp = strtok(address,"/");
  JsonObject& tmpJson = root["ESP_IN_PC_OUT"];
  bool success = true;
  while(tmp != NULL && success == true){
    Serial.println(tmp);
    if(tmpJson.containsKey(tmp)){
      tmpJson = tmpJson[tmp];        // Error: use of deleted function 'ArduinoJson::JsonObject& ArduinoJson::JsonObject::operator=(const ArduinoJson::JsonObject&)'
      tmp = strtok(NULL,"/");
    } else {
      success = false;
    }
  }
  if(success == true){
    Serial.println((const char*)tmpJson["type"]);
  } else {
    Serial.println("Address not found");
  }
}

void loop() {
}

但是,这给了我以下错误信息:

JSON_OSC_settings2:26: error: use of deleted function 'ArduinoJson::JsonObject& ArduinoJson::JsonObject::operator=(const ArduinoJson::JsonObject&)'

       tmpJson = tmpJson[tmp];

               ^

In file included from C:\Users\Pieter\Documents\Arduino\libraries\ArduinoJson-master/include/ArduinoJson.hpp:12:0,

                 from C:\Users\Pieter\Documents\Arduino\libraries\ArduinoJson-master/include/ArduinoJson.h:8,

                 from C:\Users\Pieter\Documents\Arduino\libraries\ArduinoJson-master/ArduinoJson.h:8,

                 from C:\Users\Pieter\Documents\Arduino\JSON_OSC_settings2\JSON_OSC_settings2.ino:1:

C:\Users\Pieter\Documents\Arduino\libraries\ArduinoJson-master/include/ArduinoJson/JsonObject.hpp:38:7: note: 'ArduinoJson::JsonObject& ArduinoJson::JsonObject::operator=(const ArduinoJson::JsonObject&)' is implicitly deleted because the default definition would be ill-formed:

 class JsonObject : public Internals::JsonPrintable<JsonObject>,

       ^

In file included from C:\Users\Pieter\Documents\Arduino\libraries\ArduinoJson-master/include/ArduinoJson/JsonArray.hpp:13:0,

                 from C:\Users\Pieter\Documents\Arduino\libraries\ArduinoJson-master/include/ArduinoJson.hpp:11,

                 from C:\Users\Pieter\Documents\Arduino\libraries\ArduinoJson-master/include/ArduinoJson.h:8,

                 from C:\Users\Pieter\Documents\Arduino\libraries\ArduinoJson-master/ArduinoJson.h:8,

                 from C:\Users\Pieter\Documents\Arduino\JSON_OSC_settings2\JSON_OSC_settings2.ino:1:

C:\Users\Pieter\Documents\Arduino\libraries\ArduinoJson-master/include/ArduinoJson/Internals/ReferenceType.hpp:32:18: error: 'ArduinoJson::Internals::ReferenceType& ArduinoJson::Internals::ReferenceType::operator=(const ArduinoJson::Internals::ReferenceType&)' is private

   ReferenceType& operator=(const ReferenceType&);

                  ^

In file included from C:\Users\Pieter\Documents\Arduino\libraries\ArduinoJson-master/include/ArduinoJson.hpp:12:0,

                 from C:\Users\Pieter\Documents\Arduino\libraries\ArduinoJson-master/include/ArduinoJson.h:8,

                 from C:\Users\Pieter\Documents\Arduino\libraries\ArduinoJson-master/ArduinoJson.h:8,

                 from C:\Users\Pieter\Documents\Arduino\JSON_OSC_settings2\JSON_OSC_settings2.ino:1:

C:\Users\Pieter\Documents\Arduino\libraries\ArduinoJson-master/include/ArduinoJson/JsonObject.hpp:38:7: error: within this context

 class JsonObject : public Internals::JsonPrintable<JsonObject>,

       ^

exit status 1
use of deleted function 'ArduinoJson::JsonObject& ArduinoJson::JsonObject::operator=(const ArduinoJson::JsonObject&)'

我该如何解决这个问题?我可以采取什么不同的方法?

我不是 C 开发人员,但可以帮助您的是 »JSONPath«,它与 JSON 的 xPath 对应。也许您可以找到可以做到这一点的图书馆。

This好像是类似的东西

为了指向sub-object,你可以简单地使用:

JsonObject& tmpJson = root["ESP_IN_PC_OUT"]["track"]["2"]["mute"];

接下来你可以检查这个 sub-object 是否存在,将它与 JsonObject::invalid 进行比较,如下所示:

bool success = (tmpJson != JsonObject::invalid());

if(success == true){
    Serial.println((const char*)tmpJson["type"]);
} else {
    Serial.println("Address not found");
}

如果路径的一部分不存在,operator[] 将 return 引用 JsonObject::invalid 然后访问其 child 也将 return引用 JsonObject::invalid,那么迭代到不存在的 child.

是安全的

我编写了一个函数来解析简单的 json 路径字符串并从 json 字符串中提取一个值。有关详细信息,请参阅 https://github.com/bblanchon/ArduinoJson/issues/821

我最近将它改编为 ArduinoJson6 - 我不得不承认我不是 c++ 的人,所以请怜悯我的代码:

// parse jsonPaths like $.foo[1].bar.baz[2][3].value equals to foo[1].bar.baz[2][3].value
String parseJson(char* jsonString, char *jsonPath) {

    Serial.printf("parsing String '%s'\n", jsonString);

    String jsonValue;
    DynamicJsonDocument jsonBuffer(64000); // fixme!!!!

    DeserializationError err = deserializeJson(jsonBuffer, jsonString);
    JsonVariant root = jsonBuffer.as<JsonVariant>();
    JsonVariant element = root;

    if (!err) {
        // parse jsonPath and navigate through json object:
        char pathElement[40];
        int pathIndex = 0;

        Serial.printf("parsing Path '%s'\n", jsonPath);
        for (int i = 0; jsonPath[i] != '[=10=]'; i++){
            if (jsonPath[i] == '$') {
                element = root;
            } else if (jsonPath[i] == '.') {
                if (pathIndex > 0) {
                    pathElement[pathIndex++] = '[=10=]';
                    //printf("pathElement '%s'\n", pathElement);
                    pathIndex = 0;
                    element = element[pathElement];
                    if (element == nullptr) {
                        Serial.printf("failed to parse key %s\n", pathElement);
                        return nullptr;
                    }
                }
            } else if ((jsonPath[i] >= 'a' && jsonPath[i] <= 'z') 
                    || (jsonPath[i] >= 'A' && jsonPath[i] <= 'Z') 
                    || (jsonPath[i] >= '0' && jsonPath[i] <= '9')
                    || jsonPath[i] == '-' || jsonPath[i] == '_'
                    ) {
                pathElement[pathIndex++] = jsonPath[i];
            } else if (jsonPath[i] == '[') {
                if (pathIndex > 0) {
                    pathElement[pathIndex++] = '[=10=]';
                    // printf("pathElement '%s'\n", pathElement);
                    pathIndex = 0;
                    element = element[pathElement];
                    if (element == nullptr) {
                        Serial.printf("failed in parsing key %s\n", pathElement);
                        return nullptr;
                    }
                }
            } else if (jsonPath[i] == ']') {
                pathElement[pathIndex++] = '[=10=]';
                int arrayIndex = strtod(pathElement, NULL);
                // printf("index '%s' = %d\n", pathElement, arrayIndex);
                pathIndex = 0;
                element = element[arrayIndex];
                if (element == nullptr) {
                    Serial.printf("failed in parsing index %d\n", arrayIndex);
                    return nullptr;
                }
            }
        }  
        // final token if any:
        if (pathIndex > 0) {
            pathElement[pathIndex++] = '[=10=]';
            // printf("pathElement '%s'\n", pathElement);
            pathIndex = 0;
            element = element[pathElement];
            if (element == nullptr) {
                Serial.printf("failed in parsing key %s\n", pathElement);
                return nullptr;
            }
        }

        jsonValue = element.as<String>();
    } else {
        jsonValue = nullptr;
    }
    return jsonValue;
}