http://qs1969.pair.com?node_id=11138619

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

Hello, I need a way to search and find some tags and values in my input xml and if that exist, i want to create a new xml file based on that. For example my input file looks something as below
<?xml version="1.0" encoding="UTF-8"?> <TestCode version="10.0"> <TestCategory name="SmokeTest"> <Test name="CheckType_123" type="String"> <Test_description>No description available for this Test < +/Test_description> <context name="Testing"> <value>ABC</value> <value>XYZ</value> </context> </Test> <Test name="CheckType_PQR" type="String"> <Test_description>No description available for this Test</ +Test_description> <context name="SmokeTest"> <value>ABC</value> </context> </Test> <Test name="ValueAdded_123" type="String"> <Test_description>No description available for this Test</ +Test_description> <context name="Testing"> <value>ABC</value> <value>XYZ</value> </context> </Test> </TestCategory> </TestCode>
From the above input xml file, I need to check if i have tag <Test name=CheckType_* and if yes, i need to check if i have context/vlaue = XYZ. If exist i need to take the whole <Test ...> </Test> tag and put it in a new xml file. So from the above xml, the output what i need is:
<?xml version="1.0" encoding="UTF-8"?> <TestCode version="10.0"> <TestCategory name="SmokeTest"> <Test name="CheckType_123" type="String"> <Test_description>No description available for this Test</ +Test_description> <context name="Testing"> <value>ABC</value> <value>XYZ</value> </context> </Test> </TestCategory> </TestCode>
because from my input xml, the second Test tag has no value XYZ and 3rd Test tag has no name starting with CheckType_*. Can you help me with this?

Replies are listed 'Best First'.
Re: xml to xml converter
by haukex (Archbishop) on Nov 09, 2021 at 14:39 UTC

    Although my go-to XML module is XML::LibXML, XML::Twig is useful for filtering XML files. The following produces your expected output for the given input:

    use warnings; use strict; use XML::Twig; use XML::XPath; # for findnodes my $filename = 'foo.xml'; XML::Twig->new( twig_print_outside_roots => 1, keep_spaces => 1, twig_roots => { '/TestCode/TestCategory/Test' => sub { my ($t, $elt) = @_; if ( $elt->{att}{name} =~ /^CheckType_/ ) { my @values = $elt->findnodes('./context/value'); # could theoretically also use XPath for the following if ( grep { $_->text =~ /XYZ/ } @values ) { $t->flush } else { $t->purge } } else { $t->purge } }, }, )->parsefile($filename);
      Thank you for quick response but i get an error Can't locate XML/Twig.pm in @INC when running this. How can i install in module in Windows?
        Thank you for quick response but i get an error Can't locate XML/Twig.pm in @INC when running this. How can i install in module in Windows?

        The same way you would install any other module. In Strawberry Perl, cpanm XML::Twig XML::XPath works for me.

Re: xml to xml converter
by choroba (Cardinal) on Nov 09, 2021 at 16:30 UTC
    This is how you can do it in XML::XSH2, a wrapper around XML::LibXML. You can experiment with the code in its xsh shell interactively.
    my $out := create "TestCode" ; set $out/TestCode/@version "10.0" ; set $out/TestCode/TestCategory/@name "SmokeTest" ; open file.xml ; cp //Test[starts-with(@name, "CheckType_")][context/value = "XYZ"] into $out/TestCode/TestCategory ; save :f output.xml $out ;

    Or maybe, more simply, remove any Test that doesn't match the criteria:

    open 1.xml ; delete ( //Test[not(starts-with(@name, "CheckType_"))] | //Test[starts-with(@name, "CheckType_")][not(context/value = +"XYZ")] ) ; save :f 1.out ;

    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
Re: xml to xml converter
by perlfan (Vicar) on Nov 10, 2021 at 10:56 UTC
    Idk if one of the utlilties provided by WC3's HTML/XML utilities, which reminds me Perl has no interface to this. When this comes up, I always want to create a module that embeds these tools (like DBD::SQLite embeds sqlite3) and provide a Perl interface to them...maybe one day. :)