Получить текст предыдущего заголовка в HTML

#html #node.js #cheerio

#HTML #node.js #приветствие

Вопрос:

У меня есть HTML, который выглядит следующим образом:

 <h1>Title</h1>
<p>Some additional content, can be multiple, various tags</p>
<h2><a id="123"></a>Foo</h2>
<p>Some additional content, can be multiple, various tags</p>
<h3><a id="456"></a>Bar</h3>
 

Теперь, для каждого якоря с идентификатором, я хочу выяснить иерархию заголовков, например, для якоря с id="123" я хотел бы получить что-то вроде [{level: 1, title: "Title"}, {level: 2, title: "Foo"}] , аналогично для якоря с id="456" , я хотел бы получить [{level: 1, title: "Title"}, {level: 2, title: "Foo"}, {level: 3, title: "Bar"}] .

Мой код пока выглядит так:

 const linkModel: IDictionary<ILinkModelEntry> = {};
const $ = cheerio.load(html);
$("a").each((_i, elt) => {
    const anchor = $(elt);
    const id = anchor.attr().id;
    if (id) {
        const parent = anchor.parent();
        const parentTag = parent.prop("tagName");
        let headerHierarchy: any[] = [];
        if (["H1", "H2", "H3", "H4", "H5", "H6"].includes(parentTag)) {
            let level = parseInt(parentTag[1]);
            headerHierarchy = [{level, text: parent.text()}];
            level--;
            while (level > 0) {
                const prevHeader = parent.prev("h"   level);
                const text = prevHeader.text();
                headerHierarchy.unshift({level, text});
                level--;
            }
        }
        linkModel["#"   id] = {originalId: id, count: count  , headerHierarchy};
    }
});
 

Что я делаю не так, поскольку

 const prevHeader = parent.prev("h"   level);
const text = prevHeader.text();
 

всегда возвращает пустую строку (т.е. "" )?

Комментарии:

1. Вы можете сделать это с closest() помощью, но на самом деле вы хотите выполнить итерацию с самого h1 начала. Возврат вверх по дереву — признак того, что вы не очень эффективны.

2. Вы имеете в виду использовать const prevHeader = parent.closest("h" level); вместо .prev ? Похоже, тоже не работает… Ваше предложение состояло бы в том, чтобы перебирать каждый уровень заголовка и находить привязки ниже соответствующего уровня заголовка? Еще не думал о реализации, но я предполагаю, что реализация может стать очень запутанной … (не то, чтобы моя текущая реализация была очень чистой …)

3. В примере ближайший заголовок будет: $(elt).closest('h1,h2,h3,h4,h5,h6').first()

4. Спасибо. Но как я могу получить всю иерархию? Например, для <h2>Foo</h2><h3><a id="1"></a><a id="2"></a><a id="3"></a>Bar</h3> этого всегда будет возвращаться Bar , но нет Foo (использование .closest("h2") on $(elt) не работает)