Last update: 31.03.2008 | © 2024 Julian von Mendel | Datenschutz
<?php
/* xml class
* (C) 2006 Julian von Mendel (http://derjulian.net)
* License: LGPL
*/
class InvalidXMLException extends Exception {}
interface xml_widget
{
function __construct($node, $xml);
public static function dtd ();
public function output ($returntype = "xhtml");
}
interface form_widget extends xml_widget
{
public function validate ($get, $post, $files = array());
}
class xml
{
protected $xml = "";
public $beforeparsexml = False;
public $data = array();
public $freeid = 0;
public $protocols = array();
private $forcechildnodes = array("textarea", "script");
private $a_inside = array("p", "li", "td", "th", "dt", "dd", "div", "span", "h1", "h2", "h3", "h4", "h5", "h6", "strong", "sub", "sup", "em");
private $a_outside = array("img");
public $workafterwards = array();
protected $tags = array();
protected $replacements = array();
protected $replacementnr = 0;
public $doctypes = array
(
"xhtml1-strict" => "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">",
"xhtml1-transitional" => "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">"
);
public function setDataItem($key, $val)
{
$this->data[$key] = $val;
}
public function getDataItem($key)
{
if (!isset($this->data[$key])) return False;
return $this->data[$key];
}
public function getFreeID()
{
return $this->freeid++;
}
public function setBeforeParseCallback($callback)
{
if (!is_callable($callback))
return False;
$this->beforeparsexml = $callback;
}
public function addReplacement($callback, $key = False)
{
if (!is_callable($callback))
return False;
if (!$key)
{
$key = "<rEpLaCeThIs".($this->replacementnr++)." />";
}
$this->replacements[$key] = $callback;
return $key;
}
public function addFunction($callback)
{
if (!is_callable($callback))
return False;
$this->workafterwards[] = $callback;
}
public function setProtocol($key, $val)
{ // i. e. "callback:db://" => array($dbclass, "getvalue")
if (substr($key, 0, 9) == "callback:" && !is_callable($val))
return False;
$this->protocols[$key] = $val;
}
public function output($xml, $returntype = "xhtml", $doctype = "xhtml1-strict")
{
foreach(get_declared_classes() as $class)
{
if (substr($class,0,4) == "xml_")
{
$this->tags[] = substr($class, 4);
}
}
$this->returntype = $returntype;
$this->xml = $xml;
$output = xml::parse($this->xml);
$this->xml = $output["content_string"];
if (isset($this->doctypes[$doctype]))
{
$doctype = $this->doctypes[$doctype];
}
if ($doctype != "")
{
$this->xml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n".$doctype."\n".$this->xml;
}
foreach($this->workafterwards as $function)
{
$this->xml = call_user_func($function, $this->xml);
}
foreach($this->replacements as $key => $val)
{
$val = call_user_func($val, $this->xml);
$this->xml = str_replace($key, $val, $this->xml);
}
$this->xml = str_replace(" clear=\"none\"", "", $this->xml);
$this->xml = str_replace(" rowspan=\"1\" colspan=\"1\"", "", $this->xml);
return $this->xml;
}
public function url($url)
{
foreach($this->protocols as $protocol => $replace)
{
if (substr($protocol, 0, 9) == "callback:")
{
$callback = True;
$protocol = substr($protocol, 9);
}
else
{
$callback = False;
}
if (substr($url, 0, strlen($protocol)) == $protocol)
{
$url = substr($url, strlen($protocol));
if ($callback)
{
$protocol = call_user_func($replace, $url);
}
else
{
$protocol = str_replace("%s", $url, $replace);
$protocol = str_replace("%u", urlencode($url), $protocol);
}
return $protocol;
}
}
return $url;
}
public static function mask_xml($xml)
{
return xml::mask(utf8_encode($xml));
}
public static function mask($xml)
{
$xml = htmlspecialchars($xml, ENT_QUOTES);
return preg_replace("/�*39;/", "'", $xml);
}
public function parse($xml, $onlychilds = False)
{
$xml = call_user_func($this->beforeparsexml, $xml);
if (substr(trim($xml), 0, 1) != "<")
{
$xml = "<section toc=\"no\">".$xml."</section>";
$onlychilds = True;
}
if (substr(trim($xml), 0, 6) != "<?xml ")
{
$xml = "<?xml version=\"1.0\" encoding=\"iso8859-1\" ?>\n".$xml;
}
$dom = new DomDocument();
$dom->resolveExternals = True;
if (!$dom->loadXML($xml))
{
$xml = explode("\n", self::mask($xml));
echo "<pre>\n";
$i = 1;
foreach($xml as $line)
{
echo $i.": ".$line."\n";
$i++;
}
echo "</pre>";
throw InvalidXMLException("Invalid XML.");
}
$xml = $this->parseNode($dom->documentElement, $onlychilds);
return $xml;
}
public function parseNode
(
$node ,
$onlychilds = False ,
$returncontent = True ,
$xmlfuncs = True ,
$attributes = array(),
$tags = array(),
$level = 0
)
{
$workthroughchilds = False;
$content_string = "" ;
$attributes_string = "" ;
$attributes_array = array();
$tags_array = array();
$childnodes = $node->childNodes;
if ($node->nodeType == XML_TEXT_NODE)
$content_string = xml::mask($node->nodeValue);
elseif ($node->nodeType == XML_COMMENT_NODE)
$content_string = "<!--".$node->nodeValue."-->";
elseif ($node->nodeType == XML_CDATA_SECTION_NODE)
$content_string = "<![CDATA[".$node->nodeValue."]]>";
else if ($node->nodeType == XML_ENTITY_REF_NODE)
$content_string = $node->textContent;
else
$workthroughchilds = True;
if (!$workthroughchilds)
{
return array
(
"content_string" => $content_string ,
"attributes_string" => $attributes_string,
"attributes_array" => $attributes_array ,
"tags_array" => $tags_array
);
}
foreach($childnodes as $child)
{
if ($child->nodeName == "parentattr")
{
$content = self::parseNode
(
$child ,
True ,
True ,
$xmlfuncs
);
$attributes_array[$child->getAttribute("name")] = $this->url($content["content_string"]);
}
else if ($tags == "*" || in_array($child->nodeName, $tags))
{
if ($child->nodeName[0] == "#") continue;
if ($level == 0)
{
$data = $this->parseNode
(
$child ,
True ,
True ,
$xmlfuncs
);
}
else
{
$data = $this->parseNode
(
$child ,
True ,
True ,
$xmlfuncs ,
array() ,
"*" ,
$level - 1
);
$data["content_string"] = $data["tags_array"];
}
if (!isset($tags_array[$child->nodeName]))
$tags_array[$child->nodeName] = array();
$tags_array[$child->nodeName][] = array("content" => $data["content_string"], "attributes" => $data["attributes_array"], "node" => $child);
}
else if ($returncontent && $xmlfuncs && in_array($child->nodeName, $this->tags))
{
$class = "xml_".$child->nodeName;
$class = new $class($child, $this);
$output = $class->output($this->returntype);
if (is_array($output) && isset($output["reparse"]))
{
$output = $this->parse("<test>".$output["output"]."</test>", True);
$output = $output["content_string"];
}
$content_string .= $output;
}
elseif ($returncontent)
{
$data = $this->parseNode
(
$child ,
False ,
True ,
$xmlfuncs ,
$attributes
);
$content_string .= $data["content_string"];
}
}
if (is_object($node->attributes))
{
for($i=0; $attribute = $node->attributes->item($i); $i++)
{
if (!$attribute)
{
break;
}
$attributes_array[$attribute->nodeName] = $this->url($attribute->nodeValue);
}
}
$inside = in_array($node->nodeName, $this->a_inside );
$outside = in_array($node->nodeName, $this->a_outside);
if (is_array($attributes))
{
foreach($attributes_array as $key => $val)
{
if (in_array($key, $attributes) || (($inside || $outside) && $key == "href"))
{
continue;
}
$attributes_string .= " ".$key."=\"".self::mask($val)."\"";
unset($attributes_array[$key]);
}
foreach($attributes as $key)
{
if (!isset($attributes_array[$key]))
{
$attributes_array[$key] = "";
}
}
}
if (!$onlychilds)
{
if ($content_string == "" && !in_array($node->nodeName, $this->forcechildnodes))
{
$content_string = $this->href("<".$node->nodeName.$attributes_string." />", "", $attributes_array);
}
else
{
if ($inside || $outside)
{
$xml_string = "<".$node->nodeName.$attributes_string.">%s</".$node->nodeName.">";
$content_string = $this->href($xml_string, $content_string, $attributes_array, $inside);
}
else
{
$content_string = "<".$node->nodeName.$attributes_string.">".$content_string."</".$node->nodeName.">";
}
}
}
return array
(
"content_string" => $content_string ,
"attributes_string" => $attributes_string,
"attributes_array" => $attributes_array ,
"tags_array" => $tags_array
);
}
public function attributes($node, $attributes = array())
{
return $this->parseNode($node, True, False, True, $attributes);
}
public function href($xml, $content, $attributes, $child = False)
{
if (!isset($attributes["href"]) || $attributes["href"] == "")
{
$xml = str_replace("%s", $content, $xml);
return $xml;
}
$rule = "<a href=\"".self::mask($this->url($attributes["href"]))."\">%s</a>";
if (!$child)
{
$xml = str_replace("%s", $content, $xml );
$xml = str_replace("%s", $xml , $rule);
return $xml;
}
$xml = str_replace("%s", $rule , $xml);
$xml = str_replace("%s", $content, $xml);
return $xml;
}
}
?>
© 2009 Julian von Mendel (http://derjulian.net) | Datum: 10.09.2024