Javascript NodeJS解析流,定义块的起点和终点

Javascript NodeJS解析流,定义块的起点和终点,javascript,xml,node.js,node.js-stream,Javascript,Xml,Node.js,Node.js Stream,被节点的文件系统解析弄糊涂了。这是我的密码: var fs = require('fs'), xml2js = require('xml2js'); var parser = new xml2js.Parser(); var stream = fs.createReadStream('xml/bigXML.xml'); stream.setEncoding('utf8'); stream.on('data', function(chunk){ parser.parseS

被节点的文件系统解析弄糊涂了。这是我的密码:

var fs = require('fs'),
    xml2js = require('xml2js');

var parser = new xml2js.Parser();

var stream = fs.createReadStream('xml/bigXML.xml');
stream.setEncoding('utf8');

stream.on('data', function(chunk){ 

    parser.parseString(chunk, function (err, result) {
        console.dir(result);
        console.log('Done');
    });
});


stream.on('end', function(chunk){
    // file have been read over,do something...
    console.log("IT'S OVER")
});
这导致……什么也不会发生。XML2JS/解析器根本没有输出。当我尝试
console.log(chunk)
时,似乎除了字节大小之外,
chunk
没有以任何类型的有意义的chunk输出。一个“块”的输出为:

<?xml version="1.0" encoding="UTF-8"?>
    <merchandiser xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="merchandiser.xsd">
    <header><merchantId>1237</merchantId><merchantName>NORDSTROM.com</merchantName><createdOn>12/13/2013 23:50:57</createdOn></header>
    <product product_id="52863929">// product info</product>
    <product product_id="26537849">// product info</product>
    <product product_id="25535647">// product info</product>

xml2js用于完全加载的xml

在使用sax的情况下,它是一个流解析器:

//安装

npm install sax
//此代码用于打印所有产品标识

var fs = require('fs');
var sax = require('sax');

var saxStream = sax.createStream();

saxStream.onopentag = function (node) {
    if(node.name === 'PRODUCT'){
        console.log(node.attributes.PRODUCT_ID);
    }
};

fs.createReadStream('xml/bigXML.xml').pipe(saxStream);
输出:

52863929
26537849
25535647

你有两种可能来解决你的问题

如damphat所述,XML2JS需要完整的XML内容才能解析数据。但是您有一个文件流,它可以一块一块地流数据。第一种解决方案是将此数据流转换成一个漂亮的大缓冲区,然后将其发送到XML2JS。为此,您可以使用(
npm i stream to
)将文件流转换为一个缓冲区数组,然后我们将使用以下方法将其连接为一个缓冲区:

var fs = require('fs')
var streamTo = require('stream-to')
var xml2js = require('xml2js')

var file = fs.createReadStream('input.xml')

streamTo.array(file, function (err, arr) {
    if (err) return console.log(err.message)

    var content = Buffer.concat(arr)
    var parser = new xml2js.Parser()
    parser.parseString(content, function (err, res) {
        if (err) return console.log(err.message)
        console.log(res.merchandiser.product)
    })
})
这工作得很好,但是因为它需要将完整的文件保存到内存中,所以如果您的输入文件太大,它将无法工作。要处理非常大的文件,需要使用流式XML解析器,例如
sax
。但是,
sax
不创建Javascript对象,而是一个EventEmitter,使用起来有点困难,因为您必须处理所有相关事件来动态构建对象

您可以使用实例,它支持XPath语法的一小部分。该库每次匹配XPath模式时都会发出一个
match
事件。下面是一个例子:

var saxpath = require('saxpath')
var fs = require('fs')
var sax = require('sax')

var saxParser = sax.createStream(true)
var streamer = new saxpath.SaXPath(saxParser, '/merchandiser/product')

streamer.on('match', function(xml) {
    console.log(xml);
});

fs.createReadStream('input.xml').pipe(saxParser)
然后您有两个选项:

  • 由于现在XML一次只匹配一个产品,因此可以使用
    xml2js
    一次解析单个产品
  • SaXPath支持多个记录器:默认记录器侦听sax事件并重新创建相应的XML(这允许我们使用第一个解决方案),但您可以推出自己的记录器,它侦听sax事件并动态创建javascript对象

  • 此操作已结束-请参见编辑以了解
    节点中包含的内容的示例。使用XML2JS(仅使用
    fs
    parseString
    ),我对结果执行
    for
    循环,并将对象转换为JSON,以获取其中的所有信息。在这里使用Sax可能吗?
    onopentag
    似乎只提供了一点细节,而不是
    本身的内容。好帖子。问题是这两种解决方案对我都不起作用。该文件为1.5gb,因此缓冲区解决方案无法工作。我需要创建javascript对象,因此根据您的帖子
    sax
    也不起作用。那么…我能在这里做什么?!我找不到方法让Node加载1.5gb文件,我在尝试时遇到缓冲区错误。好吧,那么缓冲区就不可能了。我编辑了我的答案,使用SaXPath为您提供了几个选项。需要明确的是:sax将起作用。我只是需要您做更多的工作来从sax事件重新创建javascript对象。但它会工作得很好!您编辑的示例运行良好,非常感谢您的详细解释,这个问题在Stack/Google上的其他任何地方都没有很好的答案,所以希望它能对其他人有所帮助。我在这里发布的后续内容可能会对你有所帮助,因为Sax拒绝在数据中包含
    CDATA
    var saxpath = require('saxpath')
    var fs = require('fs')
    var sax = require('sax')
    
    var saxParser = sax.createStream(true)
    var streamer = new saxpath.SaXPath(saxParser, '/merchandiser/product')
    
    streamer.on('match', function(xml) {
        console.log(xml);
    });
    
    fs.createReadStream('input.xml').pipe(saxParser)