<?php
class my_xmlreader implements Iterator
{
/**
* Field Separator;
*/
protected $_separator = '_';
/**
* XML file path
*
* @var string
*/
protected $_file = null;
/**
* XML reader object
*
* @var XMLReader
*/
protected $_reader = null;
/**
* Current _node
*
* @var array
*/
protected $_node = null;
/**
* Dummy-key for iteration.
* Has no real value except maybe act as a counter
*
* @var integer
*/
protected $_key = 0;
/**
* Level of depth we are at.
*
* @var int $depth
*/
protected $_depth = 0;
/**
* Warpping element name.
*
* @var string
*/
protected $_mainElement = null;
/**
* Pass this method the $file to be parsed.
*
* @param string $file
*/
function __construct($file)
{
$this->_file = $file;
}
/**
* @see Iterator::current()
*/
public function current()
{
return $this->_node;
}
/**
* @see Iterator::key()
*/
public function key()
{
return $this->_key;
}
/**
* @see Iterator::next()
*/
public function next()
{
$this->_node = null;
}
/**
* @see Iterator::rewind()
*/
public function rewind()
{
$this->_reader = new XMLReader();
$this->_reader->open($this->_file);
$this->_node = null;
$this->_key = 0;
}
/**
* @see Iterator::valid()
*/
public function valid()
{
if (is_null($this->_node)) {
$this->_loadNext();
}
return (!is_null($this->_node));
}
/**
* Loads the next _node
*
* @return void
*/
protected function _loadNext()
{
$capture = false;
$values = array();
$nest = array();
$s = $this->_separator;
while ($this->_reader->read()) {
switch ($this->_reader->nodeType) {
case XMLReader::ELEMENT:
if (1 === $this->_depth) {
$this->_mainElement = $this->_reader->name;
//$nest[] = $this->_reader->name;
if ($this->_reader->hasAttributes) {
$count = $this->_reader->attributeCount;
for($n=0; $n<$count; $n++) {
$this->_reader->moveToAttributeNo($n);
$nest[] = 'attr' . $s . $this->_reader->localName;
$values[implode($s, $nest)] = $this->_reader->value;
/*$nest[] = $this->_reader->name . '_attribue_' . ($n+1);
$values[implode('_', $nest)] = $this->_reader->getAttributeNo($n);*/
array_pop($nest);
}
// Hack to get back to the element we were on.
$this->_reader->moveToElement($this->_reader->name);
unset($n, $count);
}
}
if ($capture) {
$nest[] = $this->_reader->name;
$values[implode($s, $nest)] = null;
if ($this->_reader->hasAttributes) {
$count = $this->_reader->attributeCount;
for($n=0; $n<$count; $n++) {
$this->_reader->moveToAttributeNo($n);
$nest[] = 'attr' . $s . $this->_reader->localName;
$values[implode($s, $nest)] = $this->_reader->value;
array_pop($nest);
}
// Hack to get back to the element we were on.
$this->_reader->moveToElement($this->_reader->name);
unset($n, $count);
}
}
if ($this->_reader->name == $this->_mainElement) {
$capture = true;
}
//echo 'Main element: ' . $this->_reader->name . PHP_EOL;
//echo $this->_depth . PHP_EOL;
++$this->_depth;
break;
case XMLReader::TEXT:
if ($capture) {
$values[implode($s, $nest)] = $this->_reader->value;
}
break;
case XMLReader::END_ELEMENT:
$this->_depth --;
if ($this->_reader->name == $this->_mainElement) {
$this->_node = $values;
$this->_key++;
//$this->_depth = 1;
break 2;
}
if ($capture) {
array_pop($nest);
}
break;
}
}
}
}
?>
<?php
require_once 'classes/my_xmlreader.php';
class XmlAdapter
{
protected $_xml = null;
protected $_file = null;
/**
* @param $file
*/
public function __construct($file = null)
{
$this->_file = $file;
$this->_xml = new my_xmlreader($this->_file);
$this->_xml->rewind();
}
/**
* @return array
*/
public function getFieldNames()
{
$this->reset();
$output = array();
// I have tried using the "my_xmlreader" itterator with a foreach loop,
// hoever, I get the same problem.
/*$i = 0;
foreach ($this->_xml as $key) {
$output = array_merge($output, $key);
$i ++;
if ($i > 3) {
echo 'More than 20';
break 1;
}
}*/
// After 3 rows, return with field names.
$i = 0;
while ($record = $this->getRecord()) {
$output = array_merge($output, $record);
$i++;
if ($i > 3) {
break;
}
}
$headers = array();
foreach ($output as $k => $v) {
$headers[] = $k;
}
// Reset to the beginning of the file after getting field names.
$this->reset();
return $headers;
}
public function reset()
{
$this->_xml->rewind();
}
public function getRecord()
{
$current = null;
if ($this->_xml->valid()) {
$current = $this->_xml->current();
//echo print_r($current, 1) . PHP_EOL;
$this->_xml->next();
}
return $current;
}
}
// File contents shown above.
$file = 'testfeed.xml';
$xml = new XmlAdapter($file);
// Now when we do this, we get no rows from the getRecord() method,
// comment this out and getRecord() returns correct result as expected.
$headers = $xml->getFieldNames();
print_r($headers);
// Comment the two lines above out and this works... When not commented, it only returns 1 row?
while (!is_null($record = $xml->getRecord())) {
print_r($record);
}
As you can see, when the getFieldNames() method is run and there are more than 3 rows, we break (exit the loop) and return the rows we have accumulated. We merge the fields and returnt them. The assumption is that all the field headers will be in the first 3 records.
So what's the problem?
After the "break" has been executed in the getFieldNames(), the getRecord() method no longer returns anything. However, if I call the getRecord() without calling getFieldNames() it correctly returns the 5 records from the sample xml file.