是否有一个针对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。


当前回答

除了XML::XSH和XML::XSH2之外,还有一些类似grep的实用程序,如App::xml_grep2和XML::Twig(包括xml_grep而不是xml_grep2)。在处理大型或大量XML文件以实现快速联机程序或Makefile目标时,这些功能非常有用。当您想要比$SHELL和xmllint xstlproc提供更多的处理时,XML::Twig特别适合用于perl脚本方法。

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

其他回答

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

在我搜索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"

我所遇到的解决方案是稳定的,简短的,可以在许多平台上工作,并且是成熟的,是ruby中内置的rexml库:

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

启发我找到这篇文章的是下面的文章:

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

除了XML::XSH和XML::XSH2之外,还有一些类似grep的实用程序,如App::xml_grep2和XML::Twig(包括xml_grep而不是xml_grep2)。在处理大型或大量XML文件以实现快速联机程序或Makefile目标时,这些功能非常有用。当您想要比$SHELL和xmllint xstlproc提供更多的处理时,XML::Twig特别适合用于perl脚本方法。

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

系统上很可能已经安装了python-lxml包。如果是这样,这是可能的,无需安装任何额外的包:

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

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