5

Node のファイルシステムの解析に混乱しています。これが私のコードです:

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)chunks、おそらくバイトサイズ以外に基づいて、意味のあるチャンクで出力されていないようです。1 つの「チャンク」の出力は次のとおりです。

<?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>

<product>このチャンクには、内部に XML からの非常に多くのエントリが含まれています。チャンクはエントリの途中で終了し<product>、次のチャンクは中断したところから始まります。

主な質問は、で始まり、で終わるチャンクを出力するにはどうすればよいですか?createReadStream<product</product>

編集: 適切な出力を得るために、最初から最後までの XML は<product>次のようになります。

<?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" name="Teva 'Psyclone' Print Sandal (Baby, Walker &amp; Toddler) Camo/ Dark Olive 6 M" sku_number="52863929" manufacturer_name="Teva" part_number="1001701">
    <category>
      <primary>Toddler Unisex</primary>
      <secondary>Shoes~~Sandals/Slides</secondary>
    </category>
    <URL>
      <product>http://click.linksynergy.com/link?id=LUyP0GcLCGc&amp;offerid=276223.52863929&amp;type=15&amp;murl=http%3A%2F%2Fshop.nordstrom.com%2FS%2F3297406%3Fcm_cat%3Ddatafeed%26cm_pla%3Dshoes%3Asandals%252fslides%26cm_ite%3Dteva_%2527psyclone%2527_print_sandal_%2528baby%252c_walker_%2526_toddler%2529%3A503158_1%26cm_ven%3DLinkshare</product>
      <productImage>http://content.nordstrom.com/imagegallery/store/product/large/0/_6880020.jpg</productImage>
      <buy></buy>
    </URL>
    <description>
      <short>Rugged construction and stylish good looks define a sporty sandal, with the added convenience and security of hook-and-loop closures across the toe and at the instep.Rugged construction and stylish good looks define a sporty sandal, with the added
        convenience and security of h...</short>
      <long>Rugged construction and stylish good looks define a sporty sandal, with the added convenience and security of hook-and-loop closures across the toe and at the instep.Rugged construction and stylish good looks define a sporty sandal, with the added
        convenience and security of hook-and-loop closures across the toe and at the instep. Color(s): camo/ dark olive, daisy blue. Brand: Teva. Style Name: Teva 'Psyclone' Print Sandal (Baby, Walker &amp; Toddler). Style Number: 503158_1.</long>
    </description>
    <discount currency="USD">
      <amount></amount>
      <type>amount</type>
    </discount>
    <price currency="USD">
      <sale begin_date="" end_date="">24.95</sale>
      <retail>24.95</retail>
    </price>
    <brand>Teva</brand>
    <shipping>
      <cost currency="USD">
        <amount>0.00</amount>
        <currency>USD</currency>
      </cost>
      <information></information>
      <availability>Y</availability>
    </shipping>
    <keywords></keywords>
    <upc>737872649135</upc>
    <m1>503158_1.</m1>
    <pixel>http://ad.linksynergy.com/fs-bin/show?id=LUyP0GcLCGc&amp;bids=276223.52863929&amp;type=15&amp;subid=0</pixel>
    <attributeClass class_id="60">
      <Misc></Misc>
      <Product_Type>Shoes</Product_Type>
      <Size>6 M</Size>
      <Material></Material>
      <Color>CAMO/ DARK OLIVE</Color>
      <Gender>Unisex</Gender>
      <Style></Style>
      <Age></Age>
    </attributeClass>
  </product>
4

2 に答える 2

9

問題に取り組むには 2 つの可能性があります。

ダンプハットが述べたように、XML2JS はデータを解析する前に完全な XML コンテンツを必要とします。しかし、データ チャンクをチャンクごとにストリーミングするファイル ストリームがあります。最初の解決策は、このデータ ストリームを大きな Buffer に変換し、それを XML2JS に送信することです。この目的のために、次のように、ファイル ストリームをバッファの配列に変換するstream-toパッケージ( npm i stream-to) を使用できます。次に、 を使用して 1 つのバッファに連結しますBuffer.concat

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 などのストリーミング XML パーサーを使用する必要がありますsax。ただしsax、Javascript オブジェクトは作成しませんが、EventEmitter であり、関連するすべてのイベントを処理してその場でオブジェクトを構築する必要があるため、使用するのが少し難しくなります。

たとえば、XPath 構文の小さなサブセットをサポートするSaXPath ライブラリを使用できます。このライブラリはmatch、XPath パターンに一致するたびにイベントを発行します。次に例を示します。

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)

次に、2 つのオプションがあります。

  1. 一度に 1 つの製品のみに一致する XML があるため、 を使用して一度に 1 つの製品xml2jsを解析できます。
  2. SaXPath は複数のレコーダーをサポートしています。デフォルトのレコーダーは sax イベントをリッスンし、対応する XML を再作成します (これにより、最初のソリューションを使用できました)。しかし、独自のレコーダーを展開して、sax イベントをリッスンし、 JavaScript オブジェクトを飛ばします。
于 2013-12-16T13:56:30.893 に答える
0

xml2js は、完全にロードされた xml 用です。

sax を使用している場合、これはストリーム パーサーです。

// インストール

npm install sax

// このコードはすべての product_id を出力するためのものです

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
于 2013-12-16T04:25:59.727 に答える