Javascript 发送/解析多个 JSON 对象

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4209527/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 11:23:27  来源:igfitidea点击:

Sending/Parsing multiple JSON objects

javascriptsinatra

提问by Kenny Peng

I have a Sinatra server that is returning multiple JSON objects from the database in a streaming manner. The objects would look like:

我有一个 Sinatra 服务器,它以流式方式从数据库返回多个 JSON 对象。对象看起来像:

{"a": 1, "b": 2, "c": 3}
{"a": 4, "b": 5, "c": 6}
...

but this is invalid JSON. I can add a hack into Sinatra's event processing (manually injecting the missing array delimiters) to make the response look like:

但这是无效的 JSON。我可以在 Sinatra 的事件处理中添加一个 hack(手动注入丢失的数组分隔符),使响应看起来像:

[
{"a": 1, "b": 2, "c": 3}
, {"a": 4, "b": 5, "c": 6}
]

which is valid JSON now, but this technique is inelegant. Is there some way to do this client-side? Basically, what I want is to have a JavaScript function read a string and consume a valid JSON object, and then return to me the JSON object and the remainder of the string, iteratively being called until the entire string is consumed.

现在是有效的 JSON,但这种技术不雅。有什么方法可以做到这个客户端?基本上,我想要的是让 JavaScript 函数读取一个字符串并使用一个有效的 JSON 对象,然后将 JSON 对象和字符串的其余部分返回给我,迭代地被调用,直到使用完整个字符串。

采纳答案by Alex Jasmin

The native JSON.parse()function expect the whole string to be valid JSON. I'm not aware of a parser that only consumes the first valid objectas you'd like. And people should really be producing valid JSON anyways.

本机JSON.parse()函数希望整个字符串都是有效的 JSON。我不知道解析器只按照您的意愿使用第一个有效对象。无论如何,人们真的应该生成有效的 JSON。

If you know that there is one object per line you could simply split the string by line using the split()function and parse each line individually.

如果您知道每行有一个对象,您可以简单地使用该split()函数逐行拆分字符串并单独解析每一行。

var str = '{"a": 1, "b": 2, "c": 3}\n'+
          '{"a": 4, "b": 5, "c": 6}';

var strLines = str.split("\n");


for (var i in strLines) {
  var obj = JSON.parse(strLines[i]);
  console.log(obj.a);
}

You could also use a bit of string manipulation to transform each line into an array element and parse the whole thing.

您还可以使用一些字符串操作将每一行转换为数组元素并解析整个内容。

str = "["+str.replace(/\n/g, ",")+"]";
JSON.parse(str);

回答by Chris

I would do this:

我会这样做:

var str = '{"a": 1, "b": 2, "c": 3}{"a": 4, "b": 5, "c": 6}';

var res = JSON.parse('[' + str.replace(/}{/g, '},{') + ']');

Edit:

编辑:

as awnser on tremby's comment

作为 tremby 评论的 awnser

var str = '{"a": 1, "b": 2, "c": 3}{"a": 4, "b": 5, "c": 6}';

var res = JSON.parse('[' + str.replace(/}{(?=([^"]*"[^"]*")*[^"]*$)/g, '},{') + ']');

回答by Alin Purcaru

If the JSON strings are single line you can do something like this:

如果 JSON 字符串是单行,您可以执行以下操作:

var splitPoint = remainingData.indexOf("\n");
var currentJSONStr = splitPoint > -1 ? remainingData.substr(0, splitPoint) : remainingData;
remainingData =  splitPoint > -1 ? remainingData.substr(splitPoint+1) : '';
var dataObj = youJSONDecodeFuncOrEval(currentJSONStr);

If not, just ignore my answer.

如果没有,请忽略我的回答。

I hope this helps you,
Alin

我希望这对你有帮助,
阿林



Note: I tried to fulfill the requirement

注意:我试图满足要求

Basically, what I want is to have a JavaScript function read a string and consume a valid JSON object, and then return to me the JSON object and the remainder of the string, iteratively being called until the entire string is consumed.

基本上,我想要的是让 JavaScript 函数读取一个字符串并使用一个有效的 JSON 对象,然后将 JSON 对象和字符串的其余部分返回给我,迭代地被调用,直到使用完整个字符串。

this is why I didn't use .split("\n").

这就是为什么我没有使用.split("\n").

回答by roto

This may not be the most efficient, but should get the job done.

这可能不是最有效的,但应该可以完成工作。

var s = '{"a": 1, "b": 2, "c": 3}{"a": 4, "b": 5, "c": 6}';
var sTemp = "";
var aObjs = [];
for(var i=0; i<s.length; ++i)
{
    sTemp += s[i];
    if (s[i] == "}")
    {
        aObjs.push(JSON.parse(sTemp));
        sTemp = "";
    }
}

If you know there is a new line character in between objects, it becomes much simpler.

如果您知道对象之间有一个换行符,它会变得简单得多。

var sBad = '{"a": 1, "b": 2, "c": 3}\n{"a": 4, "b": 5, "c": 6}';
var sGood = "[" + sBad.replace(/\n/g, ",") + "]";
var aObjs = JSON.parse(sGood);

回答by Kishore Ganti

o.string is json Object.

o.string 是 json 对象。

add some string like "new" to array of objects or multiple json objects.

将一些像“new”这样的字符串添加到对象数组或多个 json 对象中。

for eg:

例如:

json object----

{"id":2,"method":"listWirings","params":{"language":"anonymousLanguage","name":"mytest","working":"{\"modules\":[{\"config\":{\"position\":[186,59],\"xtype\":\"WireIt.ImageContainer\"},\"name\":\"Start\",\"value\":{}},{\"config\":{\"position\":[188,265],\"xtype\":\"WireIt.ImageContainer\"},\"name\":\"Stop\",\"value\":{}}],\"properties\":{\"description\":\"gfd\",\"name\":\"gf\"},\"wires\":[{\"src\":{\"moduleId\":0,\"terminal\":\"_OUTPUT\"},\"tgt\":{\"moduleId\":1,\"terminal\":\"StpIn\"}}]}"},"version":"json-rpc-2.0"}new

  var str = o.toString();
                var s = str.split("new");
                for (var i = 0; i < s.length-1; i++)
                {
                    var r = YAHOO.lang.JSON.parse(s[i]);
                }

hope this will to parse multiple json objects .

希望这将解析多个 json 对象。

回答by LuSt

I wrote this little JavaScript function, which allows you to parse any string to Json objects. It works by passing through each character and taking note of the hierarchy. The benefit of this Solution is, that you can get all the Json objects of a text without knowing what is separating them.

我编写了这个 JavaScript 小函数,它允许您将任何字符串解析为 Json 对象。它通过遍历每个角色并注意层次结构来工作。这个解决方案的好处是,你可以在不知道是什么分隔它们的情况下获取文本的所有 Json 对象。

function evaluateJsonString(string){
    var start = string.indexOf('{');
    if(start == -1)
        return false;
    let hierarchy = 0;
    let characters = string.split('');
    let objects = [];
    for(var index = start; index < characters.length; index++){
        let char = characters[index];
        if(char == '{')
            hierarchy++;
        if(char == '}')
            hierarchy--;
        if(hierarchy == 0){
            objects.push(JSON.parse(characters.slice(start, index + 1).join('')));
            index = start = index + characters.slice(index, characters.length).indexOf('{') - 1;
            if(start == -1)
                break;
        }
    }
    return objects;
}

let result = evaluateJsonString('This is {"name": "John", "age": 32, "hobbies": ["sport", "programming"]} He goes to {"name": "University", "director": {"name": "Peter", "age": 66, "hobbies": ["drinking coffee"]}}');

console.log(result);

回答by tremby

I wrote a small module today to do this and published it on NPM as json-multi-parse. The code is available on Github.

我今天写了一个小模块来做到这一点,并将其作为json-multi-parse. 该代码可以在Github上

My solution is simple, but admittedly possibly brittle since it relies on the error message JSON.parsethrows when parsing such a string. It uses the position number given in the error (the number in "Unexpected token { in JSON at position xyz") to parse everything up to before that, then recurse and parse everything after.

我的解决方案很简单,但无可否认可能很脆弱,因为它依赖于JSON.parse解析这样的字符串时抛出的错误消息。它使用错误中给出的位置号(“Unexpected token { in JSON at position xyz”中的数字)来解析之前的所有内容,然后递归并解析之后的所有内容。

However, it won't break due to curly braces in strings as some of the other suggestion solutions here will.

但是,它不会像这里的其他一些建议解决方案那样由于字符串中的花括号而中断。

Here's the simple version of the code, which will work in Chrome and Node.

这是代码的简单版本,可在 Chrome 和 Node.js 中使用。

const ERROR_REGEX = /^Unexpected token { in JSON at position (\d+)$/;
function jsonMultiParse(input, acc = []) {
    if (input.trim().length === 0) {
        return acc;
    }
    try {
        acc.push(JSON.parse(input));
        return acc;
    } catch (error) {
        const match = error.message.match(ERROR_REGEX);
        if (!match) {
            throw error;
        }
        const index = parseInt(match[1], 10);
        acc.push(JSON.parse(input.substr(0, index)));
        return jsonMultiParse(input.substr(index), acc);
    }
}

It gets more complicated if you want to support Firefox too, which gives its error in a format giving line number and character within that line. The module I linked above handles this case.

如果您也想支持 Firefox,它会变得更加复杂,这会以在该行中给出行号和字符的格式给出错误。我上面链接的模块处理这种情况。

回答by YodasWs

If the data stream is giving you multiple JSON objects in one line, you need to separate them into an array:

如果数据流在一行中为您提供多个 JSON 对象,您需要将它们分成一个数组:

const str = '{"a": 1, "b": 2, "c": 3}\n' +
      '{"a": 4, "b": 5, "c": 6}' +
      '{"a": 7, "b": 8, "c": 9}';

const json = '[' + str.replace(/}\n?{/g, '},{') + ']';

JSON.parse(json).forEach((obj) => {
  console.log('a:', obj.a);
});

回答by user6481728

I wrote a java converter (using the Hymanson library) that turns multiple JSON objects in a file into the proper JSON array:

我编写了一个 java 转换器(使用 Hymanson 库),它将文件中的多个 JSON 对象转换为正确的 JSON 数组:

import java.io.File;
import com.fasterxml.Hymanson.core.JsonFactory;
import com.fasterxml.Hymanson.core.JsonParser;
import com.fasterxml.Hymanson.core.JsonToken;
import com.fasterxml.Hymanson.databind.JsonNode;
import com.fasterxml.Hymanson.databind.MappingJsonFactory;
import com.fasterxml.Hymanson.databind.ObjectMapper;
import com.fasterxml.Hymanson.databind.node.ArrayNode;
import com.fasterxml.Hymanson.databind.node.JsonNodeFactory;
import com.fasterxml.Hymanson.databind.node.ObjectNode;

public class ParseJson {
    ObjectMapper mapper = new ObjectMapper();

  public static void main(String[] args) throws Exception {
      File file = new File(args[0]);
      JsonNode jn = new Parser().parse(file);

      System.out.println(jn.toString());
  }

  private enum ParserState {
      start,
      object,
      array,
      field,
      done
  };

  private static class Parser {   

      public Parser() {
      }

      public JsonNode parse(File file) throws Exception {
          JsonNodeFactory factory = JsonNodeFactory.instance;
          JsonFactory mappingFactory = new MappingJsonFactory();          
          @SuppressWarnings("deprecation")
        JsonParser jp = mappingFactory.createJsonParser(file);

          int n = 0;
          JsonNode result = null;
          JsonNode jn;

          while((jn = parseNode(jp, false)) != null) {
              if(n == 0) {
                  result = jn;
              } else if(n == 1) {
                  ArrayNode an = factory.arrayNode();
                  an.add(result);
                  an.add(jn);
                  result = an;
              } else if(n > 1) {
                  ArrayNode an = (ArrayNode)result;
                  an.add(jn);
              } else {
                  throw new Exception("Unexpected parser state");
              }
              n++;
          }

          return result;
      }

      private JsonNode parseNode(JsonParser jp, boolean current) throws Exception {
          JsonNodeFactory factory = JsonNodeFactory.instance;

          ParserState state = ParserState.start;
          JsonNode result = null;
          String fieldName = null;

          JsonToken token = current ? jp.getCurrentToken() : jp.nextToken();

          for(; token != null; token = jp.nextToken()) {

              // System.out.println("Token: "+token+": "+jp.getValueAsString());

              switch(token) {
                /**
                 * NOT_AVAILABLE can be returned if {@link JsonParser}
                 * implementation can not currently return the requested
                 * token (usually next one), or even if any will be
                 * available, but that may be able to determine this in
                 * future. This is the case with non-blocking parsers --
                 * they can not block to wait for more data to parse and
                 * must return something.
                 */
              case NOT_AVAILABLE: {
                  break;
              }

                /**
                 * START_OBJECT is returned when encountering '{'
                 * which signals starting of an Object value.
                 */
              case START_OBJECT: {
                    switch(state) {
                        case start: {
                            assert result == null;
                            assert fieldName == null;

                            result = factory.objectNode();
                            state = ParserState.object;
                            break;
                        }
                        case field: {
                            assert result != null;
                            assert fieldName != null;

                            ObjectNode on = (ObjectNode)result;
                            JsonNode jn = parseNode(jp, true);
                            on.set(fieldName, jn);
                            fieldName = null;
                            state = ParserState.object;
                            break;
                        }
                        case array: {
                            assert result != null;
                            assert fieldName == null;

                            ArrayNode an = (ArrayNode)result;
                            JsonNode jn = parseNode(jp, true);
                            an.add(jn);
                            break;
                        }
                        default: {
                            throw new Exception("Unexpected state: "+state+", for token: "+token);
                        }
                    }

                  break;                  
              }

                /**
                 * END_OBJECT is returned when encountering '}'
                 * which signals ending of an Object value
                 */
              case END_OBJECT: {
                    switch(state) {
                        case object: {
                            assert result != null;
                            assert fieldName == null;

                            state = ParserState.done;
                            break;
                        }
                        default: {
                            throw new Exception("Unexpected state: "+state+", for token: "+token);
                        }
                    }

                  break;                  
              }

                /**
                 * START_ARRAY is returned when encountering '['
                 * which signals starting of an Array value
                 */
              case START_ARRAY: {
                    switch(state) {
                        case start: {
                            assert result == null;
                            assert fieldName == null;

                            result = factory.arrayNode();
                            state = ParserState.array;
                            break;
                        }
                        case field: {
                            assert result != null;
                            assert fieldName != null;

                            ObjectNode on = (ObjectNode)result;
                            JsonNode jn = parseNode(jp, true);
                            on.set(fieldName, jn);
                            fieldName = null;
                            state = ParserState.object;
                            break;
                        }
                        case array: {
                            assert result != null;
                            assert fieldName == null;

                            ArrayNode an = (ArrayNode)result;
                            JsonNode jn = parseNode(jp, true);
                            an.add(jn);
                            break;
                        }
                        default: {
                            throw new Exception("Unexpected state: "+state+", for token: "+token);
                        }
                    }

                  break;                  
              }

                /**
                 * END_ARRAY is returned when encountering ']'
                 * which signals ending of an Array value
                 */
              case END_ARRAY: {
                    switch(state) {
                        case array: {
                            assert result != null;
                            assert fieldName == null;

                            state = ParserState.done;
                            break;
                        }
                        default: {
                            throw new Exception("Unexpected state: "+state+", for token: "+token);
                        }
                    }

                  break;                  
              }

                /**
                 * FIELD_NAME is returned when a String token is encountered
                 * as a field name (same lexical value, different function)
                 */
              case FIELD_NAME: {
                    fieldName = jp.getValueAsString();
                    switch(state) {
                        case object: {
                            assert result != null;
                            assert fieldName == null;

                            state = ParserState.field;
                            break;
                        }
                        default: {
                            throw new Exception("Unexpected state: "+state+", for token: "+token);
                        }
                    }

                    break;
              }

                /**
                 * Placeholder token returned when the input source has a concept
                 * of embedded Object that are not accessible as usual structure
                 * (of starting with {@link #START_OBJECT}, having values, ending with
                 * {@link #END_OBJECT}), but as "raw" objects.
                 *<p>
                 * Note: this token is never returned by regular JSON readers, but
                 * only by readers that expose other kinds of source (like
                 * <code>JsonNode</code>-based JSON trees, Maps, Lists and such).
                 */
              case VALUE_EMBEDDED_OBJECT: {
                  throw new Exception("Token not supported: "+token);
              }

                /**
                 * VALUE_STRING is returned when a String token is encountered
                 * in value context (array element, field value, or root-level
                 * stand-alone value)
                 */
              case VALUE_STRING: {
                    switch(state) {
                        case start: {
                            assert result == null;
                            assert fieldName == null;

                            result = factory.textNode(jp.getValueAsString());
                            state = ParserState.done;
                            break;
                        }
                        case field: {
                            assert result != null;
                            assert fieldName != null;

                            ObjectNode on = (ObjectNode)result;
                            JsonNode jn = factory.textNode(jp.getValueAsString());
                            on.set(fieldName, jn);
                            fieldName = null;
                            state = ParserState.object;
                            break;
                        }
                        case array: {
                            assert result != null;
                            assert fieldName == null;

                            ArrayNode an = (ArrayNode)result;
                            JsonNode jn = factory.textNode(jp.getValueAsString());
                            an.add(jn);
                            break;
                        }
                        default: {
                            throw new Exception("Unexpected state: "+state+", for token: "+token);
                        }
                    }

                    break;
              }

                /**
                 * VALUE_NUMBER_INT is returned when an integer numeric token is
                 * encountered in value context: that is, a number that does
                 * not have floating point or exponent marker in it (consists
                 * only of an optional sign, followed by one or more digits)
                 */
              case VALUE_NUMBER_INT: {
                    switch(state) {
                        case start: {
                            assert result == null;
                            assert fieldName == null;

                            result = factory.numberNode(jp.getLongValue());
                            state = ParserState.done;
                            break;
                        }
                        case field: {
                            assert result != null;
                            assert fieldName != null;

                            ObjectNode on = (ObjectNode)result;
                            JsonNode jn = factory.numberNode(jp.getLongValue());
                            on.set(fieldName, jn);
                            fieldName = null;
                            state = ParserState.object;
                            break;
                        }
                        case array: {
                            assert result != null;
                            assert fieldName == null;

                            ArrayNode an = (ArrayNode)result;
                            JsonNode jn = factory.numberNode(jp.getLongValue());
                            an.add(jn);
                            break;
                        }
                        default: {
                            throw new Exception("Unexpected state: "+state+", for token: "+token);
                        }
                    }

                    break;
              }

                /**
                 * VALUE_NUMBER_INT is returned when a numeric token other
                 * that is not an integer is encountered: that is, a number that does
                 * have floating point or exponent marker in it, in addition
                 * to one or more digits.
                 */
              case VALUE_NUMBER_FLOAT: {
                    switch(state) {
                        case start: {
                            assert result == null;
                            assert fieldName == null;

                            result = factory.numberNode(jp.getDoubleValue());
                            state = ParserState.done;
                            break;
                        }
                        case field: {
                            assert result != null;
                            assert fieldName != null;

                            ObjectNode on = (ObjectNode)result;
                            JsonNode jn = factory.numberNode(jp.getDoubleValue());
                            on.set(fieldName, jn);
                            fieldName = null;
                            state = ParserState.object;
                            break;
                        }
                        case array: {
                            assert result != null;
                            assert fieldName == null;

                            ArrayNode an = (ArrayNode)result;
                            JsonNode jn = factory.numberNode(jp.getDoubleValue());
                            an.add(jn);
                            break;
                        }
                        default: {
                            throw new Exception("Unexpected state: "+state+", for token: "+token);
                        }
                    }

                    break;
              }

                /**
                 * VALUE_TRUE is returned when encountering literal "true" in
                 * value context
                 */
              case VALUE_TRUE: {
                    switch(state) {
                        case start: {
                            assert result == null;
                            assert fieldName == null;

                            result = factory.booleanNode(true);
                            state = ParserState.done;
                            break;
                        }
                        case field: {
                            assert result != null;
                            assert fieldName != null;

                            ObjectNode on = (ObjectNode)result;
                            JsonNode jn = factory.booleanNode(true);
                            on.set(fieldName, jn);
                            fieldName = null;
                            state = ParserState.object;
                            break;
                        }
                        case array: {
                            assert result != null;
                            assert fieldName == null;

                            ArrayNode an = (ArrayNode)result;
                            JsonNode jn = factory.booleanNode(true);
                            an.add(jn);
                            break;
                        }
                        default: {
                            throw new Exception("Unexpected state: "+state+", for token: "+token);
                        }
                    }

                    break;
              }

                /**
                 * VALUE_FALSE is returned when encountering literal "false" in
                 * value context
                 */
              case VALUE_FALSE: {
                    switch(state) {
                        case start: {
                            assert result == null;
                            assert fieldName == null;

                            result = factory.booleanNode(false);
                            state = ParserState.done;
                            break;
                        }
                        case field: {
                            assert result != null;
                            assert fieldName != null;

                            ObjectNode on = (ObjectNode)result;
                            JsonNode jn = factory.booleanNode(false);
                            on.set(fieldName, jn);
                            fieldName = null;
                            state = ParserState.object;
                            break;
                        }
                        case array: {
                            assert result != null;
                            assert fieldName == null;

                            ArrayNode an = (ArrayNode)result;
                            JsonNode jn = factory.booleanNode(false);
                            an.add(jn);
                            break;
                        }
                        default: {
                            throw new Exception("Unexpected state: "+state+", for token: "+token);
                        }
                    }

                    break;
              }

                /**
                 * VALUE_NULL is returned when encountering literal "null" in
                 * value context
                 */
              case VALUE_NULL: {
                    switch(state) {
                        case start: {
                            assert result == null;
                            assert fieldName == null;

                            result = factory.nullNode();
                            state = ParserState.done;
                            break;
                        }
                        case field: {
                            assert result != null;
                            assert fieldName != null;

                            ObjectNode on = (ObjectNode)result;
                            JsonNode jn = factory.nullNode();
                            on.set(fieldName, jn);
                            fieldName = null;
                            state = ParserState.object;
                            break;
                        }
                        case array: {
                            assert result != null;
                            assert fieldName == null;

                            ArrayNode an = (ArrayNode)result;
                            JsonNode jn = factory.nullNode();
                            an.add(jn);
                            break;
                        }
                        default: {
                            throw new Exception("Unexpected state: "+state+", for token: "+token);
                        }
                    }

                    break;
              }

              default: {
                  throw new Exception("Token not supported: "+token);
              }

              }

              if(state == ParserState.done) {
                  break;
              }
          }           

          return result;
      }
  }
}