Как мне проанализировать файл с 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));

адресация комментариев - сначала некоторая документация:

DOMParse документация

Массив # уменьшить документацию

Функция # вызов документации

Теперь, чтобы объяснить [].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-коллекцию как массив без необходимости в промежуточной переменной

Другие вопросы по тегам