$args); while(list($key,$val) = each($args)) $this->prop($key, $val); if(strpos($this->data, "<") === false && file_exists($this->data)) $this->data = $this->filecont($this->data); } /*-- ---- ---- ---- ---- ---- ---- ---- ---- ---- --*/ function prop($name, $value = null) { if(isset($value)) $this->$name = $value; return $this->$name; } /*-- ---- ---- ---- ---- ---- ---- ---- ---- ---- --*/ function parse() { $this->offset = 0; $this->tree = $this->make_structure($this->new_element()); return true; } /*-- ---- ---- ---- ---- ---- ---- ---- ---- ---- --*/ // Internal routines, and functions //-- // make_structure // find_element 2011/09/13 // next_element 2011/09/12 // next_part // define_element: structure an element from a declaration string. // new_element /*-- ---- ---- ---- ---- ---- ---- ---- ---- ---- --*/ function & make_structure($element) { $loop = 0; $loop_limit = 1000; do { if(++$loop > $loop_limit) { trigger_error("Over $loop_limit times looping!"); break; } $part = $this->next_part(); if(is_null($part)) break; $child = $this->define_element($part); if(is_scalar($child)) { if(trim($child) == "") continue; $element["-content"] = $child; $loop2 = 0; $loop2_limit = 500; do { if(++$loop2 > $loop2_limit) { trigger_error("Over $loop2_limit times looping!"); break; } $part = $this->next_part(); if(is_null($part)) { if($tag = $element["-tag"]) trigger_error("Missing close-tag for '$tag' at $this->offset"); break 2; } $child = $this->define_element($part); if(is_scalar($child)) $element["-content"] .= $child; else { if($child["-type"] == "close" && $child["-tag"] == $element["-tag"]) { $element["-type"] = "pair"; break 2; } else { if($child["-type"] != "comment") $element["-content"] .= $part; } } } while(true); } else { if($child["-type"] == "close") { if($child["-tag"] == $element["-tag"]) { $element["-type"] = "pair"; break; } else { $tag = $child["-tag"]; $for = $element["-tag"]; trigger_error("Missmatched close-tag '$tag' for '$for' at $this->offset"); continue; } } //if($child["-type"] == "pi") // ignore PIs currently // continue; if($child["-type"] == "comment") // ignore comments currently continue; if($child["-type"] == "open") $child = $this->make_structure($child); $name = $child["-tag"]; if($this->collapse) if(empty($child["-childs"]) && empty($child["-attrs"])) $child = $child["-content"]; if(isset($element[$name])) { if(isset($element[$name]["-type"])) $element[$name] = array($element[$name]); $element[$name][] = $child; } else { $element[$name] = $child; $element["-childs"][] = $name; } } } while(true); // # remove all working variables // foreach(array_keys($element) as $key) // if(strpos($key, "!") === 0) // unset($element[$key]); return $element; } /*-- ---- ---- ---- ---- ---- ---- ---- ---- ---- --*/ // function find_element($cond = array()) // {} /*-- ---- ---- ---- ---- ---- ---- ---- ---- ---- --*/ function next_element() { $part = $this->next_part(); if(is_null($part)) return $part; return $this->define_element($part); } /*-- ---- ---- ---- ---- ---- ---- ---- ---- ---- --*/ function next_part() { $part = null; // possible to be '0' $CAP = PREG_OFFSET_CAPTURE; $pos = $this->offset; do { if(! preg_match('/\G\s*(?:(<[\!\?]?)|[^<]+)/s', $this->data, $m, $CAP, $pos)) break; $pos = $m[0][1] + strlen($m[0][0]); $part = $m[0][0]; $start = @ $m[1][0]; if(empty($start)) break; $lst = substr($start, -1, 1); if($lst == "!") { $reg = '/\G(?:\[CDATA\[.*?\]\]|\-\-.*?\-\-)>/s'; if(! preg_match($reg, $this->data, $m, $CAP, $pos)) { trigger_error("Unknown declaration at $pos"); $part = null; } } elseif($lst == "?") { if(! preg_match('/\G.*?\?>/s', $this->data, $m, $CAP, $pos)) { trigger_error("Missing close-tag for 'reg_attrs.'\s*)*/?\s*>|s'; if(! preg_match($reg, $this->data, $m, $CAP, $pos)) { trigger_error("Unknown declaration at $pos"); $part = null; } } if(is_null($part)) break; $pos = $m[0][1] + strlen($m[0][0]); $part = $start.$m[0][0]; } while(false); $this->offset = $pos; return $part; } /*-- ---- ---- ---- ---- ---- ---- ---- ---- ---- --*/ function define_element($part) { $decl = trim($part); $fst = substr($decl, 0, 1); $lst = substr($decl, -1, 1); if($fst != "<" || $lst != ">") { $part = $this->unsanitize($part); return $part; } $decl = trim(substr($decl, 1, strlen($decl)-2)); if(empty($decl)) return ""; $elem = $this->new_element(); //$elem["-part"] = $part; $fst = substr($decl, 0, 1); $lst = substr($decl, -1, 1); if($fst == "!") { $reg = '/^\!(?:\[CDATA\[(.*?)\]\]|\-\-(.*?)\-\-)/s'; if(preg_match($reg, $decl, $m)) { if(@ $m[1]) { return $m[1]; } elseif(@ $m[2]) { $elem["-type"] = "comment"; $elem["-content"] = $m[2]; } } else { trigger_error("Unsupported declaration: <$decl>"); return; } } elseif($fst == "?") { if($lst == "?") { $elem["-type"] = "pi"; $decl = substr($decl, 1, strlen($decl)-2); } else { trigger_error("Missing processing instruction: $part"); return; } } elseif($fst == "/") { $elem["-type"] = "close"; $decl = substr($decl, 1); } elseif($lst == "/") { $elem["-type"] = "alone"; $decl = substr($decl, 0, strlen($decl)-1); } else $elem["-type"] = "open"; if($elem["-type"] != "comment") { $decl = trim($decl); preg_match_all("/$this->reg_attrs/s", $decl, $m); $elem["-tag"] = @ $m[1][0]; for($i=1; isset($m[0][$i]); $i++) { $name = $m[1][$i]; $qt = $m[2][$i]; $val = @ $m[3][$i]; $val = preg_replace("/\\x5C$qt/", $qt, $val); // escaped quotes $val = $this->unsanitize($val); $elem["-attrs"][] = $name; $elem["@{$name}"] = $val; } } return $elem; } /*-- ---- ---- ---- ---- ---- ---- ---- ---- ---- --*/ function new_element() { $elem = array( //"-part" => null, "-type" => null, "-tag" => null, "-content" => null, "-childs" => array(), "-attrs" => array(), ); return $elem; } /*-- ---- ---- ---- ---- ---- ---- ---- ---- ---- --*/ //-- npfuncs // string filecont 2009/06/07 - 2011/06/30 // string unsanitize 2011/12/07 /*-- ---- ---- ---- ---- ---- ---- ---- ---- ---- --*/ function filecont($fname) { if(! is_file($fname)) { trigger_error("File not found: $fname"); return false; } $cont = ""; if($fh = fopen($fname, "rb") and @ flock($fh, 1)) { if($fsize = filesize($fname)) $cont = fread($fh, $fsize); } else { trigger_error("Cannot open file: $fname"); return false; } return $cont; } /*-- ---- ---- ---- ---- ---- ---- ---- ---- ---- --*/ function unsanitize($str) { if(empty($str)) return $str; $from = array("<", ">", """, "'", "&"); $to = array("<", ">", '"', "'", "&"); return str_replace($from, $to, $str); } } ?>