Replace dynamic content in XML file
Solution 1
You can use xmlstarlet
to edit a XML
file in a shell
like this :
xmlstarlet edit -L -u "/scs-shop/price[@type='double']" -v '99.66' file.xml
NOTE
-
"/scs-shop/price[@type='double']"
is a Xpath expression - see
xmlstarlet ed --help
Solution 2
The XML way is cool, but if you need to use normal bash tools, you can modify a line using sed. For instance:
PRICE=123
sed -i "s/\(<price.*>\)[^<>]*\(<\/price.*\)/\1$PRICE\2/" $XML_FILE_TO_MODIFY
This will replace the price with 123.
That sed command seems daunting, so let me break it down:
\(<price.*>\)[^<>]*\(<\/price.*\)
is the pattern to match. \(
... \)
are parenthesis for grouping. <price.*>
matches the opening price tag. [^<>]*
matches anything except angle brackets, and in this case will match the contents of the price tag. <\/price.*
matches the end of the price tag. Forward slash is a delimiter in sed, so I escape it with a back slash.
\1$PRICE\2
is the text to replace the matched text with. \1
refers to the first matched parenthesis group, which is the opening price tag. $PRICE
is the variable with the desired price in it. \2
refers to the second parenthesis group, in this case the closing tag.
Solution 3
I did not have the luxury of having xmlstarlet. I found a solution though simply by doing an inline replacement;
template-parameter.xml
<ns:Parameter>
<ns:Name required="true">##-ParamName-##</ns:Name>
<ns:Value>
<ns:Text>##-ParamValue-##</ns:Text>
</ns:Value>
</ns:Parameter>
Snippet
tokenName="foo"
tokenValue="bar"
#Replace placeholders in parameter template element
myParamElement=$(cat template-parameter.xml)
myParamElement=${myParamElement//##-ParamName-##/$tokenName}
myParamElement=${myParamElement//##-ParamValue-##/$tokenValue}
Result
<ns:Parameter>
<ns:Name required="true">foo</ns:Name>
<ns:Value>
<ns:Text>bar</ns:Text>
</ns:Value>
</ns:Parameter>
Related videos on Youtube
Clucky
Updated on June 05, 2020Comments
-
Clucky almost 4 years
Quick Summary: I need to create a Bash script to change the text within a node automatically every week. The script will match the node and replace the text inside them (if this is possible)? How would I do this?
Long Summary: I host a Minecraft server which has shops, each of which have their own .xml file in the /ShowcaseStandalone/ffs-storage/ directory. Every Sunday my server restarts and executes several commands into the terminal to reset several things. One thing that I am trying to make change is one of the shops. I am wanting to change the text in the node <itemstack> and the text in the node <price>. I am simply wanting to take text from a .txt file in a different folder, and insert it into that node. The problem is, that the text in the node will change every week. Is there any way to replace a specific line or text within two nodes using bash?
XML file:
<?xml version="1.0" encoding="UTF-8"?> <scs-shop usid="cac8480951254352116d5255e795006252d404d9" version="2" type="storage"> <enchantments type="string"/> <owner type="string">Chadward27</owner> <world type="string">Frisnuk</world> <itemStack type="string">329:0</itemStack> <activity type="string">BUY</activity> <price type="double">55.0</price> <locX type="double">487.5</locX> <locY type="double">179.0</locY> <locZ type="double">-1084.5</locZ> <amount type="integer">0</amount> <maxAmount type="integer">0</maxAmount> <isUnlimited type="boolean">true</isUnlimited> <nbt-storage usid="23dffac5fb2ea7cfdcf0740159e881026fde4fa4" version="2" type="storage"/> </scs-shop>
Operating System: Linux Ubuntu 12.04
-
Gilles Quenot over 11 yearsSo you just want to change usid from scs-shop tag ?
-
Brian Cain over 11 yearsXML manipulation using exclusively
bash
? Why limit yourself? -
Clucky over 11 years@sputnick Sorry, I had to ad < and > tags because it killed my nodes, but no, I need to replace the text in the nodes "itemstack" and "price"
-
Clucky over 11 years@Brian-Cain Is there any other way to do this from terminal? Because these commands all execute upon the server shutting off
-
Brian Cain over 11 yearsI'd recommend python -- does your server have python installed, or can it? If not, java might be another option.
-
Clucky over 11 years@Brian-Cain I believe it does have python and it most certainly has Java. I heard you can do this using perl also; however, the only way I think perl would work for this specific script is if I also used RegEx (something I do not know). Also, am I tagging correctly? I'm brand new at this website, although I use it often for script references.
-
tripleee over 8 yearsThe duplicate stackoverflow.com/questions/23560215/replace-xml-value-with-sed has a few more answers if the ones here are unsuitable for some reason.
-
-
Clucky over 11 yearsI don't mean to make you do all the work for me, but I am a visual learner. How could I use this to replace "<price type="double">55.0<price>" with "<price type="double">25.0<price>"?
-
Gilles Quenot over 11 yearsI can give you the full syntax if you give me a valid XML
-
Gilles Quenot over 11 yearsYou can test it like this :
xmlstarlet val file.xml
-
Clucky over 11 yearsThere, I fixed it. Sorry I'm brand new to stackoverflow so I don't know how to format correctly. But it should be a valid xml file now.
-
Gilles Quenot over 11 yearsPost edited with an example for price tag, it's quite very simple to adapt it for other tags
-
Clucky over 11 yearsWorked like a charm. Thank you so much!
-
Gilles Quenot over 11 yearsThis is the wrong way. You can't realistically parse tag-based markup languages like HTML or XML using Bash, grep, sed, cut, etc. See codinghorror.com/blog/archives/001311.html (you know the blog website from SO creator ?) This is about HTML, but this is the same for XML...
-
Dan Bliss over 11 yearsIf linux came with a good xml tool like xmlstarlet then I would agree that this is the wrong way. Until it does, sed is my go-to tool. Realistically, you can use sed in 99% of cases, including this one.
-
Gilles Quenot over 11 yearsI don't said "that don't work" but : "that's not reliable". In a simple case like this this seems "fine" for some people, but what happens when the XML will becomes more complicated with nested tags ? I'm talking about reliable way to makes things clean.
sudo apt-get install xmlstarlet
is not a big deal there. -
Dan Bliss over 11 years"but I think that's just as wrongheaded as demanding every trivial HTML processing task be handled by a full-blown parsing engine" is a quote from the blog post you cite. Regardless, for the record: I prefer the xmlstarlet solution. But if xmlstarlet is not available, sed will get er done.
-
BeniBela over 11 years@sputnick: apt-get install is not so easy, e.g. you need a internet connection and free space on the HD (if you use something like Backtrack you have a 4GB ramdisk and if it is full, it crashes). And recently my apt system broke, and I could not use apt-get install for anything for 3 months!
-
Clucky over 11 yearsIt is definately good to have both of these resources at my hands in case one fails. Thank you btw for the use of regular expression, that was where i was initially getting at with this post. I do enjoy the more simplistic design of xmlstarlet
-
tripleee over 7 yearsThe blanket wildcard
.*
here is definitely dangerous. Try to limit matching with[^<>]*
to avoid spanning across tags. There are still many corner cases where this could fail; for example, many XML schemata will allow a line break before a close tag, which will completely break one of the fundamental assumptions of this solution. Altogether, these points illustrate exactly why this approach is problematic. -
Dan Bliss over 7 yearsAgree that excluding the angle brackets is better.
-
Sirojiddin Komolov about 5 yearsThen how to change the result file again?