2015-10-27 10 views
8

Ho alcuni file XML in cui desidero utilizzare alcune informazioni da essi. Ho scritto un codice che legge quei file e poi cerca alcune condizioni.Estrazione di dati da un documento XML che utilizza gli spazi dei nomi

Il problema è che questi file XML inizia con

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

e Perl non li poteva leggere (almeno nel mio codice!). Ma quando sono aggiungendo queste righe nella prima riga del file di XML

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

funziona molto bene.

Alcune linee dal mio file XML 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> 

e il codice Perl per la lettura del file XML è:

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

Eventuali duplicati di [Perchè X ML :: LibXML non trova nodi per questa query xpath quando si utilizza un namespace] (http: // stackoverflow.it/questions/4083550/why-does-xmllibxml-find-no-nodes-per-this-xpath-query-when-using-a-namespace) – nwellnhof

+0

Si prega di non chiudere come duplicato di quella domanda. L'XML di quella domanda è illegale, complicando il problema e rendendo irrilevante la soluzione a questa domanda. Mi piacerebbe avere questa domanda disponibile come un esempio pulito. – ikegami

risposta

11

Il nodo radice di tale documento è un elemento che ha il nome SquishReport nello spazio dei nomi http://www.froglogic.com/XML2. Conciso, possiamo dire che il nodo radice è un

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


Quando si utilizza SquishReport (al contrario di prefix:SquishReport) in un XPath, che cerca di abbinare un elemento che ha nome SquishReport nello spazio nullo. In modo conciso, possiamo dire che tenta di abbinare un

{}SquishReport 


Per specificare lo spazio dei nomi, si usa prefissi definiti in un context, come segue:

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; 
} 


Nota: Il prefisso utilizzato nel XPath non hanno alcuna relazione con i prefissi utilizzati nel documento XML (se presente). Ci si aspetta che tu conosca lo spazio dei nomi in cui risiedono gli elementi per i quali stai cercando, ma non i prefissi usati da un determinato documento.

+0

Grazie mille per la grande risposta !! – Royeh

+0

Questo è veramente pulito e chiaro! Tendo ad usare i moduli costruiti da 'XML :: LibXML', ma lo stai facendo sembrare facile qui. L'XML non se ne andrà mai e perl ha alcuni strumenti davvero potenti per affrontarlo. –

0

Perl ha così tanti eccellenti strumenti XML - grazie a tutti gli sviluppatori di moduli e libxml2, XML sembra quasi facile. Uno di questi strumenti è XML::Dataset - un comodo modulo "scaffolding" che si basa su XML::LibXML e utilizza un linguaggio di markup "profilo" per acquisire dati da sorgenti XML (NB: Il markup del profilo è sensibile agli spazi bianchi e finali di linea).

es .:

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> 

uscita:

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