Skip to content

Instantly share code, notes, and snippets.

@hakre
Created July 21, 2011 14:08
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hakre/1097266 to your computer and use it in GitHub Desktop.
Save hakre/1097266 to your computer and use it in GitHub Desktop.
XMLReader based parser in form of an iterator and filteriterator
<?php
/*
XMLReader based parser in form of an iterator and filteriterator
Author: hakre <hakre.wordpress.com>
Copyright (c) 2011, some rights reserved
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Related: http://goo.gl/?url=http://goo.gl/u4sYl
*/
error_reporting(~0);
$xml = <<<EOD
<?xml version="1.0" encoding="ISO-8859-1"?>
<library>
<book isbn="781">
<name>SCJP 1.5</name>
<info>Sun Certified Java Programmer book</info>
</book>
<book isbn="194">
<name>jQuery is Awesome!</name>
<info>jQuery Reference Book</info>
</book>
<book isbn="199">
<name>jQuery 101</name>
<info>All you need to know about jQuery</info>
</book>
</library>
EOD;
$file = 'data://text/plain;base64,'.base64_encode($xml);
class XMLBookIterator implements iterator
{
private $file;
private $reader;
private $state;
private $key = 0;
private $book;
private $valid;
public function __construct($file)
{
$this->file = $file;
}
public function current()
{
return $this->book;
}
public function key()
{
return $this->key;
}
public function next()
{
$reader = $this->reader;
while ($next = $reader->read())
{
switch ($reader->nodeType)
{
case (XMLREADER::ELEMENT):
$case = $reader->localName.'|'.$this->state;
switch($case)
{
case 'library|0':
break;
case 'book|1':
$this->book = new stdClass;
$this->book->isbn = $reader->getAttribute('isbn');
break;
case 'name|2':
$this->book->name = $reader->readInnerXML();
break;
case 'info|3':
$this->book->info = $reader->readInnerXML();
$this->state=0;
break;
default:
throw new Exception(sprintf('Invalid State: %s.', $case));
}
$this->state++;
if ($this->state === 1) break 2;
}
}
$this->valid = $next;
$this->key++;
}
public function rewind()
{
if ($this->reader) $this->reader->close();
$this->reader = new XMLReader();
$this->reader->open($this->file);
$this->state = 0;
$this->next(); // move to first element or invalidate
if ($this->valid) $this->next(); // get first book
$this->key = 0;
}
public function valid()
{
return $this->valid;
}
}
class BookFilterIterator extends FilterIterator
{
private $term;
public function __construct($iterator, $term)
{
parent::__construct($iterator);
$this->term = $term;
}
public function accept() {
$book = parent::current();
$name = $book->name;
return false !== stripos($name, $this->term);
}
}
// all books:
$books = new XMLBookIterator($file);
foreach($books as $key => $book)
{
echo 'book (', $key, '):', "\n";
print_r($book);
}
// filtered books:
$filtered = new BookFilterIterator($books, 'jQuery');
foreach($filtered as $key => $book)
{
echo 'book (', $key, '):', "\n";
print_r($book);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment