Как извлечь HTML-тег по идентификатору?

Как я могу извлечь HTML-контент на странице по идентификатору?

Я пытался исследовать решения sed/grep в течение часа. Ни один не работал. Затем я сдался и изучил парсеры HTML/XML. html-xml-utils может получить элемент только по классу, а не по идентификатору, что делает его совершенно бесполезным. Я проконсультировался с руководством, и кажется, что нет никакого способа получить id.

xmlstarlet казался более многообещающим, но он скулит, когда я пытаюсь передать ему HTML-файлы, а не XML-файлы. Следующее выдает не менее 100 ошибок:

cat /home/com/interlinked/blog.html | tail -n +2 | xmlstarlet sel -T -t -m '/div/article[@id = "post33"]' -v '.' -n

Я использовал здесь кошку, потому что не хочу изменять фактический файл. Я использовал tail, чтобы вырезать объявление DOCTYPE, которое раньше вызывало проблемы: Extra content at the end of the document

Контент на странице хорошо отформатирован и составлен. Контент выглядит так:

<article id = "post44">
    ... more HTML tags and content here...
</article>

Я хотел бы иметь возможность извлекать все между конкретными тегами статьи здесь по идентификатору (например, если я передам ему «44», он вернет содержимое post44, если я передам его 34, он вернет содержимое post34).

Что отличает это от других вопросов, так это то, что мне нет нужен только контент, я хочу фактический HTML между тегами статьи. Мне не нужны сами теги статьи, хотя их удаление, вероятно, тривиально.

Есть ли способ сделать это с помощью встроенных инструментов Unix, xmlstarlet или html-xml-utils? Я также попробовал следующий sed, который также не сработал:

article=`patt=$(printf 'article id = "post%d"' $1); sed -n '/<$patt>/,/</article>/{ /article>/d; p }' $file`

Здесь я передаю путь к файлу как $file, а $1 — это идентификатор сообщения в блоге (44 или 34 или что-то еще). Причина двух операторов в одном заключается в том, что $1 не оценивается в операторе sed иначе из-за одинарных кавычек. Это помогает разрешать переменную в связанной команде grep, но не в этой команде sed.

Полная структура HTML:

<!doctype html>
<html lang = "en">
<head>
    <title>Page</title>
</head>
<body>
    <header>
        <nav>
            <div id = "sitelogo">
                <a href = "/"><img src = "/img/logo/logo.png" alt = "InterLinked"></img></a>
            </div>
            <ul>
                <p>Menu</p>
            </ul>
        </nav>
        <hr>
    </header>
    <div id = "main">
        <h1>Blog</h1>
        <div id = "bloglisting">
            <article id = "post44">
                <p>Content</p>
            </article>
            <article id = "post43">
                </p>Content</p>
            </article>
        </div>
    </div>
</body>
</html>

Кроме того, чтобы уточнить, мне нужно, чтобы это работало на 2 разных страницах. Некоторые сообщения встроены в эту главную страницу, но у более длинных есть собственная страница. Структура похожа, но не совсем та же. Мне нужно решение, которое просто находит идентификатор и не нужно беспокоиться о родительских тегах, если это возможно. Сами теги статьи форматируются одинаково на обоих типах страниц. Например, в более длинном сообщении в блоге с собственной страницей отличие здесь:

<div id = "main">
        <h1>Why Ridesharing Is Evil</h1>
        <div id = "blogpost">
            <article id = "post43">
                <div>

В этом случае div bloglisting становится blogpost. Это действительно единственная большая разница.

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
1 015
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы можете использовать инструменты libxml2 для правильного разбора HTML/XML с правильным пониманием синтаксиса. В вашем случае вы можете использовать xmllint и попросить его проанализировать HTML-файл с флагом --html и предоставить запрос xpath с верхнего уровня, чтобы получить узел по вашему выбору.

Например, чтобы получить содержимое для идентификатора сообщения post43 используйте фильтр, например

xmllint --html --xpath \
   "//html/body/div[@id='main']/div[@id='bloglisting']/article[@id='post43']" html

Если xmllint, скомпилированный на вашем компьютере, не понимает несколько последних (HTML5) тегов, таких как <article> или <nav>, отключите предупреждения, добавив 2>/dev/null в конце команды.

Если вы хотите получить только содержимое внутри <article> и не иметь самих тегов, удалите первую и последнюю строку, передав результат в sed, как показано ниже.

xmllint --html --xpath \
   "//html/body/div[@id='main']/div[@id='bloglisting']/article[@id='post43']" html 2>/dev/null | 
   sed '1d; $d'

Чтобы использовать переменную для пост-идентификатора, определите переменную оболочки и используйте ее в запросе xpath.

postID = "post43"
xmllint --html --xpath \
   "//html/body/div[@id='main']/div[@id='bloglisting']/article[@id='"$postID"']" html 2>/dev/null | 
   sed '1d; $d'

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