views:

4157

answers:

4

While parsing an XML File using the XMLReader Method, how do I get the parent node of an element ?

$xml = new XMLReader();
$xml->XML($xmlString);
while($xml->read())
{

$xml->localName; // gives tag name
$xml->value; // gives tag value

// how do I access the parent of this element 
}
A: 

I think you want: XMLReader::moveToElement

cbrulak
+6  A: 

Short Version: You don't, at least not directly. It's up to the programmer to code context into their parsing algorithm with XMLReader.

Long Version: PHP's XMLReader is what's called a pull parser. Pull parsers differ from a tree/dom based parser in that they can deal with text streams. In other words, they can begin parsing the document before they have the entire document. This differs from a tree based/DOM parser like SimpleXML or DOMDocument that needs to load the entire document into memory before it can do anything.

The advantage is, if you have a 75MB XML file you don't need 75MB of free RAM to deal with it (as you would with a tree based parser). The trade-off is pull parsers never have the context of an entire document. The only have the context of whatever node they happen to be processing at the moment.

Another way to think of it is a tree/dom based parser has to know about every single part of the document because it doesn't know what you're going to ask it for. You and the pull parser, however, have made a different arrangement. It'll keep throwing nodes at you and leave it up to your to deal with their contents.

Here's some example code that is (hopefully) close to what you're after.

$xml = new XMLReader();
$xml->XML(file_get_contents('example.xml'));

$last_node_at_depth = array();
while($xml->read())
{    
 //stash the XML of the entire node in an array indexed by depth
 //you're probably better off stashing exactly what you need from
 $last_node_at_depth[$xml->depth] = $xml->readOuterXML();

 $xml->localName; // gives tag name
 $xml->value;   // gives tag value  

 //so, right now we're at depth n in the XML document.  depth n-1 
 //would be our parent node
 if ($xml->depth > 0) {
  //gives the fragment that starts with the parent node  
  $last_node_at_depth[($xml->depth-1)]; 
 }
}
Alan Storm
+1  A: 

I have started using the expand() function of the XMLReader. It gives a DOM representation of the current xml tag. I used expand() on the parent node, it gave me the DOM element of the parent tag, then using the usual DOMDocument() way of parsing extracted the child values.

//usage
$xml = new XMLReader();
$xml = $xml->XML($xmlResponse);
while($xml->read())
{
$parent = $xml->expand();

$firstChildValue = $parent->getElementsByTagName('child')->item(0)->nodeValue;
}

Using the expand function loads only that much part of XML into memory rather than loading the entire XML into memory.

Undefined
I use this approach too, since it's a lot simpler than using XMLReader to read the whole doc, but it's pretty slow.
julio
A: 

I'm using xmlreader to load an xml file like:

<head> <element param="hello"/> <element param="hello"/> <element param="hello"/> </head>

And all is OK!

But now i need to write many times the xml and append elements... I have a problem with the <head></head>!!!!!!!!!!!!

without should be perfect, i could simply append using php functions: <element param="hello"/> <element param="hello"/> <element param="hello"/> <element param="hello"/> <element param="hello"/> ...

But without <head></head> xmlreader give error at opening!!

How can i read using xmlreader an xml <head></head>??? or How can i write an xml between the last element and the </head> ??? Please help

Roberto