public function parse()
{
$counter = 0;
$continue = true;
while ($continue) {
$continue = $this->readNextChunk();
++$counter;
if (!isset($this->rootNode)) {
// Find root node
if (isset($this->customRootNode)) {
$customRootNodePos = strpos($this->chunk, "<{$this->customRootNode}");
if ($customRootNodePos !== false) {
// Found custom root node
// Support attributes
$closer = strpos(substr($this->chunk, $customRootNodePos), '>');
$readFromChunkPos = $customRootNodePos + $closer + 1;
// Custom child node?
if (isset($this->customChildNode)) {
// Find it in the chunk
$customChildNodePos = strpos(substr($this->chunk, $readFromChunkPos), "<{$this->customChildNode}");
if ($customChildNodePos !== false) {
// Found it!
$readFromChunkPos = $readFromChunkPos + $customChildNodePos;
} else {
// Didn't find it - read a larger chunk and do everything again
continue;
}
}
$this->rootNode = $this->customRootNode;
$this->readFromChunkPos = $readFromChunkPos;
} else {
// Clear chunk to save memory, it doesn't contain the root anyway
$this->readFromChunkPos = 0;
$this->chunk = '';
continue;
}
} else {
// XML1.0 standard allows almost all Unicode characters even Chinese and Cyrillic.
// see: http://en.wikipedia.org/wiki/XML#International_use
preg_match('/<([^>\\?]+)>/', $this->chunk, $matches);
if (isset($matches[1])) {
// Found root node
$this->rootNode = $matches[1];
$this->readFromChunkPos = strpos($this->chunk, $matches[0]) + strlen($matches[0]);
} else {
// Clear chunk to save memory, it doesn't contain the root anyway
$this->readFromChunkPos = 0;
$this->chunk = '';
continue;
}
}
}
while (true) {
$fromChunkPos = substr($this->chunk, $this->readFromChunkPos);
// Find element
// XML1.0 standard allows almost all Unicode characters even Chinese and Cyrillic.
// see: http://en.wikipedia.org/wiki/XML#International_use
preg_match('/<([^>]+)>/', $fromChunkPos, $matches);
if (isset($matches[1])) {
// Found element
$element = $matches[1];
// Is there an end to this element tag?
$spacePos = strpos($element, ' ');
$crPos = strpos($element, "\r");
$lfPos = strpos($element, "\n");
$tabPos = strpos($element, "\t");
// find min. (exclude false, as it would convert to int 0)
$aPositionsIn = array($spacePos, $crPos, $lfPos, $tabPos);
$aPositions = array();
foreach ($aPositionsIn as $iPos) {
if ($iPos !== false) {
$aPositions[] = $iPos;
}
}
$minPos = $aPositions === array() ? false : min($aPositions);
if ($minPos !== false && $minPos != 0) {
$sElementName = substr($element, 0, $minPos);
$endTag = '</' . $sElementName . '>';
} else {
$sElementName = $element;
$endTag = "</{$sElementName}>";
}
$endTagPos = false;
// try selfclosing first!
// NOTE: selfclosing is inside the element
$lastCharPos = strlen($element) - 1;
if (substr($element, $lastCharPos) == '/') {
$endTag = '/>';
$endTagPos = $lastCharPos;
$iPos = strpos($fromChunkPos, '<');
if ($iPos !== false) {
// correct difference between $element and $fromChunkPos
// "+1" is for the missing '<' in $element
$endTagPos += $iPos + 1;
}
}
if ($endTagPos === false) {
$endTagPos = strpos($fromChunkPos, $endTag);
}
if ($endTagPos !== false) {
// Found end tag
$endTagEndPos = $endTagPos + strlen($endTag);
$elementWithChildren = trim(substr($fromChunkPos, 0, $endTagEndPos));
$continueParsing = $this->processNode($elementWithChildren, $sElementName, $this->nodeIndex++);
$this->chunk = substr($this->chunk, strpos($this->chunk, $endTag) + strlen($endTag));
$this->readFromChunkPos = 0;
if (isset($continueParsing) && $continueParsing === false) {
$this->chunkCompleted();
break 2;
}
} else {
break;
}
} else {
break;
}
}
$this->chunkCompleted();
}
return isset($this->rootNode);
fclose($this->handle);
}