Функции Bash сами по себе не очень хорошо подходят для анализа XML.
Этот известный FAQ по Bash гласит следующее:
Не попытка [извлечь данные из файла XML] с помощью sed , awk , grep и т. Д. (Приводит к нежелательные результаты ).
Рассмотрите возможность использования специального инструмента командной строки XML, такого как XMLStarlet . См. Информацию о загрузке здесь , если у вас еще не установлен XML Starlet.
Решение:
Используя XML Starlet, вы можете запустить следующую команду для выводажелаемые результаты для вашего терминала:
xml ed -N x="http://www.w3.org/2005/Atom" -d '//x:entry[not(child::x:link[@href="https://myhomesite.com"])]' /path/to/file.rss
Примечание: Часть /path/to/file.rss
в конце команды, показанной выше, должна быть заменена реальным путем к фактическому .rss
файл.
Объяснение:
Части вышеупомянутой разбивки команд следующие:
xml
- вызов команды XML Starlet. ed
- редактирование / обновление документа XML. -N x="http://www.w3.org/2005/Atom"
- Параметр -N
связывает пространство имен, то есть http://www.w3.org/2005/Atom
, с префиксом, который мы произвольно назвали x
. -d
-удалите совпадающие узлы. '//x:entry[not(child::x:link[@href="https://myhomesite.com"])]'
Выражение xpath , используемое для поиска / сопоставления соответствующих узлов, как указано в вашем вопросе.
все узлы (/ feed / entry), где ссылка href! = http://myhomesite.com
.
Как вы можете видеть, в выражении XPath мыдобавьте префикс x
к именам узлов элемента, то есть x:entry
и x:link
, чтобы убедиться, что мы обращаемся к элементам в правильном пространстве имен.
/path/to/file.rss
- Путь к исходному файлу .rss
.
Сохранение результирующего XML (RSS)
Для сохранения результирующего XML вы можете:
Добавьте параметр --inplace
к вышеупомянутой команде - это заменит исходный .rss
с желаемым результатом. Например:
xml ed --inplace -N x="http://www.w3.org/2005/Atom" -d '//x:entry[not(child::x:link[@href="https://myhomesite.com"])]' /path/to/file.rss
Или используйте оператор перенаправления (>
) и укажите путь к месту, в котором следует сохранить выходные данные. Например, следующая составная команда сохранит результаты в новом файле:
xml ed -N x="http://www.w3.org/2005/Atom" -d '//x:entry[not(child::x:link[@href="https://myhomesite.com"])]' /path/to/file.rss > /path/to/results.rss
Примечание: /path/to/results.rss
в конце вышеупомянутой составной команды следует заменитьс реальным путем, куда вы хотите сохранить новый файл.
XPath с local-name()
:
Учитывая, что ваш пример исходного XML (RSS)не включает в себя QNames , также возможно использовать функцию XPath local-name()
. Это избавит от необходимости связывать пространство имен, используя опцию XMLStarlet -N
. Например:
xml ed -d '//*[local-name() = "entry" and not(child::*[local-name() = "link"][@href="https://myhomesite.com"])]' /path/to/file.rss
ВАЖНО: Вам может необходимо заменить ведущую часть xml
во всех примерах команд, показанных в этом посте, наxmlstarlet
вместо. Например:
xmlstarlet ed -N x="http://www.w3.org/2005/Atom" -d '//x:entry[not(child::x:link[@href="https://myhomesite.com"])]' /path/to/file.rss.
^^^^^^^^^^
Редактировать:
Учитывая ваш пример XML, также возможно использовать упрощенный синтаксис для пространства имен по умолчанию, которое заключается в использовании_:
вместо x:
. Используя подчеркивание (_
), вам не нужно использовать опцию -N
, чтобы связать пространство имен с префиксом. Обратитесь к разделу 1.3. Более удобное решение в документации XMLStarlet для получения дополнительной информации об этой функции.
Например:
xml ed -d '//_:entry[not(child::_:link[@href="https://myhomesite.com"])]' /path/to/file.rss
Для дальнейшего понимания использования XMLStarlet, когда ваш исходный XML использует пространства имен, я предлагаю также прочитать Пространства имен и пространство имен по умолчанию в документации.
Редактировать 2:
Автор ОП впоследствии написал следующее в комментариях:
Еще один вопрос. Состояние [not(child::_:link[@href="myhomesite.com"])]
строгое. Я хочу начать что-то вроде myhomesite.com
, но URI не важен, т.е. myhomesite.com**anything**
. Это возможно? [sic]
как-то так .. xmlstarlet ed -N x="http://www.w3.org/2005/Atom" -d '//x:entry[not(child::x:link[matches(@href, '^https://myhomesite.com/' )]/@href)]' feed.rs
Рассмотрите возможность использования функции starts-with()
Xpath с любым из ранее приведенных примеров. Например:
Использование опции -N
и starts-with()
:
xml ed -N x="http://www.w3.org/2005/Atom" -d '//x:entry[not(child::x:link[starts-with(@href, "https://myhomesite.com")])]' file.rss
Использование local-name()
и starts-with()
:
xml ed -d '//*[local-name() = "entry" and not(child::*[local-name() = "link"][starts-with(@href, "https://myhomesite.com")])]' file.rss
Использование упрощенного синтаксиса для пространства имен по умолчанию, то есть подчеркивания, и starts-with()
:
xml ed -d '//_:entry[not(child::_:link[starts-with(@href, "https://myhomesite.com")])]' file.rss