วิธีการใช้งาน XPath one-liners จาก shell?


192

มีแพ็คเกจออกมาสำหรับ Ubuntu และ / หรือ CentOS ที่มีเครื่องมือบรรทัดคำสั่งที่สามารถใช้ XPath แบบหนึ่งบรรทัดเหมือนfoo //element@attribute filename.xmlหรือfoo //element@attribute < filename.xmlและส่งคืนผลลัพธ์ทีละบรรทัดได้หรือไม่

ฉันกำลังมองหาบางสิ่งบางอย่างที่จะทำให้ฉันเป็นapt-get install fooหรือแค่yum install fooนั้นก็ทำงานนอกกรอบไม่มีการห่อหุ้มหรือการดัดแปลงอื่น ๆ ที่จำเป็น

นี่คือตัวอย่างของสิ่งที่เข้ามาใกล้:

Nokogiri ถ้าฉันเขียน wrapper นี้ฉันสามารถเรียก wrapper ตามวิธีที่อธิบายไว้ข้างต้น:

#!/usr/bin/ruby

require 'nokogiri'

Nokogiri::XML(STDIN).xpath(ARGV[0]).each do |row|
  puts row
end

XML :: XPath จะทำงานกับ wrapper นี้:

#!/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 ไม่สามารถจัดการกับนิพจน์ที่ไม่ส่งคืนองค์ประกอบดังนั้นจึงไม่สามารถใช้เพื่อแยกค่าแอตทริบิวต์โดยไม่มีการประมวลผลเพิ่มเติม

แก้ไข:

echo cat //element/@attribute | xmllint --shell filename.xmlxpathผลตอบแทนที่เสียงคล้ายกับ

xmllint --xpath //element/@attribute filename.xmlattribute = "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="'&#10;'"/>
    </xsl:for-each> 
  </xsl:template>
</xsl:stylesheet>

xsltproc --stringparam pattern //element/@attribute --stringparam value . arbitrary-xpath.xslt filename.xmlทำงานด้วย


+1 สำหรับคำถามที่ดีและเพื่อระดมสมองเกี่ยวกับการหาวิธีที่ง่ายและเชื่อถือได้ในการพิมพ์ผลลัพธ์หลายรายการโดยขึ้นบรรทัดใหม่
Gilles Quenot

1
โปรดทราบว่า "เสียง" จากxpathอยู่ใน STDERR ไม่ใช่ STDOUT
miken32

@ miken32 ไม่ฉันต้องการเฉพาะค่าสำหรับผลลัพธ์ hastebin.com/ekarexumeg.bash
clacke

คำตอบ:


271

คุณควรลองใช้เครื่องมือเหล่านี้:

  • xmlstarlet : สามารถแก้ไขเลือกแปลง ... ไม่ได้ติดตั้งโดยค่าเริ่มต้น xpath1
  • xmllint: มักจะติดตั้งโดยค่าเริ่มต้นด้วยlibxml2-utils, xpath1 (ตรวจสอบwrapperของฉันที่จะมีการ--xpathเปิดรุ่นเก่ามากและขึ้นบรรทัดใหม่ที่คั่นด้วยผลลัพธ์ (v <2.9.9)
  • xpath: ติดตั้งผ่านโมดูลของ perl XML::XPath, xpath1
  • xml_grep: ติดตั้งผ่านโมดูลของ perl XML::Twig, xpath1 (การใช้ xpath จำกัด )
  • xidel: xpath3
  • saxon-lint : โปรเจ็กต์ของฉันเองคลุมทับไลบรารี Saxon-HE Java ของ @Michael Kay xpath3

xmllintมาพร้อมกับlibxml2-utils(สามารถใช้เป็นเชลล์แบบโต้ตอบกับ--shellสวิตช์ได้)

xmlstarletxmlstarletเป็น

xpath มาพร้อมกับโมดูลของ perl XML::Xpath

xml_grep มาพร้อมกับโมดูลของ perl XML::Twig

xidel คือ xidel

saxon-lintใช้SaxonHE 9.6 , XPath 3.x (เข้ากันได้ + ย้อนยุค)

เช่น

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

.


7
ยอดเยี่ยม xmlstarlet sel -T -t -m '//element/@attribute' -v '.' -n filename.xmlทำสิ่งที่ฉันต้องการ!
clacke

2
หมายเหตุ: xmlstarlet มีข่าวลือว่าถูกยกเลิก แต่ขณะนี้อยู่ระหว่างการพัฒนาอีกครั้ง
clacke

6
หมายเหตุ: รุ่นเก่าบางรุ่นxmllintไม่สนับสนุนอาร์กิวเมนต์บรรทัดคำสั่งแต่ส่วนใหญ่ดูเหมือนจะสนับสนุน--xpath --shellเอาต์พุตสกปรกเล็กน้อย แต่ก็ยังมีประโยชน์ในการผูก
kevinarpe

ฉันยังคงมีปัญหาในการค้นหาเนื้อหาโหนดไม่ใช่แอตทริบิวต์ ทุกคนสามารถให้ตัวอย่างสำหรับสิ่งนั้นได้หรือไม่? ด้วยเหตุผลบางอย่างฉันยังพบว่า xmlstarlet ยากที่จะเข้าใจและได้รับสิทธิระหว่างการจับคู่ค่ารูทเพื่อดูโครงสร้างเอกสารและอื่น ๆ แม้จะมีsel -t -m ... -v ...ตัวอย่างแรกจากหน้านี้: arstechnica.com/information-technology/2005 / 11 / linux-20051115/2 , จับคู่ทั้งหมดยกเว้นโหนดสุดท้ายและบันทึกอันนั้นสำหรับนิพจน์ค่าเช่นกรณีการใช้ของฉัน, ฉันยังไม่สามารถหาได้, ฉันเพิ่งได้ผลลัพธ์ที่ว่างเปล่า ..
Pysis

เป็นคนดีในรุ่นของ xpath - ฉันเพิ่งเจอข้อ จำกัด ของ xmllint ที่ยอดเยี่ยมนี้เป็นอย่างอื่น
JonnyRaa

20

นอกจากนี้คุณยังสามารถลองของฉันXidel มันไม่ได้อยู่ในแพ็คเกจในที่เก็บ แต่คุณสามารถดาวน์โหลดได้จากหน้าเว็บ (มันไม่มีการพึ่งพา)

มันมีไวยากรณ์ที่เรียบง่ายสำหรับงานนี้:

xidel filename.xml -e '//element/@attribute' 

และเป็นหนึ่งในเครื่องมือหายากที่สนับสนุน XPath 2


2
Xidel ดูดีมาก แต่คุณควรพูดถึงว่าคุณเป็นผู้เขียนเครื่องมือนี้ที่คุณแนะนำด้วย
FrustratedWithFormsDesigner

1
แซ็กซอนและแซ็กซอน - ผ้าสำลีใช้ xpath3;)
Gilles Quenot

Xidel (0..8.win32.zip) แสดงว่ามีมัลแวร์ใน Virustotal ดังนั้นลองใช้virustotal.com/
JGFMK

ยอดเยี่ยม - ฉันจะเพิ่ม xidel ในกล่องเครื่องมือส่วนบุคคลของฉัน
maoizm

15

python-lxmlแพคเกจหนึ่งที่มีโอกาสมากที่จะได้รับการติดตั้งในระบบอยู่แล้ว ถ้าเป็นเช่นนั้นสามารถทำได้โดยไม่ต้องติดตั้งแพ็คเกจเพิ่มเติม:

python -c "from lxml.etree import parse; from sys import stdin; print '\n'.join(parse(stdin).xpath('//element/@attribute'))"

1
จะส่งชื่อไฟล์ได้อย่างไร
Ramakrishnan Kannan

4
stdinนี้ทำงานบน ซึ่งช่วยลดความจำเป็นในการรวมopen()และclose()ซับในแบบยาวหนึ่งบรรทัด ในการแยกวิเคราะห์ไฟล์เพียงแค่เรียกใช้python -c "from lxml.etree import parse; from sys import stdin; print '\n'.join(parse(stdin).xpath('//element/@attribute'))" < my_file.xmlและให้เชลล์ของคุณจัดการการค้นหาไฟล์เปิดและปิด
clacke

10

ในการค้นหาของฉันเพื่อค้นหาไฟล์ paven.xml maven ฉันวิ่งข้ามคำถามนี้ อย่างไรก็ตามฉันมีข้อ จำกัด ดังต่อไปนี้:

  • ต้องเรียกใช้ข้ามแพลตฟอร์ม
  • ต้องมีอยู่ในการกระจาย linux ที่สำคัญทั้งหมดโดยไม่ต้องติดตั้งโมดูลเพิ่มเติม
  • ต้องจัดการกับไฟล์ xml ที่ซับซ้อนเช่นไฟล์ maven pom.xml
  • ไวยากรณ์อย่างง่าย

ฉันได้ลองหลายอย่างแล้วโดยไม่ประสบความสำเร็จ:

  • python lxml.etree ไม่ได้เป็นส่วนหนึ่งของการแจกไพ ธ อนมาตรฐาน
  • xml.etree เป็น แต่ไม่จัดการไฟล์ pom.xml maven ที่ซับซ้อนได้ดีไม่ได้ขุดลึกพอ
  • python xml.etree ไม่จัดการไฟล์ maven pom.xml ด้วยเหตุผลที่ไม่ทราบสาเหตุ
  • xmllint ไม่ทำงานอย่างใดอย่างหนึ่งการถ่ายโอนข้อมูลหลักมักจะอยู่บน Ubuntu 12.04 "xmllint: การใช้ libxml รุ่น 20708"

วิธีแก้ปัญหาที่ฉันเจอนั่นคือเสถียรสั้นและทำงานได้บนหลาย ๆ แพลตฟอร์มและนั่นก็เป็นผู้ใหญ่แล้วคือ rexml lib builtin ใน ruby:

ruby -r rexml/document -e 'include REXML; 
     puts XPath.first(Document.new($stdin), "/project/version/text()")' < pom.xml

สิ่งที่เป็นแรงบันดาลใจให้ฉันพบสิ่งนี้คือบทความต่อไปนี้:


1
นั่นเป็นเกณฑ์ที่แคบกว่าคำถามดังนั้นจึงเหมาะกับคำตอบอย่างแน่นอน ฉันแน่ใจว่าหลายคนที่ประสบปัญหาของคุณจะได้รับความช่วยเหลือจากงานวิจัยของคุณ ฉันรักษาxmlstarletเป็นคำตอบที่ได้รับการยอมรับเพราะมันตรงกับเกณฑ์ที่กว้างขึ้นของฉันและมันเป็นอย่างจริงๆ แต่ฉันอาจจะใช้สำหรับการแก้ปัญหาของคุณเป็นครั้งคราว
clacke

2
ฉันจะเพิ่มที่เพื่อหลีกเลี่ยงคำพูดรอบ ๆ ผลใช้putsแทนpในคำสั่ง Ruby
TomG

10

แซ็กซอนจะทำเช่นนี้ไม่เพียง แต่สำหรับ XPath 2.0 แต่ยังสำหรับ XQuery 1.0 และ (ในเวอร์ชั่นเชิงพาณิชย์) 3.0 มันไม่ได้มาเป็นแพ็คเกจ Linux แต่เป็นไฟล์ jar วากยสัมพันธ์ (ซึ่งคุณสามารถล้อมด้วยสคริปต์ง่ายๆ) คือ

java net.sf.saxon.Query -s:source.xml -qs://element/attribute

2563 ปรับปรุง

Saxon 10.0 มีเครื่องมือ Gizmo ซึ่งสามารถใช้งานแบบโต้ตอบหรือเป็นชุดจากบรรทัดคำสั่ง ตัวอย่างเช่น

java net.sf.saxon.Gizmo -s:source.xml
/>show //element/@attribute
/>quit

SaxonB อยู่ในอูบุนตู, แพคเกจlibsaxonb-javaแต่ถ้าฉันเรียกsaxonb-xquery -qs://element/@attribute -s:filename.xmlฉันได้รับปัญหาเช่นเดียวกับกับเช่นSENR0001: Cannot serialize a free-standing attribute node xml_grep
clacke

3
หากคุณต้องการดูรายละเอียดทั้งหมดของโหนดแอ็ตทริบิวต์ที่เลือกโดยเคียวรีนี้ให้ใช้อ็อพชัน -wrap บนบรรทัดรับคำสั่ง หากคุณต้องการค่าสตริงของแอททริบิวต์ให้เพิ่ม / string () ลงในคิวรี
Michael Kay

ขอบคุณ การเพิ่ม / string () เข้ามาใกล้ยิ่งขึ้น แต่จะส่งออกส่วนหัว XML และวางผลลัพธ์ทั้งหมดในหนึ่งแถวดังนั้นจึงไม่มีซิการ์
clacke

2
หากคุณไม่ต้องการส่วนหัวของ XML ให้เพิ่มตัวเลือก! method = text
Michael Kay

หากต้องการใช้เนมสเปซให้เพิ่มใน-qsลักษณะนี้:'-qs:declare namespace mets="http://www.loc.gov/METS/";/mets:mets/mets:dmdSec'
igo

5

นอกจากนี้คุณยังอาจจะสนใจในXSH มันมีโหมดการโต้ตอบที่คุณสามารถทำสิ่งที่คุณต้องการด้วยเอกสาร:

open 1.xml ;
ls //element/@id ;
for //p[@class="first"] echo text() ;

ดูเหมือนจะไม่สามารถใช้งานได้เป็นแพคเกจอย่างน้อยก็ไม่ใช่ใน Ubuntu
clacke

1
@clacke: มันไม่ได้ แต่ก็สามารถติดตั้งจาก CPAN cpan XML::XSH2โดย
choroba

@choroba ฉันได้ลองใช้กับ OS X แล้ว แต่ไม่สามารถติดตั้งได้มีข้อผิดพลาด makefile บางประเภท
cnst

@cnst: คุณติดตั้ง XML :: LibXML หรือไม่
choroba

@choroba ฉันไม่รู้ แต่ประเด็นของฉันคือcpan XML::XSH2ไม่สามารถติดตั้งอะไรก็ได้
cnst

5

คำตอบของ clackeนั้นยอดเยี่ยม แต่ฉันคิดว่าใช้ได้เฉพาะถ้าซอร์สของคุณมีรูปแบบ 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'))

ใช่ฉันรู้สึกผิดกับข้อสันนิษฐานของตัวเอง XPath มีความหมายว่า XML คำตอบนี้เป็นส่วนเสริมที่ดีสำหรับคนอื่น ๆ ที่นี่และขอขอบคุณที่แจ้งให้เราทราบเกี่ยวกับ html5lib!
clacke

3

คล้ายกับคำตอบของ Mike และ clacke ต่อไปนี้เป็น python one-liner (ใช้ python> = 2.5) เพื่อรับบิลด์เวอร์ชันจากไฟล์ pom.xml ที่รับข้อเท็จจริงว่าไฟล์ pom.xml นั้นไม่มี dtd หรือ เนมสเปซที่เป็นค่าเริ่มต้นดังนั้นอย่าปรากฏรูปแบบที่ดีเป็น 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 และไม่จำเป็นต้องติดตั้งแพ็คเกจเพิ่มเติม


2
ฉันใช้สิ่งนี้วันนี้! สร้างเซิร์ฟเวอร์ของเรามีค่าlxmlมิได้xmllintหรือแม้กระทั่งทับทิม ด้วยจิตวิญญาณของรูปแบบในคำตอบของตัวเองฉันเขียนมันเหมือนpython3 -c "from xml.etree.ElementTree import parse; from sys import stdin; print(parse(stdin).find('.//element[subelement=\"value\"]/othersubelement').text)" <<< "$variable_containing_xml"ทุบตี .getroot()ดูเหมือนจะไม่จำเป็น
3066 clacke

2

นอกเหนือจากXML :: XSHและXML :: XSH2ยังมีgrepยูทิลิตี้ที่มีลักษณะคล้ายดูดApp::xml_grep2และXML::Twig(ซึ่งรวมถึงxml_grepมากกว่าxml_grep2) สิ่งเหล่านี้มีประโยชน์มากเมื่อทำงานกับไฟล์ XML ขนาดใหญ่หรือจำนวนมากสำหรับผู้สร้างหรือMakefileเป้าหมายด่วน XML::Twigโดยเฉพาะอย่างยิ่งเป็นสิ่งที่ดีที่ได้ทำงานร่วมกับperlวิธีการเขียนสคริปต์เมื่อคุณต้องการประมวลผลมากกว่า$SHELLและxmllint xstlprocข้อเสนอของคุณเล็กน้อย

ชุดรูปแบบการกำหนดหมายเลขในชื่อแอปพลิเคชันระบุว่า "2" รุ่นเป็นรุ่นที่ใหม่กว่า / ใหม่กว่าของเครื่องมือเดียวกันซึ่งอาจต้องใช้รุ่นที่ใหม่กว่าของโมดูลอื่น ๆ (หรือของperlตัวเอง)


xml_grep2 -t //element@attribute filename.xmlใช้งานได้และทำงานตามที่ฉันคาดไว้ ( xml_grep --root //element@attribute --text_only filename.xmlยังไม่ส่งคืนข้อผิดพลาด "นิพจน์ที่ไม่รู้จัก") ที่ดี!
clacke

เกี่ยวกับxml_grep --pretty_print --root '//element[@attribute]' --text_only filename.xmlอะไร ไม่แน่ใจว่าสิ่งที่เกิดขึ้นหรือสิ่งที่มี XPath กล่าวเกี่ยวกับ[]ในกรณีนี้ แต่รอบ @attributeด้วยวงเล็บทำงานให้และxml_grep xml_grep2
G. Cito

ผมหมายถึงไม่ได้//element/@attribute //element@attributeไม่สามารถแก้ไขได้ แต่ปล่อยให้อยู่ที่นั่นแทนที่จะลบ + แทนที่เพื่อไม่ให้สับสนกับประวัติของการสนทนานี้
clacke

//element[@attribute]องค์ประกอบเลือกชนิดที่มีแอตทริบิวต์element attributeฉันไม่ต้องการองค์ประกอบเพียงคุณลักษณะ <element attribute='foo'/>ควรให้ฉันไม่ได้เต็มรูปแบบfoo <element attribute='foo'/>
clacke

... และ--text_onlyในบริบทนั้นให้สตริงว่างในกรณีขององค์ประกอบที่<element attribute='foo'/>ไม่มีโหนดข้อความอยู่ภายใน
clacke

2

มันบอกว่า nokogiri มาพร้อมกับเครื่องมือบรรทัดคำสั่งซึ่งควรติดตั้งด้วย gem install nokogiriว่าตัวเองพร้อมกับเครื่องมือบรรทัดคำสั่งซึ่งควรจะติดตั้งกับ

คุณอาจพบบล็อกนี้โพสต์ที่มีประโยชน์


2

ฉันลองอรรถประโยชน์ 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 ซึ่งไม่รวมอยู่ในห้องสมุดหลามมาตรฐาน pip install lxmlติดตั้งด้วย บน Linux / OSX อาจต้อง prefixing 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 เทียบกับมาร์กอัปของหน้าเว็บคุณสามารถทำได้โดยตรงจาก devtools ของ Chrome: คลิกขวาที่หน้าใน Chrome> เลือกตรวจสอบจากนั้นใน DevTools คอนโซลวางนิพจน์ XPath ของคุณเป็น $x("//spam/eggs")ของคุณเป็น

รับผู้เขียนทั้งหมดในหน้านี้:

$x("//*[@class='user-details']/a/text()")

ไม่ได้เป็นหนึ่งซับและlxmlได้กล่าวถึงแล้วในสองอื่น ๆคำตอบปีก่อนที่จะแสดงความนับถือ
3066 clacke

2

นี่คือหนึ่งใน 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

สังเกตความซับซ้อน (IMO ไม่จำเป็น) ด้วย namespaces (ns, ประกาศด้วย -N) ซึ่งทำให้ฉันเกือบยอมแพ้กับ xpath และ xmlstarlet และเขียนตัวแปลงเฉพาะกิจอย่างรวดเร็ว


xmlstarlet นั้นยอดเยี่ยม แต่คำตอบที่ได้รับการยอมรับและการจัดอันดับหลักได้กล่าวถึงแล้ว ข้อมูลเกี่ยวกับวิธีจัดการเนมสเปซอาจมีความเกี่ยวข้องในฐานะความคิดเห็น ทุกคนที่ประสบปัญหากับเนมสเปซและ xmlstarlet สามารถพบการสนทนาที่
clacke

2
แน่นอนว่า @clacke, xmlstarlet มีการพูดถึงหลายครั้ง แต่ก็ยากที่จะเข้าใจและมีเอกสารไม่เพียงพอ ฉันคาดเดาประมาณหนึ่งชั่วโมงเพื่อให้ได้ข้อมูลจากองค์ประกอบที่ซ้อนกัน ฉันหวังว่าฉันจะมีตัวอย่างนั่นคือเหตุผลที่ฉันโพสต์ไว้ที่นี่เพื่อหลีกเลี่ยงคนอื่นที่เสียเวลา (และตัวอย่างยาวเกินไปสำหรับความคิดเห็น)
diemo

2

สคริปต์ Python ของฉันxgrep.pyทำสิ่งนี้ทุกประการ เพื่อค้นหาคุณลักษณะทั้งหมดattributeขององค์ประกอบelementในไฟล์filename.xml ...คุณจะเรียกใช้ดังต่อไปนี้:

xgrep.py "//element/@attribute" filename.xml ...

มีสวิตช์ต่าง ๆ สำหรับการควบคุมเอาต์พุตเช่น-cสำหรับการจับคู่การนับ-iเพื่อเยื้องส่วนการจับคู่และ-lสำหรับการส่งออกชื่อไฟล์เท่านั้น

สคริปต์นี้ไม่พร้อมใช้งานเป็นแพ็คเกจ Debian หรือ Ubuntu แต่การพึ่งพาทั้งหมดนั้นมี


และคุณกำลังโฮสต์บน sourcehut! ดี!
clacke

1

เนื่องจากโครงการนี้ค่อนข้างใหม่ให้ลองดูhttps://github.com/jeffbr13/xqดูเหมือนจะเป็น wrapper รอบ ๆlxmlแต่นั่นคือทั้งหมดที่คุณต้องการ (และโพสต์โซลูชัน ad hoc โดยใช้ lxml ในคำตอบอื่น ๆ ด้วย)


1

ฉันไม่มีความสุขกับ Python One-liners สำหรับการสืบค้น HTML XPath ดังนั้นฉันจึงเขียนของตัวเอง สมมติว่าคุณติดตั้งpython-lxmlแพคเกจหรือวิ่งpip install --user lxml:

function htmlxpath() { python -c 'for x in __import__("lxml.html").html.fromstring(__import__("sys").stdin.read()).xpath(__import__("sys").argv[1]): print(x)' $1 }

เมื่อคุณมีแล้วคุณสามารถใช้มันได้ในตัวอย่างนี้:

> curl -s https://slashdot.org | htmlxpath '//title/text()'
Slashdot: News for nerds, stuff that matters

0

ติดตั้งฐานข้อมูลBaseXจากนั้นใช้"โหมดบรรทัดคำสั่งแบบสแตนด์อโลน"ดังนี้:

basex -i - //element@attribute < filename.xml

หรือ

basex -i filename.xml //element@attribute

ภาษาคิวรีเป็นจริง XQuery (3.0) ไม่ใช่ XPath แต่เนื่องจาก XQuery เป็นชุดของ XPath คุณสามารถใช้คิวรี XPath ได้โดยไม่ต้องสังเกต

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.