¿Cómo editar XML usando el script bash?

 1 2  

Necesita cambiar los valores 1 y 2 de bash

Puede usar el comando xsltproc (del paquete xsltproc en distros basados ​​en Debian) con la siguiente hoja XSLT:

                      

Luego usa el comando:

 xsltproc --stringparam tagReplacement polop \ --stringparam tag1Replacement palap \ transform.xsl input.xml 

O también puedes usar expresiones regulares, pero modificar XML a través de expresiones regulares es pura maldad 🙂

Para cambiar el valor de la tag a 2 y el valor de tag1 a 3 , usando XMLStarlet :

 xmlstarlet ed \ -u '/root/tag' -v 2 \ -u '/root/tag1' -v 3 \ new.xml 

Usando su entrada de muestra:

 xmlstarlet ed \ -u '/root/tag' -v 2 \ -u '/root/tag1' -v 3 \ <<<'12' 

… emite como salida:

   2 3  

mi $ 0.02 en python porque está en todos los servidores con los que te conectarás alguna vez

 import sys, xml.etree.ElementTree as ET data = "" for line in sys.stdin: data += line tree = ET.fromstring(data) nodeA = tree.find('.//tag') nodeB = tree.find('.//tag1') tmp = nodeA.text nodeA.text = nodeB.text nodeB.text = tmp print ET.tostring(tree) 

esto se lee de stdin para que pueda usarlo así:

 $ echo 'hi!this' | python xml_process.py thishi! 

EDITAR – reto aceptado

Aquí hay una implementación de xmllib en funcionamiento (debería funcionar de regreso a Python 1.6). Como pensé que sería más divertido apuñalar mis ojos con un tenedor. Lo único que diré sobre esto es que funciona para el caso de uso dado.

 import sys, xmllib class Bag: pass class NodeSwapper(xmllib.XMLParser): def __init__(self): print 'making a NodeSwapper' xmllib.XMLParser.__init__(self) self.result = '' self.data_tags = {} self.current_tag = '' self.finished = False def handle_data(self, data): print 'data: ' + data self.data_tags[self.current_tag] = data if self.finished: return if 'tag1' in self.data_tags.keys() and 'tag' in self.data_tags.keys(): b = Bag() b.tag1 = self.data_tags['tag1'] b.tag = self.data_tags['tag'] b.t1_start_idx = self.rawdata.find(b.tag1) b.t1_end_idx = len(b.tag1) + b.t1_start_idx b.t_start_idx = self.rawdata.find(b.tag) b.t_end_idx = len(b.tag) + b.t_start_idx # swap if b.t1_start_idx < b.t_start_idx: self.result = self.rawdata[:b.t_start_idx] + b.tag + self.rawdata[b.t_end_idx:] self.result = self.result[:b.t1_start_idx] + b.tag1 + self.result[b.t1_end_idx:] else: self.result = self.rawdata[:b.t1_start_idx] + b.tag1 + self.rawdata[t1_end_idx:] self.result = self.result[:b.t_start_idx] + b.tag + self.rresult[t_end_idx:] self.finished = True def unknown_starttag(self, tag, attrs): print 'starttag is: ' + tag self.current_tag = tag data = "" for line in sys.stdin: data += line print 'data is: ' + data parser = NodeSwapper() parser.feed(data) print parser.result parser.close() 

Ya que das un ejemplo sed en uno de los comentarios, me imagino que quieres una solución pura bash?

 while read input; do for field in tag tag1; do case $input in *"<$field>"*""* ) pre=${input#*"<$field>"} suf=${input%""*} # Where are we supposed to be getting the replacement text from? input="${input%$pre}SOMETHING${input#$suf}" ;; esac done echo "$input" done 

Esto es completamente poco inteligente, y obviamente solo funciona con una entrada bien formada con la etiqueta de inicio y la etiqueta final en la misma línea, no puede tener múltiples instancias de la misma etiqueta en la misma línea, la lista de tags a sustituir es codificado, etc.

No puedo imaginar una situación en la que esto sea realmente útil, y preferible a un script o un enfoque XML adecuado.