0

I need to get a XML File into a Database. Thats not the problem. Cant read it, parse it and create some Objects to map to the DB. Problem is, that sometimes the XML File can contain namespaces and sometimes not. Furtermore sometimes there is no namespace defined at all.

So what i first got was something like this:

<?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> 

And the parsing:

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

Thats fine as long as there are no namespaces. Here comes the XML File with namespaces:

<?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> 

I now came up with something like this:

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

That works with namespaces and without. But i feel that there must be a better way. Before that i could do something like this:

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

But that just wont work with namespaces.

0

3 Answers 3

1

You could make 'http://www.w3schools.com/test/' the default namespace. This way a:objectswould match regardless of whether the document says <a:objects> or <objects>.

If memory usage is not a issue you can even do it with a textual replacement, e.g.

$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; } 
Sign up to request clarification or add additional context in comments.

1 Comment

i would love to do it this way, but it aint working. $sxe = simplexml_import_dom($doc->importNode($this->reader->expand(), true)); $sxe->registerXPathNamespace('a', "w3schools.com/test"); foreach($sxe->xpath('a:object') as $n) { print_r($n->node_1); }
0

You can make your XPATH statements more generic by matching on any element * and using a predicate filter to match on the local-name(), which will match on the element name with/without namespaces.

An XPATH like this:

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

Applied to the code sample you were using:

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

1 Comment

this wont work: $t = $xml->xpath('/*[local-name()="objects"]/*[local-name()="object"]'); this works: $t = $xml->xpath('/*[local-name()="objects"]/*[local-name()="object"]/*'); but then i cant access the keys...
0

Take a look at This http://blog.sherifmansour.com/?p=302 It helped me a lot.

1 Comment

RIP link. Link is dead.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.