2015-10-27 14 views
8

Ich habe einige XML-Dateien, wo ich einige Informationen von ihnen verwenden möchte. Ich habe einen Code geschrieben, der diese Dateien liest und dann nach bestimmten Bedingungen sucht.Extrahieren von Daten aus einem XML-Dokument, das Namespaces verwendet

Das Problem ist, dass diese XML-Datei

<SquishReport version="2.1" xmlns="http://www.froglogic.com/XML2"> 

mit

beginnt und Perl kann sie nicht lesen (zumindest in meinem Code!). Aber wenn ich diese Zeilen Anfügen in der ersten Zeile der Datei XML

<?xml version="1.0" encoding="UTF-8"?> 
    <?xml-stylesheet type="text/xsl"?> 

funktioniert sehr gut.

Einige Zeilen aus meiner XML-Datei test.xml:

<SquishReport version="2.1" xmlns="http://www.froglogic.com/XML2"> 
    <test name="TEST"> 
     <prolog time="2015-10-01T03:45:22+02:00"/> 
     <test name="tst_start_app"> 
      <prolog time="2015-02-01T03:45:23+02:00"/> 
      <message line="38" type="LOG" file="C:\squish\test\sources.py" time="2015-02-01T03:45:23+02:00"> 
       <description> 
       <![CDATA[>> >> >> start: init (global) - testcase C:\squish\test\tst_start_app]]></description> 
      </message> 
     </test> 
    </test> 
</SquishReport> 

und der Perl-Code die XML-Datei zum Lesen ist:

use strict; 
use warnings; 
use feature 'say'; 
use XML::LibXML; 

# Parse the XML 
my $xml = XML::LibXML->load_xml(location => 'test.xml'); 

# Iterate the entries 
for my $entry ($xml->findnodes('/SquishReport/test/test')) { 
    my $key = $entry->findvalue('@name'); 
    say "$key"; 
} 
+0

Mögliche Duplikat [Warum funktioniert X ML :: LibXML findet keine Knoten für diese xpath-Abfrage, wenn ein Namespace verwendet wird] (http: // stackoverflow.com/questions/4083550/why-does-xmllibxml-find-no-nodes-für-diese-xpath-query-wenn-namespace verwendet) – nwellnhof

+0

Bitte nicht als Duplikat dieser Frage schließen. Das XML dieser Frage ist illegal, verkompliziert das Problem und macht die Lösung dieser Frage für diese Frage irrelevant. Ich möchte diese Frage als ein sauberes Beispiel zur Verfügung stellen. – ikegami

Antwort

11

Der Wurzelknoten des Dokuments ein Element, das Namen hat, ist SquishReport im Namespace http://www.froglogic.com/XML2. Prägnanter, können wir sagen, der Wurzelknoten ein

{http://www.froglogic.com/XML2}SquishReport 


ist, wenn man in einem SquishReport verwendet XPath (im Gegensatz zu prefix:SquishReport gegen), die ein Element, das Namen SquishReport in dem Namensraum hat null übereinstimmen versucht. Prägnant, können wir sagen, dass es einen Namespace angeben

{}SquishReport 


anzupassen versucht, ein Präfix verwendet in einem context wie folgt definiert:

Hinweis
use strict; 
use warnings; 
use feature qw(say); 

use XML::LibXML    qw(); 
use XML::LibXML::XPathContext qw(); 

my $xpc = XML::LibXML::XPathContext->new(); 
$xpc->registerNs(sr => 'http://www.froglogic.com/XML2'); 

my $doc = XML::LibXML->load_xml(location => 'test.xml'); 
for my $entry ($xpc->findnodes('/sr:SquishReport/sr:test/sr:test', $doc)) { 
    my $key = $entry->findvalue('@name'); 
    say $key; 
} 


: Das Präfix in der XPath verwendet haben keine Beziehung zu den im XML-Dokument verwendeten Präfixen (falls vorhanden). Es wird erwartet, dass Sie den Namespace kennen, in dem sich die Elemente befinden, nach denen Sie suchen, aber nicht die Präfixe, die von einem bestimmten Dokument verwendet werden.

+0

Vielen Dank für die tolle Antwort !! – Royeh

+0

Das ist wirklich sauber und klar! Ich neige dazu, Module zu verwenden, die aus 'XML :: LibXML' aufgebaut sind, aber Sie machen es hier einfach. XML wird nie verschwinden und Perl hat einige wirklich mächtige Werkzeuge, um damit umzugehen. –

0

Perl hat so viele ausgezeichnete XML-Tools - dank allen Modulentwicklern und libxml2 scheint XML fast einfach. Eines dieser Tools ist XML::Dataset - ein Convenience- "Scaffolding" -Modul, das auf XML::LibXML aufbaut und eine "Profil" -Markierungssprache verwendet, um Daten aus XML-Quellen abzurufen (). NB: Die Profilmarkierung ist empfindlich für Leerzeichen und Zeilenenden.

z.B .:

use XML::Dataset; 
use DDP; 

my $xml = "Squish.xml" ; 
open my $fh, "<", $xml or die "aiiieee!"; 
my $test_data = do { local $/; <$fh> }; 

# describe the data using XML::Dataset simplified markup: 
my $data_profile 
    = q(
      SquishReport 
      test 
       test 
       name = dataset:name); 

# parse it with XML::Dataset profile 
my $parsed_data = parse_using_profile($test_data, $data_profile); 

# view the element with Data::Printer 
foreach my $element ($parsed_data->{name}){ 
    p $element ; 
}; 

Squish.xml:

<SquishReport version="2.1" xmlns="http://www.froglogic.com/XML2"> 
    <test name="TEST"> 
     <prolog time="2015-10-01T03:45:22+02:00"/> 
     <test name="tst_start_app"> 
      <prolog time="2015-02-01T03:45:23+02:00"/> 
      <message line="38" type="LOG" file="C:\squish\test\sources.py" time="2015-02-01T03:45:23+02:00"> 
       <description> 
       <![CDATA[>> >> >> start: init (global) - testcase C:\squish\test\tst_start_app]]></description> 
      </message> 
     </test> 
    </test> 
</SquishReport> 

Ausgang:

\ [ 
    [0] { 
     name "tst_start_app" 
    } 
]