2010-04-01 12 views
18

Tengo un archivo xml que quiero configurar usando un script bash. Por ejemplo, si tuviera esta xml:Agregar/eliminar etiquetas xml usando un script bash

<a> 

    <b> 
    <bb> 
     <yyy> 
      Bla 
     </yyy> 
    </bb> 
    </b> 

    <c> 
    <cc> 
     Something 
    </cc> 
    </c> 

    <d> 
    bla 
    </d> 
</a> 

(información confidencial retirada)

me gustaría escribir un script bash que eliminará la sección <b> (o comentario) pero mantener el resto de la xml intacto Soy bastante nuevo, es todo el guión. Me preguntaba si alguien podría darme una pista sobre lo que debería investigar.

Pensaba que se podía usar sed excepto sed es un editor de línea. Creo que sería fácil de quitar las etiquetas <b> sin embargo estoy seguro si SED sería capaz de eliminar todo el texto entre los<b> etiquetas.

que también tendrá que escribir un script para volver a agregar la sección eliminada.

+2

tendría que desaconsejan el uso de bash/sed/awk/etc. para este tipo de cosas y recomendamos usar Python, Ruby o Perl. –

Respuesta

22

Esto no sería difícil de hacer en sed, ya que sed también funciona en rangos.

probar este (suponiendo xml está en una foo.xml nombre del archivo):

sed -i '/<b>/,/<\/b>/d' foo.xml 

-i escribirá el cambio en el archivo original (-i uso.bak, para mantener una copia de seguridad del original)

Este comando sed realizará una d acción (eliminar) en todas las líneas especificado en el rango

# all of the lines between a line that matches <b> 
# and the next line that matches <\/b>, inclusive 
/<b>/,/<\/b>/ 

Así, en la llanura Inglés, este comando eliminar todas las líneas entre e incluyendo la línea con <b> y la línea con </b >

Si prefiere comentar las líneas, intenta uno de estos:

# block comment 
sed -i 's/<b>/<!-- <b>/; s/<\/b>/<\/b> -->/' foo.xml 

# comment out every line in the range 
sed -i '/<b>/,/<\/b>/s/.*/<!-- & -->/' foo.xml 
+4

Esto funciona si no hay nada de importancia en '' anterior en la misma línea, y nada de importancia después de '' en la misma línea, es decir, no t trabajo para XML en general, pero puede funcionar para el caso especial del solicitante. – Arkku

+0

El comentario de bloque (reemplazando con

+0

Esa consideración aumenta mi percepción de que XML es excesivo para los archivos de configuración;) – a1an

9

puede utilizar un XSLT como este que es transformar una identidad modificada. Copia todos los contenidos de forma predeterminada, y cuenta con una plantilla vacía para b que no hace nada (eliminando efectivamente de salida):

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 

<!--Identity transform copies all items by default --> 
<xsl:template match="@* | node()"> 
    <xsl:copy> 
     <xsl:apply-templates select="@*|node()"/> 
    </xsl:copy> 
</xsl:template> 

<!--Empty template to match on b elements and prevent it from being copied to output --> 
<xsl:template match="b"/> 

</xsl:stylesheet> 

crear un script bash que ejecuta la transformada using Java and the Xalan commandline utility así:

java org.apache.xalan.xslt.Process -IN foo.xml -XSL foo.xsl -OUT foo.out

El resultado es este:

<?xml version="1.0" encoding="UTF-16"?><a><c><cc> 
     Something 
    </cc></c><d> 
    bla 
    </d></a> 

EDIT: si usted prefiere tener la b comentada, para que sea más fácil de poner de nuevo, a continuación, utilizar esta hoja de estilo:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 

    <!--Identity transform copies all items by default --> 
    <xsl:template match="@* | node()"> 
     <xsl:copy> 
      <xsl:apply-templates select="@*|node()"/> 
     </xsl:copy> 
    </xsl:template> 

    <!--Match on b element, wrap in a comment and construct text representing XML structure by applying templates in "comment" mode --> 
    <xsl:template match="b"> 
     <xsl:comment> 
      <xsl:apply-templates select="self::*" mode="comment" /> 
     </xsl:comment> 
    </xsl:template> 

    <xsl:template match="*" mode="comment"> 
     <xsl:value-of select="'&lt;'"/> 
      <xsl:value-of select="name()"/> 
     <xsl:value-of select="'&gt;'"/> 
      <xsl:apply-templates select="@*|node()" mode="comment" /> 
     <xsl:value-of select="'&lt;/'"/> 
      <xsl:value-of select="name()"/> 
     <xsl:value-of select="'&gt;'"/> 
    </xsl:template> 

    <xsl:template match="text()" mode="comment"> 
     <xsl:value-of select="."/> 
    </xsl:template> 

    <xsl:template match="@*" mode="comment"> 
     <xsl:value-of select="name()"/> 
     <xsl:text>="</xsl:text> 
     <xsl:value-of select="."/> 
     <xsl:text>" </xsl:text> 
    </xsl:template> 

</xsl:stylesheet> 

Se produce esta salida:

<?xml version="1.0" encoding="UTF-16"?><a><!--<b><bb><yyy> 
      Bla 
     </yyy></bb></b>--><c><cc> 
     Something 
    </cc></c><d> 
    bla 
    </d></a> 
3

@OP, se puede utilizar por ejemplo awk

$ cat file 
<a>        

some text before <b> 
    <bb> 
     <yyy> 
      Bla 
     </yyy> 
    </bb> 
    </b> some text after 

    <c> 
    <cc> 
     Something 
    </cc> 
    </c> 

    <d> 
    bla 
    </d> 
</a> 

$ awk 'BEGIN{RS="</b>"}/<b>/{gsub(/<b>.*/,"")}1' file 
<a> 

some text before 
some text after 

    <c> 
    <cc> 
     Something 
    </cc> 
    </c> 

    <d> 
    bla 
    </d> 
</a> 
+0

Thx me ayudó: D – Chris

14

Usando xmlstarlet:

#xmlstarlet ed -d "https://stackoverflow.com/a/b" file.xml > tmp.xml 
xmlstarlet ed -d "//b" file.xml > tmp.xml 
mv tmp.xml file.xml 
+0

Probablemente debería hacerlo bien y agregar un condicional (para cambiar el nombre solo sobre el archivo original si la operación tiene éxito). Para hacerlo aún más correctamente, también se puede usar 'mktemp' para generar un archivo temporal con un nombre garantizado que no sea conflictivo, que también puede tener el efecto secundario de evitar algunos ataques de seguridad relacionados con el uso de nombres de archivos temporales constantes. –

+1

Incluso con esas advertencias, sin embargo, esta sigue siendo una respuesta mucho mejor que usar 'sed'. –

2
# edit file inplace 
xmlstarlet ed -L -d "//b" file.xml 
+0

apt-get install xmlstarlet en la versión ubuntu 9.x, con repositorios predeterminados. no encontró -L indicador en la documentación. ¿está en ubuntu 10.0.4? – user77115