0

Using a Perl replace statement (s//) I'd like to modify some XML by adding an attribute to some items if missing. Here's an example :

...
<car color="red" owner="john">...</car>
<car color="green" age="3">...</car>
...

Let's say I'd like to add a default owner to ownlerless cars. I tried the following without success :

s/(<car[^>]*)(?!owner="[^"]*")(.*>)|$1 owner="steve"$2/iUg

Any help appreciated.

Renaud Cerrato
  • 1,297
  • 16
  • 20
  • 1
    possible duplicate of [In Perl, how can I change an element in an XML file without changing the format of the XML file?](http://stackoverflow.com/questions/1327720/in-perl-how-can-i-change-an-element-in-an-xml-file-without-changing-the-format) – Schwern Jan 22 '12 at 17:53
  • 1
    avoid using regexes to parse / change XML or HTML documents. that's a general recommendation. – snoofkin Jan 22 '12 at 23:00

3 Answers3

5

While you may be able to get away with a regex, an XML parser is always recommended.

Perl/CPAN offerings include:

Zaid
  • 36,680
  • 16
  • 86
  • 155
  • 1
    You missed out on an opportunity to link to [the most awesome SO answer ever](http://stackoverflow.com/a/1732454/301832). – Donal Fellows Jan 22 '12 at 21:15
1

I usually use XML::XSH2 for XML manipulation. Your problem can be solved easily in it:

for //car[not(@owner)] set @owner "steve" ;
choroba
  • 231,213
  • 25
  • 204
  • 289
0

you can try this one

#!/usr/bin/perl -w

$str = <<EOF;
<car color="red" owner="john">.*#?§<car color="pink"> </car>.*#?§</car>
<car color="green" age="3">.*#?§</car>
<car owner="bill"></car>
EOF

$str =~ s/(<car(?![^>]+?owner))([^>]*?)>/$1$2 owner="steve">/g;

print $str;

best regards


PS: most likely it's a typo but anyway, the vertical bar in your regex must be replaced by a slash

user1146332
  • 2,630
  • 1
  • 15
  • 19
  • 1
    There's no need for the empty while loop. `/g` already makes sure it runs over all elements of `$str`. The loop just makes it run twice, and the second time around it doesn't match anything so it returns 0 (the number of matches). This could easily become an infinite loop, for example: `s{foo}{foofoo}g`. – Schwern Jan 22 '12 at 17:56
  • @Schwern thanks for your comment. I remember:`m//g != s///g` best regards – user1146332 Jan 22 '12 at 20:56