Как выполнить XPath на один-вкладыши из раковины?
есть ли там пакет для Ubuntu и / или CentOS, который имеет инструмент командной строки, который может выполнять XPath one-liner, например foo //element@attribute filename.xml
или foo //element@attribute < filename.xml
и возвращать результаты строка за строкой?
я ищу что-то, что позволит мне просто apt-get install foo
или yum install foo
а затем просто работает из коробки, без обертки или другой адаптации необходимо.
вот несколько примеров того, что близко:
Nokogiri. Если я напишу эту обертку я можно вызвать обертку описанным выше способом:
#!/usr/bin/ruby
require 'nokogiri'
Nokogiri::XML(STDIN).xpath(ARGV[0]).each do |row|
puts row
end
XML:: XPath. Будет работать с этой оберткой:
#!/usr/bin/perl
use strict;
use warnings;
use XML::XPath;
my $root = XML::XPath->new(ioref => 'STDIN');
for my $node ($root->find($ARGV[0])->get_nodelist) {
print($node->getData, "n");
}
xpath
из XML::XPath возвращает слишком много шума, -- NODE --
и attribute = "value"
.
xml_grep
из XML:: Twig не может обрабатывать выражения, которые не возвращают элементы, поэтому их нельзя использовать для извлечения значений атрибутов без дальнейшей обработки.
EDIT:
echo cat //element/@attribute | xmllint --shell filename.xml
возвращает шум, подобный xpath
.
xmllint --xpath //element/@attribute filename.xml
возвращает attribute = "value"
.
xmllint --xpath 'string(//element/@attribute)' filename.xml
возвращает то, что я хочу, но только на первый матч.
для другого решения, почти удовлетворяющего вопросу, вот XSLT, который можно использовать для оценки произвольных выражений XPath (требуется Dyn: оценить поддержку в процессоре XSLT):
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
xmlns:dyn="http://exslt.org/dynamic" extension-element-prefixes="dyn">
<xsl:output omit-xml-declaration="yes" indent="no" method="text"/>
<xsl:template match="/">
<xsl:for-each select="dyn:evaluate($pattern)">
<xsl:value-of select="dyn:evaluate($value)"/>
<xsl:value-of select="'
'"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
запустить с xsltproc --stringparam pattern //element/@attribute --stringparam value . arbitrary-xpath.xslt filename.xml
.
13 ответов:
вы должны попробовать эти средства :
xmlstarlet
: можно редактировать, выбирать, преобразовывать... Не установлен по умолчанию, xpath1xmllint
: часто устанавливается по умолчанию сlibxml2
, xpath1 (проверьте мой фантик чтобы новые строки разделяли выводxpath
: устанавливается через модуль perlXML::XPath
, xpath1xml_grep
: устанавливается через модуль perlXML::Twig
, xpath1 (ограниченное использование xpath)xidel
: xpath3saxon-lint
: мой собственный проект, wrapper over @Michael Kay'S Saxon-HE Java library, xpath3
xmllint
входитlibxml2-utils
(может использоваться как интерактивная оболочка с--shell
переключатель)
xmlstarlet
иxmlstarlet
.
xpath
поставляется с модулем perlXML::Xpath
xml_grep
поставляется с модулем perlXML::Twig
xidel
isxidel
saxon-lint
используя SaxonHE 9.6, XPath 3.x (+ретро совместимость)Ex:
xmllint --xpath '//element/@attribute' file.xml xmlstarlet sel -t -v "//element/@attribute" file.xml xpath -q -e '//element/@attribute' file.xml xidel -se '//element/@attribute' file.xml saxon-lint --xpath '//element/@attribute' file.xml
.
один пакет, который, скорее всего, будет установлен в системе уже
python-lxml
. Если да, то это возможно без установки какого-либо дополнительного пакета:python -c "from lxml.etree import parse; from sys import stdin; print '\n'.join(parse(stdin).xpath('//element/@attribute'))"
вы также можете попробовать мой Xidel. Он не находится в пакете в репозитории, но вы можете просто загрузить его с веб-страницы (он не имеет зависимостей).
Он имеет простой синтаксис для выполнения этой задачи:
xidel filename.xml -e '//element/@attribute'
и это один из редких из этих инструментов, который поддерживает XPath 2.
Saxon сделает это не только для XPath 2.0, но и для XQuery 1.0 и (в коммерческой версии) 3.0. Он поставляется не как пакет Linux, а как файл jar. Синтаксис (который вы можете легко обернуть в простой скрипт)
java net.sf.saxon.Query -s:source.xml -qs://element/attribute
в моем поиске для запроса maven pom.xml-файлы, которые я запустил, пересекают этот вопрос. Однако у меня были следующие ограничения:
- должен работать кросс-платформенный.
- должен существовать на всех основных дистрибутивах linux без установки каких-либо дополнительных модулей
- должен обрабатывать сложные xml-файлы, такие как maven pom.xml-файлы
- простой синтаксис
Я пробовал многие из вышеперечисленных без успеха:
- python lxml.etree не является частью стандартного дистрибутива python
- xml.etree - это, но не обрабатывает сложный maven pom.xml файлы ну, не копали достаточно глубоко
- python xml.etree не обрабатывает maven pom.xml файлы по неизвестной причине
- xmllint тоже не работает, ядро часто дампы на ubuntu 12.04 "xmllint: использование libxml версии 20708"
единственное решение, с которым я столкнулся, является стабильным, коротким и работает на многих платформах и то есть зрелым является rexml lib встроенный в ruby:
ruby -r rexml/document -e 'include REXML; p XPath.first(Document.new($stdin), "/project/version/text()")' < pom.xml
что вдохновило меня найти этот был следующие статьи:
вы также можете быть заинтересованы в xsh. Он имеет интерактивный режим, где вы можете делать все, что вам нравится с документом:
open 1.xml ; ls //element/@id ; for //p[@class="first"] echo text() ;
ответ клака отлично, но я думаю, что работает только если ваш источник хорошо сформирован XML, а не обычный HTML.
чтобы сделать то же самое для обычного веб-контента-HTML-документов, которые не обязательно хорошо сформированы XML:
echo "<p>foo<div>bar</div><p>baz" | python -c "from sys import stdin; \ from lxml import html; \ print '\n'.join(html.tostring(node) for node in html.parse(stdin).xpath('//p'))"
и вместо этого использовать html5lib (чтобы убедиться, что вы получаете то же поведение синтаксического анализа, что и веб-браузеры-потому что, как и Парсеры браузера, html5lib соответствует требованиям синтаксического анализа в спецификации HTML).
echo "<p>foo<div>bar</div><p>baz" | python -c "from sys import stdin; \ import html5lib; from lxml import html; \ doc = html5lib.parse(stdin, treebuilder='lxml', namespaceHTMLElements=False); \ print '\n'.join(html.tostring(node) for node in doc.xpath('//p'))
кроме XML:: XSH и XML:: XSH2 есть немного
grep
- как утилиты сосут какApp::xml_grep2
иXML::Twig
(которая включает в себяxml_grep
, а неxml_grep2
). Они могут быть весьма полезны при работе с большими или многочисленными XML-файлами для быстрых oneliners илиMakefile
цели.XML::Twig
особенно приятно работать сperl
скриптовый подход, когда вы хотите немного больше обработки, чем ваш$SHELL
иxmllint
xstlproc
предложение.схема нумерации в именах приложений указывает, что версии " 2 " являются более новыми/более поздними версиями по существу того же инструмента, который может потребовать более поздних версий других модулей (или ).
подобно ответам Майка и клака, вот python one-liner (используя python >= 2.5), чтобы получить версию сборки из pom.xml-файл, который обходит тот факт, что pom.xml-файлы обычно не имеют пространства имен dtd или default, поэтому они не выглядят хорошо сформированными для libxml:
python -c "import xml.etree.ElementTree as ET; \ print(ET.parse(open('pom.xml')).getroot().find('\ {http://maven.apache.org/POM/4.0.0}version').text)"
протестировано на Mac и Linux, и не требует установки каких-либо дополнительных пакетов.
следует отметить, что сам nokogiri поставляется с инструментом командной строки, который должен быть установлен с
gem install nokogiri
.вы можете найти это сообщение в блоге полезно.
я пробовал пару утилит командной строки XPath, и когда я понял, что трачу слишком много времени на поиск и выяснение того, как они работают, поэтому я написал самый простой из возможных парсеров XPath в Python, который сделал то, что мне нужно.
сценарий ниже показывает строковое значение, если выражение XPath вычисляется в строку, или показывает весь подузел XML, если результатом является узел:
#!/usr/bin/env python import sys from lxml import etree tree = etree.parse(sys.argv[1]) xpath = sys.argv[2] for e in tree.xpath(xpath): if isinstance(e, str): print(e) else: print((e.text and e.text.strip()) or etree.tostring(e))
он использует
lxml
- быстрый синтаксический анализатор XML, написанный на C, который не входит в стандартной библиотеке python. Установите его с помощьюpip install lxml
. В Linux / OSX может потребоваться префикс сsudo
.использование:
python xmlcat.py file.xml "//mynode"
lxml также может принимать URL в качестве входных данных:
python xmlcat.py http://example.com/file.xml "//mynode"
извлеките атрибут url под узлом вложения, т. е.
<enclosure url="http:...""..>)
:python xmlcat.py xmlcat.py file.xml "//enclosure/@url"
Xpath в Google Chrome
как несвязанная сторона примечание: если случайно вы хотите запустить выражение XPath против разметки веб-страницы, то вы можете это сделать прямо из Chrome devtools: щелкните правой кнопкой мыши страницу в Chrome > выберите проверить, а затем в консоли DevTools вставьте выражение XPath как
$x("//spam/eggs")
.получить всех авторов на этой странице:
$x("//*[@class='user-details']/a/text()")
поскольку этот проект, по-видимому, довольно новый, проверьте https://github.com/jeffbr13/xq, кажется, обертка вокруг
lxml
, но это все, что вам действительно нужно (и опубликованные специальные решения с использованием lxml в других ответах)
вот один случай использования xmlstarlet для извлечения данных из вложенных элементов elem1, elem2 в одну строку текста из этого типа XML (также показано, как обрабатывать пространства имен):
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> <mydoctype xmlns="http://xml-namespace-uri" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xml-namespace-uri http://xsd-uri" format="20171221A" date="2018-05-15"> <elem1 time="0.586" length="10.586"> <elem2 value="cue-in" type="outro" /> </elem1> </mydoctype>
выход будет
0.586 10.586 cue-in outro
в этом фрагменте-m соответствует вложенному элементу elem2, - V выводит значения атрибутов (с выражениями и относительной адресацией), - o буквальный текст, - n добавляет новую строку:
xml sel -N ns="http://xml-namespace-uri" -t -m '//ns:elem1/ns:elem2' \ -v ../@time -o " " -v '../@time + ../@length' -o " " -v @value -o " " -v @type -n file.xml
если от elem1 требуется больше атрибутов, можно сделать это следующим образом (также показывает функцию concat ()):
xml sel -N ns="http://xml-namespace-uri" -t -m '//ns:elem1/ns:elem2/..' \ -v 'concat(@time, " ", @time + @length, " ", ns:elem2/@value, " ", ns:elem2/@type)' -n file.xml
обратите внимание на (ИМО ненужное) осложнение с пространствами имен (ns, объявленное с-N), которое заставило меня почти отказаться от xpath и xmlstarlet и написать быстрый специальный конвертер.