2009-11-03 5 views
2

Je tente d'analyser XML dans le format suivant (de la Banque centrale européenne flux de données) en utilisant libxml-ruby:Parsing XML en utilisant libxml un espace de noms-ruby

<?xml version="1.0" encoding="UTF-8"?> 
<gesmes:Envelope xmlns:gesmes="http://www.gesmes.org/xml/2002-08-01" 
       xmlns="http://www.ecb.int/vocabulary/2002-08-01/eurofxref"> 
    <gesmes:subject>Reference rates</gesmes:subject> 
    <gesmes:Sender> 
    <gesmes:name>European Central Bank</gesmes:name> 
    </gesmes:Sender> 
    <Cube> 
    <Cube time="2009-11-03"> 
     <Cube currency="USD" rate="1.4658"/> 
     <Cube currency="JPY" rate="132.25"/> 
     <Cube currency="BGN" rate="1.9558"/> 
    </Cube> 
    </Cube> 
</gesmes:Envelope> 

Je chargement du document comme suit :

require 'rubygems' 
require 'xml/libxml' 
doc = XML::Document.file('eurofxref-hist.xml') 

Mais je me bats pour arriver à la configuration de l'espace de noms correct pour permettre des requêtes XPath sur les données.

Je peux extraire tous les Cube noeuds en utilisant le code suivant:

doc.find("//*[local-name()='Cube']") 

Mais étant donné que les deux le nœud parent et les nœuds enfants sont tous deux appelés Cube cela ne m'a vraiment aide pas itérer sur seulement les nœuds parents . Peut-être que je pourrais modifier ce XPATH pour trouver seulement ces nœuds avec un paramètre time?

Mon but est d'être en mesure d'extraire tous les Cube noeuds qui ont un attribut time (à savoir <Cube time="2009-11-03">) donc je peut alors extraire la date et itérer sur les taux de change chez l'enfant Cube nœuds.

Quelqu'un peut-il aider?

Répondre

3

ou l'autre de ces travailleront:

/gesmes:Envelope/Cube/Cube - direct path from root 
//Cube[@time] - all cube nodes (at any level) with a time attribute 

Ok, ceci est testé et fonctionnel

arrNS = ["xmlns:http://www.ecb.int/vocabulary/2002-08-01/eurofxref", "gesmes:http://www.gesmes.org/xml/2002-08-01"] 
doc.find("//xmlns:Cube[@time]", arrNS) 
+0

Aucune de ces œuvres en fait, ils retournent pas de nœuds. J'ai essayé le premier moi-même initialement sans succès. Fait intéressant, si je supprime tous les espaces de noms et que j'utilise une balise racine de 'test' alors '/ test/Cube/Cube' fonctionne bien comme prévu. Des idées? – Olly

+1

Voir ci-dessus pour le code de travail. A pris une bonne quantité d'essais et d'erreurs pour obtenir – Zack

+0

Aha! Merci pour cela. J'ai en fait trouvé une solution que je viens de poster, mais votre solution me sauve un lien de code :) – Olly

0

Je compris cela. Le nœud racine définit deux espaces de noms, l'un avec un préfixe, un sans:

xmlns:gesmes="http://www.gesmes.org/xml/2002-08-01 
xmlns="http://www.ecb.int/vocabulary/2002-08-01/eurofxref" 

Lorsqu'un préfixe est défini, vous pouvez référencer facilement le préfixe namespaced noms. En utilisant le XML de la question initiale, ce XPATH:

/gesmes:Envelope/gesmes:subject 

retournera "taux de référence".

Parce que ne sont pas préfixés les Cube nœuds, nous avons d'abord besoin de définir un préfixe d'espace de noms pour l'espace de noms global. Voici comment j'ai réalisé ceci:

doc = XML::Document.file('eurofxref-hist-test.xml') 
context = XML::XPath::Context.new(doc) 
context.register_namespace('euro', 'http://www.ecb.int/vocabulary/2002-08-01/eurofxref') 

Une fois que cela est défini, trouver les nœuds Cube avec des attributs temps est trivial:

context.find("//euro:Cube[@time]").each {|node| .... } 
+0

t = XML :: XPath :: Context.new (doc) ne nécessite aucun argument ... – mArtinko5MB