Эквивалент Grep и Sed для обработки командной строки XML

147

При выполнении сценариев оболочки, как правило, данные будут в файлах однострочных записей, таких как CSV. Это действительно просто обрабатывать эти данные с помощью grepи sed. Но мне часто приходится иметь дело с XML, поэтому мне бы очень хотелось, чтобы скрипт мог получить доступ к этим XML-данным через командную строку. Каковы лучшие инструменты?

Джозеф Холстен
источник
xml_grep подходит для поиска, как указано в stackoverflow.com/a/2222224/871134
Удаление

Ответы:

105

Я обнаружил, что xmlstarlet довольно хорош в подобных вещах.

http://xmlstar.sourceforge.net/

Также должно быть доступно в большинстве дистрибутивов. Вводное руководство здесь:

http://www.ibm.com/developerworks/library/x-starlet.html

Russ
источник
1
Я подумал, что на сайте Sourceforge есть бинарные файлы для Windows.
Стив Беннетт
Хотя, насколько я могу судить, XQuery не поддерживает.
Стив Беннетт
@SteveBennett действительно этого не делает, но функции, которые он добавляет к сырому XPath, достаточно хороши, чтобы сделать его конкурентоспособным с «grep and sed». Если вы хотите причудливого, причудливого совершенства XQuery ... ну, это больше похоже на XML, эквивалентный perl или awk. :)
Чарльз Даффи
36

Некоторые перспективные инструменты:

  • nokogiri : анализ HTML / XML DOM в ruby ​​с использованием селекторов XPath и CSS

  • hpricot : устарел

  • fxgrep : использует собственный XPath-подобный синтаксис для запроса документов. Написано на SML, поэтому установка может быть затруднена.

  • LT XML : XML инструментарий , полученный из инструментов SGML, в том числе sggrep, sgsort, xmlnormи другие. Использует собственный синтаксис запроса. Документация очень формальная. Написано на C. LT XML 2 заявляет о поддержке XPath, XInclude и других стандартов W3C.

  • xmlgrep2 : простой и мощный поиск с XPath. Написан на Perl с использованием XML :: LibXML и libxml2.

  • XQSharp : поддерживает XQuery, расширение для XPath. Написано для .NET Framework.

  • xml-coreutils : набор инструментов Лейрда Брейера, эквивалентный GNU coreutils. Обсуждается в интересном эссе о том, что идеальный инструментарий должен включать.

  • xmldiff : простой инструмент для сравнения двух XML-файлов.

  • xmltk : похоже, не имеет пакетов в Debian, Ubuntu, Fedora или MacPort, не выпускал с 2007 года и использует непереносимую автоматизацию сборки.

xml-coreutils кажется наиболее документированным и наиболее ориентированным на UNIX.

Джозеф Холстен
источник
1
Не могли бы вы создать скрипт-обертку для программы Ruby и передать массив аргументов в скрипте hpricot? Например, в сценарии оболочки PHP должно работать что-то вроде следующего: <? Php / path / to / hpricot $ argv?>
alastairs
25

К превосходному списку Джозефа Холстена я добавляю скрипт командной строки xpath, который поставляется с библиотекой Perl XML :: XPath. Отличный способ извлечь информацию из файлов XML:

 xpath -q -e '/entry[@xml:lang="fr"]' *xml
bortzmeyer
источник
3
Это установлено по умолчанию в OSX, но без -q -eпараметров. Пример, получить значение атрибута «package» из узла «manifest» в «AndroidManifest.xml»:xpath AndroidManifest.xml 'string(/manifest/@package)' 2> /dev/null
antonj
25

Есть также xml2и 2xmlпара. Это позволит обычным инструментам редактирования строк обрабатывать XML.

Пример. q.xml:

<?xml version="1.0"?>
<foo>
    text
    more text
    <textnode>ddd</textnode><textnode a="bv">dsss</textnode>
    <![CDATA[ asfdasdsa <foo> sdfsdfdsf <bar> ]]>
</foo>

xml2 < q.xml

/foo=
/foo=   text
/foo=   more text
/foo=   
/foo/textnode=ddd
/foo/textnode
/foo/textnode/@a=bv
/foo/textnode=dsss
/foo=
/foo=    asfdasdsa <foo> sdfsdfdsf <bar> 
/foo=

xml2 < q.xml | grep textnode | sed 's!/foo!/bar/baz!' | 2xml

<bar><baz><textnode>ddd</textnode><textnode a="bv">dsss</textnode></baz></bar>

PS Есть также html2/ 2html.

Vi.
источник
@ Джозеф Холстен Да. Это позволяет взламывать XML, не продумывая XPath.
Ви.
Ницца! Я сосредоточился на инструментах, которые не используют промежуточный формат, но идея высокоточного линейно-ориентированного представления xml кажется отличным способом продолжать использовать настоящий grep и sed. Ты пробовал Пикси? Как это сравнить? Любые другие линейно-ориентированные представления? Считаете ли вы это лучше, чем просто заменить xml символами новой строки на сущность (& # 10;)? Это позволит вам размещать записи по крайней мере на одной строке. О, а не могли бы вы отредактировать свой пост, добавив ссылку на проект?
Джозеф Холстен
@ Джозеф Хольстен: Нет, я не думаю, что формат pyxie был бы более полезным, чем формат xml2. xml2 обеспечивает «полный путь» во вложенных XML-элементах, поэтому допускает более линейное сопоставление и замену. Также 2xmlможно легко воссоздать XML из частичного (отфильтрованного) xml2вывода.
Ви.
5
+1 Я не могу высказать это достаточно ... cat foo.xml | xml2 | grep /bar | 2xml- дает вам ту же структуру, что и оригинал, но все элементы были удалены, кроме элементов "бар". Потрясающие.
mogsie
14

Вы можете использовать xmllint:

xmllint --xpath //title books.xml

Должен быть в комплекте с большинством дистрибутивов, а также в комплекте с Cygwin.

$ xmllint --version
xmllint: using libxml version 20900

Видеть:

$ xmllint
Usage : xmllint [options] XMLfiles ...
        Parse the XML files and output the result of the parsing
        --version : display the version of the XML library used
        --debug : dump a debug tree of the in-memory document
        ...
        --schematron schema : do validation against a schematron
        --sax1: use the old SAX1 interfaces for processing
        --sax: do not build a tree but work just at the SAX level
        --oldxml10: use XML-1.0 parsing rules before the 5th edition
        --xpath expr: evaluate the XPath expression, inply --noout
Дейв Джарвис
источник
2
Нет --xpathаргументов для xmllint: manpagez.com/man/1/xmllint
переменная
1
@MiserableVariable: страница справочника неверна. Я только что посмотрел справочную страницу для моей версии: аргумент xpath не указан. Это ошибка документации. Попробуйте запустить программу.
Дейв Джарвис
2
@MiserableVariable --xpath- сравнительно недавнее дополнение, например, не в версиях RHEL 6 xmllint.
Даниэль Бек
2
Чтобы быть более точным, xmllint --xpathбыл введен в libxml2 2.7.7 (в 2010 году).
Марбу
9

Если вы ищете решение для Windows, Powershell имеет встроенную функциональность для чтения и записи XML.

test.xml:

<root>
  <one>I like applesauce</one>
  <two>You sure bet I do!</two>
</root>

Скрипт Powershell:

# load XML file into local variable and cast as XML type.
$doc = [xml](Get-Content ./test.xml)

$doc.root.one                                   #echoes "I like applesauce"
$doc.root.one = "Who doesn't like applesauce?"  #replace inner text of <one> node

# create new node...
$newNode = $doc.CreateElement("three")
$newNode.set_InnerText("And don't you forget it!")

# ...and position it in the hierarchy
$doc.root.AppendChild($newNode)

# write results to disk
$doc.save("./testNew.xml")

testNew.xml:

<root>
  <one>Who likes applesauce?</one>
  <two>You sure bet I do!</two>
  <three>And don't you forget it!</three>
</root>

Источник: /server/26976/update-xml-from-the-command-line-windows

глина
источник
Несколько часов сражался с различными инструментами Linux, прежде чем прибегнуть к Powershell. Я удивлен, что это так сложно - linux cmd-line обычно очень хорош, но здесь, похоже, есть дыра. Примечание: вариант использования для меня был: 1) найти узлы по xpath, 2) удалить, если найден, 3) добавить новые узлы, 4) сохранить файл. Я обновлял кучу конфигов solr. Если кто-нибудь знает простой и надежный способ сделать это, я весь в ушах
Ричард Хауэр
Вау, это действительно на цыпочках до линии приемлемого решения. Но, честно говоря, я бы, наверное, согласился бы, если бы это выглядело как xps $doc .root.one xps $doc 'AppendChild("three")'и xps $doc '.three.set_InnerText("And don't you forget it!")', что явно уступает!
Джозеф Холстен
6

Зависит от того, что именно вы хотите сделать.

XSLT может быть способом пойти, но есть кривая обучения. Попробуйте xsltproc и обратите внимание, что вы можете передать параметры.

Адриан Муат
источник
4

Там же saxon-lintиз командной строки есть возможность использовать XPath 3.0 / XQuery 3.0. (Другие инструменты командной строки используют XPath 1.0).

ПРИМЕРЫ :

HTTP / HTML:

$ saxon-lint --html --xpath 'count(//a)' http://stackoverflow.com/q/91791
328

XML:

$ saxon-lint --xpath '//a[@class="x"]' file.xml
Жиль Квено
источник
4

Д. Богдан поддерживает репозиторий GitHub с открытым исходным кодом, в котором хранится список инструментов командной строки для инструментов структурированного текста, а также раздел для инструментов XML / HTML:

https://github.com/dbohdan/structured-text-tools#xml-html

Devy
источник
3

XQuery может быть хорошим решением. Он (относительно) прост в освоении и является стандартом W3C.

Я бы порекомендовал XQSharp для процессора командной строки.

Оливер Хэллам
источник
1
BaseX также имеет процессор XQuery для командной строки (в дополнение к режиму базы данных) и соответствует новейшим версиям стандарта (достаточно близко следуя развивающемуся проекту XQuery 3.0).
Чарльз Даффи
3

Сначала я использовал xmlstarlet и до сих пор его использую. Когда запрос становится сложным, мне нужна поддержка функций XML xpath2 и xquery, я обращаюсь к xidel http://www.videlibri.de/xidel.html

truthadjustr
источник
1

Grep Эквивалент

Вы можете определить функцию bash, скажем «xp» («xpath»), которая оборачивает некоторый код python3. Чтобы использовать его, вам нужно установить python3 и python-lxml. Преимущества:

  1. соответствие регулярных выражений, которое вам не хватает, например, xmllint.
  2. Использовать в качестве фильтра (в трубе) в командной строке

Это легко и эффективно использовать как это:

xmldoc=$(cat <<EOF
<?xml version="1.0" encoding="utf-8"?>
<job xmlns="http://www.sample.com/">programming</job>
EOF
)
selection='//*[namespace-uri()="http://www.sample.com/" and local-name()="job" and re:test(.,"^pro.*ing$")]/text()'
echo "$xmldoc" | xp "$selection"
# prints programming

xp () выглядит примерно так:

xp()
{ 
local selection="$1";
local xmldoc;
if ! [[ -t 0 ]]; then
    read -rd '' xmldoc;
else
    xmldoc="$2";
fi;
python3 <(printf '%b' "from lxml.html import tostring\nfrom lxml import etree\nfrom sys import stdin\nregexpNS = \"http://exslt.org/regular-expressions\"\ntree = etree.parse(stdin)\nfor e in tree.xpath('""$selection""', namespaces={'re':regexpNS}):\n  if isinstance(e, str):\n    print(e)\n  else:\n    print(tostring(e).decode('UTF-8'))") <<< "$xmldoc"
}

Эквивалент Sed

Подумайте об использовании xq, который дает вам всю мощь jq "языка программирования". Если у вас установлен python-pip, вы можете установить xq с помощью pip install yq , тогда в следующем примере мы заменим «Keep Accounts» на «Keep Accounts 2»:

xmldoc=$(cat <<'EOF'
<resources>
    <string name="app_name">Keep Accounts</string>
    <string name="login">"login"</string>
    <string name="login_password">"password:"</string>
    <string name="login_account_hint">input to login</string>
    <string name="login_password_hint">input your password</string>
    <string name="login_fail">login failed</string>
</resources>
EOF
)
echo "$xmldoc" | xq '.resources.string = ([.resources.string[]|select(."#text" == "Keep Accounts") ."#text" = "Keep Accounts 2"])' -x
Мафусаил-0
источник
-1

JEdit имеет плагин под названием «XQuery», который обеспечивает функциональность запросов для документов XML.

Не совсем командная строка, но она работает!

Бен
источник
Хотя JEdit, вероятно, имеет способ поиска по файлу, он не делает его конкурентом grep(1).
Джозеф Холстен