0

I am novice here and I am trying to search and replace a string in a xml file which is as given below:

<name>xxx.yyy_zzz</name>
      <constructor_arguments />
      <parameters>
        <parameter>
          <name>Name</name>
          <string>
            <value>yyy</value>
          </string>
        </parameter>
        <parameter>
          <name>abc</name>
          <bool>
            <value>false</value>
          </bool>
        </parameter>
        <parameter>
          <name>abcd</name>
          <bool>
            <value>true</value>
          </bool>
        </parameter>
        <parameter>
          <name>aa</name>
          <integer>
            <value>10</value>
          </integer>
        </parameter>
        <parameter>
          <name>bb</name>
          <integer>
            <value>100</value>
          </integer>
        </parameter>
        <parameter>
          <name>runtime_disabled</name>
          <bool>
            <value>false</value>
          </bool>

I have tried the following to change runtime_disabled value to true but it did not happen which I expect to happen, can anyone tell why is it so and provide suitable solution for the same to work

$data=~ s/(xxx\.i\yyy\_zzz\s*?<\/name>(.+?)runtime_disabled\s*?<\/name>\s*?<bool>\s*?<value>\s*?<value>.*?<\/value>)/$1true$2/g;
2
  • 2
    seems like you are trying to get names so always better to use parser for xml docs try this link stackoverflow.com/questions/2052179/… Commented Oct 29, 2016 at 16:55
  • 3
    Trying to parse XML with a regex is a recipe for pain. Commented Oct 29, 2016 at 19:37

1 Answer 1

1

Parsing well-formed XML should practically always be done using modules. Much has been said about that over time, see for example this page and this page, among many others. I also hear that truly bad things may come to pass otherwise.

Here is an example of how to do what you ask using XML::libXML. Another excellent module is XML::Twig. I completed your sample so to make it a well-formed XML file (shown below code).

use strict 'all';
use warnings;

use XML::LibXML;    

my $file = 'file.xml';

my $doc = XML::LibXML->load_xml(location => $file, no_blanks => 1); 

# Form the XPath expression used to find the 'name' nodes
my $xpath = '//doc/constructor_arguments/parameters/parameter/name';

foreach my $node ($doc->findnodes($xpath)) 
{
    # Select the particular 'name' tag that is needed
    if ($node->to_literal eq 'runtime_disabled') 
    {   
        # Query the parent node, for <name>'s sibling <bool>
        foreach my $bval ($node->parentNode->findnodes('./bool/value/text()')) 
        {
            my $content = $bval->toString;
            $content =~ s/false/true/;
            $bval->setData($content);
        }
    }   
}

# Write a new file with the change
$doc->toFile('changed_' . $file, 1); 

This is meant to be basic, there are quite a few other ways to do the same.

The posted sample was padded as follows

<doc>
... posted text ...
            </parameter>
        </parameters>
    </constructor_arguments>
</doc>
Sign up to request clarification or add additional context in comments.

2 Comments

Since it is a XML file I am moving to the method you are suggesting and the eg., mentioned is found to be working.
@Emman Great -- parsing XML by hand (regex) leads to no end of trouble. By the time you'd clean up one such file you'll learn how to use a module, and then you are taken care of. With either of the two modules I mention you have full control over everything, while simple things are simple. It is instructive reading some of the posts on this topic. I'll add a few links to them.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.