Poor Mans XML
This is just a quick script i created to do some XML parsing and XPath querying when only the basic XML php extension is installed. I’m amazed at how many hosting companies, especially those that use the ensim application, barely have XML support.
<?php
class PoorMansXML {
var $parser = null;
var $tree = null;
var $current = null;
function PoorMansXML(){
$this->parser = xml_parser_create();
xml_set_object($this->parser,$this);
xml_set_character_data_handler($this->parser, 'dataHandler');
xml_set_element_handler($this->parser, "startHandler", "endHandler");
$this->tree = new Node();
$this->current = &$this->tree;
}
function parse($path){
if (!file_exists($path)) {
die("Cannot open XML data file: $path");
return false;
}
$xml = implode(file($path));
if (!xml_parse($this->parser, $xml)) {
die(sprintf("XML error: %s at line %d",
xml_error_string(xml_get_error_code($this->parser)),
xml_get_current_line_number($this->parser)));
xml_parser_free($this->parser);
}
return true;
}
function startHandler($parser, $name, $attribs){
$name = strtolower(preg_replace('/^.*?\:/','',$name));
if ( !$this->current->{$name} ){
$this->current->{$name} = array();
}
$id = count($this->current->{$name});
$this->current->{$name}[$id] =& new Node($name,$attribs);
$this->current->{$name}[$id]->__parent =& $this->current;
$this->current = &$this->current->{$name}[$id];
}
function dataHandler($parser, $data){
$this->current->__data = $data;
}
function endHandler($parser, $name){
$this->current = &$this->current->__parent;
}
function query($xpath){
return $this->tree($xpath);
}
}
class Node {
function Node(){
$this->__parent = NULL;
if ( func_num_args() >= 1 ){
$this->__name = func_get_arg(0);
}
if ( func_num_args() >= 2 ){
$this->__attributes = func_get_arg(1);
}
}
function attribute($name){
return $this->__attributes[strtoupper($name)];
}
function data(){
return $this->__data;
}
/**
* @returns array of indexes which pass the condition
*/
function select($ppath,$node){
}
/**
* @returns array of indexes which pass the condition
*/
function filter($cond,$node_array){
$ids = array();
for ($j=0; $j<count($node_array); $j++){
// /object[/attributes/name@id == ]
}
return $ids;
}
/**
* @return Array Hash of path parts.
*/
function path_info($ppath){
preg_match('/\/(\/)?([^\/\[]*)(?:\[(.*?)\])?(\/.*$)?/',$ppath,$ppath_parts);
return (array(
'full'=>$ppath_parts[0],
'all' =>$ppath_parts[1],
'name'=>$ppath_parts[2],
'cond'=>$ppath_parts[3],
'rest'=>$ppath_parts[4]));
}
/**
* Very big and not-efficent xpath parser
*/
function query($xpath){
$list = array();
$nodes = get_object_vars($this);
preg_match('/\/(\/)?([^\/\[]*)(?:\[(.*?)\])?(\/.*$)?/',$xpath,$xpath_parts);
list($full,$all,$nodename,$cond,$rest) = $xpath_parts;
//if cond is set, get node ids for ones which satisfy//
if ( !$all ){
if ( !$rest ){
if ( $nodename == '*' ){
foreach ( $nodes as $name => $node ){
if ( $name{0} != '_' ){
$list = array_merge($list,$node);
}
}
} else {
if ( $cond == ''){
$list = $this->{$nodename};
} else {
if ( is_numeric($cond) ){
$list[] = $this->{$nodename}[$cond];
} else {
foreach ( $this->{$nodename} as $index => $node ){
if ( eval('return('.preg_replace('/\@([a-zA-Z0-9_]+)/','$node->attribute($1)',$cond) . ');') ){
$list[] = $node;
}
}
}
}
}
} else {
if ( $cond == ''){
$list = $this->{$nodename}[0]->query($rest);
} else {
if ( is_numeric($cond) ){
$list = $this->{$nodename}[$cond]->query($rest);
} else {
foreach ( $this->{$nodename} as $index => $node ){
if ( eval('return('.preg_replace('/\@([a-zA-Z0-9_]+)/','$node->attribute($1)',$cond) . ');') ){
$list = $node->query($rest);
}
}
}
}
}
} else {
foreach ( $nodes as $name => $node ){
if ( $name{0} != '_' ){
if ( $name == $nodename ){
if ( $cond == '' ){
$list = array_merge($list,$node);
} else {
if ( is_numeric($cond) ){
$list[] = $node[$cond];
} else {
for ( $j=0; $j < count($node); $j++){
if ( eval('return('.preg_replace('/\@([a-zA-Z0-9_]+)/','$node[$j]->attribute($1)',$cond) . ');') ){
$list[] = $node[$j];
}
}
}
}
}
for ( $j=0; $j < count($node); $j++){
$list = array_merge($list,$node[$j]->query($full));
}
}
}
}
return $list;
}
}
?>
/**
TO USE:
$p =& new PoorMansXML();$p->parse('my.xml');
$nodes = $p->tree->query('//attribute[@name=="name"]');
*/

