9

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?

ajay_t
  • 2,347
  • 7
  • 37
  • 62

3 Answers3

9

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
Farvardin
  • 5,336
  • 5
  • 33
  • 54
5

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.

jaypal singh
  • 74,723
  • 23
  • 102
  • 147
1

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
potong
  • 55,640
  • 6
  • 51
  • 83
  • Here if tag is like New Name, then how can I handle this whitespace. – ajay_t Apr 23 '14 at 10:58
  • @Optimus for the variable just remember that the last character of each line (but the last) must end in `\\`. For the file solution just write the text as you see it. – potong Apr 23 '14 at 11:02