如何从shell执行XPath单行程?
有没有一个软件包,Ubuntu和/或CentOS,有一个命令行工具,可以像foo //element@attribute filename.xml
或foo //element@attribute < filename.xml
一样执行XPath并逐行返回结果?
我正在寻找的东西,可以让我只是apt-get install foo
或yum 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) xmlstarlet
是xmlstarlet
。
使用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_grep2
和XML::Twig
(其中包括xml_grep
而不是xml_grep2
)。 当处理大量或大量的XML文件以获得快速的链接或Makefile
目标时,这些可能非常有用。 当你想要比$SHELL
和xmllint
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()")