Собственный набор команд оболочки для извлечения значения узла из XML

Я пытаюсь извлечь значение узла из pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project>
    <parent>
        <groupId>org.me.labs</groupId>
        <artifactId>my-random-project</artifactId>
        <version>1.5.0</version>
    </parent>
    ...
</project>

Мне нужно извлечь артефакт и версию из XML с помощью команды оболочки. У меня есть следующие требования/наблюдения:

  1. Сценарий оболочки будет выполнен в файле сборки сборки, который мы используем на работе, поэтому чем меньше сценарий, тем лучше.
  2. Поскольку он будет использоваться в нескольких системах (обычно RHEL5), я ищу что-то, что может работать изначально на образах по умолчанию.
  3. Подобные теги могут встречаться в другом месте pom, поэтому я не могу просто использовать эти теги.

Я пробовал следующее:

  1. xpath работает на моем Mac, но по умолчанию недоступен на компьютерах RHEL. Аналогично для xmllint --xpath, который, я думаю, доступен только в более поздних версиях xmllint, которого у меня нет и я не могу применить.
  2. xmllint --pattern показался многообещающим, но я не могу получить вывод из xmllint --pattern '//project/parent/version' pom.xml (распечатывает весь XML) или xmllint --stream --pattern '//project/parent/version' pom.xml (без вывода).

Я понимаю, что это распространенный вопрос здесь, на SO, но из-за приведенных выше пунктов я не могу использовать эти ответы. ТИА за помощь.


person Karthik V    schedule 06.06.2013    source источник


Ответы (6)


--format используется только для форматирования (отступа и т. д.) документа. Вы можете сделать это, используя --xpath (проверено в Ubuntu, libxml v20900):

$ xmllint --xpath "//project/parent/version/text()" pom.xml
1.5.0
person Salem    schedule 06.06.2013
comment
Как я уже сказал, моя версия xmllint не поддерживает вариант --xpath. И я не хочу, чтобы он был доступен в моих системах сборки. - person Karthik V; 06.06.2013
comment
Ой, извините, я не заметил. python/libxml2 вариант? - person Salem; 06.06.2013
comment
Также: xpath -q -e "//project/parent/version/text()" pom.xml - person Salem; 06.06.2013
comment
Я стараюсь держаться подальше от сторонних библиотек (libxml2) или каких-либо инструментов (xpath), которые, я не могу гарантировать, будут доступны на компьютере с Linux. взломать как-то. - person Karthik V; 06.06.2013
comment
Что касается вашего ответа, я имел в виду xmllint --pattern. Я внес изменения в пост. - person Karthik V; 06.06.2013

На данный момент мне удалось решить эту проблему с помощью этого довольно неуклюжего скрипта с использованием xmllint --shell.

echo "cat //project/parent/version" | xmllint --shell pom.xml | sed '/^\/ >/d' | sed 's/<[^>]*.//g'

Если узлы XML имеют атрибуты пространства имен, такие как мой pom.xml, все усложняется, в основном извлекая узел по имени:

echo "cat //*[local-name()='project']/*[local-name()='parent']/*[local-name()='version']" | xmllint --shell pom.xml | sed '/^\/ >/d' | sed 's/<[^>]*.//g'

Надеюсь, поможет. Если кто-то может просто эти выражения, я был бы признателен.

person Karthik V    schedule 06.06.2013
comment
В качестве альтернативы вы можете использовать это: echo "cat //*[local-name()='project']/*[local-name()='parent']/*[local-name()='version']/text()" | xmllint --shell pom.xml | sed '/^\/ >/d', поэтому вам нужно только sed удалить материал оболочки xmllint - person Ivaylo Slavov; 06.01.2015
comment
Если у вас достаточно недавний xmllint, то вам не нужны вещи --shell: xmllint --xpath /*[local-name()=="project"]/...' pom.xml. Часть local-name() была тем, чего мне не хватало в моем сценарии. - person Guss; 18.09.2016
comment
Спасибо за ответ echo "cat //*[local-name()='project']/*[local-name()='parent']/*[local-name()='version']" | xmllint --shell pom.xml | sed '/^\/ >/d' | sed 's/<[^>]*.//g' - person Ashwaq; 19.01.2021

Я пришел сюда в поисках хорошего способа получить значение с веб-сайта. Следующий пример может быть полезен тем (в отличие от плаката), у кого есть версия xmllint, поддерживающая --xpath.

Мне нужно было получить самую последнюю стабильную версию .debfile elasticsearch и установить ее. Сопровождающие любезно поместили номер версии в диапазон с классом «версия».

version=`curl -s http://www.elasticsearch.org/download/ |\
 xmllint --html --xpath '//span[@class="version"]/text()'\
 2>/dev/null - `;

Что происходит:

Мы используем опцию curl -s (silent).

curl -s http://www.elasticsearch.org/download/

Мы используем переключатели xmllint --html и --xpath. Аргументы xpath (в одинарных кавычках)

'//span[@class="version"]/text()'

... ищет узел ‹span› с атрибутом класса (@class) «версия» и извлекает текстовое значение (/text()).

Поскольку xmllint является (сюрприз!) линтером, он будет кричать о неизбежном мусоре в вашем html-потоке. Направляем stderr в /dev/null обычным способом:

 2>/dev/null

Наконец, обратите внимание на «-» в конце команды xmllint, которая сообщает xmllint, что поток исходит из стандартного ввода.

person lysdexia    schedule 05.12.2013
comment
Картик. V, это не лучший ответ для вас, но ваш вопрос хорошо назван, поэтому он довольно высоко в поиске Google. Я подумал, что добавлю это для таких людей, как я, которые ищут быстрый ответ и имеют разные инструменты. - person lysdexia; 05.12.2013

Использование функции text() XPath дает вам значение элемента, а не удаление тегов XML:

echo "cat //project/parent/version/text()" | xmllint --shell pom.xml
person jpwilksch    schedule 06.11.2013
comment
Извините, text() не работает и не работает /value/text() Какую версию libxml2 вы используете? у меня 2.7.6 - person Dejan; 11.11.2013

Можешь попробовать

xmllint --xpath "/*[name()='project']/*[name()='groupId']/text()" pom.xml

person Tex    schedule 17.10.2017
comment
Это работало нормально. Я пробовал раньше - xpath неизвестен. Я просто скопировал ваш ответ и модифицировал его в соответствии с моим требованием, и он работает .... !!! - person ArrchanaMohan; 22.09.2019

При использовании POM могут возникать проблемы с пространствами имен, которые мешают xmllint работать должным образом. Эта статья указывает на альтернативное и очень хорошее решение (см. абзац sed).

person Antonio Petricca    schedule 23.04.2018