当前位置: 首页 > 知识库问答 >
问题:

javascript - 如何解析stream流式json数据?

宿文栋
2023-05-10

问题:假设有一个json对象如下:

{
    table: [
        {
            name: 'js',
            age: 20
        }
    ]
}

现在以上对象在服务端被格式化stream流返回(一个请求,分为多个片段返回),并且每个片段的内容都是不确定的,前端接收到内容后,都需要用JSON.parse解析代码,并渲染到界面上。
假设服务端返回的每个片段可能如下:

// 1
"{"
// 2
"table: ["
// 3
"{name: 'js',"
// 4
"age: 20"
// 5
"}"
// 6
"]"
// 7
"}"

从上面可以看出,服务端每个片段返回到可能是总的json中任意片段长度的字符串,前端需要每次都能解析出来,我的理解是每次都自动拼接对应的后续缺失的},],'等。比如收到第一个片段时,自动拼接上},此时整体变成{}就可以直接使用JSON.parse解析而不会报错,到第二个片段时,应该拼接后变成{ table: [] },以此类推,如果某个片段返回了对应}或者]则需要移除前面手动拼接的}]

有没有类似的专门处理以上需求的算法,或者npm包呢。

共有3个答案

段曦
2023-05-10

你可以JSONStream这个库:https://github.com/dominictarr/JSONStream
先安装:

npm install JSONStream

再用JSONStream.parse()方法来解析数据流:

const JSONStream = require('JSONStream');
const request = require('request');

const url = 'http://your-server.com/streaming-json-api';

// 用 request 库获取 JSON 数据流
request(url)
  .pipe(JSONStream.parse('table.*'))
  .on('data', (data) => {
    // 处理解析到的 JSON 片段
    console.log('Parsed JSON piece:', data);
  });
邵阳辉
2023-05-10

可以看看这个 https://github.com/creationix/jsonparse。

算法的话,我能想到的就是 Stack,LeetCode 有一道题叫 Valid Parentheses 就是说这个的,只不过这个放在 json string 上面逻辑更复杂一些。

实际上我觉得看你用到什么程度,如果是大概代码能“跑”就行的话,其实不用做到完美拼接那么麻烦,就直接用 JSON.parse 试错迭代就完事儿了。当然为了降低频率,可以简单的进行方括号和花括号的拼接,我随便撸了个简单版本:

const { Readable } = require("node:stream");

const jsonSegmentsRS = Readable.from([
  // 1
  "{",
  // 2
  '"table": [',
  // 3
  '{"name": "js",',
  // 4
  '"age',
  // 5
  '": 20}',
  // 6
  "]",
  // 7
  "}",
]);

const KeyWords = {
  CURLY_BRACE: {
    L: "{",
    R: "}",
  },
  SQUARE_BRACKET: {
    L: "[",
    R: "]",
  },
  // todo: also needs to resolve the special char, eg: comma
};

class StreamMannerJsonParser {
  records = [];
  bufferStack = [];
  pairStack = [];

  parse(segment) {
    const chars = segment.replace("s", "").split("");

    chars.forEach((c) => {
      this.bufferStack.push(c);

      switch (c) {
        case KeyWords.CURLY_BRACE.L:
        case KeyWords.SQUARE_BRACKET.L:
          this.pairStack.push(c);
          break;
        case KeyWords.CURLY_BRACE.R:
          if (this.pairStack.at(-1) === KeyWords.CURLY_BRACE.L)
            this.pairStack.pop();
          break;
        case KeyWords.SQUARE_BRACKET.R:
          if (this.pairStack.at(-1) === KeyWords.SQUARE_BRACKET.L)
            this.pairStack.pop();
          break;
      }
    });

    try {
      // todo: simple bypass the failed parse action
      return JSON.parse(
        this.bufferStack
          .concat(
            [...this.pairStack]
              .reverse()
              .map((c) =>
                c === KeyWords.CURLY_BRACE.L
                  ? KeyWords.CURLY_BRACE.R
                  : KeyWords.SQUARE_BRACKET.R
              )
          )
          .join("")
      );
    } catch (err) {
      console.warn("warn: parse failed, waiting for another chunk");
    }
  }
}

const parser = new StreamMannerJsonParser();

jsonSegmentsRS.on("data", (chunk) => {
  const parsedChunk = parser.parse(chunk);

  typeof parsedChunk !== "undefined" && console.log(parsedChunk);
});

执行结果(改了点你的数据,因为有些地方不是合法的 json 字符串):
image.png

我这里为了图省事儿,就当做 string stream 来处理了,实际上真要实现的话,应该用 object mode,然后封装成 Readable Stream(或双工) 直接和响应请求的 Stream pipe 起来就行了。

方恺
2023-05-10

试试这个叫做clarinet的库
下面的文章是其中一个使用场景
使用clarinet(browser&node.js)解析不合法的json字符串

arinet会解析json字符串,在每个json字符串关键点触发回调,
始一个object,进入一个key,进入一个value,开始一个array,
利用这些回调,拼装出期望的格式
 类似资料:
  • 问题内容: 我正在使用Sencha Touch(ExtJS)从服务器获取JSON消息。我收到的消息是这个: 我的问题是我无法解析此JSON对象,因此我可以使用每个计数器对象。 我正在尝试像这样完成: 我究竟做错了什么 ?谢谢! 问题答案: Javascript具有针对字符串的内置JSON解析,我想这就是您拥有的: 在您的示例中使用此代码将是: 编辑 :for循环的使用中有一个错误(我在初读时就错过

  • 问题内容: 我有一个AJAX调用,返回的是这样的JSON: 在div中,我将得到: 如何遍历此数据并将每个名称放在div中? 问题答案: 假设您的服务器端脚本未设置正确的响应标头,则需要使用参数向jQuery指示这是JSON 。 然后,您可以使用该函数遍历数据: 或使用方法:

  • 主要内容:什么是 JSON,在 JavaScript 中解析 JSON 数据,解析嵌套的 JSON 数据,将数据转换为 JSONJSON 全称为“JavaScript Object Notation”,是当前最流行的一种轻量级的数据交换格式,用来存储和传输数据,通常服务器端与客户端在进行交互时就是使用 JSON 格式的数据。 什么是 JSON JSON 是从 JavaScript 脚本中演变而来的,并且使用 JavaScript 中的语法来描述数据。与 XML 一样,JSON 也是一种基于文本的

  • 问题内容: 我正在使用NewtonsoftJson库来解析json,但我不知道如何使用它。我使用JObject解析了字符串。当我在即时窗口中输出JObject实例的值时,我得到了:- 我应该怎么做才能获得这个工作的价值? 问题答案: 我个人更喜欢将JavaScriptSerializer与.NET环境中的JSON一起使用。默认情况下,它将返回Dictionary结果,但可用于解析到自定义对象(或者

  • information.json 我想解析这个json文件。 其中,我希望解析'items:[{...}]'内容中的内容但是教程没有告诉我如何做到这一点。 我用Java,但Kotlin也可以(Android) GSON会删除标记吗?还是我该把它移除?如果后者呢?

  • 本文向大家介绍JavaScript处理解析JSON数据过程详解,包括了JavaScript处理解析JSON数据过程详解的使用技巧和注意事项,需要的朋友参考一下 JSON (JavaScript Object Notation)一种简单的数据格式,比xml更轻巧。 JSON 是 JavaScript 原生格式,这意味着在 JavaScript 中处理 JSON 数据不需要任何特殊的 API 或工具包