Как анализировать XML из URL с помощью Node
Я использую node-xml2js для анализа XML. У меня возникла проблема с анализом XML из URL. Я использовал этот ответ SO как модель. Но когда я использую код ниже, я получаю null
в качестве результата. Любые мысли о том, что я делаю неправильно?
UPDATE: я обновил URL-адрес для xml на фактическом сайте.
var eyes = require('eyes');
var https = require('https');
var fs = require('fs');
var xml2js = require('xml2js');
var parser = new xml2js.Parser();
parser.addListener('end', function(result) {
eyes.inspect(result);
console.log('Done.');
});
https.get('https://tsdrapi.uspto.gov/ts/cd/casestatus/sn78787878/info.xml', function(result) {
result.on('data', function (data) {
parser.parseString(data);
});
}).on('error', function(e) {
console.log('Got error: ' + e.message);
});
Ответы
Ответ 1
Я не вижу xml2js, способного анализировать xml своими кусками, поэтому нам нужно буферировать весь HTTP-ответ. Для этого я использовал глобальное значение здесь, но лучше использовать что-то вроде concat-stream
(я опубликую это позже).
Я пробовал этот, и он работает для меня:
var eyes = require('eyes');
var https = require('https');
var fs = require('fs');
var xml2js = require('xml2js');
var parser = new xml2js.Parser();
parser.on('error', function(err) { console.log('Parser error', err); });
var data = '';
https.get('https://tsdrapi.uspto.gov/ts/cd/casestatus/sn78787878/info.xml', function(res) {
if (res.statusCode >= 200 && res.statusCode < 400) {
res.on('data', function(data_) { data += data_.toString(); });
res.on('end', function() {
console.log('data', data);
parser.parseString(data, function(err, result) {
console.log('FINISHED', err, result);
});
});
}
});
Только когда ответ завершает отправку, мы анализируем XML. xml2js
использует sax
, который, похоже, поддерживает потоковое вещание, но не уверен, что xml2js
использует его.
Я создал небольшой пример, в котором используется разбор фрагментов по цепочке (аналогично вашему примеру), но он не дает ошибки при анализе, потому что в неактивном xml-блоке появляется - вот почему нам нужно буферировать весь ответ.
Если ваш xml очень большой, попробуйте разные парсеры, такие как sax
, у которых есть поддержка потока.
Вы также можете добавить обработчик error
в parser
, чтобы иметь возможность печатать ошибки, если он встречает их.
Конкатентный поток
С конкатентным потоком вы можете более элегантно конкатрировать все вызовы .on('data'...)
:
var https = require('https');
var xml2js = require('xml2js');
var parser = new xml2js.Parser();
var concat = require('concat-stream');
parser.on('error', function(err) { console.log('Parser error', err); });
https.get('https://tsdrapi.uspto.gov/ts/cd/casestatus/sn78787878/info.xml', function(resp) {
resp.on('error', function(err) {
console.log('Error while reading', err);
});
resp.pipe(concat(function(buffer) {
var str = buffer.toString();
parser.parseString(str, function(err, result) {
console.log('Finished parsing:', err, result);
});
}));
});
Вы можете использовать sax
, чтобы иметь возможность не буферизовать весь файл (в случае больших файлов xml), но он является более низким уровнем, однако его соединение с потоком очень похоже.
Ответ 2
По вашему вопросу решение должно быть примерно таким.
Оба параметра работают как ожидалось и дают действительный json-объект xml.
Вы можете настроить как разбирать xml, как описано в read.me из xml2js
Native
var eyes = require('eyes'),
https = require('https'),
fs = require('fs'),
xml2js = require('xml2js'),
parser = new xml2js.Parser();
https.get('https://tsdrapi.uspto.gov/ts/cd/casestatus/sn78787878/info.xml', function(res) {
var response_data = '';
res.setEncoding('utf8');
res.on('data', function(chunk) {
response_data += chunk;
});
res.on('end', function() {
parser.parseString(response_data, function(err, result) {
if (err) {
console.log('Got error: ' + err.message);
} else {
eyes.inspect(result);
console.log('Done.');
}
});
});
res.on('error', function(err) {
console.log('Got error: ' + err.message);
});
});
ASYNC * Без обратного вызова hell
var eyes = require('eyes'),
https = require('https'),
async =require('async'),
xml2js = require('xml2js');
async.waterfall([
function(callback) {
https.get('https://tsdrapi.uspto.gov/ts/cd/casestatus/sn78787878/info.xml', function(res) {
var response_data = '';
res.setEncoding('utf8');
res.on('data', function(chunk) {
response_data += chunk;
});
res.on('end', function() {
callback(null, response_data)
});
res.on('error', function(err) {
callback(err);
});
});
},
function(xml, callback) {
var parser = new xml2js.Parser();
parser.parseString(xml, function(err, result) {
if (err) {
callback(err);
} else {
callback(null, result);
}
});
},
function(json, callback) {
// do something usefull with the json
eyes.inspect(json);
callback();
}
], function(err, result) {
if (err) {
console.log('Got error');
console.log(err);
} else {
console.log('Done.');
}
});
Ответ 3
Используя xml2js
, это очень просто.
var parseString = require('xml2js').parseString;
var xmldata = "XML output from the url";
console.log(xmldata);
parseString(xmldata, function (err, result) {
// Result contains XML data in JSON format
});
Ответ 4
var https = require('https');
var parseString = require('xml2js').parseString;
var xml = '';
function xmlToJson(url, callback) {
var req = https.get(url, function(res) {
var xml = '';
res.on('data', function(chunk) {
xml += chunk;
});
res.on('error', function(e) {
callback(e, null);
});
res.on('timeout', function(e) {
callback(e, null);
});
res.on('end', function() {
parseString(xml, function(err, result) {
callback(null, result);
});
});
});
}
var url = "https://tsdrapi.uspto.gov/ts/cd/casestatus/sn78787878/info.xml"
xmlToJson(url, function(err, data) {
if (err) {
// Handle this however you like
return console.err(err);
}
// Do whatever you want with the data here
// Following just pretty-prints the object
console.log(JSON.stringify(data, null, 2));
});