How can I parse the first JSON object on a stream in JS

后端 未结 2 780
执念已碎
执念已碎 2020-12-08 16:14

I have a stream of JSON objects, as with JSON-RPC over TCP or WebSockets. There\'s no length prefix or delimiter, because JSON is self-delimiting. So, when I read from the s

相关标签:
2条回答
  • 2020-12-08 16:52

    Here is a simple JSON Object separator. It assumes that you receive a series of JSON objects (not array) and that are well formed.

    function JSONObjectSepaator() {
    
        this.onObject = function (JSONStr) {};
    
        this.reset = function () {
            this.brace_count = 0;
            this.inString = false;
            this.escaped = false;
            this.buffer = "";
        };
    
        this.receive = function (S) {
            var i;
            var pos=0;
            for (i = 0; i < S.length; i++) {
                var c = S[i];
                if (this.inString) {
                    if (this.escaped) {
                        this.escaped = false;
                    } else {
                        if (c == "\\") {
                            this.escaped = true;
                        } else if (c == "\"") {
                            this.inString = false;
                        }
                    }
                } else {
                    if (c == "{") {
                        this.brace_count++;
                    } else if (c == "}") {
                        this.brace_count--;
                        if (this.brace_count === 0) {
                            this.buffer += S.substring(pos,i+1);
                            this.onObject(this.buffer);
                            this.buffer = "";
                            pos=i+1;
                        }
                    } else if (c == "\"") {
                        this.inString = true;                   
                    } 
                }
            }
            this.buffer += S.substring(pos);
        };
    
        this.reset();
        return this;
    }
    

    To use it, you can do it this way:

    var separator = new JSONObjectSepaator();
    separator.onObject = function (o) {
        alert("Object received: "+o);
    };
    
    separator.receive('{"id":1,"result":{"answer":23},"error":null, "x');
    separator.receive('x":"\\\""}{"id":2,"result":{"answer":42},"error":null}{"id":');
    separator.receive('3,"result":{"answer":43},"err{or":3}');
    
    0 讨论(0)
  • 2020-12-08 16:56

    After a month of searching for alternatives and not finding anything useful, I decided to code up a bunch of different implementations and test them out, and I went with my modification of Crockford's reference recursive-descent parser (as described in the question, available here).

    It wasn't the fastest, but it was more than fast enough in every test I did. More importantly, it catches clearly erroneous JSON, when that's not ambiguous with incomplete JSON, much better than most of the other alternatives. Most importantly, it required very few, and pretty simple, changes from a well-known and -tested codebase, which makes me more confident in its correctness.

    Still, if anyone knows of a better library than mine (and just being used by lots of projects instead of just me would count as a major qualification), I'd love to know about it.

    0 讨论(0)
提交回复
热议问题