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

Update:

Posting here seems to mobilise me to look harder, even on a Friday afternoon before a 3 day weekend...
XML::Simple seems to do what I asked for below.

Of course, comments still welcome.

------

I have been looking at XML parsing modules all day and either can't find the one I need or found it and couldn't figure out how to use it... so I humbly ask for help.

Given this XML

<City name="Some City"> <Properties location="SomeCountry"> <StreetList version="1"> <Street name="Foo Street" bars="none"> <Street name="Bar Street" bars="plenty"> </StreetList> </City> <City name="Other City"> <Properties location="Narnia"> <StreetList version="5"> <Street name="Lovely Street" bars="some"> <Street name="Gray Street" bars="none"> </StreetList> </City>

What is the best way to load only a single 'City' element with its related information, to query further?
I want to choose a street to visit while I'm in a given city with something like

my $current_city = 'Some City'; my $xml = Module->parse('myfile.xml', //City[@name=$current_city); my @street_list = $xml->findnodes('/Street'); print "In $current_city these streets have bars: "; foreach my $street (@street_list) { if ($street->{bars} ne 'none') { my $street_name = $street->{name}; print "$street_name"; } }

Running that would produce

In Some City these streets have bars: Bar Street

Replies are listed 'Best First'.
Re: XML Parsing
by choroba (Cardinal) on May 27, 2016 at 14:04 UTC
    You XML is not well-formed. Many closing tags are missing, or you can make the Properties and Street tags empty.
    <Properties location="SomeCountry"/> <!-- ^ -->

    Then, the correct XPath expression to use is

    //City[@name=$current_city]/StreetList/Street[@bars!='none']/@name

    Tested in XML::XSH2 (after wrapping the fixed XML chunk into a Cities element), a wrapper around XML::LibXML:

    open cities.xml ; my $current_city = 'Some City' ; echo //City[@name=$current_city]/StreetList/Street[@bars!='none']/@nam +e ;

    Update: The same thing using XML::LibXML:

    #!/usr/bin/perl use warnings; use strict; use feature qw{ say }; use XML::LibXML; # Only needed if the city name can contain a double quote. Tested with + "Some" City". sub quote { my $string = shift; if ($string =~ /"/) { my @substrings = split /"/, $string, -1; $string = 'concat("' . join(q(", '"', "), @substrings) . '")'; } else { substr $string, $_, 0, '"' for 0, -1; } return $string } my $current_city = 'Some City'; my $dom = 'XML::LibXML'->load_xml( location => shift ); my $quoted_city = quote($current_city); my @streets = $dom->findnodes('//City[@name=' . $quoted_city . ']/Stre +etList/Street[@bars!="none"]'); say for map $_->findvalue('@name'), @streets;

    ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,
Re: XML Parsing
by Laurent_R (Canon) on May 27, 2016 at 17:38 UTC
    XML::Simple seems to do what I asked for below.
    Well, maybe not the best choice.

    Please take a look at this thread:

    XML::Simple needs to go!

Re: XML Parsing -- XML::Twig
by Discipulus (Canon) on May 28, 2016 at 18:45 UTC
    UPDATE: do not use XML::Simple; use XML::Twig see also Re: Parsing xml

    use strict; use warnings; use XML::Twig; my %ok_cities; my $twig= XML::Twig->new(pretty_print => 'indented', twig_handlers=>{ '/cities/City/StreetList/Street'=>sub{ if ($_[1]->att('bars')!~/none/){ push @{$ok_cities{$_[1]->parent()->parent()->at +t('name')}}, $_[1]->att('name'); } } } ); $/=''; $twig->parse(<DATA>); print map {"In '$_' these streets have bars: ". (join',',@{$ok_cities{$_}}). "\n"} sort keys %ok_cities; __DATA__ <?xml version="1.0" encoding="UTF-8"?> <cities> <City name="Some City"> <Properties location="SomeCountry"/> <StreetList version="1"> <Street name="Foo Street" bars="none"/> <Street name="Bar Street" bars="plenty"/> </StreetList> </City> <City name="Other City"> <Properties location="Narnia"/> <StreetList version="5"> <Street name="Lovely Street" bars="some"/> <Street name="Gray Street" bars="none"/> </StreetList> </City> </cities>

    L*

    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.