2010-02-08 21 views
31

Tengo un archivo XML con el contenido:La extracción de datos desde un simple archivo XML

<?xml version="1.0" encoding="utf-8"?> 
<job xmlns="http://www.sample.com/">programming</job> 

necesito una manera de extraer lo que está en los <job..></job> etiquetas, PROGRAMACIÓN en este caso. Esto debe hacerse en el prompt del comando de Linux, usando grep/sed/awk.

+0

Si el archivo XML contenía esto: < xmlns = trabajo "http://www.sample.com/" > Tom & Jerry sería desea que el resultado tenga XML escape que deja solo: Tom & Jerry o ¿le gustaría que el escape a ser deshecho, como un analizador XML haría: Tom & Jerry Si es lo último, lo siento, no sé cómo hacer eso con las herramientas de texto de Unix. –

+0

@Paul 's/&/\ &/g', lo mismo para' " 'etc., por supuesto que no se generalizará para entidades definidas por el usuario, etc. – 13ren

Respuesta

51

¿De verdad tienen que uso sólo aquellas herramientas? No están diseñados para el procesamiento de XML, y aunque es posible conseguir algo que funciona bien la mayor parte del tiempo, se producirá un error en casos extremos, como la codificación, saltos de línea, etc.

recomiendo xml_grep:

xml_grep 'job' jobs.xml --text_only 

que da la salida:

programming 

en Ubuntu/Debian, xml_grep es en el paquete XML-ramita-herramientas.

+0

Las instrucciones de instalación estrictas serían geniales para xml_grep –

+0

sudo apt-get install xml-twig-tools – FredFury

0

¿Qué tal:

cat a.xml | grep '<job' | cut -d '>' -f 2 | cut -d '<' -f 1 
+3

UUOC. 'grep ' ghostdog74

+0

@ghost * pero pero, creo que es más limpio/más agradable/¡no tanto desperdicio/mi derecho a perder procesos! * Http://partmaps.org/era/unix/award.html#cat (en realidad, creo que es más fácil editar el nombre del archivo, porque está más cerca del inicio) – 13ren

+3

Si usa ' Thor

11
grep '<job' file_name | cut -f2 -d">"|cut -f1 -d"<" 
+0

solo que falla si las etiquetas están en líneas separadas – ghostdog74

+7

Hay alrededor de una docena de formas distintas en que XML bien formado puede hacer que falle. –

6

simplemente use awk, no necesita otras herramientas externas. A continuación, funciona si las etiquetas deseadas aparecen en multitine.

$ cat file 
test 
<job xmlns="http://www.sample.com/">programming</job> 
<job xmlns="http://www.sample.com/"> 
programming</job> 

$ awk -vRS="</job>" '{gsub(/.*<job.*>/,"");print}' file 
programming 

programming 
+0

'' es válido, pero su script no lo reconoce. '

+3

Existe una cantidad significativa de herramientas diferentes que usan notación XPath estándar para extraer información de XML, '' xmlstarlet' es solo una. Otros incluyen 'xmllint',' xpath', etc. Consulte http://stackoverflow.com/questions/15461737/how-to-execute-xpath-one-liners-from-shell – tripleee

8

Por favor, no use la línea y el análisis basado en XML de expresiones regulares. Es una mala idea Puede tener XML semánticamente idéntico con diferentes formatos, y el análisis basado en expresiones y líneas simplemente no lo puede hacer.

Cosas como etiquetas unarios y el ajuste de línea variable de estos fragmentos - 'decir' lo mismo:

<root> 
    <sometag val1="fish" val2="carrot" val3="narf"></sometag> 
</root> 


<root> 
    <sometag 
     val1="fish" 
     val2="carrot" 
     val3="narf"></sometag> 
</root> 

<root 
><sometag 
val1="fish" 
val2="carrot" 
val3="narf" 
></sometag></root> 

<root><sometag val1="fish" val2="carrot" val3="narf"/></root> 

Esperamos que esto hace que sea claro por qué haciendo un analizador basado en expresiones regulares/línea es difícil? Afortunadamente, no es necesario. Muchos lenguajes de scripting tienen al menos una, a veces más opciones de analizador.

Como un cartel anterior ha hecho alusión a - xml_grep está disponible. Esa es en realidad una herramienta basada en la biblioteca perl XML::Twig. Sin embargo, lo que hace es usar 'xpath expressions' para encontrar algo, y diferencia entre la estructura del documento, los atributos y el 'contenido'.

E.g.:

xml_grep 'job' jobs.xml --text_only 

Sin embargo, en interés de la toma de mejores respuestas, aquí hay un par de ejemplos de 'hágalo usted mismo' basado en los datos de origen:

Primera forma:

Uso twig handlers que las capturas de los elementos de un tipo particular y actúa sobre ellos. La ventaja de hacerlo de esta manera es que analiza el XML 'sobre la marcha', y le permite modificarlo en el vuelo si es necesario. Esto es particularmente útil para descartar XML 'procesada' cuando se trabaja con archivos de gran tamaño, utilizando purge o flush:

#!/usr/bin/perl 

use strict; 
use warnings; 

use XML::Twig; 

XML::Twig->new(
    twig_handlers => { 
     'job' => sub { print $_ ->text } 
    } 
    )->parse(<>); 

que utilizará para tomar <> entrada (hilo en, o especificado a través de comandos ./myscript somefile.xml) y el proceso de it - cada elemento job, extraerá e imprimirá cualquier texto asociado. (Es posible que desee print $_ -> text,"\n" para insertar un salto de línea).

Debido a que se emparejan en los elementos de trabajo '', también igualaremos en elementos de trabajo anidadas:

<job>programming 
    <job>anotherjob</job> 
</job> 

coincidirán dos veces, pero algunos de imprimir la salida dos veces también. Sin embargo, puede, si lo prefiere, hacer coincidir el /job. Útil: esto te permite, por ejemplo, imprima y elimine un elemento o copie y pegue uno modificando la estructura XML.

alternativa - Analiza en primer lugar, y 'impresión' basado en la estructura:

my $twig = XML::Twig->new()->parse(<>); 
print $twig -> root -> text; 

Como job es el elemento raíz, todo lo que necesitamos hacer es imprimir el texto de la misma.

Pero podemos ser un poco más exigente, y buscar job o /job y de impresión que específicamente en su lugar:

my $twig = XML::Twig->new()->parse(<>); 
print $twig -> findnodes('/job',0)->text; 

puede utilizar la opción XML::Twig s pretty_print volver a formatear el XML también:

XML::Twig->new('pretty_print' => 'indented_a')->parse(<>) -> print; 

Hay una variedad de opciones de formato de salida, pero para XML más simple (como el suyo) la mayoría se verá bastante similar.

0

Un poco tarde para el espectáculo.

xmlcutty recorta los nodos del XML:

$ cat file.xml 
<?xml version="1.0" encoding="utf-8"?> 
<job xmlns="http://www.sample.com/">programming</job> 
<job xmlns="http://www.sample.com/">designing</job> 
<job xmlns="http://www.sample.com/">managing</job> 
<job xmlns="http://www.sample.com/">teaching</job> 

Los nombres de los argumentos path la ruta al elemento que desea cortar. En este caso, puesto que no estamos interesados ​​en las etiquetas de todo, cambiar el nombre del tag para \n, por lo que tenemos una buena lista:

$ xmlcutty -path /job -rename '\n' file.xml 
programming 
designing 
managing 
teaching 

Tenga en cuenta, que el XML no era válido, para empezar (sin raíz elemento). xmlcutty también puede funcionar con XML ligeramente roto.

2

Usando sed comando:

Ejemplo:

$ cat file.xml 
<note> 
     <to>Tove</to> 
       <from>Jani</from> 
       <heading>Reminder</heading> 
     <body>Don't forget me this weekend!</body> 
</note> 

$ cat file.xml | sed -ne '/<heading>/s#\s*<[^>]*>\s*##gp' 
Reminder 

Explicación:

cat file.xml | sed -ne '/<pattern_to_find>/s#\s*<[^>]*>\s*##gp'

n - suprimir la impresión de todas las líneas
e - Script

/<pattern_to_find>/ - encuentra líneas que contienen patrón especificado lo que podría ser, por ejemplo, <heading>

siguiente es parte sustitución s///p que elimina todo excepto valor deseado donde / se sustituye con # para una mejor legibilidad:

s#\s*<[^>]*>\s*##gp
\s* - incluye espacios en blanco si existe (mismo al final)
<[^>]*> representa <xml_tag> como causa alternativa no codiciosa <.*?> no funciona para sed
g - sustituye todo, por ejemplo xml cierre </xml_tag> etiqueta

Cuestiones relacionadas