基于字符串递归输入Json对象

Recursively entering Json object based on string

本文关键字:Json 对象 输入 递归 字符串      更新时间:2023-10-16

我有以下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"应该返回一个Json对象,如下所示:

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

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

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

#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    },nnn    "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:UsersPieterDocumentsArduinolibrariesArduinoJson-master/include/ArduinoJson.hpp:12:0,
                 from C:UsersPieterDocumentsArduinolibrariesArduinoJson-master/include/ArduinoJson.h:8,
                 from C:UsersPieterDocumentsArduinolibrariesArduinoJson-master/ArduinoJson.h:8,
                 from C:UsersPieterDocumentsArduinoJSON_OSC_settings2JSON_OSC_settings2.ino:1:
C:UsersPieterDocumentsArduinolibrariesArduinoJson-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:UsersPieterDocumentsArduinolibrariesArduinoJson-master/include/ArduinoJson/JsonArray.hpp:13:0,
                 from C:UsersPieterDocumentsArduinolibrariesArduinoJson-master/include/ArduinoJson.hpp:11,
                 from C:UsersPieterDocumentsArduinolibrariesArduinoJson-master/include/ArduinoJson.h:8,
                 from C:UsersPieterDocumentsArduinolibrariesArduinoJson-master/ArduinoJson.h:8,
                 from C:UsersPieterDocumentsArduinoJSON_OSC_settings2JSON_OSC_settings2.ino:1:
C:UsersPieterDocumentsArduinolibrariesArduinoJson-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:UsersPieterDocumentsArduinolibrariesArduinoJson-master/include/ArduinoJson.hpp:12:0,
                 from C:UsersPieterDocumentsArduinolibrariesArduinoJson-master/include/ArduinoJson.h:8,
                 from C:UsersPieterDocumentsArduinolibrariesArduinoJson-master/ArduinoJson.h:8,
                 from C:UsersPieterDocumentsArduinoJSON_OSC_settings2JSON_OSC_settings2.ino:1:
C:UsersPieterDocumentsArduinolibrariesArduinoJson-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&)'

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

我编写了一个函数来解析简单的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] != ''; i++){
            if (jsonPath[i] == '$') {
                element = root;
            } else if (jsonPath[i] == '.') {
                if (pathIndex > 0) {
                    pathElement[pathIndex++] = '';
                    //printf("pathElement '%s'n", pathElement);
                    pathIndex = 0;
                    element = element[pathElement];
                    if (element == nullptr) {
                        Serial.printf("failed to parse key %sn", 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++] = '';
                    // printf("pathElement '%s'n", pathElement);
                    pathIndex = 0;
                    element = element[pathElement];
                    if (element == nullptr) {
                        Serial.printf("failed in parsing key %sn", pathElement);
                        return nullptr;
                    }
                }
            } else if (jsonPath[i] == ']') {
                pathElement[pathIndex++] = '';
                int arrayIndex = strtod(pathElement, NULL);
                // printf("index '%s' = %dn", pathElement, arrayIndex);
                pathIndex = 0;
                element = element[arrayIndex];
                if (element == nullptr) {
                    Serial.printf("failed in parsing index %dn", arrayIndex);
                    return nullptr;
                }
            }
        }  
        // final token if any:
        if (pathIndex > 0) {
            pathElement[pathIndex++] = '';
            // printf("pathElement '%s'n", pathElement);
            pathIndex = 0;
            element = element[pathElement];
            if (element == nullptr) {
                Serial.printf("failed in parsing key %sn", pathElement);
                return nullptr;
            }
        }
        jsonValue = element.as<String>();
    } else {
        jsonValue = nullptr;
    }
    return jsonValue;
}

我不是C开发人员,但是可以帮助您的是所谓的»JSONPath«,它意味着JSON的xPath对应。也许你可以找到一个可以这样做的库。

这似乎是类似的事情。

为了指向子对象,您可以简单地使用:

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

接下来,您可以检查此子对象是否存在,将其与JsonObject::invalid进行比较,如下所示:

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

如果路径的一部分不存在,operator[]将返回对JsonObject::invalid的引用,然后访问它的子节点也将返回对JsonObject::invalid的引用,那么迭代到不存在的子节点是安全的。