2010-03-20 5 views
0

Je dois obtenir un fichier XML dans une base de données. Ce n'est pas le problème. Je ne peux pas le lire, l'analyser et créer des objets à mapper à la base de données. Le problème est que parfois le fichier XML peut contenir des espaces de noms et parfois non. De plus, parfois, il n'y a aucun espace de nommage défini.PHP analyse fichier XML avec et sans espaces de noms

Alors ce que je suis arrivé était quelque chose comme ceci:

<?xml version="1.0" encoding="UTF-8"?> 
<struct xmlns:b="http://www.w3schools.com/test/"> 
<objects> 
<object> 
<node_1>value1</node_1> 
<node_2>value2</node_2> 
<node_3 iso_land="AFG"/> 
<coords lat="12.00" long="13.00"/> 
</object> 
</objects> 
</struct> 

Et l'analyse syntaxique:

$obj = new stdClass(); 
$nodes = array('node_1', 'node_2'); 

$t = $xml->xpath('/objects/object');  
    foreach($nodes AS $node) { 
     if($t[0]->$node) { 
      $obj->$node = (string) $t[0]->$node; 
     } 
    } 

Cest bien tant qu'il n'y a pas namespaces. Voici le fichier XML avec espaces de noms:

<?xml version="1.0" encoding="UTF-8"?> 
<b:struct xmlns:b="http://www.w3schools.com/test/"> 
<b:objects> 
<b:object> 
<b:node_1>value1</b:node_1> 
<b:node_2>value2</b:node_2> 
<b:node_3 iso_land="AFG"/> 
<b:coords lat="12.00" long="13.00"/> 
</b:object> 
</b:objects> 
</b:struct> 

je maintenant est venu avec quelque chose comme ceci:

$xml = simplexml_load_file("test.xml"); 
$namespaces = $xml->getNamespaces(TRUE); 
$ns = count($namespaces) ? 'a:' : ''; 
$xml->registerXPathNamespace("a", "http://www.w3schools.com/test/"); 

$nodes = array('node_1', 'node_2'); 

$obj = new stdClass(); 

foreach($nodes AS $node) { 
    $t = $xml->xpath('/'.$ns.'objects/'.$ns.'object/'.$ns.$node); 
    if($t[0]) { 
     $obj->$node = (string) $t[0]; 
    } 
} 

$t = $xml->xpath('/'.$ns.'objects/'.$ns.'object/'.$ns.'node_3'); 
if($t[0]) { 
    $obj->iso_land = (string) $t[0]->attributes()->iso_land; 
}  

$t = $xml->xpath('/'.$ns.'objects/'.$ns.'object/'.$ns.'coords'); 
if($t[0]) { 
    $obj->lat = (string) $t[0]->attributes()->lat; 
    $obj->long = (string) $t[0]->attributes()->long; 
} 

qui fonctionne avec les espaces de noms et sans. Mais je pense qu'il doit y avoir un meilleur moyen. Avant cela, je pouvais faire quelque chose comme ça:

$t = $xml->xpath('/'.$ns.'objects/'.$ns.'object'); 
foreach($nodes AS $node) { 
    if($t[0]->$node) { 
     $obj->$node = (string) $t[0]->$node; 
    } 
} 

Mais cela ne fonctionnera pas avec les espaces de noms.

Répondre

0

Vous pouvez faire vos XPATH déclarations plus générique en faisant correspondre à tout élément * et en utilisant un filtre sous-jacente pour correspondre à la local-name(), qui correspondra au nom de l'élément avec/sans namespaces.

Un XPATH comme ceci:

/*[local-name()='struct']/*[local-name()='objects']/*[local-name()='object']/*[local-name()='coords'] 

Appliqué à l'exemple de code que vous utilisez:

$obj = new stdClass(); 
$nodes = array('node_1', 'node_2'); 

$t = $xml->xpath('/*[local-name()="objects"]/*[local-name()="object"]');  
    foreach($nodes AS $node) { 
     if($t[0]->$node) { 
      $obj->$node = (string) $t[0]->$node; 
     } 
    } 
+0

cela ne fonctionnera pas: $ t = $ xml-> xpath ('/ * [nom-local() = "objets"]/* [nom-local() = "objet"]'); cela fonctionne: $ t = $ xml-> xpath ('/ * [nom-local() = "objets"]/* [nom-local() = "objet"]/*'); mais je ne peux pas accéder aux clés ... – Mike

1

Vous pouvez faire 'http://www.w3schools.com/test/' l'espace de noms par défaut. De cette façon, a:objects correspondrait indépendamment du fait que le document indique < a: objets > ou <objets>.

Si l'utilisation de la mémoire n'est pas un problème, vous pouvez même le faire avec un remplacement textuel, par ex.

$data = '<?xml version="1.0" encoding="UTF-8"?> 
<struct xmlns:b="http://www.w3schools.com/test/"> 
    <objects> 
    <object> 
     <node_1>value1</node_1> 
     <node_2>value2</node_2> 
     <node_3 iso_land="AFG"/> 
     <coords lat="12.00" long="13.00"/> 
    </object> 
    </objects> 
</struct>'; 

$data = str_replace(// or preg_replace(,,,1) if you want to limit it to only one replacement 
    'xmlns:b="http://www.w3schools.com/test/"', 
    'xmlns="http://www.w3schools.com/test/" xmlns:b="http://www.w3schools.com/test/"', 
    $data 
); 
$xml = new SimpleXMLElement($data); 
$xml->registerXPathNamespace("a", "http://www.w3schools.com/test/"); 

foreach($xml->xpath('//a:objects/a:object') as $n) { 
    echo $n->node_1; 
} 
+0

J'aimerais le faire de cette façon, mais il ne fonctionne pas. $ sxe = simplexml_import_dom ($ doc-> importNode ($ this-> lecteur-> expand(), true)); $ sxe-> registerXPathNamespace ('a', "http://www.w3schools.com/test"); foreach ($ sxe-> xpath ('a: object') sous la forme $ n) { print_r ($ n-> node_1); } – Mike

Questions connexes