【问题标题】:How to get xml2js results out of the parser in ES6?如何从 ES6 的解析器中获取 xml2js 结果?
【发布时间】:2018-01-02 03:34:14
【问题描述】:

我正在 Node 中构建一个服务器,它将搜索文件夹以查看是否存在 XML 文件 (glob),如果存在,则将 (fs) 中的文件作为 JSON 对象 (xml2js) 读取并最终存储它在某处的数据库中。我想将解析器的结果输出到另一个变量中,这样我就可以对数据做其他事情了。据我所知,有些东西正在同步运行,但我不知道如何停止它并让我等到它完成才能继续前进。

我将我的函数从 app.js 中分离到其他地方的控制器中:

app.controller.js

const fs = require('fs-extra');
const glob = require('glob');
const xml2js = require('xml2js');

exports.requests = {};

exports.checkFileDrop = async () => {
  console.log('Checking for xml in filedrop...');
  // this is the only place await works...
  await glob('./filedrop/ALLREQUESTS-*.xml', (err, files) => {
    var parser = new xml2js.Parser();
    // this is looking for a specific file now, which I'll address later once I can figure out this issue
    fs.readFile('./filedrop/ALLREQUESTS-20170707.xml', 'utf16le', function (err, data) { 
      if (err) {
        console.log('ERROR: ', err);
      } else {
        parser.parseString(data, (err, result) => {
          if (err) {
            console.log('ERROR: ', err);
          } else {
            console.log('data found');
            exports.requests = JSON.stringify(result.Records.Record);
            // data is outputted here correctly
            console.log(exports.requests);
            // this doesn't even seem to want to save to exports.requests anyways...
          }
        });
      }
    });
  });
}

app.js

const appController = require('./controllers/app.controller');

// check if there is file in filedrop
appController.checkFileDrop();
// prints out an empty object
console.log(appController.requests);
// can't do anything if it doesn't exist yet
appController.saveToDB(appController.requests);

【问题讨论】:

    标签: javascript node.js ecmascript-6 fs xml2js


    【解决方案1】:

    await 将等待 Promise 值解析,否则它只会将它给出的值包装在一个承诺中并立即解决该承诺。在你的例子中,

    await glob('./filedrop/ALLREQUESTS-*.xml', (err, files) => {
    

    glob 的调用不会返回Promise,因此await 基本上是无用的。所以你需要自己创建 Promise。

    exports.checkFileDrop = async () => {
      console.log('Checking for xml in filedrop...');
    
      const files = await new Promise((resolve, reject) => glob('./filedrop/ALLREQUESTS-*.xml', (err, files) => {
        if (err) reject(err);
        else resolve(files);
      });
    
      const parser = new xml2js.Parser();
    
      const data = await new Promise((resolve, reject) => fs.readFile('./filedrop/ALLREQUESTS-20170707.xml', 'utf16le', function (err, data) {
        if (err) reject(err);
        else resolve(data);
      });
    
      const result = await new Promise((resolve, reject) => parser.parseString(data, (err, result) => {
        if (err) reject(err);
        else resolve(result);
      });
    
      console.log('data found');
    
      const requests = JSON.stringify(result.Records.Record);
    
      console.log(requests);
    }
    

    请注意,现在这个函数将拒绝它返回的承诺,而不是强制记录错误。

    您也可以使用助手将其压缩。例如,节点 8 包含 util.promisify 以使这样的代码更易于编写,例如

    const util = require('util');
    
    exports.checkFileDrop = async () => {
      console.log('Checking for xml in filedrop...');
    
      const files = await util.promisify(glob)('./filedrop/ALLREQUESTS-*.xml');
      const parser = new xml2js.Parser();
    
      const data = await util.promisify(fs.readFile)('./filedrop/ALLREQUESTS-20170707.xml', 'utf16le');
    
      const result = await util.promisify(parser.parseString.bind(parser))(data);
    
      console.log('data found');
    
      const requests = JSON.stringify(result.Records.Record);
    
      console.log(requests);
    }
    

    【讨论】:

    • 所以现在我正在为这个函数的所有 3 个部分创建承诺,我如何将 requests 对象放入我的另一个函数中,而不直接传递它?
    • 你是return requests;,然后无论你在哪里使用checkFileDrop,你要么await它的结果,要么做.then的承诺以获得价值。
    • 呃!我只是在尝试这个并且仍在不知不觉中使用我的exports.requests,这仍然给了我一个空对象。相反,现在我只使用了appController.checkFileDrop().then((data) => console.log(data));(用于测试),我得到了我想要的。非常感谢您的帮助!我迷路了,在一个又一个功能中被埋没:)
    【解决方案2】:

    你可以使用异步/等待

    import fs from 'fs';
    import { promisify } from 'util';
    
    const xmlToJson = async filePath => {
      const parser = new xml2js.Parser
      try {
        const data = await fs.promises.readFile(filePath, 'utf8')
        const result = await promisify(parser.parseString)(data);
        const requests = JSON.stringify(result.merchandiser.product);
        return requests
      }
      catch(err) {
        console.log(err)
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2016-06-15
      • 2019-10-24
      • 1970-01-01
      • 1970-01-01
      • 2012-06-21
      • 2019-05-10
      • 1970-01-01
      • 2014-10-21
      相关资源
      最近更新 更多