1

We have an xml file (abc_lop.xml) in which I need to remove a line which is present in a tag:

Below is an xml file, I have shorten it down as it is very big.

<HELLO version="4.2" xmlns="http://www.bacd.org/HELLO-4_2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.bacd.org/HELLO-4_2 http://www.bacd.org/v4-2/hello-4-2.xsd">


    <!-- some data here  -->

</HELLO>

As you can see I have this line xsi:schemaLocation="http://www.bacd.org/HELLO-4_2 http://www.bacd.org/v4-2/hello-4-2.xsd" in HELLO tag above. I need to remove this line and keep other stuff.

As of now I am adding some header and footer to the above xml file which is shown below in my shell script and then storing it in file variable: Here $word is abc.

file=$(printf '%s\n%s\n%s' "$header" "$(cat "$path/${word}_lop.xml")" "$footer")

Now I want to make sure file variable should have xml file data but with that line remove as well from HELLO tag.

I am using this $file variable later on for some other purpose so I want to make sure $file should have header, footer and that line removed as well. That line which has key=value pair will only be present once.

1

To remove the xsi:schemaLocation entry, leaving the rest of the file intact:

$ sed 's/xsi:schemaLocation="[^"]*"//' "$path/${word}_lop.xml"
<HELLO version="4.2" xmlns="http://www.bacd.org/HELLO-4_2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" >


    <!-- some data here  -->

</HELLO>

s/xsi:schemaLocation="[^"]*"// is a substitute command. It replaces anything matching the regex xsi:schemaLocation="[^"]*" with nothing.

To combine this with your script:

file=$(printf '%s\n%s\n%s' "$header" "$(sed 's/xsi:schemaLocation="[^"]*"//' "$path/${word}_lop.xml")" "$footer")
  • Thanks for your example. Can you help me understand how can I integrate this in my single line script which I have above? – user1950349 Sep 17 '15 at 5:29
  • @user1950349 OK. I just added code for that to the answer. – John1024 Sep 17 '15 at 5:32
  • hey John, I have one more similar question. I guess we can use sed here as well. See if you can help me out. – user1950349 Sep 17 '15 at 6:18
2

PLEASE don't use regular expressions to fiddle with XML. The XML spec allows for a bunch of things that simply don't mesh well with regex based parsing.

It's a VERY BAD IDEA because you create brittle code. One day, the source XML you're using might just change to something else perfectly valid (as far as the XML spec is concerned) and your downstream munging script will break.

This is exactly the sort of thing that makes sysadmins and maintenence programmers very sad.

PLEASE use an XML parser. xmlstarlet is one option. Both perl and python have parsing options too. Both these things handle the strange cases in XML (like line wrapping, pretty printing, etc.) and ensure your downstream XML is valid - it's important to output valid XML, because invalid XML is supposed to be a fatal condition.

So specifically - removing an attribute from your HELLO element:

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

use XML::Twig;

my $twig = XML::Twig -> new ( 'pretty_print' => 'indented_a' ) -> parse ( \*DATA );

foreach my $hello ( $twig -> findnodes ('//HELLO') ) {
    $hello -> del_att('xmlns:xsi');
}
$twig -> print;

__DATA__
<HELLO version="4.2" xmlns="http://www.bacd.org/HELLO-4_2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.bacd.org/HELLO-4_2 http://www.bacd.org/v4-2/hello-4-2.xsd">


    <!-- some data here  -->

</HELLO>

Note - I've 'pretty printed' the result:

<HELLO
    version="4.2"
    xmlns="http://www.bacd.org/HELLO-4_2"
    xsi:schemaLocation="http://www.bacd.org/HELLO-4_2 http://www.bacd.org/v4-2/hello-4-2.xsd">
    <!-- some data here  -->
</HELLO>

To give us one example of why regex based parsing is a bad idea - because that's valid XML.

So is:

<HELLO version="4.2" xmlns="http://www.bacd.org/HELLO-4_2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.bacd.org/HELLO-4_2 http://www.bacd.org/v4-2/hello-4-2.xsd">
    <!-- some data here  -->
</HELLO>

And:

<HELLO
version="4.2"
xmlns="http://www.bacd.org/HELLO-4_2"
xsi:schemaLocation="http://www.bacd.org/HELLO-4_2 http://www.bacd.org/v4-2/hello-4-2.xsd"
>
    <!-- some data here  -->
</HELLO>

And:

<HELLO version="4.2" xmlns="http://www.bacd.org/HELLO-4_2" xsi:schemaLocation="http://www.bacd.org/HELLO-4_2 http://www.bacd.org/v4-2/hello-4-2.xsd"><!-- some data here  --></HELLO>

But XML parsers are easy and good to use.

To simplify your code into a one liner like sed:

perl -0777 -MXML::Twig -e 'XML::Twig -> new ( pretty_print => "indented_a", twig_handlers => { "HELLO" => sub { $_ -> del_att("xmlns:xsi") }} ) -> parse ( <> ) -> print;'

Should work if fed data on STDIN or via specifying a filename.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.