how to edit XML using bash script?
To change tag
's value to 2
and tag1
's value to 3
, using XMLStarlet:
xmlstarlet ed \ -u '/root/tag' -v 2 \ -u '/root/tag1' -v 3 \ <old.xml >new.xml
Using your sample input:
xmlstarlet ed \ -u '/root/tag' -v 2 \ -u '/root/tag1' -v 3 \ <<<'<root><tag>1</tag><tag1>2</tag1></root>'
...emits as output:
<?xml version="1.0"?><root> <tag>2</tag> <tag1>3</tag1></root>
You can use the xsltproc
command (from package xsltproc
on Debian-based distros) with the following XSLT sheet:
<?xml version="1.0" encoding="UTF-8"?><xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes"/> <xsl:param name="tagReplacement"/> <xsl:param name="tag1Replacement"/> <xsl:template match="node()|@*"> <xsl:copy> <xsl:apply-templates select="node()|@*"/> </xsl:copy> </xsl:template> <xsl:template match="tag"> <xsl:copy> <xsl:value-of select="$tagReplacement"/> </xsl:copy> </xsl:template> <xsl:template match="tag1"> <xsl:copy> <xsl:value-of select="$tag1Replacement"/> </xsl:copy> </xsl:template></xsl:stylesheet>
Then use the command:
xsltproc --stringparam tagReplacement polop \ --stringparam tag1Replacement palap \ transform.xsl input.xml
Or you could also use regexes, but modifying XML through regexes is pure evil :)
my $0.02 in python because its on every server you will ever log in to
import sys, xml.etree.ElementTree as ETdata = ""for line in sys.stdin: data += linetree = ET.fromstring(data)nodeA = tree.find('.//tag')nodeB = tree.find('.//tag1')tmp = nodeA.textnodeA.text = nodeB.textnodeB.text = tmp print ET.tostring(tree)
this reads from stdin so you can use it like this:
$ echo '<node><tag1>hi!</tag1><tag>this</tag></node>' | python xml_process.py <node><tag1>this</tag1><tag>hi!</tag></node>
EDIT - challenge accepted
Here's a working xmllib implementation (should work back to python 1.6). As I thought it would be more fun to stab my eyes with a fork. The only think I will say about this is it works for the given use case.
import sys, xmllibclass Bag: passclass 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 = tagdata = ""for line in sys.stdin: data += lineprint 'data is: ' + dataparser = NodeSwapper()parser.feed(data)print parser.resultparser.close()