Find and Increment a Number in an XML File Find and Increment a Number in an XML File xml xml

Find and Increment a Number in an XML File


Process the file using an XML parser. This is just better in every way than hacking it with a regex.

use warnings;use strict;use XML::LibXML;my $file = shift // die "Usage: $0 file\n";my $doc = XML::LibXML->load_xml(location => $file);my ($node) = $doc->findnodes('//value');my $new_value = $node->to_literal =~ s/node1\-\K([0-9]+)/1+$1/er;$node->removeChildNodes();$node->appendText($new_value);$doc->toFile('new_' . $file);   # or just $file to overwrite

Change the output filename to the input name ($file) to overwrite, once tested fully.

Removing and adding a node like above is one way to change an XML object.

Or, setData on the first child

$node->firstChild->setData($new_value);

where setData can be used on a node of type text, cdata or comment.

Or, search for text and then work with a text node directly

my ($tnode) = $doc->findnodes('//value/text()');my $new_value = $tnode =~ s/node1\-\K([0-9]+)/1+$1/er;$tnode->setData($new_value);print $doc->toString;

There's more. What method to use depends on all that need be done. If the sole job is indeed to just edit that text then the simplest way is probably to get a text node.


Here's an example using Perl's XML::Twig. Basically, you create a handler for a node, then do whatever you need to do in that handler. You can see the current text, make a new string, and set the node text to that string. It's a bit intimidating at first, but it's very powerful once you get used to it. I prefer this to other Perl XML parsers, but for very simple things it might not be the best tool:

#!perluse v5.26;use XML::Twig;my $xml = <<~"XML";    <attribute>        <name>test</name>        <type>java.lang.String</type>        <value>node1-3</value>    </attribute>    XMLmy $twig = XML::Twig->new(    pretty_print  => 'indented',    twig_handlers => {        # the key is the name of the node you want to process        value => sub {            # each handler gets the twig and the current node            my( $t, $node ) = @_;            my $current = $node->text;            # how you modify the text is not important. This            # is just a Perl substitution that does not modify            # the original but returns the new string            my $next = $current =~ s/(\d+)\z/ $1 + 1 /re;            $node->set_text( $next );            }        }    );$twig->parse( $xml );my $updated_xml = $twig->sprint;say $updated_xml;

Some other things to read for XML::Twig:


Just for fun, I used Perl's Mojo::DOM to do the same task using CSS selectors. This isn't as powerful as XML::Twig (no stream parsing!), but for simple things it can work out nicely:

#!perluse v5.26;use Mojo::DOM;my $xml = <<~"XML";    <attribute>        <name>test</name>        <type>java.lang.String</type>        <value>node1-3</value>    </attribute>    XMLmy $dom = Mojo::DOM->new( $xml );my $node = $dom->at( 'attribute value' ); # CSS Selectormy $current = $node->text;say "Current text is $current";# how you change the value is up to you. This line is# just how I did it.my $next = $current =~ s/(\d+)\z/ $1 + 1 /re;say "Next text is $next";$node->content( $next );say $dom;

It's not so bad as a one-liner, but it's a bit verbose for that. The -0777 enables paragraph mode to slurp in all the content on the first line read (there's file name command-line argument at the end):

$ perl -MMojo::DOM -0777 -E '$d=Mojo::DOM->new(<>); $n=$d->at(q(attribute value)); $n->content($n->text =~ s/(\d+)\z/$1+1/er); say $d' text.xml<attribute>    <name>test</name>    <type>java.lang.String</type>    <value>node1-4</value></attribute>

Mojo has an ojo module (so, with -M, spells Mojo) that makes this slightly simpler at the expense of declaring variables. It's x() is a shortcut for Mojo::DOM->new():

$ perl -Mojo -0777 -E 'my $d=x(<>); my $n=$d->at(q(attribute value)); $n->content($n->text =~ s/(\d+)\z/$1+1/er); say $d' text.xml<attribute>    <name>test</name>    <type>java.lang.String</type>    <value>node1-4</value></attribute>