Manipulación de línea de comando XML (script de shell)

9

¿Cómo manipular XML desde la línea de comandos en el script de shell?

Hay muchos comandos para manipular datos tabulares, sustituir variables de entorno o reemplazar fragmentos de texto con expresiones regulares, pero no he encontrado nada para XML.

Mi script de compilación necesita insertar una etiqueta con contenido dentro de la etiqueta principal del documento xml, y me resulta excesivo instalar java, perl o python en el sistema operativo para ese propósito (mis scripts se realizan en gitlab con imágenes de acoplador, por lo que mi trabajo con herramientas disponibles en maven: la imagen 3.5-jdk-8 sería un sueño).

No quiero manipular XML con sed, aunque en mi script de compilación funcionaría, porque es malo .

Ejemplo: tengo el siguiente xml:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>  
  <!-- a lot of other tags-->
</project>  

Y quiero insertar el siguiente bloque:

<distributionManagement>
    <repository>
        <id>private-releases</id>
        <url>https://my.private.server.com/nexus/repository/maven-releases/</url>
    </repository>
</distributionManagement>

dentro de la etiqueta del proyecto (y no importa si estará al principio o al final).

9ilsdx 9rvj 0lo
fuente
publique su entrada xml y salida esperada
RomanPerekhrest
Entonces, ¿los requisitos específicos son para un analizador XML que se puede invocar desde la línea de comandos que no está implementado en ninguno de los principales lenguajes de secuencias de comandos, sino una utilidad independiente C o C ++ (u otra compilación)?
Kusalananda
@Kusalanda He especificado que estoy ejecutando scipts dentro de los contenedores de la ventana acoplable, por lo que es muy importante para mí agregar lo menos posible a la imagen de la ventana acoplable.
9ilsdx 9rvj 0lo
Si tienes una imagen con Maven y un JDK, Java me parece la mejor opción ... ¿Por qué consideras que Java es un peso pesado en este caso?
Daniel Pryden
Probablemente valga la pena hacer esta pregunta sobre Stack Overflow y etiquetar con maven: sospecho que hay una mejor manera de hacer lo que estás tratando de hacer dentro de Maven.
Daniel Pryden

Respuestas:

10

XMLStarlet ( http://xmlstar.sourceforge.net/overview.php ) está escrito en C y usa libxml2y libxslt.

Dado el documento XML

<?xml version="1.0"?>
<root>
  <tag>data</tag>
</root>

rootse puede insertar un subnodo en

xml ed -s '/root' -t elem -n 'newtag' -v 'newdata' file.xml

que produce

<?xml version="1.0"?>
<root>
  <tag>data</tag>
  <newtag>newdata</newtag>
</root>

Insertar muchas cosas (usando el original file.xmlen la parte superior aquí):

xml ed -s '/root' -t elem -n 'newtag' \
       -s '/root/newtag' -t elem -n 'subtag' -v 'subdata' file.xml

Esto produce

<?xml version="1.0"?>
<root>
  <tag>data</tag>
  <newtag>
    <subtag>subdata</subtag>
  </newtag>
</root>

Para el ejemplo en la pregunta:

xml ed -N x="http://maven.apache.org/POM/4.0.0" \
       -s '/x:project' -t elem -n 'distributionManagement' \
       -s '/x:project/distributionManagement' -t elem -n 'repository' \
       -s '/x:project/distributionManagement/repository' -t elem -n 'id' \
         -v 'private-releases' \
       -s '/x:project/distributionManagement/repository' -t elem -n 'url' \
         -v 'https://my.private.server.com/nexus/repository/maven-releases/' \
    file.xml

Resultado:

<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>
  <!-- a lot of other tags-->
  <distributionManagement>
    <repository>
      <id>private-releases</id>
      <url>https://my.private.server.com/nexus/repository/maven-releases/</url>
    </repository>
  </distributionManagement>
</project>

Insertar un archivo XML previamente preparado en una ubicación en el XML:

Suponiendo que el XML original de la pregunta está dentro file.xmly los bits adicionales que deberían ir en el nuevo distributinManagementnodo están dentro new.xml(pero no la etiqueta del nodo en sí), se podría hacer lo siguiente para insertar new.xmlen el nodo raíz:

xml ed -N x="http://maven.apache.org/POM/4.0.0" \
       -s '/x:project' -t elem -n 'distributionManagement' \
       -v "$(<new.xml)" file.xml | xml unesc | xml fo

XMLStarlet escapará automáticamente de los datos que necesitan escapar, como los caracteres <y >. El xml unescbit desempaqueta los datos insertados (en realidad desempaqueta todo el documento, lo que puede o no ser un problema) y xml foreformatea el documento XML resultante.

El resultado es

<?xml version="1.0"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>
  <!-- a lot of other tags-->
  <distributionManagement>
    <repository>
      <id>private-releases</id>
      <url>https://my.private.server.com/nexus/repository/maven-releases/</url>
    </repository>
  </distributionManagement>
</project>

Me inquieta un poco hacerlo de esta manera, "pero funciona".

Consulte también esta pregunta relacionada sobre StackOverflow: /programming/29298507/xmlstarlet-xinclude-xslt

Kusalananda
fuente
Parece interesante, aunque para insertar más de una etiqueta, la sintaxis es bastante larga. Solo que en ubuntu se llama 'xmlstarlet'. ¿Es posible insertar el contenido de otro archivo como etiqueta, suponiendo que el contenido sea un xml válido?
9ilsdx 9rvj 0lo
@ 9ilsdx9rvj0lo Ver respuesta actualizada.
Kusalananda
"En realidad, desempaqueta todo el documento, lo que puede o no ser un problema". Sí problema masivo, todos los & amp; existentes se descodificaron, lo que provocó que XML dejara de ser válido :(
robar
1

Me resulta excesivo instalar java, perl o python en el sistema operativo para ese propósito (mis scripts se realizan en gitlab con imágenes de acoplador, por lo que hacer mi trabajo con las herramientas disponibles en maven: la imagen 3.5-jdk-8 sería un sueño).

probablemente todavía sea excesivo, pero si solo le preocupa el tamaño del contenedor, podría usar un lenguaje muy liviano como Lua o Guile.

de los documentos de Lua:

Agregar Lua a una aplicación no lo hincha. El tarball para Lua 5.3.4, que contiene código fuente y documentación, toma 297K comprimidos y 1.1M sin comprimir. La fuente contiene alrededor de 24000 líneas de C. En Linux de 64 bits, el intérprete de Lua construido con todas las bibliotecas estándar de Lua toma 246K y la biblioteca de Lua toma 421K.

bruno cuconato
fuente
Vale la pena considerar simplemente agregar LUA al contenedor maven, gracias por la sugerencia.
9ilsdx 9rvj 0lo