Search code examples
xmlperlparent

How to get parent node's parent node in XML


I'm using the XML::Parser to parse different XML files and put their content into the database. Since the structure of the files can vary from file to file, I can't hardcode any node name in my code. At some point I need to know the parent node's parent node. Is it possible to get it somehow?

Here's my current script:

use XML::Parser;
use XML::Parser::Nodes;
use DBI qw(:sql_types);
use Error qw(:try);

my %var;

my $filename='x.xml';

my $parser=XML::Parser->new(Style=>'Nodes', Handlers=>{
  Init => \&handle_doc_start
  , Final => \&handle_doc_end
  , Start=>\&handle_start
  , End=>\&handle_end
  , Char=>\&handle_char
  , Default=>\&handle_default });
$parser->parsefile( $filename );

sub handle_doc_start { }
sub handle_doc_end { }

sub handle_start {
  my($expat,$element,%attrs) = @_;

  my $row_id=$expat->element_index;
  my $depth=$expat->depth;
  my $parent=$expat->current_element;

  if (defined($var{$parent.$element.$depth})) { $var{$parent.$element.$depth}++; }
  else { $var{$parent.$element.$depth}=1; }

  # write the tags/elements data into the database

  if(%attrs) {
    while (my ($key,$value)=each(%attrs)) {
      # write the attributes into the database
    }
  }
}

sub handle_end {}

sub handle_char {
  my ($expat,$data) = @_;
  my $row_id=$expat->element_index;

  chomp $data;
  $data=~ s/^\s+//; $data=~ s/\s+$//;

  if (defined($data) && ($data ne '')) {
    # write the values into the database
  }
}

sub handle_default {}

Thank you for your help in advance!


Solution

  • Did you try the context method?

    context
               Returns a list of element names that represent open elements, with
               the last one being the innermost. Inside start and end tag handlers,
               this will be the tag of the parent element.
    

    BTW, I am not sure mixing XML::Parser::Nodes and handlers is a good idea. Since XML::Parser::Nodes declares its own handlers (mostly re-using XML::Parser's Tree style handlers) I strongly suspect either your handlers or XML::Parser::Nodes' are ignored. If your handlers are run then it looks like you could get rid of XML::Parser::Nodes.