'How to insert existing xml line using xmlstarlet
I've tried searching and reading the xmlstarlet help and I apologize if I missed the answer. I'm trying to take an existing line of XML and add it to an xml file using xmlstarlet. ie:
I have a line like this: <somedata name="aname" val="aval"/>
and an xml file similar to
<xml>
<subxml/>
</xml>
I would like the output to be
<xml>
<subxml>
<somedata name="aname" val="aval"/>
</subxml>
</xml>
I haven't been able to find a way to either just echo the line i have and insert it or some other method without having to parse the line and then insert used all the xmlstarlet edit options (-n -v...).
Thanks in advance for the help!
Solution 1:[1]
a workaround, to insert raw XML code with xmlstarlet
- insert a temporary xml node with xmlstarlet
- replace that node with sed
the temp node must be unique in the file
file="input.xml" # will be modified in-place
xpath="/xml/subxml"
raw_xml='<foo type="asdf">pipe||||amp&&&&back\0\1\2\3</foo>'
esc_xml=$(echo "$raw_xml" | sed -e 's/[\/&]/\\&/g' | sed ':a;N;$!ba;s,\n,\\n,g')
temp=node$(date | sha256sum | cut -d' ' -f1)
xmlstarlet ed -L -s "$xpath" -t elem -n $temp "$file"
sed -i "s|<$temp/>|$esc_xml|" "$file"
this will use a temp node like
<node6044c3e85d715b423cafd58c17bbda2748d7b51d9481b11c792a5313ddced18b/> which should be safe from collisions
related: https://superuser.com/questions/422459/substitution-in-text-file-without-regular-expressions/
Solution 2:[2]
As a quick answer I wound up appending the lines I wanted to the end of the existing file, and then just using a move command in xmlstarlet to put the data in the right spot and format it correctly. Also, I removed the last closing tag and re-added just to be sure it properly formatted xml. It's creative but not the best way to do it, but it works. Basically it looked something like this:
sed -i -e 's/<\/xml>//' file.xml
echo "<somedata name="aname" val="aval"/>" >> file.xml
echo "</xml>
xmlstarlet ed -L -O -m //somedata //xml//subxml file.xml
If anyone has a better way to accomplish this I'd still be very interested.
Solution 3:[3]
It's really bad practice to use sed to edit xml-files. xmlstarlet can do this just fine:
$ xmlstarlet ed -O \
-s '//subxml' -t elem -n somedata \
-i '//subxml/somedata' -t attr -n name -v aname \
-i '//subxml/somedata' -t attr -n val -v aval \
input.xml
<xml>
<subxml>
<somedata name="aname" val="aval"/>
</subxml>
</xml>
xidel is another option:
$ xidel -s input.xml -e '
x:replace-nodes(
//subxml,
<subxml><somedata name="aname" val="aval"/></subxml>
)
' --output-node-format=xml --output-node-indent
<xml>
<subxml>
<somedata name="aname" val="aval"/>
</subxml>
</xml>
$ xidel -s input.xml -e '
x:replace-nodes(
//subxml,
element subxml {
element somedata {
attribute name {"aname"},
attribute val {"aval"}
}
}
)
' --output-node-format=xml --output-node-indent
<xml>
<subxml>
<somedata name="aname" val="aval"/>
</subxml>
</xml>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | Dan Fumosa |
| Solution 3 |
