Search code examples
perlxml-simple

Search XML Element Value By Name Perl


I am basically a java developer but my client gave me small task in perl. The task is that I will get xml input in that I need to search a element and print it's value(save value in String variable). e.g. in below xml I want to read the value of FileName tag.

<ConnectHome SchemaVersion="1.0.8">
  <TransType>0090</TransType>
  <Node>
    <ExternalFiles>
      <FileName>some file name</FileName>
    </ExternalFiles>
  </Node>
</ConnectHome>

I am using XML:Simple library to parse XML. And I am also able to read the value of element using below code.

$xmlSimple = new XML::Simple(KeepRoot   => 1);
$dataXML = $xmlSimple->XMLin("RepeatedElement.xml");
my $fileNameValue = $dataXML->{ConnectHome}->{Node}->{ExternalFiles}->{FileName};

But my client want to search the value using element name as the path may change in xml.

"FileName"

and not the hard coded path.

So my question is how I can get value by name of the element instead of hardcoded path? Is there a method to search element by name? I will pass name of element in string variable.


Solution

  • If this is your only task, you could switch to another library, like XML::Twig, that would make this a lot easier.

    Also consider this note from XML::Simple's documentation

    The use of this module in new code is discouraged. Other modules are available which provide more straightforward and consistent interfaces. In particular, XML::LibXML is highly recommended.

    The major problems with this module are the large number of options and the arbitrary ways in which these options interact - often with unexpected results.

    Patches with bug fixes and documentation fixes are welcome, but new features are unlikely to be added.

    Here's an example utilizing XML::Twig. Set handlers for the elements you're interested in. (in this case, I'm pushing the text contents into an array).

    use XML::Twig;
    
    my @filenames;
    my $twig = XML::Twig->new(
      twig_handlers => {FileName => sub {push @filenames, $_->text}}
    );
    
    $twig->parse(*DATA);
    # $twig->parsefile('RepeatedElement.xml'); # you probably want this
    
    
    say ">>$_<<"for @filenames;
    
    __DATA__
    <ConnectHome SchemaVersion="1.0.8">
      <TransType>0090</TransType>
      <Node>
        <ExternalFiles>
          <FileName>some file name</FileName>
        </ExternalFiles>
      </Node>
    </ConnectHome>
    

    Another way you could go is take some basic parsing library, like XML::Parser, XML::Parser::Expat, XML::TokeParser, XML::LibXML and assemble the text yourself, though this might be too tedious for such a simple task.

    You could also use XML::XPath (xpath is a query language designed to navigate within an DOM tree):

    use XML::XPath;
    
    my $xp = XML::XPath->new(filename => 'RepeatedElement.xml');
    my $filename = $xp->find('//FileName');