in reply to XML::Twig - parsing an XML doc to separate files : Maintaining 'absolute' path

It seems to me that for each element of the appropriate level, you want to output the entire tree, including the element, then delete the element so when you get to the next element you get a "clean" tree.

The code below gives you the output you want:

#!/usr/local/bin/perl -w use strict; use XML::Twig; my $xml_twig = XML::Twig->new( pretty_print => 'indented', NoLWP => 1, discard_spaces => 1, twig_handlers => { 'level(1)' => \&dump_partial_tree } ); $xml_twig->parse ( \*DATA ) || die "\nError parsing data $@\n"; sub dump_partial_tree { my( $xml_twig, $element)= @_; print "\n\nName : " . $element->name . "\n"; $xml_twig->print; print "\n"; $element->delete; } __DATA__ <myconfig_data> <level1> <tag>hello1</tag> </level1> <level2> <tag>hello2</tag> </level2> <level3> <tag>hello3</tag> </level3> </myconfig_data>
  • Comment on Re: XML::Twig - parsing an XML doc to separate files : Maintaining 'absolute' path
  • Download Code

Replies are listed 'Best First'.
Re^2: XML::Twig - parsing an XML doc to separate files : Maintaining 'absolute' path
by Anonymous Monk on Feb 22, 2006 at 16:22 UTC
    Excellent. Thanks ( I hadn't considered using 'level' ) To expand this however, should I them wish to further parse child-elements, or maybe deeper, into separate files, how would I best go about this ?

    I possibly naively considered the approach :

    Parse the twig.

    then, for ( various 'xpaths' )

    jump to element, print 'absolute' recursive output for element

    remove element

    done

    I suppose I am looking to 'move around' my parsed twig, but without using a handler, in my mind this would maybe give me more flexibility.

    Is this possible, and / or unwise ?

      Of course it is possible. I like using handlers because then you get rid of some of the tree before having to load it entirely in memory, plus I am used to it, and I find it often simpler than using XPath or navigation to get to the elements I want to process.

      If size is not a problem you can certainly load the tree, and then write custom code to output the element and the tree "above it":

      #!/usr/local/bin/perl -w use strict; use XML::Twig; my $xml_twig = XML::Twig->new( pretty_print => 'indented', NoLWP => 1, discard_spaces => 1, EltClass => 'my_elt', ); $xml_twig->parse ( \*DATA ) || die "\nError parsing data $@\n"; # here I split on the 'split' attribute, but any other # way of getting the list of elements to split on is OK foreach my $elt ($xml_twig->findnodes( '//*[@split]')) { print "Element: ", $elt->name, "\n\n", $elt->sub_doc, "\n\n"; $elt->delete; } package my_elt; use base 'XML::Twig::Elt'; sub sub_doc { my $elt= shift; return $elt->start_tags . $elt->sprin +t . $elt->end_tags; } sub start_tags { my $elt= shift; return join '', map { $_->start_tag } + reverse $elt->ancestors; } sub end_tags { my $elt= shift; return join '', map { $_->end_tag } + reverse $elt->ancestors; } package main; __DATA__ <myconfig_data foo="bar"> <level1 split="1"> <tag>hello1</tag> </level1> <level2> <sub split="1"> <tag>hello2</tag> </sub> <sub split="1"> <tag>hello3</tag> </sub> </level2> <level3 split="1"> <tag>hello4</tag> </level3> </myconfig_data>