GNU/Linux >> Tutoriales Linux >  >> Linux

Cómo analizar XML y quitar etiquetas usando ejemplos de XPATH en Linux (Cómo combinar varios comandos usando PIPE en Linux)

Este tutorial explica el proceso de creación de comandos útiles de varias partes pieza por pieza.

Para construir comandos complejos en la terminal, necesitamos entender la tubería. La canalización consiste básicamente en tomar la salida de un comando y enviarla a otro comando como entrada. Esto se hace con el | (tubería) símbolo.

El mes pasado, un pequeño proyecto me obligó a leer repetidamente archivos XML similares para proporcionar datos de prueba para otro programa. Tendría que hacerlo con tanta frecuencia que sería molesto tener que descargar, guardar, analizar y repetir. Los requisitos básicos eran:

  1. Obtener XML de URL
  2. Analice el XML y seleccione solo dos atributos de todos los elementos
  3. Elimine las etiquetas para que solo quede el contenido
  4. Enviar a salida estándar

1. Demostrar que la línea de comandos puede analizar XML

Había usado la biblioteca de Ruby REXML::Xpath para un script el año pasado y recordé que había una versión de Perl disponible en la línea de comandos. Puedes instalarlo con CPAN:

$ cpan XML::XPath

Usemos un archivo de empleado de muestra para jugar con la idea. Abra este archivo employee.xml en un navegador, ábralo en un navegador y guárdelo como employee.xml.

Ahora tenemos nuestro comando xpath y un archivo con el que jugar.

Pruébelo con una ruta simple:

$ xpath employees.xml '/DIRECTORY/EMPLOYEE/FIRST_NAME'
­­ NODE ­­
<FIRST_NAME>Steven</FIRST_NAME>­­ NODE ­­
<FIRST_NAME>Susan</FIRST_NAME>­­ NODE ­­
<FIRST_NAME>Marigold</FIRST_NAME>­­ NODE ­­
...
<FIRST_NAME>Sunny</FIRST_NAME>­­ NODE ­­
<FIRST_NAME>Flo</FIRST_NAME>

¡Excelente! Imprime el atributo FIRST_NAME de cada /EMPLOYEE en la ruta seleccionada. Pero, ¿cómo seleccionamos múltiples elementos XPath? Mirando la sintaxis de XPath, vemos una manera. Combinando las expresiones XPath con el | carácter, creamos una expresión OR.

$ xpath employees.xml '/DIRECTORY/EMPLOYEE/ FIRST_NAME | /DIRECTORY/EMPLOYEE/LAST_NAME'
--­­ NODE ­­--
<FIRST_NAME>Steven</FIRST_NAME>­­-- NODE ­­--
<LAST_NAME>Sanguini</LAST_NAME>­--­ NODE ­--­
<FIRST_NAME>Susan</FIRST_NAME>­­-- NODE ­­--
<LAST_NAME>Aquilegia</LAST_NAME>--­­ NODE --­­
...
<FIRST_NAME>Flo</FIRST_NAME>­­-- NODE ­­--
<LAST_NAME>Lobalessia</LAST_NAME>

Aviso, aquí | se interpreta como el operador OR y no como una redirección de salida.

Además, en esta declaración, estamos seleccionando tanto X como Y. ¿Por qué OR selecciona ambos? Evalúa cada nodo en el documento XML por separado y si el nodo es A o B, pasa la evaluación y pasa a la salida.

2. Descargar XML y enviar a STDOUT

Este próximo paso en realidad vendrá antes en la línea de comando y lo construiremos por separado. Prefiero construir las entradas de comando más difíciles o "no puedes hacer eso" primero como prueba de concepto. No tendría sentido hacer que la línea de comandos circundante funcione si el primer paso no funciona.

cURL es un comando poderoso para las interacciones HTTP. Estos ejemplos de rizos te ayudarán a comenzar en la dirección correcta.

Especificamos una ubicación, siguiendo las redirecciones si es necesario. Para ello utiliza esta opción:-L ‘https://www.thegeekstuff.com/scripts/employees.xml’

Desactivamos la salida de información de cURL. Y especifique el protocolo GET. Para ello, utilice esta opción:-s G

Así que probemos nuestro comando en la URL del archivo que descargamos anteriormente:

$ curl -­s -­G -­L ' https://www.thegeekstuff.com/scripts/employees.xml'
<?xml version="1.0" encoding="UTF­8"?>
<DIRECTORY>
<EMPLOYEE>
<FIRST_NAME>Steven</FIRST_NAME>
<LAST_NAME>Sanguini</LAST_NAME>
<STORE_NUMBER>4</STORE_NUMBER>
<SHIFT>FIRST</SHIFT>
<AUM>$2.44</AUM>
<ID>031599</ID>
</EMPLOYEE>
..

Por defecto es STDOUT. Lo cual es bueno ya que ahora lo redirigiremos a XPath eliminando el argumento del archivo:

$ curl ­-s -­G -­L ' https://www.thegeekstuff.com/scripts/employees.xml' | xpath \
'/DIRECTORY/EMPLOYEE/LAST_NAME | /DIRECTORY/EMPLOYEE/ID'
­--­ NODE ­­--
<LAST_NAME>Sanguini</LAST_NAME>­­-- NODE ­­--
<ID>031599</ID>­­ NODE ­­
<LAST_NAME>Aquilegia</LAST_NAME>­­-- NODE -- ­­
<ID>030699</ID>­­-- NODE ­­--
...
<LAST_NAME>Lobalessia</LAST_NAME>--­­ NODE --­­
<ID>022299</ID>

Esto produce la salida esperada. ¡Excelente! No estoy seguro de por qué, pero XPath envía 'NODE' al error estándar (STDERR). Pero veremos una posible razón más adelante.

3. Eliminar etiquetas XML

Ahora necesitamos poder eliminar esas etiquetas y obtener solo el contenido. Sed es la mejor herramienta para realizar sustituciones de expresiones regulares sobre la marcha. Aprender REGEX está fuera del alcance de este artículo.

Consulte nuestra serie de artículos sobre expresiones regulares de Python para obtener más información.

Cuando hago comandos complicados con múltiples argumentos y banderas, encuentro que es mejor trabajar con un ejemplo simple hasta que lo entiendo bien, luego lo pego en contexto con los argumentos reales. Canalizamos una cadena simple a sed para una sustitución de prueba. Sed funciona en STDIN de forma predeterminada.

$ echo "This<strong> is </strong>a test." | sed ­-re 's/i//g'
Ths<strong> s </strong>a test.

Está bien. Eso funciona. Ahora reescriba la búsqueda para reemplazar una etiqueta.

$ echo "This<strong> is </strong>a test." | sed ­-re 's/<\w+>//g'
This is </strong>a test.

Bien. Eliminemos la etiqueta de cierre agregando '/' escapada con el prefijo '\' y hecha opcional con el sufijo '?'

$ echo "This<strong> is </strong>a test." | sed ­re 's/<\/?\w+>//g'
This is a test.

Perfecto. Exactamente lo que esperábamos.

4. Poniendo todo junto

Ahora que hemos creado las partes individuales de nuestro comando, las pegamos juntas en orden lógico unidas por | .

curl ­-s -­G -­L ' https://www.thegeekstuff.com/scripts/employees.xml' | \
xpath '/DIRECTORY/EMPLOYEE/LAST_NAME | /DIRECTORY/EMPLOYEE/ID ' | \
sed ­-re 's/<\/?\w+>//g'

Salida:

Found 72 nodes:
--­­ NODE -- ­­
­--­ NODE ­­--
...
Sanguini031599Aquilegia030699...

¡UH oh! Tal vez por eso los marcadores 'NODE' están ahí. Si canalizamos esto a un archivo, el texto NODO no sigue. Se envían al error estándar (STDERR), pero podemos redirigir a STDOUT usando `2>&1` (explicación) y usar el sustituto de sed `sed re 's/ NODE //g'` para eliminar de la misma manera que el etiquetas.

curl -­s -­G -­L 'https://www.thegeekstuff.com/scripts/employees.xml' | \
xpath '/DIRECTORY/EMPLOYEE/LAST_NAME | /DIRECTORY/EMPLOYEE/ID '
2>&1| sed -­re 's/­--­NODE--­­//g' | sed -­re 's/<\/?\w+>//g'

Salida:

Found 72 nodes:
Sanguini
031599
Aquilegia
030699
...
Lobalessia
022299

Perfecto. Ahora, mientras trabajo en mi proyecto, puedo obtener rápidamente datos de muestra de archivos XML en la web a STDOUT sin la molestia de guardar archivos o ejecutar algún software complicado. Incluso podemos canalizar esto a `tail –n+3` para cortar esas dos primeras líneas de respuesta.

Este artículo es solo un ejemplo de varias cosas que puede hacer si aprende a combinar varios comandos mediante la tubería.


Linux
  1. Cómo usar los comandos 'cat' y 'tac' con ejemplos en Linux

  2. Cómo deshabilitar los comandos de apagado y reinicio en Linux

  3. Cómo cambiar la prioridad del proceso usando los ejemplos de Linux Nice y Renice

  4. Cómo agregar múltiples rutas en Linux usando ejemplos de comandos ip

  5. ¿Cómo analizar XML usando shellscript?

Cómo ejecutar comandos desde la entrada estándar usando Tee y Xargs en Linux

Cómo mostrar hojas de trucos de comandos de Linux usando, por ejemplo

Cómo usar los comandos Pbcopy y Pbpaste en Linux

Cómo hacer una copia de seguridad de archivos y directorios usando Rsync en Linux

Cómo ejecutar aplicaciones de Linux en Windows 10 y 11 usando WSL

Cómo ejecutar múltiples comandos de Linux en un solo comando