Tương đương Grep và Sed để xử lý dòng lệnh XML


147

Khi thực hiện kịch bản shell, thông thường dữ liệu sẽ nằm trong các tệp của các bản ghi dòng đơn như csv. Thật đơn giản để xử lý dữ liệu này với grepsed. Nhưng tôi phải thường xuyên xử lý XML, vì vậy tôi thực sự muốn một cách để truy cập tập lệnh vào dữ liệu XML đó thông qua dòng lệnh. Các công cụ tốt nhất là gì?


xml_grep là tốt để grepping, như đã nêu trong stackoverflow.com/a/2222224/871134
Deleplace

Câu trả lời:


105

Tôi đã tìm thấy xmlstarlet khá tốt trong lĩnh vực này.

http://xmlstar.sourceforge.net/

Nên có sẵn trong hầu hết các kho distro. Một hướng dẫn giới thiệu ở đây:

http://www.ibm.com/developerworks/l Library / x-star.html


1
Tôi nghĩ rằng tôi đã chỉ ra rằng có các tệp nhị phân Windows có sẵn trên trang Sourceforge.
Steve Bennett

Không hỗ trợ XQuery, theo như tôi có thể nói.
Steve Bennett

@SteveBennett thực sự là không, nhưng các tính năng mà nó thêm vào trên XPath thô đủ tốt để khiến nó cạnh tranh với "grep và sed". Nếu bạn muốn sự tốt đẹp, lạ mắt của XQuery ... tốt, đó giống như một XML tương đương với perl hoặc awk. :)
Charles Duffy

36

Một số công cụ đầy hứa hẹn:

  • nokogiri : phân tích cú pháp HTML / XML DOM trong ruby ​​bằng cách sử dụng bộ chọn XPath & CSS

  • hpricot : không dùng nữa

  • fxgrep : Sử dụng cú pháp giống XPath của riêng nó để truy vấn các tài liệu. Được viết bằng SML, vì vậy việc cài đặt có thể khó khăn.

  • LT XML : bộ công cụ XML có nguồn gốc từ các công cụ SGML, bao gồm sggrep, sgsort, xmlnormvà những người khác. Sử dụng cú pháp truy vấn riêng của nó. Các tài liệu rất chính thức. Được viết bằng C. LT XML 2 yêu cầu hỗ trợ XPath, XInclude và các tiêu chuẩn W3C khác.

  • xmlgrep2 : tìm kiếm đơn giản và mạnh mẽ với XPath. Được viết bằng Perl bằng XML :: LibXML và libxml2.

  • XQSharp : Hỗ trợ XQuery, phần mở rộng cho XPath. Viết cho .NET Framework.

  • xml-coreutils : Bộ công cụ Laird Breyer tương đương với coreutils GNU. Thảo luận trong một bài luận thú vị về những gì bộ công cụ lý tưởng nên bao gồm.

  • xmldiff : Công cụ đơn giản để so sánh hai tệp xml.

  • xmltk : dường như không có gói trong debian, ubfox, fedora hoặc macports, đã không được phát hành từ năm 2007 và sử dụng tự động hóa bản dựng không di động.

xml-coreutils dường như là tài liệu tốt nhất và định hướng UNIX nhất.


1
Bạn không thể tạo tập lệnh bao bọc cho chương trình Ruby và chuyển mảng của đối số trong tập lệnh sang hpricot? Ví dụ: trong tập lệnh shell PHP, một cái gì đó như sau sẽ hoạt động: <? Php / path / to / hpricot $ argv?>
alastairs

25

Trong danh sách tuyệt vời của Joseph Holsten, tôi thêm tập lệnh dòng lệnh xpath đi kèm với thư viện Perl XML :: XPath. Một cách tuyệt vời để trích xuất thông tin từ các tệp XML:

 xpath -q -e '/entry[@xml:lang="fr"]' *xml

3
Điều này được cài đặt theo mặc định trong osx, nhưng không có -q -etùy chọn. Ví dụ, nhận giá trị "gói" thuộc tính từ nút "tệp kê khai" trong "AndroidManifest.xml":xpath AndroidManifest.xml 'string(/manifest/@package)' 2> /dev/null
antonj

25

Cũng có xml22xmlcặp. Nó sẽ cho phép các công cụ chỉnh sửa chuỗi thông thường xử lý XML.

Thí dụ. qDB:

<?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 cũng có html2/ 2html.


@Joseph Holsten Có. Nó cho phép hack với XML mà không cần suy nghĩ thông qua những thứ XPath.
Vi.

Đẹp! Tôi đã tập trung vào các công cụ không sử dụng định dạng trung gian, nhưng ý tưởng về đại diện xml có độ chính xác cao, hướng dòng có vẻ như là một cách tuyệt vời để tiếp tục sử dụng grep và sed thực sự. Bạn đã thử pyxie? Làm thế nào để nó so sánh? Bất kỳ đại diện định hướng dòng khác? Bạn có xem xét điều này tốt hơn là chỉ thay thế các dòng mới xml bằng một thực thể (& # 10;) không? Điều này sẽ cho phép bạn dán hồ sơ trên cùng một dòng ít nhất. Ồ, và bạn có thể chỉnh sửa bài đăng của mình để bao gồm một liên kết đến dự án không?
Joseph Holsten

@Joseph Holsten Không, tôi không nghĩ định dạng pyxie sẽ hữu ích hơn định dạng xml2. xml2 cung cấp "đường dẫn đầy đủ" trong các phần tử XML lồng nhau, do đó cho phép kết hợp và thay thế theo hướng dòng nhiều hơn. Cũng 2xmlcó thể dễ dàng tạo lại XML từ đầu ra một phần (được lọc) xml2.
Vi.

5
+1 Tôi không thể cat foo.xml | xml2 | grep /bar | 2xmlcung cấp đủ điều này ... - cung cấp cho bạn cấu trúc giống như ban đầu, nhưng tất cả các yếu tố đã bị xóa ngoại trừ các yếu tố "thanh". Tuyệt vời.
mogsie

14

Bạn có thể sử dụng xmllint:

xmllint --xpath //title books.xml

Nên được gói với hầu hết các bản phát hành, và cũng được gói cùng với Cygwin.

$ xmllint --version
xmllint: using libxml version 20900

Xem:

$ 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
Không có --xpathđối số để xmllint: manpagez.com/man/1/xmllint
Biến số khốn khổ

1
@MiserableVariable: Trang man không chính xác. Tôi chỉ nhìn vào trang man cho phiên bản của tôi: đối số xpath không được liệt kê. Đây là một lỗi tài liệu. Thay vào đó, hãy thử chạy chương trình.
Dave Jarvis

2
@MiserableVariable --xpathlà một bổ sung khá gần đây và ví dụ không có trong phiên bản RHEL 6 của xmllint.
Daniel Beck

2
Nói chính xác hơn, xmllint --xpathđã được giới thiệu trong libxml2 2.7.7 (năm 2010).
marbu

9

Nếu bạn đang tìm kiếm một giải pháp trên Windows, Powershell có chức năng tích hợp sẵn để đọc và viết XML.

test.xml:

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

Kịch bản 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>

Nguồn: /server/26976/update-xml-from-the-command-line-windows


chiến đấu với các công cụ linux khác nhau trong một vài giờ trước khi dùng đến Powershell. Tôi ngạc nhiên điều này rất khó - cmd-line linux thường rất tốt nhưng dường như có một lỗ hổng ở đây. Lưu ý: Trường hợp sử dụng đối với tôi là: 1) xác định vị trí các nút bằng xpath, 2) xóa nếu tìm thấy, 3) thêm nút mới, 4) lưu tệp. Tôi đã cập nhật một loạt các cấu hình solr. Nếu bất cứ ai biết về một cách dễ dàng / đáng tin cậy để làm điều này thì tôi đều nghe thấy
Richard Hauer

Wow, điều này thực sự dẫn đến một giải pháp chấp nhận được. Nhưng thành thật, tôi có lẽ sẽ chấp nhận nó nếu nó trông giống như xps $doc .root.one xps $doc 'AppendChild("three")'xps $doc '.three.set_InnerText("And don't you forget it!")', mà rõ ràng là kém!
Joseph Holsten


6

Phụ thuộc vào chính xác những gì bạn muốn làm.

XSLT có thể là con đường để đi, nhưng có một đường cong học tập. Hãy thử xsltproc và lưu ý rằng bạn có thể đưa ra các tham số.


4

Ngoài ra còn có saxon-lintdòng lệnh với khả năng sử dụng XPath 3.0 / XQuery 3.0. (Các công cụ dòng lệnh khác sử dụng XPath 1.0).

VÍ DỤ:

http / html:

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

xml:

$ saxon-lint --xpath '//a[@class="x"]' file.xml


3

XQuery có thể là một giải pháp tốt. Nó (tương đối) dễ học và là một tiêu chuẩn W3C.

Tôi muốn giới thiệu XQSharp cho bộ xử lý dòng lệnh.


1
BaseX cũng có bộ xử lý XQuery dòng lệnh (ngoài chế độ cơ sở dữ liệu của nó) và luôn cập nhật với các phiên bản mới nhất của tiêu chuẩn (theo dự thảo phát triển của XQuery 3.0 khá chặt chẽ).
Charles Duffy


1

Tương đương Grep

Bạn có thể định nghĩa hàm bash, nói "xp" ("xpath") bao bọc một số mã python3. Để sử dụng nó, bạn cần cài đặt python3 và python-lxml. Những lợi ích:

  1. kết hợp regex mà bạn thiếu trong ví dụ xmllint.
  2. Sử dụng làm bộ lọc (trong đường ống) trên dòng lệnh

Thật dễ dàng và mạnh mẽ để sử dụng như thế này:

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 () trông giống như thế này:

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 tương đương

Cân nhắc sử dụng xq cung cấp cho bạn toàn bộ sức mạnh của "ngôn ngữ lập trình" jq. Nếu bạn đã cài đặt python-pip, bạn có thể cài đặt xq với cài đặt pip yq , trong ví dụ dưới đây, chúng tôi sẽ thay thế "Giữ tài khoản" bằng "Giữ tài khoản 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 có một plugin gọi là "XQuery" cung cấp chức năng truy vấn cho các tài liệu XML.

Không hoàn toàn dòng lệnh, nhưng nó hoạt động!


Mặc dù JEdit có thể có cách tìm kiếm thông qua một tệp, nhưng điều đó không làm cho nó trở thành đối thủ cạnh tranh grep(1).
Joseph Holsten
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.