Existe um pacote lá fora, para o Ubuntu e / ou CentOS, que possui uma ferramenta de linha de comando que pode executar um liner XPath como foo //element@attribute filename.xml
ou foo //element@attribute < filename.xml
e retornar os resultados linha por linha?
Estou procurando por algo que me permita apenas apt-get install foo
ou yum install foo
então funcione imediatamente, sem invólucros ou outras adaptações necessárias.
Aqui estão alguns exemplos de coisas que se aproximam:
Nokogiri. Se eu escrever este wrapper, poderia chamá-lo da maneira descrita acima:
#!/usr/bin/ruby
require 'nokogiri'
Nokogiri::XML(STDIN).xpath(ARGV[0]).each do |row|
puts row
end
XML :: XPath. Trabalharia com este wrapper:
#!/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
from XML :: XPath retorna muito ruído -- NODE --
e attribute = "value"
.
xml_grep
from XML :: Twig não pode manipular expressões que não retornam elementos; portanto, não pode ser usado para extrair valores de atributos sem processamento adicional.
EDITAR:
echo cat //element/@attribute | xmllint --shell filename.xml
retorna ruído semelhante a xpath
.
xmllint --xpath //element/@attribute filename.xml
retorna attribute = "value"
.
xmllint --xpath 'string(//element/@attribute)' filename.xml
retorna o que eu quero, mas apenas para a primeira partida.
Para outra solução que quase satisfaça a pergunta, aqui está um XSLT que pode ser usado para avaliar expressões XPath arbitrárias (requer dyn: avalie 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>
Corra com xsltproc --stringparam pattern //element/@attribute --stringparam value . arbitrary-xpath.xslt filename.xml
.
fonte
xpath
está em STDERR e não em STDOUT.Respostas:
Você deve tentar estas ferramentas:
xmlstarlet
: pode editar, selecionar, transformar ... Não instalado por padrão, xpath1xmllint
: geralmente instalado por padrão comlibxml2-utils
, xpath1 (verifique meu wrapper para--xpath
ativar releases muito antigos e saída delimitada por novas linhas (v <2.9.9)xpath
: instalado via módulo do perlXML::XPath
, xpath1xml_grep
: instalado via módulo do perlXML::Twig
, xpath1 (uso limitado do xpath)xidel
: xpath3saxon-lint
: meu próprio projeto, invólucro da biblioteca Saxon-HE Java de @Michael Kay, xpath3xmllint
vem comlibxml2-utils
(pode ser usado como shell interativo com o--shell
switch)xmlstarlet
éxmlstarlet
.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 retroativa)Ex:
.
fonte
xmlstarlet sel -T -t -m '//element/@attribute' -v '.' -n filename.xml
faz exatamente o que eu quero!xmllint
do não suportam argumentos de linha de comando--xpath
, mas a maioria parece suportar--shell
. Saída mais suja, mas ainda útil em um encadernação.sel -t -m ... -v ...
exemplo desta página: arstechnica.com/information-technology/2005 / 11 / linux-20051115/2 , correspondendo a todos, exceto o último nó, e salvando esse para a expressão de valor como meu caso de uso, ainda não consigo obtê-lo, apenas recebo uma saída em branco ..Você também pode experimentar o meu Xidel . Ele não está em um pacote no repositório, mas você pode simplesmente fazer o download da página da Web (não possui dependências).
Possui uma sintaxe simples para esta tarefa:
E é uma das raras dessas ferramentas que oferece suporte ao XPath 2.
fonte
Um pacote que provavelmente está instalado em um sistema já é
python-lxml
. Nesse caso, isso é possível sem a instalação de nenhum pacote extra:fonte
stdin
. Isso elimina a necessidade de incluiropen()
eclose()
em uma linha já bastante longa. Para analisar um arquivo, basta executarpython -c "from lxml.etree import parse; from sys import stdin; print '\n'.join(parse(stdin).xpath('//element/@attribute'))" < my_file.xml
e deixar seu shell manipular a pesquisa, a abertura e o fechamento do arquivo.Na minha pesquisa para consultar arquivos maven pom.xml, corri através dessa pergunta. No entanto, eu tinha as seguintes limitações:
Eu tentei muitas das opções acima sem sucesso:
A solução que encontrei, que é estável, curta e funciona em muitas plataformas e que é madura, é a lib do rexml embutida no ruby:
O que me inspirou a encontrar este foi os seguintes artigos:
fonte
xmlstarlet
como a resposta aceita, porque se encaixa nos meus critérios mais amplos e é realmente legal . Mas provavelmente terei uso da sua solução de tempos em tempos.puts
vez dep
no comando Ruby.O Saxon fará isso não apenas no XPath 2.0, mas também no 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 você pode envolver facilmente em um script simples) é
ATUALIZAÇÃO 2020
O Saxon 10.0 inclui a ferramenta Gizmo, que pode ser usada interativamente ou em lote na linha de comando. Por exemplo
fonte
libsaxonb-java
, mas se eu executarsaxonb-xquery -qs://element/@attribute -s:filename.xml
eu receboSENR0001: Cannot serialize a free-standing attribute node
, mesmo problema que com o egxml_grep
.-qs
gostar deste:'-qs:declare namespace mets="http://www.loc.gov/METS/";/mets:mets/mets:dmdSec'
Você também pode estar interessado em xsh . Possui um modo interativo onde você pode fazer o que quiser com o documento:
fonte
cpan XML::XSH2
.cpan XML::XSH2
falha ao instalar qualquer coisa.A resposta de Clacke é ótima, mas acho que só funciona se sua fonte for XML bem formada, não HTML normal.
Portanto, faça o mesmo com o conteúdo normal da Web - documentos HTML que não são necessariamente XML bem formados:
E, em vez disso, use o html5lib (para garantir que você obtenha o mesmo comportamento de análise dos navegadores da Web - porque, como os analisadores de navegador, o html5lib está em conformidade com os requisitos de análise na especificação HTML).
fonte
Semelhante à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 arquivo pom.xml que contorna o fato de que os arquivos pom.xml normalmente não possuem um dtd ou namespace padrão, portanto, não pareça bem formado para libxml:
Testado no Mac e Linux e não requer a instalação de nenhum pacote extra.
fonte
lxml
nemxmllint
nem Ruby. No espírito do formato em minha própria resposta , escrevi comopython3 -c "from xml.etree.ElementTree import parse; from sys import stdin; print(parse(stdin).find('.//element[subelement=\"value\"]/othersubelement').text)" <<< "$variable_containing_xml"
em bash..getroot()
não parece necessário.Além do XML :: XSH e XML :: XSH2, existem alguns
grep
utilitários similares que sugam comoApp::xml_grep2
eXML::Twig
(que inclui emxml_grep
vez dexml_grep2
). Isso pode ser bastante útil ao trabalhar em arquivos XML grandes ou numerosos para oneliners ouMakefile
destinos rápidos .XML::Twig
é especialmente bom trabalhar com umaperl
abordagem de script quando você deseja um processamento um pouco mais do que o seu$SHELL
e axmllint
xstlproc
oferta.O esquema de numeração nos nomes dos aplicativos indica que as versões "2" são uma versão mais nova / posterior da essencialmente a mesma ferramenta que pode exigir versões posteriores de outros módulos (ou de
perl
si mesmo).fonte
xml_grep2 -t //element@attribute filename.xml
funciona e faz o que eu espero (xml_grep --root //element@attribute --text_only filename.xml
ainda não funciona, retorna um erro de "expressão não reconhecida"). Ótimo!xml_grep --pretty_print --root '//element[@attribute]' --text_only filename.xml
? Não tenho certeza do que está acontecendo lá ou do que o XPath diz sobre[]
este caso, mas cercar um@attribute
entre colchetes funciona paraxml_grep
exml_grep2
.//element/@attribute
, não//element@attribute
. Não é possível editá-lo aparentemente, mas deixá-lo lá em vez de excluir + substituir para não confundir o histórico desta discussão.//element[@attribute]
seleciona elementos do tipoelement
que possuem um atributoattribute
. Eu não quero o elemento, apenas o atributo.<element attribute='foo'/>
deve me darfoo
, não o total<element attribute='foo'/>
.--text_only
nesse contexto me fornece a string vazia no caso de um elemento como<element attribute='foo'/>
sem nó de texto dentro.É importante mencionar que o próprio nokogiri é fornecido com uma ferramenta de linha de comando, a qual deve ser instalada
gem install nokogiri
.Você pode achar útil esta postagem no blog .
fonte
Tentei alguns utilitários XPath da linha de comando e, quando percebi que estava gastando muito tempo pesquisando e descobrindo como eles funcionavam, escrevi o analisador XPath mais simples possível em Python, que fez o que eu precisava.
O script abaixo mostra o valor da sequência se a expressão XPath for avaliada como uma sequência ou mostra o subnó XML inteiro se o resultado for um nó:
Ele usa
lxml
- um analisador XML rápido, escrito em C, que não está incluído na biblioteca python padrão. Instale-o compip install lxml
. No Linux / OSX, pode ser necessário prefixar comsudo
.Uso:
O lxml também pode aceitar um URL como entrada:
Extraia o atributo url em um nó do gabinete, ou seja
<enclosure url="http:...""..>)
:Xpath no Google Chrome
Como uma observação lateral não relacionada: se por acaso você desejar executar uma expressão XPath na marcação de uma página da Web, poderá fazê-la diretamente nos devtools do Chrome: clique com o botão direito do mouse na página do Chrome> selecione Inspecionar e, em seguida, no DevTools console cole sua expressão XPath como
$x("//spam/eggs")
.Obter todos os autores nesta página:
fonte
lxml
já foi mencionado em duas outras respostas anos antes da sua.Aqui está um caso de uso xmlstarlet para extrair dados de elementos aninhados elem1, elem2 para uma linha de texto desse tipo de XML (mostrando também como lidar com espaços para nome):
A saída será
Nesse trecho, -m corresponde ao elem2 aninhado, -v gera valores de atributo (com expressões e endereçamento relativo), -o texto literal, -n adiciona uma nova linha:
Se forem necessários mais atributos do elem1, é possível fazer o seguinte (também mostrando a função concat ()):
Observe a complicação (desnecessária da IMO) com os espaços para nome (ns, declarados com -N), que quase me deixaram desistir do xpath e xmlstarlet e escrever um rápido conversor ad-hoc.
fonte
Meu script Python xgrep.py faz exatamente isso. Para procurar todos os atributos
attribute
dos elementoselement
nos arquivosfilename.xml ...
, você deve executá-lo da seguinte maneira:Existem várias opções para controlar a saída, como
-c
contar contagens,-i
recuar as peças correspondentes e-l
saída apenas de nomes de arquivos.O script não está disponível como um pacote Debian ou Ubuntu, mas todas as suas dependências são.
fonte
Como esse projeto é aparentemente relativamente novo, confira https://github.com/jeffbr13/xq , parece um invólucro
lxml
, mas é tudo o que você realmente precisa (e postou soluções ad hoc usando lxml em outras respostas também)fonte
Eu não estava feliz com as linhas de código Python para consultas em HTML XPath, então escrevi as minhas. Supõe que você instalou o
python-lxml
pacote ou executoupip install --user lxml
:Depois de ter, você pode usá-lo como neste exemplo:
fonte
Instale o banco de dados BaseX e use o "modo de linha de comando independente" desta maneira:
basex -i - //element@attribute < filename.xml
ou
basex -i filename.xml //element@attribute
A linguagem da consulta é na verdade XQuery (3.0), não XPath, mas como o XQuery é um superconjunto do XPath, você pode usar as consultas XPath sem perceber.
fonte