tags:

views:

191

answers:

4

Hi,

I get the following XML:

<config>
  <version general="1.2.3">
    <subtype type="a" version="1.2" />
    <subtype type="b" version="3.6" />
    ...
  </version>
  ...
</config>

I have some code in Perl to get the config node from a database.

After I get it, if I try the follwoing:

my $elem = $cfg->getElementsByTagName("version");
my $generalVer = $elem ? $elem->get_node(1)->getAttribute("general") : undef;

all is working fine, $generalVer contains 1.2.3, as exected.

But if I try this:

my $elem = $cfg->getElementsByTagName("version/subtype[@type='a']");
my $aVersion = $elem ? $elem->get_node(1)->getAttribute("version") : undef;

it fails with the message "Invalid predicate".

What can be the problem?

+3  A: 

The getElementsByTagName method expects a name, I don't think it supports XPath. To use XPath queries, you'd have to use a module like XML::XPath instead of XML::DOM.

Here's an example using XML::XPath:

#!/usr/bin/perl
use strict;
use warnings;
use XML::XPath;

my $xml = <<END;
<config>
  <version general="1.2.3">
    <subtype type="a" version="1.2" />
    <subtype type="b" version="3.6" />
  </version>
</config>
END

my $xp = XML::XPath->new(xml => $xml);
my $nodeset = $xp->find("//version/subtype[\@type='a']");
foreach my $node ($nodeset->get_nodelist) {
    my $version = $node->getAttribute("version");
    print "Version: $version\n";
}

Note that you have to escape the @ in subtype[\@type='a', otherwise Perl will be looking for an array called @type.

Andomar
correct. although this could be library specific.
George
+2  A: 

You have to use XPath to pick out your element with a path or do it in two steps. getElementsByTagName() can only handle tag names - not paths to elements. XPath is preferred when you do conditional selects, though (which you are with "@type='a'").

Björn
+5  A: 

I strongly suspect that "version/subtype[@type='a']" is not, in fact, a tag name. That looks like an XPath query.

I'm assuming you're using something like XML::DOM to parse this XML. If you want to use XPath, then you can use XML::DOM::XPath, which adds XPath support.

For example,

 use XML::DOM;
 use XML::DOM::XPath;
 ...
 my $elem = $cfg->findnodes( q{//version/subtype[@type='a']} );
friedo
I suspect you want to single quote that argument. :)
brian d foy
Good point. Fixed.
friedo
+2  A: 

Thanks everybody for the answers.

Short time after I asked the question, someone answered that the problem was the single quote and if I'll use double quotes it would work. i.e. @type="a" instead of @type='a'.

Well, this indeed solved it. But when I tried to mark his answer as the correct answer I found out that he deleted it.

So I'm posting the answer myself, just for the record.

The following code works just fine:

my $elem = $cfg->getElementsByTagName("version/subtype[@type=\"a\"]");
my $aVersion = $elem ? $elem->get_node(1)->getAttribute("version") : undef;

Thanks.

Dikla