-1

ADD_XML variable include the following

echo "$ADD_XML"
 <units>
 <unit ip="10.106.5.8" unit_type="RECOGNIZE Discovery"/>
 <unit ip="10.106.3.21" unit_type="RECOGNIZE Discovery"/>
 <unit ip="10.106.3.12" unit_type="RECOGNIZE Discovery"/>
 <unit ip="10.106.3.13" unit_type="RECOGNIZE Discovery"/>
 </units>
 <ranges/>
 </Networks>

I want to add the content of $ADD_XML after the first:

 <Networks> 

in my XML file

please advice how to implemented this by sed/awk or perl one liner line

example how it shul be in the XML file

 </Networks>
 <units>
 <unit ip="10.106.5.8" unit_type="RECOGNIZE Discovery"/>
 <unit ip="10.106.3.21" unit_type="RECOGNIZE Discovery"/>
 <unit ip="10.106.3.12" unit_type="RECOGNIZE Discovery"/>
 <unit ip="10.106.3.13" unit_type="RECOGNIZE Discovery"/>
 </units>
 <ranges/>
  </Networks>
maihabunash
  • 1,632
  • 9
  • 34
  • 60
  • If you add that then the XML data will be malformed. – Borodin Mar 16 '15 at 14:09
  • I agree , but its works for me -:) – maihabunash Mar 16 '15 at 14:09
  • 3
    I don't think I want to help you create invalid XML! – Borodin Mar 16 '15 at 14:10
  • look , this xml I use is for testing and I have only line with string , so this is the fact, and I dont see any problem here , I tested it more then 10 times – maihabunash Mar 16 '15 at 14:14
  • Whatever you tested it with is an incorrect implementation of the XML standards. – Borodin Mar 16 '15 at 14:18
  • so if you say so , please explain what are the risks here ? – maihabunash Mar 16 '15 at 14:19
  • 2
    [By allowing this, your document is no longer XML](http://www.w3.org/TR/2006/REC-xml11-20060816/#sec-terminology), so don't call it that. To read and write XML documents, use an XML library instead of regular expressions. – reinierpost Mar 16 '15 at 14:26
  • XML is a widely accepted and well defined standard. The thing with standards are - they work best if everyone sticks to them. If you've ever tried to parse HTML, you'll know there's a HORRIFIC number of edge cases, making it extremely difficult to parse. – Sobrique Mar 16 '15 at 15:20

5 Answers5

2

I'll repeat what I said on "Unix"

Don't do this.

Parsing XML with regular expressions is messy and it breaks. There are many valid things you can do with XML that will screw up a regular expression. (The simplest and most obvious being - pretty-printing gives you valid XML, but will break a regular expression). Likewise deliberately creating malformed XML is very nasty, and also prone to screwing up.

See also: Dealing with malformed XML

And: RegEx match open tags except XHTML self-contained tags

So don't do it. Use a parser.

Something like this should do what you need (If you can include a slightly bigger sample of source data, I can amend):

#!/usr/bin/perl
use strict;
use warnings;

use XML::Twig;

my $xml_text = '<XML>
<Networks><units><unit ip="1.2.3.4" /></units><ranges/></Networks>
</XML>';

my $original = XML::Twig->new( 'pretty_print' => 'indented' );
#would probably use 'parsefile' instead here
$original->parse($xml_text);

print "\nBefore:\n";
$original->print;


#read update:

my $to_insert =  XML::Twig->new -> parse ( \*DATA );

#insert a new element into 'Networks':
foreach my $unit ( $to_insert -> root -> children ) {
    $unit -> cut();
    $unit -> paste ( $original->root->first_child('Networks')->first_child('units') );
}


print "\nAfter:\n";
$original->print;


__DATA__
 <units>
 <unit ip="10.106.5.8" unit_type="RECOGNIZE Discovery"/>
 <unit ip="10.106.3.21" unit_type="RECOGNIZE Discovery"/>
 <unit ip="10.106.3.12" unit_type="RECOGNIZE Discovery"/>
 <unit ip="10.106.3.13" unit_type="RECOGNIZE Discovery"/>  
 </units>
Community
  • 1
  • 1
Sobrique
  • 52,974
  • 7
  • 60
  • 101
1
sed -e "/<Networks>/a \
$ADD_XML"

... adds the $ADD_XML after all occurrences of <Networks>.

sed -e "1,/<Networks>/s@<Networks>@&\n$ADD_XML@"

... does the trick for the first occurrence only. If $ADD_XML contains '@' characters you need to use a different character (one not used in $ADD_XML) or go for a more sophisticated solution as suggested by other answers.

yaccob
  • 1,230
  • 13
  • 16
  • hope there is only 1 line in this multiline content (it will not work because sed need a `\ ` (without space) at the end of each line inserted by `a`, you need to change the content first) and it add it to every `/` – NeronLeVelu Mar 16 '15 at 14:24
  • sed doesn't need a \ at the end of each line inserted. It just needs a newline at the end of each inserted line. – yaccob Mar 16 '15 at 15:16
1

You want something like the following awk:

    awk '$0 == "<Networks>"{print; print "'$ADD_XML'"}'
Paul Evans
  • 27,315
  • 3
  • 37
  • 54
1
echo "${ADD_XML}" >/tmp/Add.XML
sed '1,\#</Networks># {
        \#</Networks># {
           p
           r /tmp/Add.XML
           }
        }
    ' YourFile
rm /tmp/Add.XML
  • use a temporary file and r sed action (read and write content of a file)
  • sub part is to insert it only at 1st Network
  • just the p needed to print last line of Network before insterting the file (r replace the output of the current [buffer] line)
NeronLeVelu
  • 9,908
  • 1
  • 23
  • 43
1

This might work for you (GNU sed & bash):

sed '/<Networks>/r /dev/stdin' <<<"$ADD_XML" file

This reads in the contents of $ADD_XML after <Networks> using the stdin as a file.

If there are likely to be more than one <Network> tag use:

sed $'1,/<Networks>/{/<Networks>/r /dev/stdin\n}' <<<"$ADD_XML" file
potong
  • 55,640
  • 6
  • 51
  • 83