Reputation: 2385
I am using sed command to insert an xml element into the existing xml file.
I have xml file as
<Students>
<student>
<name>john</>
<id>123</id>
</student>
<student>
<name>mike</name>
<id>234</id>
</student>
</Students>
I want to add new elememt as
<student>
<name>NewName</name>
<id>NewID</id>
</student>
So my new xml file will be
<Students>
<student>
<name>john</>
<id>123</id>
</student>
<student>
<name>mike</name>
<id>234</id>
</student>
<student>
<name>NewName</name>
<id>NewID</id>
</student>
</Students>
For this I have written shell script as
#! /bin/bash
CONTENT="<student>
<name>NewName</name>
<id>NewID</id>
</student>"
#sed -i.bak '/<\/Students>/ i \ "$CONTENT" /root/1.xml
sed -i.bak '/<\/Students>/ i \'$CONTENT'/' /root/1.xml
I am getting error as
sed: can't read <name>NewName</name>: No such file or directory
sed: can't read <id>NewID</id>: No such file or directory
sed: can't read </student>: No such file or directory
And in the xml file, only <student>
is added.
The remaining elements are not added.
Does anyone know why this error?
Upvotes: 10
Views: 31791
Reputation: 3443
Please DO NOT use sed
to parse/edit XML! Use an XML-parser, like xidel and xmlstarlet, instead.
With "direct element constructors" (and Xidel's own x:replace-nodes()
):
$ xidel -s "input.xml" -e '
x:replace-nodes(
Students/student[last()],
function($x){
$x,
<student><name>NewName</name><id>NewID</id></student>
}
)
' --output-node-format=xml --output-node-indent
With "computed constructors":
$ xidel -s "input.xml" -e '
x:replace-nodes(
Students/student[last()],
function($x){
$x,
element student {
element name {"NewName"},
element id {"NewID"}
}
}
)
' --output-node-format=xml --output-node-indent
$ xmlstarlet ed -O \
-a 'Students/student[last()]' -t elem -n 'student' \
-s 'Students/student[last()]' -t elem -n 'name' -v 'NewName' \
-s 'Students/student[last()]' -t elem -n 'id' -v 'NewID' \
"input.xml"
Output in all 3 cases:
<Students>
<student>
<name>john</name>
<id>123</id>
</student>
<student>
<name>mike</name>
<id>234</id>
</student>
<student>
<name>NewName</name>
<id>NewID</id>
</student>
</Students>
Upvotes: 1
Reputation: 1
My goal was to inject xml snippets from another file into pom.xml and the following code works for me. It also ensures that \t (tabs) will be taken into the new file, so it will be formated in the correct way.
function inject_plugin_into_pom {
local plugin_file=$1
local pom_file=$2
# read from file into array
declare -a xml_array
while IFS= read -r line; do
xml_array+=("$line")
done < "$plugin_file"
# inject into xml line by line
for element in "${xml_array[@]}"; do
# echo -e | takes care of the \t
# sed 's/\//\\\//g' | replaces / with \/
escaped=$(echo -e "$element" | sed 's/\//\\\//g')
sed -i -e "s/<\/plugins>/\t${escaped}\n\t\t<\/plugins>/g" $pom_file
done
}
Upvotes: -1
Reputation: 5424
change this:
CONTENT="<student>
<name>NewName</name>
<id>NewID</id>
</student>"
to this:
CONTENT="<student>\n<name>NewName</name>\n<id>NewID</id>\n</student>"
and then:
C=$(echo $CONTENT | sed 's/\//\\\//g')
sed "/<\/Students>/ s/.*/${C}\n&/" file
Upvotes: 9
Reputation: 58548
This might work for you (GNU sed & Bash):
CONTENT=' <student>\
<name>NewName</name>\
<id>NewID</id>\
</student>'
sed '/<\/Students>/i\'"$CONTENT" file
Alternatively, put the new students in a file and:
sed '/<\/Students>/e cat new_student_file' file
Upvotes: 2
Reputation: 77175
You cannot have an unescaped newline in sed replacement text, that is $CONTENT
in your example. sed uses the newline just like the shell does, to terminate a command.
If you need a newline in the replacement text, you need to precede it with a backslash.
There is another way to add text using the r
option. For example:
Lets say your main file is;
$ cat file
<Students>
<student>
<name>john</>
<id>123</id>
</student>
<student>
<name>mike</name>
<id>234</id>
</student>
</Students>
You text you want to add is in another file (not variable):
$ cat add.txt
<student>
<name>NewName</name>
<id>NewID</id>
</student>
You can do (using gnu sed
):
$ sed '/<\/Students>/{
r add.txt
a \</Students>
d
}' file
<Students>
<student>
<name>john</>
<id>123</id>
</student>
<student>
<name>mike</name>
<id>234</id>
</student>
<student>
<name>NewName</name>
<id>NewID</id>
</student>
</Students>
However, having given this option, it is still a very bad idea to parse xml with regular expression. It makes the solution very fragile and easy to break. Consider this as a learning exercise only.
Upvotes: 6