Como executar XPath one-liners da shell?
existe um pacote lá fora, Para Ubuntu e / ou CentOS, que tem uma ferramenta de linha de comando que pode executar um XPath de um liner como foo //element@attribute filename.xml
ou foo //element@attribute < filename.xml
e devolver os resultados linha por linha?
Nokogiri. Se eu escrever este papel eu poderia chamar o papel no modo descrito acima:
#!/usr/bin/ruby
require 'nokogiri'
Nokogiri::XML(STDIN).xpath(ARGV[0]).each do |row|
puts row
end
XML:: XPath. Trabalharia com esta embalagem.
#!/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
do XML:: XPath devolve muito ruído, -- NODE --
e attribute = "value"
.
xml_grep
a partir de XML::Twig não consegue lidar com expressões que não devolvem elementos, por isso não pode ser usado para extrair valores de atributos sem processamento adicional.
editar:
echo cat //element/@attribute | xmllint --shell filename.xml
devolve um ruído semelhante ao xpath
.
xmllint --xpath //element/@attribute filename.xml
devolve attribute = "value"
.
xmllint --xpath 'string(//element/@attribute)' filename.xml
devolve o que eu quero, mas só para o primeiro jogo.
para outra solução que quase satisfaça a questão, aqui está um XSLT que pode ser usado para avaliar expressões XPath arbitrárias (requer dyn: avaliar o suporte no processador 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>
corre com xsltproc --stringparam pattern //element/@attribute --stringparam value . arbitrary-xpath.xslt filename.xml
.
13 answers
Devias experimentar estas ferramentas:
-
xmlstarlet
: pode editar, seleccionar, transformar... Não está instalado por omissão, xpath1 -
xmllint
: frequentemente instalado por omissão comlibxml2
, xpath1( verifique a minha embalagem para ter as linhas novas delimitadas de saída -
xpath
: instalado através do módulo do perlXML::XPath
, xpath1 -
xml_grep
: instalado através do módulo do perlXML::Twig
, xpath1 (utilização limitada do xpath) -
xidel
: xpath3 - O meu próprio projecto, embrulhado. @ Michael Kay's Saxon-HE Java library, xpath3
xmllint
vem com libxml2-utils
(pode ser usado como shell interactivo com o interruptor --shell
)
xmlstarlet
riz[1]}.
xpath
vem com o módulo do perlXML::Xpath
xml_grep
vem com o módulo do perlXML::Twig
xidel
é xidel
saxon-lint
usando SaxonHE 9.6 ,XPath 3.x (+compatibilidade retroactiva)
Ex:
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
.
Um pacote que é muito provável ser instalado num sistema já é python-lxml
. Em caso afirmativo, isto é possível sem a instalação de qualquer pacote extra:
python -c "from lxml.etree import parse; from sys import stdin; print '\n'.join(parse(stdin).xpath('//element/@attribute'))"
Também podes experimentar o meuXidel . Ele não está em um pacote no repositório, mas você pode apenas baixá-lo a partir da página web (ele não tem dependências).
Tem uma sintaxe simples para esta tarefa:
xidel filename.xml -e '//element/@attribute'
E é uma das raras ferramentas que suporta XPath 2.
Saxon fará isso não só para XPath 2.0, mas também para XQuery 1.0 e (na versão comercial) 3.0. Ele não vem como um pacote Linux, mas como um arquivo jar. A sintaxe (que pode facilmente envolver num programa simples) é
java net.sf.saxon.Query -s:source.xml -qs://element/attribute
- Tenho de atravessar a plataforma.
- deve existir em todas as principais distribuições linux sem qualquer instalação adicional de módulos
- deve lidar com ficheiros xml complexos como o Maven pom.ficheiros xml
- sintaxe simples
Tentei muitos dos acima sem sucesso:
- python lxml.o etree não faz parte do python padrão. distribuição
- xml.etree é mas não lida com o complexo Maven pom.ficheiros xml bem, não foram suficientemente enterrados
- xml python.etree não lida com maven pom.ficheiros xml por razão desconhecida
- o xmllint também não funciona, o core dumps frequentemente no ubuntu 12.04 "xmllint: usando a libxml versão 20708"
A única solução que encontrei que é estável, curta e que funciona em muitas plataformas e que é madura é o rexml lib builtin em ruby:
ruby -r rexml/document -e 'include REXML;
p XPath.first(Document.new($stdin), "/project/version/text()")' < pom.xml
O que foi? inspirou-me a descobrir que estes eram os seguintes artigos:
Também pode estar interessado em xsh. Ele possui um modo interativo onde você pode fazer o que quiser com o documento:
open 1.xml ;
ls //element/@id ;
for //p[@class="first"] echo text() ;
A resposta de Clacke é óptima, mas acho que só funciona se a sua fonte FOR XML bem formada, Não HTML normal.
De modo a fazer o mesmo para o conteúdo web normal-Docs HTML que não são necessariamente bem formados XML:
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'))"
E, em vez disso, usar html5lib (para garantir que você tem o mesmo comportamento de análise que os navegadores Web-porque, como os navegadores, html5lib está em conformidade com os requisitos de análise no HTML spec).
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'))
Além de XML::XSH e XML::XSH2 há alguns grep
-como utilitários de chupar como App::xml_grep2
e XML::Twig
(o que inclui xml_grep
em vez de xml_grep2
). Estes podem ser bastante úteis ao trabalhar em um grande ou numerosos arquivos XML para oneliners rápidos ou alvos Makefile
. XML::Twig
é especialmente bom trabalhar com uma abordagem de scripting perl
quando você quer um pouco mais de processamento do que o seu $SHELL
e xmllint
xstlproc
oferta.
O sistema de numeração nos nomes das aplicações indica que as versões" 2 " são versões mais recentes/posteriores essencialmente da mesma ferramenta que pode exigir versões posteriores de outros módulos (ou do próprio perl
).
Similar às respostas de Mike e clacke, aqui está o python one-liner (usando python > = 2.5) para obter a versão de compilação de um pom.ficheiro xml que contorna o facto do pom.os ficheiros xml não têm normalmente um dtd ou um espaço de nomes predefinido, por isso não aparecem bem formados na 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)"
Testado em Mac e Linux, e não requer nenhum pacote extra para ser instalado.
É preciso mencionar que o nokogiri em si navega com uma ferramenta de linha de comando, que deve ser instalada com {[[0]}.
Você pode achar este post útil.
O programa abaixo mostra o valor do texto se a expressão XPath for avaliada para um texto, ou mostra todo o subnodo XML se o resultado for um nó:
#!/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))
Ele usa lxml
- um analisador XML rápido escrito em C que não está incluído na norma biblioteca python. Instale-o com pip install lxml
. No Linux / OSX poderá ser necessário o prefixo com sudo
.
Utilização:
python xmlcat.py file.xml "//mynode"
O Lxml também pode aceitar um URL como entrada:
python xmlcat.py http://example.com/file.xml "//mynode"
Extrair o atributo url sob um nó de confinamento, i.e. <enclosure url="http:...""..>)
:
python xmlcat.py xmlcat.py file.xml "//enclosure/@url"
Xpath no Google Chrome
Como uma nota lateral não relacionada: se por acaso quiser executar uma expressão de XPath contra a marcação de uma página web, então poderá fazê-lo directamente a partir dos devtools cromados: carregue com o botão direito na página no Chrome > seleccione a opção inspeccionar e, em seguida, na consola DevTools cole a sua expressão de XPath como $x("//spam/eggs")
.
Põe todos os autores nesta página:
$x("//*[@class='user-details']/a/text()")
, uma vez que este projecto é, aparentemente, bastante novo, confira https://github.com/jeffbr13/xq , parece ser um wrapper lxml
, mas isso é tudo que você realmente precisa (e postado soluções ad hoc, usando twofish, tiger em outras respostas)
Aqui está um caso de uso de xmlstarlet para extrair dados de elementos aninhados elem1, elem2 para uma linha de texto deste tipo de XML (também mostrando como lidar com espaços de nomes):
<?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>
A saída será
0.586 10.586 cue-in outro
Neste excerto, - m corresponde aos valores dos atributos dos resultados aninhados (com expressões e endereçamento relativo), -o texto literal, -n adiciona uma nova linha:
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
Se são necessários mais atributos do elem1, pode-se fazê-lo assim (também mostrando o concat () função):
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
Note a complicação (desnecessária) com espaços de nomes (ns, declarado com-N), que me fez quase desistir do xpath e do xmlstarlet, e escrever um rápido conversor ad-hoc.