With XMLStarlet, you can add a subnode to an element, or you can update an existing element. To cover both the case when the element exists and when it doesn't already exist, we can
- Delete the element.
- Add the element with the value that we want it to have.
Let's say the element that we want to add is <newtag> and that its value should be tagval. It should also have an attribute, newattr, with value attrval. This means that what we want to add is
<newtag newattr="attrval">tagval</newtag>
To delete the element:
$ xmlstarlet ed -d '//server-group/newtag' file.xml
To add the element with an attribute:
$ xmlstarlet ed -s '//server-group' -t elem -n 'newtag' -v 'tagval' \
-s '//server-group/newtag' -t attr -n 'newattr' -v 'attrval' file.xml
Adding these together:
$ xmlstarlet ed -d '//server-group/newtag' \
-s '//server-group' -t elem -n 'newtag' -v 'tagval' \
-s '//server-group/newtag' -t attr -n 'newattr' -v 'attrval' file.xml
Given the input XML
<?xml version="1.0"?>
<server-groups>
<server-group name="main-server-group" profile="full">
<jvm name="default">
<heap size="64m" max-size="512m"/>
<jvm-options>
<option value="somevalue"/>
</jvm-options>
</jvm>
<socket-binding-group ref="full-sockets"/>
</server-group>
</server-groups>
this results in the output
<?xml version="1.0"?>
<server-groups>
<server-group name="main-server-group" profile="full">
<jvm name="default">
<heap size="64m" max-size="512m"/>
<jvm-options>
<option value="somevalue"/>
</jvm-options>
</jvm>
<socket-binding-group ref="full-sockets"/>
<newtag newattr="attrval">tagval</newtag>
</server-group>
</server-groups>
Note that the XPath expression //server-group will match all server_group elements in the input XML. If you only want to match the one whose name attribute is main-server-group, you would have to change //server-group to //server-group[@name="main-server-group"].
XMLStarlet is available from http://xmlstar.sourceforge.net/, but there's most likely a pre-packaged version available for your Unix already (use that). Sometimes, the XMLStarlet executable is called just xml rather than xmlstarlet.