2

I'm trying to automate an installation process with a script. Part of the process is finding certain sections of the XML config file (seen below), and changing certain parameters from false to true or vice versa.

There are many sections within the config file that have the <enabled> tag (in this case its the <ssh> section). So, my question is, how can I search for the specific <enabled> tag and modify it?

<ssh>
  <enabled>true</enabled>
  <ip>0.0.0.0</ip>
  <port>2024</port>
</ssh>
  • 2
    "Finding certain sections" and "changing certain parameters" is about as vague as it gets. You might want to look into sed, though. – pfnuesel Feb 15 '16 at 18:59
  • Sorry, I tried adding a pic to try and alleviate some ambiguity. – woogad Feb 15 '16 at 19:03
  • 2
    As stated above, sed is very useful for this kind of automation. I would also suggest perl since it has most of sed's features and more built in. – Peschke Feb 15 '16 at 19:08
  • sed is absolutely the wrong tool for this job. XML needs a context aware parser, and regular expressions can't do that. – Sobrique Feb 17 '16 at 16:11
1

Since multiple nodes in your config file have child-nodes with the same name, I would recommend writing your script in a way that actually understands the XML format. Here's a Perl example of modifying two of your config elements:

#!/usr/bin/perl

use strict;
use warnings;

use XML::Simple;

my $config = 'config.xml';
my $xml = XMLin($config, KeepRoot => 1, ForceArray => 1,);

$xml->{config}->[0]->{ssh}->[0]->{enabled} = 'false';
$xml->{config}->[0]->{web}->[0]->{ip} = '127.0.0.1';

XMLout($xml, KeepRoot => 1, NoAttr => 1, OutputFile => $config,);

Here's my input config.xml:

<config>
  <ssh>
    <enabled>true</enabled>
    <ip>0.0.0.0</ip>
    <port>2024</port>
  </ssh>
  <web>
    <enabled>true</enabled>
    <ip>0.0.0.0</ip>
    <port>80</port>
  </web>
</config>

And here's the output:

<config>
  <ssh>
    <enabled>false</enabled>
    <ip>0.0.0.0</ip>
    <port>2024</port>
  </ssh>
  <web>
    <enabled>true</enabled>
    <ip>127.0.0.1</ip>
    <port>80</port>
  </web>
</config>
1

You haven't really given a big enough example XML, so I am guessing a bit.

I would suggest that the tool for the job is a decent XML parser, and perl.

I would strongly suggest that you do NOT use:

Because both are brittle - they sort of work, in controlled circumstances, but you have hacky nasty code that may mysteriously break one day.

Instead - use a parser that supports xpath which is - in XML terms - a way to find/select the content you want, and modify it.

Something like XML::Twig is a low barrier to entry. (XML::LibXML is also a solid alternative, but rather more exhaustive).

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

use XML::Twig; 

#parse the content - you probably want `parsefile` here instead. 
my $twig = XML::Twig -> new ( pretty_print => 'indented_a' ) -> parse ( \*DATA );

#select the node you want, alter it. 
$twig -> get_xpath('./ssh/enabled',0) -> set_text('false');

#print the output (to STDOUT) - you can print {$output_fh} $twig->sprint; instead
$twig -> print;


__DATA__
<xml>
  <www>
    <enabled>true</enabled>
    <ip>0.0.0.0</ip>
    <port>80</port>
  </www>
  <ssh>
    <enabled>true</enabled>
    <ip>0.0.0.0</ip>
    <port>2024</port>
  </ssh>
  <smtp>
    <enabled>true</enabled>
    <ip>0.0.0.0</ip>
    <port>25</port>
  </smtp>
</xml>

Note - get_xpath uses a 'directory structure' sort of format. It supports absolute paths within the XML, as well as relative paths. The way it's run above, it will operate on the first element that matches that path (XML allows multiple).

You can, however, do it in a 'foreach' loop:

foreach my $thing ( $twig -> get_xpath ('//enabled') ) {
   $thing -> set_text('false'); 
}

to disable everything.

xpath is pretty flexible - it's a way of specifying path, element and attributes and is ideally suited to navigating XML in a regex-like manner.

So you have constructs such as // for find recursively.

Or //node[@name='test'] to find:

<node name="test">content</node>

There's a handy quick reference that gives an easy way to see how to navigate XML using xpath.

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.