leoberbert has asked for the wisdom of the Perl Monks concerning the following question:

Dear,

I have an a.xml file and need to insert the contents of the a.xml file into a different b.xml file before a string, for example:

cat a.xml <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> b.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>

In this case I need to insert before "</ catalog>" the contents of the a.xml file.

Can you help me?

Regards.

Replies are listed 'Best First'.
Re: inserting a tag before a string
by choroba (Cardinal) on Nov 30, 2017 at 22:53 UTC
    Very easy in XML::XSH2, a wrapper around XML::LibXML:
    my $book := open a.xml ; my $catalog := open b.xml ; copy $book/book append $catalog/catalog ; save :b $catalog ;
    ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,
Re: inserting a tag before a string
by roboticus (Chancellor) on Nov 30, 2017 at 18:29 UTC

    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.

      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.
Re: inserting a tag before a string
by hippo (Archbishop) on Nov 30, 2017 at 12:22 UTC
    Can you help me?

    Which part are you having trouble with?

      I can not do insert before tag "</catalog>"

        Hi leobebert. This is really basic. When you seek help on a technical forum, it's useless and annoying to those that could help you, to say only "this doesn't work" or "I can't do that".

        Give the information that will allow any willing helpers to diagnose your problem. Specifically: What tool(s) are you using, what documentation have you read, what code have you tried, what result do you get? This means, show your actual attempt and your actual results. No more vague questions!


        The way forward always starts with a minimal test.
        I can not do insert before tag "</catalog>"
        You don't provide enough information, so this is a shoot in the dark. Are you aware that it is not usually possible to directly modify the contents an ordinary sequential file (except appending new contents at the end). But there are some ways to work around that limitation.

        One of the common ways to modify a file is to read it into memory, to modify the contents in memory, and to write back the modified contents into the file (i.e. clobbering the existing content). Usually, you would first rename the original file or use a temporary file for writing, and do the necessary house-cleaning afterwards, once you have confirmed that everything went well, just to make sure you don't accidentally delete your original data.

Re: inserting a tag before a string
by Anonymous Monk on Nov 30, 2017 at 12:58 UTC