如何从shell执行XPath单行程?

有没有一个软件包,Ubuntu和/或CentOS,有一个命令行工具,可以像foo //element@attribute filename.xmlfoo //element@attribute < filename.xml一样执行XPath并逐行返回结果?

我正在寻找的东西,可以让我只是apt-get install fooyum install foo ,然后只是开箱即用,没有包装或其他适应需要。

以下是一些接近的例子:

引入nokogiri。 如果我写这个包装器,我可以按照上面描述的方式调用包装器:

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

来自XML :: XPath的xpath返回的噪音太多, -- NODE --attribute = "value"

来自XML :: Twig的xml_grep不能处理不返回元素的expression式,所以不能用来提取属性值而不做进一步的处理。

编辑:

echo cat //element/@attribute | xmllint --shell filename.xml echo cat //element/@attribute | xmllint --shell filename.xml返回类似于xpath噪音。

xmllint --xpath //element/@attribute filename.xml返回attribute = "value"

xmllint --xpath 'string(//element/@attribute)' filename.xml返回我想要的,但仅用于第一个匹配。

对于几乎满足这个问题的另一个解决scheme,下面是一个XSLT,可以用来评估任意XPathexpression式(需要在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="'
'"/> </xsl:for-each> </xsl:template> </xsl:stylesheet> 

使用xsltproc --stringparam pattern //element/@attribute --stringparam value . arbitrary-xpath.xslt filename.xml运行xsltproc --stringparam pattern //element/@attribute --stringparam value . arbitrary-xpath.xslt filename.xml xsltproc --stringparam pattern //element/@attribute --stringparam value . arbitrary-xpath.xslt filename.xml

你应该尝试这些工具:

  • xmlstarlet
  • xmllint
  • saxon-lint (自己的项目)

xmllint附带libxml2-utils (可用作与--shell开关交互的shell) xmlstarletxmlstarlet

使用SaxonHE 9.6的 saxon-lint是运行XPath 3.x (+兼容性)的唯一软件,其他软件运行XPath 1.x。

例如:

 xmllint --xpath '//element/@attribute' file.xml xmlstarlet sel -t -v "//element/@attribute" file.xml saxon-lint --xpath '//element/@attribute' file.xml 
  • xmlstarlet页面
  • 人xmllint
  • 萨克森-皮棉

一个很有可能安装在系统上的包是python-lxml 。 如果是这样,这可能没有安装任何额外的软件包:

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

你也可以试试我的Xidel 。 它不在版本库的软件包中,但是可以从网页下载(它没有依赖关系)。

这个任务有简单的语法:

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

这是支持XPath 2的这些工具中less有的一种。

撒克逊不仅为XPath 2.0,而且为XQuery 1.0和(商业版本)3.0。 它不是作为一个Linux软件包,而是一个jar文件。 语法(你可以很容易地包装在一个简单的脚本)是

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

在我search查询maven pom.xml文件时,我跑过了这个问题。 不过,我有以下限制:

  • 必须运行跨平台。
  • 必须存在于所有主要的Linux发行版中,而不需要额外的模块安装
  • 必须处理复杂的xml文件,如maven pom.xml文件
  • 简单的语法

我已经尝试了许多以上没有成功:

  • python lxml.etree不是标准python发行版的一部分
  • xml.etree是没有处理复杂的maven pom.xml文件,没有足够深入的挖掘
  • python xml.etree不能处理maven pom.xml文件,原因不明
  • xmllint也不能正常工作,经常在Ubuntu 12.04上进行核心转储“xmllint:using libxml version 20708”

我遇到的唯一的解决scheme是稳定的,简短的,在许多平台上工作,这是成熟的rubyrexml lib内置:

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

是什么启发我find这个是以下文章:

  • Ruby / XML,XSLT和XPath教程
  • IBM:Ruby on Rails和XML

您可能也对xsh感兴趣。 它具有交互模式,您可以在文档中做任何你喜欢的事情:

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

clacke的答案是伟大的,但我认为只有当你的源码格式良好的XML,而不是普通的HTML。

所以对于正常的Web内容(不一定是格式良好的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(以确保您获得与Web浏览器相同的parsing行为 – 因为与浏览器parsing器一样,html5lib符合HTML规范中的parsing要求)。

 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')) 

除了XML :: XSH和XML :: XSH2之外,还有一些类似于 grep的实用程序吸收为App::xml_grep2XML::Twig (其中包括xml_grep而不是xml_grep2 )。 当处理大量或大量的XML文件以获得快速的链接或Makefile目标时,这些可能非常有用。 当你想要比$SHELLxmllint xstlproc提供更多的处理时, XML::Twig特别适合使用perl脚本编写方法。

应用程序名称中的编号scheme表示“2”版本是本质上相同的工具的更新/更新版本,可能需要更高版本的其他模块(或perl本身)。

值得一提的是,nokogiri本身附带一个命令行工具,应该安装gem install nokogiri

你可能会觉得这个博客文章很有用 。

类似于Mike的和clacke的答案,下面是python单行(使用python> = 2.5)从pom.xml文件获取构build版本,以获取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上testing,并且不需要安装任何额外的软件包。

我已经尝试了几个命令行XPath实用程序,当我意识到我花了太多的时间search并找出它们的工作方式时,所以我用Python编写了最简单的XPathparsing器,它可以完成我所需要的工作。

下面的脚本显示了如果XPathexpression式求值为string时的string值,或者如果结果是节点,则显示整个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编写的快速XMLparsing器,它不包含在标准的Python库中。 用pip install lxml安装它。 在Linux / OSX上可能需要使用sudo前缀。

用法:

 python xmlcat.py file.xml "//mynode" 

lxml也可以接受一个URL作为input:

 python xmlcat.py http://example.com/file.xml "//mynode" 

提取机箱节点(ie)下的url属性:

 python xmlcat.py xmlcat.py file.xml "//enclosure/@url" 

Google Chrome中的Xpath

作为一个不相干的一面:如果碰巧你想运行一个XPathexpression式来对抗网页的标记,那么你可以直接从Chrome开发工具中完成:右击Chrome中的页面>selectInspect,然后在DevTools中控制台将您的XPathexpression式粘贴为$x("//spam/eggs")

获取此页面上的所有作者:

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