Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine
 
PerlMonks  

XPath with node names and attributes...

by biswanath_c (Beadle)
on Oct 16, 2009 at 15:43 UTC ( [id://801578]=perlquestion: print w/replies, xml ) Need Help??

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


Hi,

I am using XML::LibXML to parse an XML doc. I would like to use XPaths to get values of different nodes and attributes. findnodes(...) API seems to work for nodes (ex: root/head/node1 ) but it gives an error "invalid expression" for XPaths with attrbiutes (ex: root/head/node1/@att1 where att1 is an attribute of node node1).

I'd like to use a "common" API that would "find" AND "get the value of" XPaths irrespective of whether the XPath is pointing to a node or an attribute. Could someone give me an API that'd work generically both for nodes AND attributes without having to handle them separately in my code?


  • Comment on XPath with node names and attributes...

Replies are listed 'Best First'.
Re: XPath with node names and attributes...
by Corion (Patriarch) on Oct 16, 2009 at 15:58 UTC

    Just give the XPath engine properly formatted XPath queries and all will work.

    In your case, that likely means using:

    root/head/node1@att1

    instead of

    root/head/node1/@att1

      There must be something I am missing here. root/head/node1@att1 is invalid, while root/head/node1/@att1 works just fine. I tested that with several tools, including XML::LibXML.

      I would actually had the starting slash: /root/head/node1@att1.


      I tried using the XPath that you suggested (root/head/node1@att1). But in that case, i call findnodes(<XPath with attribute>) and iterate thru the resulting array and call findValue(".") on the array elements, it returns nothing! i tried calling nodeValue() also, that too returned nothing! i tried textContent(), it returned value of the node but not the value of the attribute!

      What do i do?

        Actually, I am wrong and you are right - queries for attributes also need / as the separator. I thought the @ would separate a element node from an attribute node, as the documentation seems to suggest to me in //title[@lang], but upon actually trying it, I find that only node/@attribute works for me, and likely is the correct query to use.

Re: XPath with node names and attributes...
by thunders (Priest) on Oct 16, 2009 at 16:56 UTC
    Perhaps It would help if you provide some example code and xml that demonstrates the problem you are having.

      okay! here we go. I am just giving an example here that I tested and which demonstrates my problem:


      The XML:
      <root> <head> <node1 attr1="Node1 Attribute"> Node1 Value </node1> </head> </root>


      The PERL script that tries to read the attribute:

      use XML::LibXML; $inp = $ARGV[0]; # create object my $parser = XML::LibXML->new(); # read input XML file my $inp_tree = $parser->parse_file($inp); my $inp_root = $inp_tree->getDocumentElement; my $root_text = $inp_root->toString(); $rule_source = "head/node1@attr1"; my @inp_search_nodes = $inp_root->findnodes($rule_source); my $inp_search_results = scalar @inp_search_nodes; if ( 0 == $inp_search_results ) { print "XPath $rule_source not found! \n"; } else { my $path_text = $inp_search_nodes[ 0 ]->findvalue("."); print "Xpath ->: $path_text\n"; my $val = $inp_search_nodes[ 0 ]->textContent(); + print "Value of XPath $rule_source : $val \n"; }

      If i search for XPath head/node1@attr1 , the code works fine and fetches the value of the node.

      If i use XPath XPath /head/node1@attr1 , the program gives the error :
       "/head/node1 not found!"

      If i use the Xpath, i get this error:
       Invalid expression

      If I use the XPath "/head/node1/@attr1", I get this error:
       Invalid expression


        Didn't have a chance to test your example, but I think this is the problem:

        $rule_source = "head/node1@attr1";

        Perl thinks you want to insert the contents of an array called @attr1 into the string because you used double quotes. Since there is no such array your $rule_source ends up with just "head/node1". Either escape the '@' or use a single quoted string as in the examples below:

        $rule_source = "head/node1\@attr1"; # or $rule_source = 'head/node1@attr1';

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://801578]
Approved by wfsp
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others exploiting the Monastery: (5)
As of 2025-03-25 22:09 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    When you first encountered Perl, which feature amazed you the most?










    Results (67 votes). Check out past polls.

    Notices?
    erzuuliAnonymous Monks are no longer allowed to use Super Search, due to an excessive use of this resource by robots.