对于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_grep
无法处理不返回元素的表达式,因此无法在不进一步处理的情况下提取属性值。
编辑:
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(需要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="' '"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
使用xsltproc --stringparam pattern //element/@attribute --stringparam value . arbitrary-xpath.xslt filename.xml
运行。
答案 0 :(得分:232)
您应该尝试以下工具:
xmlstarlet
:可以编辑,选择,转换......默认情况下不安装,xpath1 xmllint
:默认情况下通常会安装libxml2
,xpath1(检查我的wrapper是否有换行符分隔输出xpath
:通过perl的模块XML::XPath
安装,xpath1 xml_grep
:通过perl的模块XML::Twig
安装,xpath1(有限的xpath用法)xidel
:xpath3 saxon-lint
:我自己的项目,@Michael Kay的Saxon-HE Java库包装器,xpath3 xmllint
附带libxml2-utils
(可用作--shell
开关的交互式外壳)
xmlstarlet
是xmlstarlet
。
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
答案 1 :(得分:18)
您也可以尝试我的Xidel。它不在存储库的包中,但您可以从网页上下载它(它没有依赖项)。
此任务的语法很简单:
xidel filename.xml -e '//element/@attribute'
这是支持XPath 2的这些工具中罕见的一种。
答案 2 :(得分:15)
一个很可能已安装在系统上的软件包已经是python-lxml
。如果是这样,这可以不安装任何额外的包:
python -c "from lxml.etree import parse; from sys import stdin; print '\n'.join(parse(stdin).xpath('//element/@attribute'))"
答案 3 :(得分:10)
Saxon不仅会为XPath 2.0做到这一点,也会为XQuery 1.0和(商业版)3.0做到这一点。它不是一个Linux包,而是一个jar文件。语法(您可以轻松地将其包装在一个简单的脚本中)是
java net.sf.saxon.Query -s:source.xml -qs://element/attribute
答案 4 :(得分:10)
在我查询maven pom.xml文件的搜索中,我遇到了这个问题。但是我有以下限制:
我尝试过上述许多方法但没有成功:
我遇到的解决方案是稳定,简短并且可以在许多平台上运行,而且成熟的是内置于ruby中的rexml lib:
ruby -r rexml/document -e 'include REXML;
p XPath.first(Document.new($stdin), "/project/version/text()")' < pom.xml
让我发现这篇文章的原因是以下文章:
答案 5 :(得分:5)
您可能也对xsh感兴趣。它具有交互模式,您可以使用文档执行任何操作:
open 1.xml ;
ls //element/@id ;
for //p[@class="first"] echo text() ;
答案 6 :(得分:4)
clacke’s answer很棒,但我认为只有在您的来源是格式良好的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浏览器相同的解析行为 - 因为像浏览器解析器一样,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'))
答案 7 :(得分:3)
类似于Mike和clacke的答案,这里是python one-liner(使用python&gt; = 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上测试过,并且不需要安装任何额外的软件包。
答案 8 :(得分:2)
值得一提的是,nokogiri本身附带了一个命令行工具,该工具应与gem install nokogiri
一起安装。
您可能会找到this blog post useful。
答案 9 :(得分:2)
我的Python脚本xgrep.py正是这样做的。为了在文件attribute
中搜索元素element
的所有属性filename.xml ...
,您可以按以下方式运行它:
xgrep.py "//element/@attribute" filename.xml ...
有许多用于控制输出的开关,例如-c
用于计数匹配项,-i
用于缩进匹配部分,-l
仅用于输出文件名。
该脚本不能作为Debian或Ubuntu软件包提供,但其所有依赖项都可以。
答案 10 :(得分:2)
除了XML::XSH和XML::XSH2之外,还有一些grep
类似的实用程序很糟糕,因为App::xml_grep2
和XML::Twig
(包括xml_grep
而非比xml_grep2
)。在为快速oneliner或Makefile
目标处理大量或大量XML文件时,这些功能非常有用。如果您想要比XML::Twig
和perl
$SHELL
提供更多的处理,xmllint
特别适合使用xstlproc
脚本方法。
应用程序名称中的编号方案表示“2”版本是基本相同工具的更新版本/更高版本,可能需要更高版本的其他模块(或perl
本身)。
答案 11 :(得分:1)
我已经尝试了几个命令行XPath实用程序,当我意识到我花了太多时间在Google上搜索并弄清楚它们是如何工作的,所以我在Python中编写了最简单的XPath解析器,它完成了我需要的工作。
如果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解析器,它不包含在标准的python库中。使用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"
作为一个不相关的旁注:如果您想要针对网页的标记运行XPath表达式,那么您可以直接从Chrome devtools执行此操作:右键单击Chrome中的页面&gt;选择Inspect,然后在DevTools控制台中将XPath表达式粘贴为$x("//spam/eggs")
。
在此页面上获取所有作者:
$x("//*[@class='user-details']/a/text()")
答案 12 :(得分:1)
由于这个项目显然相当新,所以查看https://github.com/jeffbr13/xq,似乎是lxml
的包装,但这就是你真正需要的(并在其他答案中使用lxml发布临时解决方案)孔)
答案 13 :(得分:1)
我对HTML XPath查询的Python单行代码不满意,所以我写了自己的。假设您安装了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
答案 14 :(得分:0)
这是一个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不必要的)并发命名空间(ns,用-N声明),这让我几乎放弃了xpath和xmlstarlet,并编写了一个快速的ad-hoc转换器。
答案 15 :(得分:0)
安装BaseX数据库,然后像这样使用它的"standalone command-line mode":
basex -i - //element@attribute < filename.xml
或
basex -i filename.xml //element@attribute
查询语言实际上是XQuery(3.0),而不是XPath,但是由于XQuery是XPath的超集,因此您无需注意就可以使用XPath查询。
答案 16 :(得分:0)
很抱歉成为争吵中的另一个声音。我尝试了这个线程中的所有工具,但发现它们都不能满足我的需求,所以我写了自己的。您可以在这里找到它:https://github.com/charmparticle/xpe
它已上传到 pypi,因此您可以像这样使用 pip3 轻松安装它:
sudo pip3 install xpe
安装后,您可以使用它来针对各种输入运行 xpath 表达式,其灵活性与在 selenium 或 javascript 中使用 xpath 时获得的灵活性相同。是的,你可以使用 xpaths 来对抗 HTML。