Charlweed
Charlweed

Reputation: 1614

How to escape xml for use in perl multiline search and replace?

I want to use perl to replace a key-value pair in an xml file, but I am having problems escaping the xml from the regex parser. All this is supposed to run from a bash script. So I have two variables:

macDefault="<key>DefaultVolume</key>\
                <string>91630106-4A1F-4C58-81E9-D51877DE2EAB</string>"

winDefault="<key>DefaultVolume</key>\
                <string>EBD0A8B3-EE3D-427F-9A83-099C37A90556</string>"

And I want perl to replace the occurrence of the value $macDefault with the value of $winDefault in the file config.plist

Unfortunately

perl -0pe  's/'"$macDefault"'/'"$winDefault"'/' config.plist

does not work, as perl reports:

Having no space between pattern and following word is deprecated at -e line 1.
Bareword found where operator expected at -e line 1, near "s/<key>DefaultVolume</key>                <string>91630106-4A1F-4C58-81E9-D51877DE2EAB</string"
Having no space between pattern and following word is deprecated at -e line 1.
Bareword found where operator expected at -e line 1, near "<string>EBD0A8B3"
        (Missing operator before EBD0A8B3?)
Bareword found where operator expected at -e line 1, near "427F"
        (Missing operator before F?)
Bareword found where operator expected at -e line 1, near "9A83"
        (Missing operator before A83?)
Bareword found where operator expected at -e line 1, near "099C37A90556"
        (Missing operator before C37A90556?)
syntax error at -e line 1, near "s/<key>DefaultVolume</key>                <string>91630106-4A1F-4C58-81E9-D51877DE2EAB</string"
Illegal octal digit '9' at -e line 1, at end of line
Illegal octal digit '9' at -e line 1, at end of line
Execution of -e aborted due to compilation errors.

Thanks for any help!

Upvotes: 0

Views: 198

Answers (2)

albe
albe

Reputation: 551

I'll bet this would work:

macDefault="91630106-4A1F-4C58-81E9-D51877DE2EAB"

winDefault="EBD0A8B3-EE3D-427F-9A83-099C37A90556"

perl -0pe  's/'"$macDefault"'/'"$winDefault"'/' 

or, accommodating your comment:

perl -0pe 's?(<key>DefaultVolume</key>\s*<string>)'"$macDefault"'(\s*</string>)?$1'"$winDefault"$2'?s' config.plist

Noting the /s for multiline matching.

Upvotes: 1

Borodin
Borodin

Reputation: 126722

It's always better to use a proper XML parser than try to hack something together with regular expressions

Here's an example using Mojo::DOM, because it often gets overlooked in favour of XML::Twig or XML::LibXML

I've had to wrap your XML sample in a <root> element to make it well-formed. I'm sure the real document looks nothing like this, but it's the best guess I've got and the real case isn't likely to require the Perl to be changed a great deal

The input file is expected as a parameter on the command line

use strict;
use warnings;

use Mojo::DOM;

my $xml = do { local $/; <> };
my $dom = Mojo::DOM->new->xml(1)->parse($xml);

my $keys   = $dom->find('key')->grep(sub { $_->text eq 'DefaultVolume' });
my $string = $keys->[0]->next;
$string->content('EBD0A8B3-EE3D-427F-9A83-099C37A90556');

print $dom, "\n";

output

<root>
  <key>DefaultVolume</key>
  <string>EBD0A8B3-EE3D-427F-9A83-099C37A90556</string>
</root>

Upvotes: 1

Related Questions