Node JS:从树 json 制作平面 json

2024-01-03

我正在编写一个 node.js 脚本来组合目录中的所有 json 文件并将结果存储为新的 json 文件。我尝试在很大程度上完成这项工作,但它有一些缺陷。

A.json

[
  {
    "id": "addEmoticon1",
    "description": "Message to greet the user.",
    "defaultMessage": "Hello, {name}!"
  },
  {
    "id": "addPhoto1",
    "description": "How are youu.",
    "defaultMessage": "How are you??"
  }
]

B.json

[
  {
    "id": "close1",
    "description": "Close it.",
    "defaultMessage": "Close!"
  }
]

我最终需要的是:

result.json

{
  "addEmoticon1": "Hello, {name}!",
  "addPhoto1": "How are you??",
  "close1": "Close!"
}

我写了一个node.js脚本:

var fs = require('fs');

function readFiles(dirname, onFileContent, onError) {
  fs.readdir(dirname, function(err, filenames) {
    if (err) {
      onError(err);
      return;
    }
    filenames.forEach(function(filename) {
      fs.readFile(dirname + filename, 'utf-8', function(err, content) {
        if (err) {
          onError(err);
          return;
        }
        onFileContent(filename, content);
      });
    });
  });
}

var data = {};
readFiles('C:/node/test/', function(filename, content) {
  data[filename] = content;
  var lines = content.split('\n');
  lines.forEach(function(line) {
    var parts = line.split('"');
    if (parts[1] == 'id') {
      fs.appendFile('result.json', parts[3]+': ', function (err) {});
    }
    if (parts[1] == 'defaultMessage') {
      fs.appendFile('result.json', parts[3]+',\n', function (err) {});
    }
  });
}, function(err) {
  throw err;
});

它提取“id”和“defaultMessage”,但无法正确附加。

我得到什么:

result.json

addEmoticon1: addPhoto1: Hello, {name}!,
close1: How are you??,
Close!,

每次运行脚本时,此输出都会不同。

  • 目标 1:将项目用双引号引起来,

  • 目标 2:在顶部和末尾添加花括号

  • 目标 3:最后一个元素末尾没有逗号

  • 目标 4:每次运行脚本时输出相同


我将从完成的解决方案开始......

这个答案的最后有一个很大的解释。让我们先尝试着想一下大局。

readdirp('.')
  .fmap(filter(match(/\.json$/)))
  .fmap(map(readfilep))
  .fmap(map(fmap(JSON.parse)))
  .fmap(concatp)
  .fmap(flatten)
  .fmap(reduce(createMap)({}))
  .fmap(data=> JSON.stringify(data, null, '\t'))
  .fmap(writefilep(resolve(__dirname, 'result.json')))
  .then(filename=> console.log('wrote results to %s', filename), err=>console.error(err));

控制台输出

wrote results to /path/to/result.json

result.json(我添加了一个c.json一些数据表明这适用于 2 个以上的文件)

{
    "addEmoticon1": "Hello, {name}!",
    "addPhoto1": "How are you??",
    "close1": "Close!",
    "somethingelse": "Something!"
}

执行

I made Promise基于接口readdir and readFile and writeFile

import {readdir, readFile, writeFile} from 'fs';

const readdirp = dir=>
  new Promise((pass,fail)=>
    readdir(dir, (err, filenames) =>
      err ? fail(err) : pass(mapResolve (dir) (filenames))));

const readfilep = path=>
  new Promise((pass,fail)=>
    readFile(path, 'utf8', (err,data)=>
      err ? fail(err) : pass(data)));

const writefilep = path=> data=>
  new Promise((pass,fail)=>
    writeFile(path, data, err=>
      err ? fail(err) : pass(path)));

为了将函数映射到我们的 Promise,我们需要一个fmap公用事业。注意我们如何注意冒泡错误。

Promise.prototype.fmap = function fmap(f) {
  return new Promise((pass,fail) =>
    this.then(x=> pass(f(x)), fail));
};

这是其余的实用程序

const fmap = f=> x=> x.fmap(f);
const mapResolve = dir=> map(x=>resolve(dir,x));
const map = f=> xs=> xs.map(x=> f(x));
const filter = f=> xs=> xs.filter(x=> f(x));
const match = re=> s=> re.test(s);
const concatp = xs=> Promise.all(xs);
const reduce = f=> y=> xs=> xs.reduce((y,x)=> f(y)(x), y);
const flatten = reduce(y=> x=> y.concat(Array.isArray(x) ? flatten (x) : x)) ([]);

最后,一个可以完成您工作的自定义函数

const createMap = map=> ({id, defaultMessage})=>
  Object.assign(map, {[id]: defaultMessage});

这是c.json

[
  {
    "id": "somethingelse",
    "description": "something",
    "defaultMessage": "Something!"
  }
]

“为什么有这么多小功能?”

不管你怎么想,你都有一个很大的问题。大问题是通过组合几个小解决方案来解决的。该代码最突出的优点是每个函数都有非常独特的目的,并且对于相同的输入它总是会产生相同的结果。这意味着每个函数都可以在程序中的其他地方使用。另一个优点是较小的函数更容易阅读、推理和调试。

将所有这些与此处给出的其他答案进行比较; @BlazeSahlen 特别是。这有 60 多行代码,基本上只能用于解决这一特定问题。它甚至不会过滤掉非 JSON 文件。因此,下次您需要创建一系列读/写文件的操作时,您每次都必须重写这 60 行中的大部分。由于样板文件耗尽,它会产生大量重复的代码和难以发现的错误。以及所有手动错误处理...哇,现在就杀了我吧。他/她认为回调地狱很糟糕?哈哈,他/她刚刚又自己创造了另一个地狱圈。


所有代码放在一起...

函数(大致)按其使用顺序出现

import {readdir, readFile, writeFile} from 'fs';
import {resolve} from 'path';

// logp: Promise<Value> -> Void
const logp = p=> p.then(x=> console.log(x), x=> console.err(x));

// fmap : Promise<a> -> (a->b) -> Promise<b>
Promise.prototype.fmap = function fmap(f) {
  return new Promise((pass,fail) =>
    this.then(x=> pass(f(x)), fail));
};

// fmap : (a->b) -> F<a> -> F<b>
const fmap = f=> x=> x.fmap(f);

// readdirp : String -> Promise<Array<String>>
const readdirp = dir=>
  new Promise((pass,fail)=>
    readdir(dir, (err, filenames) =>
      err ? fail(err) : pass(mapResolve (dir) (filenames))));

// mapResolve : String -> Array<String> -> Array<String>
const mapResolve = dir=> map(x=>resolve(dir,x));

// map : (a->b) -> Array<a> -> Array<b>
const map = f=> xs=> xs.map(x=> f(x));

// filter : (Value -> Boolean) -> Array<Value> -> Array<Value>
const filter = f=> xs=> xs.filter(x=> f(x));

// match : RegExp -> String -> Boolean
const match = re=> s=> re.test(s);

// readfilep : String -> Promise<String>
const readfilep = path=>
  new Promise((pass,fail)=>
    readFile(path, 'utf8', (err,data)=>
      err ? fail(err) : pass(data)));

// concatp : Array<Promise<Value>> -> Array<Value>
const concatp = xs=> Promise.all(xs);

// reduce : (b->a->b) -> b -> Array<a> -> b
const reduce = f=> y=> xs=> xs.reduce((y,x)=> f(y)(x), y);

// flatten : Array<Array<Value>> -> Array<Value>
const flatten = reduce(y=> x=> y.concat(Array.isArray(x) ? flatten (x) : x)) ([]);

// writefilep : String -> Value -> Promise<String>
const writefilep = path=> data=>
  new Promise((pass,fail)=>
    writeFile(path, data, err=>
      err ? fail(err) : pass(path)));

// -----------------------------------------------------------------------------

// createMap : Object -> Object -> Object
const createMap = map=> ({id, defaultMessage})=>
  Object.assign(map, {[id]: defaultMessage});

// do it !
readdirp('.')
  .fmap(filter(match(/\.json$/)))
  .fmap(map(readfilep))
  .fmap(map(fmap(JSON.parse)))
  .fmap(concatp)
  .fmap(flatten)
  .fmap(reduce(createMap)({}))
  .fmap(data=> JSON.stringify(data, null, '\t'))
  .fmap(writefilep(resolve(__dirname, 'result.json')))
  .then(filename=> console.log('wrote results to %s', filename), err=>console.error(err));

仍然遇到困难吗?

一开始要了解这些东西是如何工作的并不容易。这是一个特别奇怪的问题,因为数据嵌套得非常快。值得庆幸的是,这并不意味着我们的代码必须是一大堆嵌套混乱才能解决问题!请注意,即使我们正在处理诸如 JSON Promises 数组的 Promise 之类的事情,代码仍然保持良好且平坦的状态...

// Here we are reading directory '.'
// We will get a Promise<Array<String>>
// Let's say the files are 'a.json', 'b.json', 'c.json', and 'run.js'
// Promise will look like this:
// Promise<['a.json', 'b.json', 'c.json', 'run.js']>
readdirp('.')

  // Now we're going to strip out any non-JSON files
  // Promise<['a.json', 'b.json', 'c.json']>
  .fmap(filter(match(/\.json$/)))

  // call `readfilep` on each of the files
  // We will get <Promise<Array<Promise<JSON>>>>
  // Don't freak out, it's not that bad!
  // Promise<[Promise<JSON>, Promise<JSON>. Promise<JSON>]>
  .fmap(map(readfilep))

  // for each file's Promise, we want to parse the data as JSON
  // JSON.parse returns an object, so the structure will be the same
  // except JSON will be an object!
  // Promise<[Promise<Object>, Promise<Object>, Promise<Object>]>
  .fmap(map(fmap(JSON.parse)))

  // Now we can start collapsing some of the structure
  // `concatp` will convert Array<Promise<Value>> to Array<Value>
  // We will get
  // Promise<[Object, Object, Object]>
  // Remember, we have 3 Objects; one for each parsed JSON file
  .fmap(concatp)

  // Your particular JSON structures are Arrays, which are also Objects
  // so that means `concatp` will actually return Promise<[Array, Array, Array]
  // but we'd like to flatten that
  // that way each parsed JSON file gets mushed into a single data set
  // after flatten, we will have
  // Promise<Array<Object>>
  .fmap(flatten)

  // Here's where it all comes together
  // now that we have a single Promise of an Array containing all of your objects ...
  // We can simply reduce the array and create the mapping of key:values that you wish
  // `createMap` is custom tailored for the mapping you need
  // we initialize the `reduce` with an empty object, {}
  // after it runs, we will have Promise<Object>
  // where Object is your result
  .fmap(reduce(createMap)({}))

  // It's all downhill from here
  // We currently have Promise<Object>
  // but before we write that to a file, we need to convert it to JSON
  // JSON.stringify(data, null, '\t') will pretty print the JSON using tab to indent
  // After this, we will have Promise<JSON>
  .fmap(data=> JSON.stringify(data, null, '\t'))

  // Now that we have a JSON, we can easily write this to a file
  // We'll use `writefilep` to write the result to `result.json` in the current working directory
  // I wrote `writefilep` to pass the filename on success
  // so when this finishes, we will have
  // Promise<Path>
  // You could have it return Promise<Void> like writeFile sends void to the callback. up to you.
  .fmap(writefilep(resolve(__dirname, 'result.json')))

  // the grand finale
  // alert the user that everything is done (or if an error occurred)
  // Remember `.then` is like a fork in the road:
  // the code will go to the left function on success, and the right on failure
  // Here, we're using a generic function to say we wrote the file out
  // If a failure happens, we write that to console.error
  .then(filename=> console.log('wrote results to %s', filename), err=>console.error(err));

全做完了 !

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Node JS:从树 json 制作平面 json 的相关文章

  • powershell 和 cmd 之间的文件大小不同[重复]

    这个问题在这里已经有答案了 我正在使用一点processconf js工具来构建configuration json来自多个文件 json files 这是我正在使用的命令 node processconf js file1 json fi
  • 使用 Perl 循环 JSON [重复]

    这个问题在这里已经有答案了 我是 Perl 的新手 想要循环这个 JSON 数据并将其打印到屏幕上 我怎样才能做到这一点 arr Year 2012 Quarter Q3 DataType Other 3 Environment STEVE
  • json支持阿拉伯字符吗?

    我想问一个简单的问题 json 是否支持阿拉伯字符 我的意思是当我搜索类似以下内容时 values database gt get by name echo json encode array returnedFromValue gt va
  • 通过 cypress JS 进行分页测试

    I need to test that when I select some model car as a result I have only that model in all pages So basically I do pagin
  • cron 任务是否会阻塞主进程或者nodejs 会创建一个worker 来执行cron 任务

    我在用节点 cron https github com ncb000gt node cron每分钟执行一些繁重的任务 更新数据库 这个任务是使用主进程来工作还是nodejs会创建一些工作人员来完成这些任务 var CronJob requi
  • 节点 mongodb:错误:由于 parseError 连接已关闭

    使用本机 mongodb npm 包 我收到 Error connection closed due to parseError 进行非常基本的查询时 collections myCollection findOne id someID f
  • .NET7 Web API 中的 JSON 多态序列化

    NET7 包括许多改进System Text Json序列化器 其中之一是使用新的类型的多态序列化 JsonPolymorphic 属性 我正在尝试在我的 Asp Net Web API 中使用它 但是尽管模型已正确设置 但它似乎并未序列化
  • Node 应用程序中的 process.env 未定义

    运行我的 Node 应用程序时node server js process env回报undefined 所以我无法访问任何环境变量 当我尝试将我的应用程序部署到Duostack http www duostack com Calling
  • 不破坏“$ref”引用的 JSON 树修改

    问题与 JSON 相关 它是序列化的结果保留引用处理 set to 保留ReferencesHandling Objects 我正在寻找巧妙的方法来修改 JSON 树的分支 特别是删除或替换分支 以便引用处理不会被破坏 考虑以下 JSON
  • Google 分析“获取配置文件”不允许我选择我的帐户

    我已经根据最新的 v4 文档完成了一个有效的谷歌分析集成 我们需要去哪里获取配置文件 from 但面临以下问题 我的谷歌分析帐户上的两个不同的应用程序有两个不同的跟踪ID 对于第一个应用程序 我得到了谷歌服务 json我将文件放置在根目录中
  • req.body 为空 Express js

    我花了几个小时试图找出为什么 req body 是空的 我在 stackoverflow 上到处查看并尝试了所有方法 但没有运气 Express js POST req body 空 https stackoverflow com ques
  • 我应该在 VS Code 中为“json.maxItemsCompulated”设置什么?

    默认状态为 5000 个符号 这取决于机器的性能还是其他什么 从 VS Code 设置 JSON 计算的最大项目数 计算的轮廓符号和折叠区域的最大数量 由于性能原因而受到限制 这与编辑器中的 GUI 按钮相关 您可以使用它来折叠 JSON
  • Delphi - 在修复 VCL 错误时,单元 x 是用不同版本的 x 编译的

    我正在使用 Delphi XE6 并在我的项目中使用 Datasnap 和 JSON 我想纠正 VCL 单元 System JSON pas 在 TJSONString ToString 函数中 中的一个错误 它应该转义反斜杠字符和引号 为
  • 如何在node.js解析查询中设置dns服务器?

    我正在尝试设置 Google DNS 服务器8 8 8 8在 Node js 中解析查询 这样做的正确方法是什么 在命令行中通常我们可以执行以下操作 nslookup stackoverflow com 8 8 8 8 Server 8 8
  • 调试firebase云函数

    如何使用 Visual Studio 代码进行调试firebase 数据库 trigger功能 我尝试了模拟器 但是当我调用它时出现错误 functions debug myMethod C functions functions gt f
  • 在 Ruby/Sinatra 中解码 Facebook 的签名请求

    由于 Facebook 不赞成使用新的 FBML 我正在寻找一种新方法来创建 显示 选项卡 向粉丝显示一个版本 向非粉丝显示另一个版本的页面选项卡 Facebook 已将数据添加到signed request 中 当用户在应用程序中选择您的
  • Nodejs:带有 URL 列表的异步请求

    我正在研究爬虫 我有一个需要请求的 URL 列表 如果我不将其设置为异步 则会同时有数百个请求 我担心它会爆炸我的带宽或产生对目标网站的大量网络访问 我应该怎么办 这是我正在做的事情 urlList forEach url index gt
  • JQuery - 使用 JSON 的属性创建输入

    我正在尝试使用 JSON 设置的 id 和 value 属性创建一个输入 我有一个获取 JSON 的 ajax 调用 返回的数据很好 对于 JSON 中的每个对象 我想创建一个带有 ID 和 JSON 值的按钮 阿贾克斯调用 ajax ty
  • 无法读取未定义的属性“isLoggedIn”

    此代码用于添加产品 然后添加到购物车和订单 并在后端使用 mongodb 创建 pdf 实际上 session isLoggedIn 是在 auth js 中定义的 检查该代码 但仍在 app js 中它给出了此错误 应用程序 JS代码 c
  • Json 对象 - 获取键和值

    我是 JSON 的新手 所以 如果这是一个非常基本的疑问 请不要责骂我 我有一个 JSON 对象引用 我想获取 Key 对象只有一个键值对 我如何在 Java 中获得它 您可以使用jsonObject keys 获取所有钥匙 然后您可以迭代

随机推荐