Beefy Boxes and Bandwidth Generously Provided by pair Networks BBQ
laziness, impatience, and hubris
 
PerlMonks  

How to fetch a portion of a XML file to save it in another xml file

by tarunmudgal4u (Sexton)
on Sep 05, 2013 at 13:59 UTC ( #1052571=perlquestion: print w/ replies, xml ) Need Help??
tarunmudgal4u has asked for the wisdom of the Perl Monks concerning the following question:

There is one requirement wherein I want to extract some nodes from a XML file and create a temporary file with those extracted nodes.

Below is testng.xml sample file -

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"> <suite name="Automation Suite" verbose="1" parallel="false"> <test name="Configuration Restore Test Suite"> <classes> <class name="com.qa.testsuite.ConfigurationRestoreTests" /> </classes> </test> <test name="Import Test Suite"> <classes> <class name="com.qa.testsuite.ImportTests" /> </classes> </test>

In the above testng.xml file, I want to extract only some of the nodes and save it in another file for further execution. for example, if I want to extract below code, then how to do it?

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"> <test name="Import Test Suite"> <classes> <class name="com.qa.testsuite.ImportTests" /> </classes> </test>

I have heard about XML::LibXML and XML::Parser modules but it seem to be difficult to understand when i saw their documentation. Is there any other modules as well which can solve my problem? Please let me know from where I can start to solve this problem.

Comment on How to fetch a portion of a XML file to save it in another xml file
Select or Download Code
Re: How to fetch a portion of a XML file to save it in another xml file
by Random_Walk (Parson) on Sep 05, 2013 at 14:03 UTC

    XML::Twig is a nice simple one. Parse your file as per the example in the docco, have a look with Data::Dumper and away you go.

    Cheers,
    R.

    Pereant, qui ante nos nostra dixerunt!
Re: How to fetch a portion of a XML file to save it in another xml file
by sundialsvc4 (Monsignor) on Sep 05, 2013 at 16:05 UTC

    I suggest that you take a good look at XSLT.   Here is a good article: http://www.xml.com/pub/a/2003/11/26/learnXSLT.html.

    The main reason why I suggest this, which BTW is not directly related to Perl (although fully supported by LibXML and hence by the Perl packages that employ it), is that:   “extracting elements from an XML document to produce another XML (or HTML) document” is a very generic business requirement.   Your browser can do it; so can Excel and many other data analysis tools.   All of them are applying XSLT technologies.   (A particularly striking example are the “interactive periodic table of the elements” sites, which, if you browse the page source-code, are predominantly using XSLT to cause your browser to do the work.)   You might not have to “construct a computer program” to do this ... not at all.   If so, that can be a big win.

    In essence, an XSLT document is an XML document which contains, among other things, directives which include “XPath expressions” that specify what you are looking for, and surrounding-material which defines the target-document into which these elements will be inserted.   It is, admittedly, a cumbersome technology, yet a very powerful one.   Yes, Perl fully supports it (through the LibXML-based packages), yet, you do not have to use Perl (nor any other programming language) to avail yourself of it.

Re: How to fetch a portion of a XML file to save it in another xml file
by Tux (Monsignor) on Sep 05, 2013 at 18:09 UTC

    I agree that XSLT is the correct way to go, (using XML:LibXSLT), but it imposes a new language: xslt might be quite confronting. OTOH, when you succeed with XSLT, you can be sure the resulting XML is healty.

    When that hurdle it too high, a look at XML::LibXML might be the easy alternative. Look at XML::LibXML::Node's documentation for the most complete starting docs.


    Enjoy, Have FUN! H.Merijn
Re: How to fetch a portion of a XML file to save it in another xml file
by Your Mother (Canon) on Sep 05, 2013 at 18:55 UTC

    Note, I closed your suite for you.

    use strictures; use XML::LibXML; my $before = <<""; <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"> <suite name="Automation Suite" verbose="1" parallel="false"> <test name="Configuration Restore Test Suite"> <classes> <class name="com.qa.testsuite.ConfigurationRestoreTests" /> </classes> </test> <test name="Import Test Suite"> <classes> <class name="com.qa.testsuite.ImportTests" /> </classes> </test> </suite> my $doc = XML::LibXML->new->load_xml( string => $before ); my ( $test_suite ) = $doc->findnodes('/suite/test[@name="Import Test S +uite"]'); $doc->setDocumentElement( $test_suite ); print $doc->serialize; # or $doc->toFile(...)

    This may or may not be sane given the DTD but it gives the output you want. Update, there is a toFile() method for the doc.

      Thanks for your input. It's working partially. In case, if I want to add multiple test nodes based on user choice how can I do that. In this example, I can extract only one node based on XPath.

      Also, I want to include suite node in the new.xml file.

        I do think it's time for you to start reading the XML::LibXML docs. See if you can at least get the multiple test nodes captured/found, it's quite a small adjustment. Post what you come up with and if you can't work it all out, I or someone will help you finish.

        Oh, ok! You wore me out and I wrote it yesterday and there's no reason for it to die of bitrot in some corner of my disk. I do hope you will try to pick up a little of it and not just get others to write it for you.

        my $doc = XML::LibXML->new->load_xml( string => $before ); my @tests = $doc->findnodes('/suite/test[@name="Import Test Suite"]'); my $suite = $doc->getDocumentElement; $suite->removeChildNodes; $suite->addChild($_) for @tests; print $doc->serialize(1); # or $doc->toFile("new.xml")
Re: How to fetch a portion of a XML file to save it in another xml file
by runrig (Abbot) on Sep 06, 2013 at 15:45 UTC
    Here's an example using XML::Rules. The only tricky part is the DOCTYPE handler, which I'm not totally sure about, but it works for your example:
    use XML::Rules; use Data::Dumper; my $xml = <<XML; <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd"> <suite name="Automation Suite" verbose="1" parallel="false"> <test name="Configuration Restore Test Suite"> <classes> <class name="com.qa.testsuite.ConfigurationRestoreTests" /> </classes> </test> <test name="Import Test Suite"> <classes> <class name="com.qa.testsuite.ImportTests" /> </classes> </test> </suite> XML my @rules = ( '^test' => sub { $_[1]->{name} eq 'Import Test Suite' }, ); my $xr = XML::Rules->new( style => 'filter', rules => \@rules, handlers => { Doctype => sub { my (undef, $name, $sysid) = @_; print qq(<!DOCTYPE $name SYSTEM "$sysid">\n); }}, );

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1052571]
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others scrutinizing the Monastery: (10)
As of 2014-04-25 08:57 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    April first is:







    Results (585 votes), past polls