쉘에서 XPath one-liners를 실행하는 방법은 무엇입니까?


192

Ubuntu 및 / 또는 CentOS 용 XPath one-liner를 실행 foo //element@attribute filename.xml하거나 foo //element@attribute < filename.xml한 줄씩 결과를 반환 할 수있는 명령 줄 도구가있는 패키지가 있습니까?

나는 단지 apt-get install foo또는 yum install foo즉시 사용할 수 있고 래퍼 또는 다른 적응이 필요없는 것을 찾고 있습니다.

다음은 가까이 오는 것들의 예입니다.

노코 기리. 이 래퍼를 작성하면 위에서 설명한 방식으로 래퍼를 호출 할 수 있습니다.

#!/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");
}

xpathXML에서 :: XPath는 너무 많은 소음 반환 -- NODE --하고 attribute = "value".

xml_grep from XML :: Twig는 요소를 리턴하지 않는 표현식을 처리 할 수 ​​없으므로 추가 처리없이 속성 값을 추출하는 데 사용할 수 없습니다.

편집하다:

echo cat //element/@attribute | xmllint --shell filename.xml와 유사한 노이즈를 반환합니다 xpath.

xmllint --xpath //element/@attribute filename.xml을 반환합니다 attribute = "value".

xmllint --xpath 'string(//element/@attribute)' filename.xml 내가 원하는 것을 반환하지만 첫 번째 일치에 대해서만.

거의 모든 질문을 충족시키는 다른 솔루션을 위해 임의의 XPath 표현식을 평가하는 데 사용할 수있는 XSLT가 있습니다 (XSLT 프로세서에서 dyn : evaluate 지원 필요).

<?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는 STDOUT이 아니라 STDERR에 있습니다.
miken32

@ miken32 아니요. 출력 값만 원했습니다. hastebin.com/ekarexumeg.bash
clacke

답변:


271

다음 도구를 사용해보십시오.

  • xmlstarlet : 편집, 선택, 변환 가능 ... 기본적으로 설치되지 않음, xpath1
  • xmllint: 종종 libxml2-utilsxpath1을 사용 하여 기본적으로 설치됩니다 ( 래퍼--xpath매우 오래된 릴리스와 줄 바꿈으로 구분 된 출력 을 켜 려면 래퍼 를 확인하십시오 (v <2.9.9)
  • xpath: perl의 모듈 XML::XPathxpath1을 통해 설치
  • xml_grep: perl의 모듈 XML::Twigxpath1 (제한된 xpath 사용법)을 통해 설치
  • xidel: xpath3
  • saxon-lint : 내 자신의 프로젝트, @Michael Kay의 Saxon-HE Java 라이브러리 xpath3을 래퍼

xmllint함께 제공 libxml2-utils합니다 (대화 형 쉘로 사용할 수 있습니다 --shell스위치)

xmlstarlet입니다 xmlstarlet.

xpath 펄 모듈과 함께 제공 XML::Xpath

xml_grep 펄 모듈과 함께 제공 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의 한계에
부딪 쳤습니다

20

Xidel을 사용해 볼 수도 있습니다 . 저장소의 패키지에는 없지만 웹 페이지에서 다운로드 할 수 있습니다 (종속성이 없음).

이 작업에 대한 간단한 구문이 있습니다.

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

그리고 XPath 2를 지원하는 것은 드문 도구 중 하나입니다.


2
Xidel은 매우 근사해 보이지만 자신이 추천 한이 도구의 저자이기도합니다.
FrustratedWithFormsDesigner

1
색슨 족과 색슨 - 보풀이 사용 xpath3)
질 Quenot

Xidel (0..8.win32.zip)은 Virustotal에 맬웨어가있는 것으로 나타납니다. 따라서 자신의 위험을 시도하십시오 virustotal.com/#/file/…
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

maven pom.xml 파일을 쿼리하는 검색 에서이 질문에 대해 실행했습니다. 그러나 나는 다음과 같은 한계가 있었다.

  • 크로스 플랫폼을 실행해야합니다.
  • 추가 모듈 설치없이 모든 주요 Linux 배포에 존재해야합니다.
  • maven pom.xml 파일과 같은 복잡한 xml 파일을 처리해야합니다.
  • 간단한 구문

나는 성공하지 않고 위의 많은 것들을 시도했다.

  • python lxml.etree는 표준 python 배포의 일부가 아닙니다
  • xml.etree는 복잡한 maven pom.xml 파일을 잘 처리하지 못하고 깊이 파고 들지 않았습니다.
  • python xml.etree가 알 수없는 이유로 maven pom.xml 파일을 처리하지 않습니다.
  • xmllint도 작동하지 않습니다. 우분투 12.04에서 종종 코어 덤프 "xmllint : using libxml version 20708"

내가 찾은 해결책은 안정적이고 짧으며 많은 플랫폼에서 작동하며 성숙한 솔루션은 루비에 내장 된 rexml lib입니다.

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

이 기사를 찾게 된 계기는 다음과 같습니다.


1
그것은 질문보다 더 좁은 기준이므로 답으로 적합합니다. 귀하의 상황에 부딪친 많은 사람들이 귀하의 연구에 도움이 될 것입니다. 나는 xmlstarlet더 넓은 기준에 맞고 정말 깔끔 하기 때문에 받아 들여진 대답으로 유지 하고 있습니다 . 그러나 아마도 귀하의 솔루션에 때때로 사용할 것입니다.
clacke

2
결과 주위에 따옴표 하려면 Ruby 명령 puts대신을 사용 p하십시오.
TomG

10

Saxon은 XPath 2.0뿐만 아니라 XQuery 1.0 및 (상업용 버전) 3.0에서도이 작업을 수행합니다. Linux 패키지가 아니라 jar 파일로 제공됩니다. 구문 (간단한 스크립트로 쉽게 랩핑 할 수 있음)은

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

2020 업데이트

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() ;

적어도 우분투에서는 패키지로 제공되지 않는 것 같습니다.
clacke

1
@clacke : 그렇지는 않지만 CPAN에서 설치할 수 있습니다 cpan XML::XSH2.
choroba

@ choroba, OS X에서 시도했지만 일종의 makefile 오류로 설치하지 못했습니다.
cnst

@cnst : XML :: LibXML이 설치되어 있습니까?
choroba

@choroba, 나는 모른다; 그러나 내 요점은 cpan XML::XSH2아무것도 설치하지 못한다는 것입니다.
cnst

5

clacke의 대답 은 훌륭하지만 소스가 정상적인 HTML이 아닌 올바른 형식의 XML 인 경우에만 작동한다고 생각합니다.

따라서 정상적인 웹 컨텐트에 대해서도 동일하게 수행해야합니다. XML 형식이 아닌 HTML 문서는 다음과 같습니다.

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 파일에서 일반적으로 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"bash 와 같이 썼다 . .getroot()필요하지 않은 것 같습니다.
clacke

2

뿐만 아니라 XML :: XSHXML :: XSH2은 몇 가지가 있습니다 grep-like 유틸리티로 빨아 App::xml_grep2하고 XML::Twig(이 포함 xml_grep보다는 xml_grep2). 빠른 oneliner 또는 Makefile대상을 위해 많은 XML 파일을 작업 할 때 매우 유용 할 수 있습니다 . 귀하의 제안 및 제안 보다 약간 더 많은 처리를 원할 때 스크립팅 접근 방식 XML::Twig으로 작업하는 것이 특히 좋습니다 .perl$SHELLxmllint 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_grepand에서 작동합니다 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

나는 몇 가지 명령 줄 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표준 파이썬 라이브러리에 포함되지 않은 C로 작성된 빠른 XML 파서를 사용 합니다. 로 설치하십시오 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"

Chrome의 Xpath

관련이없는 참고 사항 : 우연히 웹 페이지의 마크 업에 대해 XPath 표현식을 실행하려면 Chrome devtools에서 바로 수행 할 수 있습니다 .Chrome에서 페이지를 마우스 오른쪽 버튼으로 클릭하고> 검사를 선택한 다음 DevTools에서 XPath 표현식을로 붙여 넣습니다 $x("//spam/eggs").

이 페이지의 모든 저자를 확보하십시오.

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

하나의 라이너가 아니며 lxml이미 몇 년 전에 다른 가지 답변 에서 언급되었습니다 .
clacke

2

중첩 된 요소 elem1, elem2에서이 유형의 XML에서 한 줄의 텍스트로 데이터를 추출하는 하나의 xmlstarlet 유스 케이스가 있습니다 (네임 스페이스 처리 방법도 표시).

<?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

xpath와 xmlstarlet을 거의 포기하고 빠른 애드혹 변환기를 작성하는 네임 스페이스 (ns, -N으로 선언)와의 (IMO 불필요) 합병증에 주목하십시오.


xmlstarlet은 훌륭하지만 받아 들인 주요 순위 답변에 이미 언급되어 있습니다. 네임 스페이스를 처리하는 방법에 대한 정보는 주석과 관련이있을 수 있습니다. 네임 스페이스와 xmlstarlet 문제로 실행 사람은 훌륭한 찾을 수 있습니다 문서 토론
clacke

2
물론, @clacke, xmlstarlet은 여러 번 언급되었지만 이해하기 어려우며 문서화가 잘되지 않았습니다. 중첩 된 요소에서 정보를 얻는 방법을 한 시간 정도 추측했습니다. 나는 그 예를 가졌기를 바랍니다. 그래서 다른 사람들이 시간을 잃는 것을 피하기 위해 여기에 게시하고 있습니다 (예는 설명이 너무 길다).
diemo

2

내 파이썬 스크립트 xgrep.py 는 정확하게 이것을 수행합니다. files attribute요소의 모든 속성을 검색하려면 다음과 같이 실행하십시오.elementfilename.xml ...

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

-c일치 횟수 계산 -i, 일치하는 부분 들여 쓰기 및 -l파일 이름 출력과 같은 출력 제어를위한 다양한 스위치가 있습니다 .

이 스크립트는 데비안 또는 우분투 패키지로 사용할 수 없지만 모든 종속성이 있습니다.


그리고 당신은 sourcehut에서 호스팅하고 있습니다! 좋은!
clacke

1

이 프로젝트는 상당히 새롭기 때문에 https://github.com/jeffbr13/xq를 확인하고 래퍼 인 것처럼 보이지만 lxml실제로 필요한 것입니다 (그리고 다른 답변에도 lxml을 사용하여 임시 솔루션을 게시했습니다)


1

HTML XPath 쿼리를위한 Python one-liner에 만족하지 않아서 직접 작성했습니다. 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

쿼리 언어는 실제로는 XPath가 아닌 XQuery (3.0)이지만 XQuery는 XPath의 상위 집합이므로 XPath 쿼리를 눈치 채지 않고도 사용할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.