Как мне проанализировать файл с XML-подобной структурой, но с самозакрывающимися тегами рядом с контентом (вместо включения контента)
У меня есть файл следующей структуры. Это не XML, но мне нужно как-то сделать из него JSON.
Так что пока я ожидаю, что файл будет выглядеть так:
<chapter>
<line> Some text which I want to grab. </line>
<line> Some more text which I want to grab. </line>
<line> Even more text which I want to grab. </line>
</chapter>
Это на самом деле структурировано так:
<chapter>
<line /> Some text which I want to grab.
<line /> Some more text which I want to grab.
<line /> Even more text which I want to grab.
</chapter>
Таким образом, "строки" каждой главы просто стоят рядом с самозакрывающимися тегами строк. Можете ли вы порекомендовать метод получения этих? Возможно в javascript / nodejs?
1 ответ
Формат действительный XML, так что вы можете использовать обычные методы XML... т.е. DOMParser
разобрать контент
Однако вам просто нужно немного разбираться в разборе строк - вы хотите найти каждую строку и собрать все родственные узлы, которые являются текстовыми узлами (должен быть только один, но код, который я представляю, не делает никаких предположений)
Вы не указали выходную "структуру", но вот один метод, который вы можете использовать для вывода вложенного массива - первый уровень - главы, в каждой главе - массив строк
var xml = `<chapter>
<line /> Some text which I want to grab.
<line /> Some more text which I want to grab.
<line /> Even more text which I want to grab.
</chapter>`
var parser = new DOMParser();
var content = parser.parseFromString(xml, 'application/xml')
var chapters = content.getElementsByTagName('chapter');
var obj = [].reduce.call(chapters, function(result, chapter) {
var lines = chapter.getElementsByTagName('line');
result.push([].reduce.call(lines, function(result, line) {
var text = '';
for(var node = line.nextSibling; node && node.nodeType == 3; node = node.nextSibling) {
text += node.nodeValue;
}
result.push(text);
return result;
}, []))
return result;
}, []);
console.log(JSON.stringify(obj));
адресация комментариев - сначала некоторая документация:
Массив # уменьшить документацию
Теперь, чтобы объяснить [].reduce.call(array, fn)
в этом коде
[].reduce.call
это сокращение для Array.prototype.reduce.call
getElementsByTagName
возвращает HTMLCollection
... который ведет себя как массив, за исключением того, что он не один... есть несколько способов сделать массив из HTMLCollection - самый примитивный:
var array = [];
for(var i = 0; i < collection.length; i++) {
array[i] = collection[i];
}
или же
var array = Array.prototype.slice.call(collection);
или (ES2015+) - недоступно в IE, если вы не заполнили - см. документацию
var array = Array.from(collection);
Однако, используя .call
метод на [].reduce
позволяет первый аргумент (this
аргумент) быть любым итеративным, а не просто массивом, и это так же, как использование array
сверху как array.reduce(fn)
- это способ обрабатывать HTML-коллекцию как массив без необходимости в промежуточной переменной