是否有一个针对Ubuntu和/或CentOS的包,它有一个命令行工具,可以执行像foo //element@attribute filename.xml或foo //element@attribute < filename.xml这样的XPath一行程序,并逐行返回结果?

我正在寻找一些东西,这将允许我只是apt-get安装foo或yum安装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");
}

xpath从XML:: xpath返回太多噪音,——NODE——和attribute = "value"。

来自XML::Twig的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(需要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。


当前回答

您可能还对xsh感兴趣。它的特点是一个交互模式,你可以做任何你喜欢的文档:

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

其他回答

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

你可能会发现这篇博客文章很有用。

很抱歉又加入了争论。我尝试了这篇文章中的所有工具,但没有一个能满足我的需求,所以我自己编写了一个。你可以在这里找到它:https://github.com/charmparticle/xpe

它已经上传到pypi,所以你可以很容易地用pip3安装它,就像这样:

sudo pip3 install xpe

安装后,您可以使用它对各种输入运行xpath表达式,其灵活性与在selenium或javascript中使用xpath所获得的灵活性相同。你可以用xpaths来对抗HTML。

你也可以试试我的Xidel。它不在存储库中的包中,但您可以从网页下载它(它没有依赖关系)。

对于这个任务,它有简单的语法:

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

它是少数支持XPath 2的工具之一。

您可能还对xsh感兴趣。它的特点是一个交互模式,你可以做任何你喜欢的文档:

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

A minimal wrapper for python's lxml module that will print all matching nodes by name (at any level), e.g. mysubnode or an XPath subset e.g. //intermediarynode/subnode. If the expression evaluates to text then text will be printed, if it evaluates to an element then the entire raw element will be rendered to text. It also attempts to handle XML namespaces in a way that allows using local tag names without prefixing. With extended XPath mode enabled via the -x flag the default namespace needs to be referenced with the p: prefix, e.g. //p:tagname/p:subtag

#!/usr/bin/env python3
import argparse
import os
import sys

from lxml import etree

DEFAULT_NAMESPACE_KEY = 'p'

def print_element(elem):
    if isinstance(elem, str):
        print(elem)
    elif isinstance(elem, bytes):
        print(elem.decode('utf-8'))
    else:
        print(elem.text and elem.text.strip() or etree.tostring(elem, encoding='unicode', pretty_print=True))


if __name__ == '__main__':

    parser = argparse.ArgumentParser(description='XPATH lxml wrapper',
                                     usage="""
    Print all nodes by name in XML file:                                     
    \t{0} myfile.xml somename

    Print all nodes by XPath selector (findall: reduced subset):                                     
    \t{0} myfile.xml //itermediarynode/childnode

    Print attribute values by XPath selector 'p' maps to default namespace (xpath 1.0: extended subset):                                     
    \t{0} myfile.xml //p:itermediarynode/p:childnode/@src -x
                          
     """.format(os.path.basename(sys.argv[0])))
    parser.add_argument('xpath_file',
                        help='XPath file path')
    parser.add_argument('xpath_expression',
                        help='tag name or xpath expression')
    parser.add_argument('--force_xpath', '-x',
                        action='store_true',
                        default=False,
                        help='Use lxml.xpath (rather than findall)'
    )

    args = parser.parse_args(sys.argv[1:])
    xpath_expression = args.xpath_expression

    tree = etree.parse(args.xpath_file)

    ns = tree.getroot().nsmap

    if args.force_xpath:
        if ns.keys() and None in ns:
            ns[DEFAULT_NAMESPACE_KEY] = ns.pop(None)
        for node in tree.xpath(xpath_expression, namespaces=ns):
            print_element(node)

    elif xpath_expression.isalpha():
        for node in tree.xpath(f"//*[local-name() = '{xpath_expression}']"):
            print_element(node)
    else:
        for el in tree.findall(xpath_expression, namespaces=ns):
            print_element(el)


它使用lxml -一个用C编写的快速XML解析器,它不包含在标准python库中。使用pip Install lxml安装它。在Linux/OSX上可能需要用sudo作为前缀。

用法:

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

lxml也可以接受URL作为输入:

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

提取框节点下的url属性,即<enclosure url="http:…""..>)(-x强制扩展XPath 1.0子集):

python3 xmlcat.py xmlcat.py file.xml "//enclosure/@url" -x

在谷歌Chrome中的Xpath

作为一个无关的边注:如果碰巧你想运行一个XPath表达式对网页的标记,那么你可以直接从Chrome devtools:右键单击页面在Chrome >选择检查,然后在devtools控制台粘贴你的XPath表达式为$x("//spam/eggs")。

获取本页上的所有作者:

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