Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"
 
PerlMonks  

Re: inserting a tag before a string

by roboticus (Chancellor)
on Nov 30, 2017 at 18:29 UTC ( [id://1204624]=note: print w/replies, xml ) Need Help??


in reply to inserting a tag before a string

leoberbert:

You can certainly do it with a regex or string substitution. But if you're going to be maintaining this and/or plan to work with more XML data, you'll really want to just learn how to work with XML. I've lately been playing with XML::Twig and find it pretty reasonable, though I still have much to learn.

So I went ahead and converted your question to an XML::Twig answer, though I had adjusted your problem a little: Specifically, I'm assuming you'll be wanting to add any number of new books to your catalog at a time. So for the input files, I used:

new_items.xml
<newitems> <book id="bk101"> <author>Gambardella, Matthew</author> <title>XML Developer's Guide</title> <genre>Computer</genre> <price>44.95</price> <publish_date>2000-10-01</publish_date> <description>An in-depth look at creating applications with XML.</description> </book> </newitems>
current_catalog.xml
<?xml version="1.0"?> <catalog> <book id="bk112"> <author>Galos, Mike</author> <title>Visual Studio 7: A Comprehensive Guide</title> <genre>Computer</genre> <price>49.95</price> <publish_date>2001-04-16</publish_date> <description>Microsoft Visual Studio 7 is explored in depth, looking at how Visual Basic, Visual C++, C#, and ASP+ are integrated into a comprehensive development environment.</description> </book> </catalog>

And the program I whipped up to merge the new items into your catalog:

#!/usr/bin/perl use strict; use warnings; use XML::Twig; my $xmlParser = XML::Twig->new(); # Fetch the new books to add to the catalog my $new_items = fetch_xml('new_items.xml'); my @add; for my $book ($new_items->root->children('book')) { push @add, $book->copy(); } print scalar(@add), " new books to add to the catalog!\n"; # Add the books to the catalog my $cur_catalog = fetch_xml('current_catalog.xml'); for my $book (@add) { # Each book will be added after the last book in the catalog $book->paste(last_child => $cur_catalog->root); } # Now dump our current catalog $cur_catalog->flush( \*STDERR, pretty_print=>'indented' ); sub fetch_xml { my $fname = shift; my $txt = do { open my $FH, '<', $fname or die "$fname: $!"; local $/; <$FH>; }; $xmlParser->parse($txt); return $xmlParser; }

Which (when run on my machine) gives:

$ perl ex_XML_merge_twig.pl 1 new books to add to the catalog! <?xml version="1.0"?> <catalog> <book id="bk112"> <author>Galos, Mike</author> <title>Visual Studio 7: A Comprehensive Guide</title> <genre>Computer</genre> <price>49.95</price> <publish_date>2001-04-16</publish_date> <description>Microsoft Visual Studio 7 is explored in depth, looking at how Visual Basic, Visual C++, C#, and ASP+ are integrated into a comprehensive development environment.</description> </book> <book id="bk101"> <author>Gambardella, Matthew</author> <title>XML Developer's Guide</title> <genre>Computer</genre> <price>44.95</price> <publish_date>2000-10-01</publish_date> <description>An in-depth look at creating applications with XML.</description> </book> </catalog>

I originally tried to have two XML documents open and copy/paste items from one into the other, but my XML::Twig-fu isn't adequate. So I opted to build an array of books copied out of the first one, then paste the copies into the new document. I'll have to bone up a bit more on XML::Twig to see how to process multiple documents at once. But this should hopefully get you off to a good start in XML whacking after you tire of the "fun" of regexes and string manipulation.

...roboticus

When your only tool is a hammer, all problems look like your thumb.

Replies are listed 'Best First'.
Re^2: inserting a tag before a string (XML::Twig) -- oneliner
by Discipulus (Canon) on Nov 30, 2017 at 22:16 UTC
    Hello roboticus,

    > I originally tried to have two XML documents open and copy/paste items from one into the other

    Well, possible it's possible, not beauty (and I added some spaces..;) but..

    perl -MXML::Twig -e "BEGIN{$f=shift @ARGV} map{ XML::Twig->new(twig_handlers => { 'newitems/book' => sub { push @ +content, $_; $_->cut }})->parsefile($_) }@ARGV; XML::Twig->new(pretty_print=>'indented',twig_handlers => {'catalog' => sub {foreach my $content ( @content ) {$content->paste( last_child +=> $_ );}}})->parsefile($f)->flush " current_catalog.xml new_items.xml

    L*

    PS updated, obfuscated and shortened

    perl -MXML::Twig -e "map{$t=XML::Twig->new(twig_handlers=>{$s?('catalo +g'=>sub{foreach$c(@c){$c->paste(last_child=>$_)}}):('newitems/book'=> +sub{push@c,$_;$_->cut})})->parsefile($_);$s++;}@ARGV;$t->flush" newb +ook.xml catalog.xml

    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://1204624]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others romping around the Monastery: (2)
As of 2024-04-24 22:52 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found