Grep і Sed еквівалентні для обробки командного рядка XML


147

Під час виконання сценаріїв оболонок, як правило, дані будуть знаходитись у файлах однорядкових записів, таких як csv. Дійсно обробляти ці дані за допомогою grepта sed. Але мені доводиться стикатися з XML часто, тому мені дуже сподобається спосіб скриптування доступу до цих XML-даних за допомогою командного рядка. Які найкращі інструменти?


xml_grep відмінно підходить для змісту, як зазначено в stackoverflow.com/a/2222224/871134
Deleplace

Відповіді:


105

Я знайшов xmlstarlet дуже гарним у подібних речах.

http://xmlstar.sourceforge.net/

Має бути доступним і в більшості дистрибутивів дистрибутива. Вступний посібник тут:

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


1
Думав, я зазначу, що на сайті Sourceforge доступні двійкові файли Windows.
Стів Беннетт

Хоча, наскільки я можу, не підтримує XQuery.
Стів Беннетт

@SteveBennett насправді це не так, але функції, які він додає, крім сирого XPath, досить хороші, щоб зробити його конкурентоспроможним "grep and sed". Якщо ви хочете фантазії, фантазії доброти XQuery ... ну, це більше схоже на еквівалент XML perl або awk. :)
Чарльз Даффі

36

Деякі перспективні інструменти:

  • nokogiri : аналіз HTML / XML DOM в рубіні за допомогою селекторів 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 : інструментарій Laird Breyer, еквівалентний GNU coreutils. Обговорено в цікавому нарисі про те, що повинен містити ідеальний інструментарій.

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

  • xmltk : схоже, не має пакета в debian, ubuntu, fedora чи макпортах, не мав випуску з 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

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.


@ Джозеф Холстен. Так. Це дозволяє злому XML, не продумуючи речі XPath.
Ві.

Приємно! Я зосереджувався на інструментах, які не використовують проміжний формат, але ідея про високоточне, лінійно-орієнтоване представлення xml здається чудовим способом продовжувати використовувати реальні grep і sed. Ви пробували pyxie? Як воно порівнюється? Будь-які інші лінійно-орієнтовані подання? Чи вважаєте ви це кращим, ніж просто замінити xml нові рядки сутністю (& # 10;)? Це дозволить вам принаймні записувати записи в одному рядку. О, а ви могли б відредагувати свою публікацію, щоб включити посилання на проект?
Джозеф Холстен

@Joseph Holsten Ні, я не думаю, що формат 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 р.).
березня 1414

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. Я здивований, що це так важко - lmd-cmd-лінія, як правило, дуже добре, але тут, здається, є дірка. Примітка: Для мене застосовано випадок: 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

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

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


3

XQuery може бути хорошим рішенням. Це (відносно) легко вивчити і є стандартом W3C.

Я б рекомендував XQSharp для процесора командного рядка.


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

3

Я вперше використав xmlstarlet і досі його використовую. Коли запит стає жорстким, мені потрібна підтримка функції xpath2 і xquery XML, я звертаюся до xidel http://www.videlibri.de/xidel.html


1

Греп-еквівалент

Ви можете визначити функцію 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"
}

Сід еквівалентний

Подумайте про використання xq, що дає повну потужність jq "мови програмування". Якщо у вас встановлено python-pip, ви можете встановити xq за допомогою pip install yq , тоді в наведеному нижче прикладі ми замінюємо "Зберігати облікові записи" на "Зберігати акаунти 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

-1

JEdit має плагін під назвою "XQuery", який забезпечує функціональність запитів для XML-документів.

Не зовсім командний рядок, але він працює!


Хоча JEdit, ймовірно, має спосіб пошуку по файлу, але це не робить його конкурентом grep(1).
Джозеф Холстен
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.