XML :: libxml findnodes () nevrací výsledky, je-li přítomna xmlns

hlasů
1

Jsem pomocí XML :: libxml :: Reader zpracovat rozsáhlý dokument a narazit na problém, kterým je atribut xmlns způsobuje findnodes () se nezdaří. Opravil jsem ji z přidané regex odstranit atribut xmls ale napadlo mě, jestli tam byl elegantnější řešení zahrnující bez regexes. Pokud odeberete regex linku ($ xml = ~ s {xmlns ...) uvidíte, že říkají Loc = $ loc neprodukuje žádné výsledky.

Zde je kód:

use strict;
use warnings;
use feature qw( say );
use XML::LibXML::Reader qw( XML_READER_TYPE_ELEMENT );

my $xml = <<'__EOI__';
<url xmlns=http://www.sitemaps.org/schemas/sitemap/0.9>
    <loc>http://example.com</loc>
    <lastmod>2018-10-19</lastmod>
</url>
__EOI__


$xml =~ s{xmlns=http://www.sitemaps.org/schemas/sitemap/0.9}{};

my $reader = XML::LibXML::Reader->new( string => $xml);
while ( $reader->read ) {
    next unless $reader->nodeType == XML_READER_TYPE_ELEMENT;
    next unless $reader->name eq 'url';
    my $xml = $reader->readOuterXml;
    my $doc = XML::LibXML->load_xml(string => $xml);
    say Doc = $doc;
    my ($loc) = $doc->findnodes('//loc');
    say Loc = $loc;
}
Položena 20/10/2018 v 12:37
zdroj uživatelem
V jiných jazycích...                            


2 odpovědí

hlasů
4

Ptáš se najít uzly s namespace null as názvem loc. Neexistují žádné takové uzly v dokumentu, takže findnodessprávně vrátí nic.

Chcete-li najít uzly s názvů http://www.sitemaps.org/schemas/sitemap/0.9a s názvem loc. Můžete použít následující dosáhnout toho, aby:

my $doc = XML::LibXML->load_xml( string => $xml );

my $xpc = XML::LibXML::XPathContext->new();
$xpc->registerNs( sm => 'http://www.sitemaps.org/schemas/sitemap/0.9' );

my ($loc) = $xpc->findnodes('//sm:loc', $doc);
Odpovězeno 20/10/2018 v 13:23
zdroj uživatelem

hlasů
1

Váš kód začíná pomocí XML::LibXML::ReaderAPI a později používá XML::LibXML->load_xmlk vytvoření DOM z části dokumentu. XML::LibXML::ReaderAPI se obvykle používá pouze s obrovskými XML dokumenty, které by spotřebovávají velké množství paměti při zatížení jako DOM. Pokud je váš XML dokument není velký, pak je to mnohem jednodušší použít postup jako Ikegami je odpověď , která právě používá DOM API načíst celý dokument a potom dotaz ho XPath.

Nicméně, pokud jste opravdu mít obrovský XML dokument, pak byste měli mít zájem na vyřešení problému pomocí Reader API:

my $sitemap_uri = 'http://www.sitemaps.org/schemas/sitemap/0.9';
my $xpc = XML::LibXML::XPathContext->new();
$xpc->registerNs(sm => $sitemap_uri);

my $reader = XML::LibXML::Reader->new(location => './sitemap.xml');
while ($reader->read) {
    $reader->nextElement('url', $sitemap_uri) or last;
    my $doc = $reader->copyCurrentNode(1);
    say "Doc = $doc";
    my ($loc) = $xpc->findnodes('//sm:loc', $doc);
    say "Loc = $loc";
}

Volání $reader->nextElementje rychlý způsob, jak přeskočit vpřed na další výskyt určitého prvku. V tomto příkladu jsem odpovídal na obou názvu elementu a je to namespace.

Volání $reader->copyCurrentNode(1)je metoda pohodlí, které vrátí tento uzel a všechny je to podřízené uzly jako fragment DOM. Budete muset použít XML::LibXML::XPathContextna dotaz, který DOM pomocí XPath prohlášení jmenného prostoru vědomi.

Můj XML :: libxml tutorial zahrnuje informace o práci s XML jmenných prostorů , jakož i práci s velkými dokumenty .

Odpovězeno 21/10/2018 v 01:29
zdroj uživatelem

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more