phast/lib/phast/server/Parser/XMLParser.inc.php

367 lines
7.9 KiB
PHP

<?php
namespace UniversalEditor\ObjectModels\Markup;
class MarkupAttribute
{
public $Prefix;
public $Name;
public $Value;
public function GetFullName()
{
if ($this->Prefix != "")
{
return $this->Prefix . ":" . $this->Name;
}
else
{
return $this->Name;
}
}
public function SetFullName($name)
{
$names = explode(":", $name);
if (count($names) > 1)
{
$this->Prefix = $names[0];
$this->Name = $names[1];
}
else if (count($names) == 1)
{
$this->Prefix = "";
$this->Name = $names[0];
}
}
public function __construct($name, $value, $prefix = null)
{
if ($prefix == null)
{
$this->SetFullName($name);
}
else
{
$this->Prefix = $prefix;
$this->Name = $name;
}
$this->Value = $value;
}
}
abstract class MarkupElement
{
public abstract function GetOuterMarkup();
public abstract function GetInnerMarkup();
public static function FromArray($array)
{
if (!isset($array["Type"])) return null;
switch ($array["Type"])
{
case "MarkupTagElement":
{
$element = new MarkupTagElement();
$element->Name = $array["Name"];
if (isset($array["Attributes"]))
{
$attributes = $array["Attributes"];
foreach ($attributes as $name => $value)
{
$element->Attributes[] = new MarkupAttribute($name, $value);
}
}
if (isset($array["Elements"]))
{
$elements = $array["Elements"];
foreach ($elements as $elem)
{
$element->Elements[] = MarkupElement::FromArray($elem);
}
}
if (isset($array["Value"]))
{
$element->Value = $array["Value"];
}
return $element;
}
case "MarkupLiteralElement":
{
$element = new MarkupLiteralElement();
$element->Value = $array["Value"];
return $element;
}
}
return null;
}
}
class MarkupLiteralElement extends MarkupElement
{
public $Value;
public function GetOuterMarkup()
{
return $this->GetInnerMarkup();
}
public function GetInnerMarkup()
{
return $this->Value;
}
}
class MarkupTagElement extends MarkupElement
{
/**
* The name of this MarkupTagElement.
* @var string
*/
public $Name;
/**
* The MarkupAttributes associated with this MarkupTagElement.
* @var MarkupAttribute[]
*/
public $Attributes;
/**
* The child MarkupElements of this MarkupTagElement.
* @var MarkupTagElement[]
*/
public $Elements;
public function __construct()
{
$this->Attributes = array();
$this->Elements = array();
}
public function GetOuterMarkup()
{
$str = "<" . $this->Name;
if (count($this->Attributes) != 0)
{
foreach ($this->Attributes as $attr)
{
$str .= " " . $attr->Name . "=\"" . $attr->Value . "\"";
}
}
if (count($this->Elements) == 0)
{
$str .= " />";
}
else
{
$str .= ">" . $this->GetInnerMarkup() . "</" . $this->Name . ">";
}
return $str;
}
public function GetInnerMarkup()
{
$str = "";
foreach ($this->Elements as $elem)
{
$str .= $elem->GetOuterMarkup();
}
return $str;
}
public function GetAttributeValue($name, $index = 0) : ?string
{
$attr = $this->GetAttribute($name, $index);
if ($attr != null)
return $attr->Value;
return null;
}
public function GetAttribute($name, $index = 0) : ?MarkupAttribute
{
$i = 0;
$last = null;
foreach ($this->Attributes as $attribute)
{
if ($attribute->Name == $name)
{
$last = $attribute;
$i++;
if ($i == $index) return $attribute;
}
}
return $last;
}
public function GetAttributes()
{
return $this->Attributes;
}
public function HasAttribute($name)
{
return ($this->GetAttribute($name) != null);
}
/**
* Gets a MarkupElement with the specified name.
* @param string $name The name of the element to retrieve.
* @param number $index The index of the element to retrieve if there is more than one element with the specified name.
* @return MarkupTagElement|MarkupLiteralElement|MarkupElement|null
*/
public function GetElement($name, $index = 0)
{
$i = 0;
$last = null;
foreach ($this->Elements as $element)
{
if (is_numeric($name))
{
if ($i == $name) return $element;
continue;
}
if (get_class($element) == "UniversalEditor\\ObjectModels\\Markup\\MarkupLiteralElement") continue;
if ($element->Name == $name)
{
$last = $element;
$i++;
if ($i == $index) return $element;
}
}
return $last;
}
public function GetElements()
{
return $this->Elements;
}
}
class MarkupObjectModel
{
public $Elements;
/**
* Gets a MarkupElement with the specified name.
* @param string $name The name of the element to retrieve.
* @param number $index The index of the element to retrieve if there is more than one element with the specified name.
* @return MarkupTagElement|MarkupLiteralElement|MarkupElement
*/
public function GetElement($name, $index = 0)
{
$i = 0;
$last = null;
foreach ($this->Elements as $element)
{
if ($element->Name == $name)
{
$last = $element;
$i++;
if ($i == $index) return $element;
}
}
return $last;
}
public function GetElements()
{
return $this->Elements;
}
public static function FromFile($filename)
{
$parser = new XMLParser();
$markup = $parser->LoadFile($filename);
return $markup;
}
public function __construct()
{
$this->Elements = array();
}
public static function FromArray($array)
{
$markup = new MarkupObjectModel();
$markup->LoadArray($array);
return $markup;
}
public function LoadArray($array)
{
$count = count($array);
for ($i = 0; $i < $count; $i++)
{
$this->Elements[] = MarkupElement::FromArray($array[$i]);
}
}
}
class XMLParser
{
public $RemoveWhitespace;
private $mvarOutput;
var $resParser;
var $strXmlData;
public function __construct()
{
$this->RemoveWhitespace = true;
}
/**
* Loads an XML file and returns the MarkupObjectModel.
* @param string $filename
* @return MarkupObjectModel
*/
public function LoadFile($filename)
{
$file = fopen($filename, "r");
$input = fread($file, filesize($filename));
return $this->Load($input);
}
public function Load($input)
{
$this->mvarOutput = array();
$input = html_entity_decode($input);
$this->resParser = \xml_parser_create ();
\xml_parser_set_option($this->resParser, XML_OPTION_CASE_FOLDING, 0);
\xml_set_object($this->resParser, $this);
\xml_set_element_handler($this->resParser, "tagOpen", "tagClosed");
\xml_set_character_data_handler($this->resParser, "tagData");
$this->strXmlData = \xml_parse($this->resParser, $input);
if(!$this->strXmlData)
{
$message = \xml_error_string(xml_get_error_code($this->resParser));
$lineNumber = \xml_get_current_line_number($this->resParser);
die(sprintf("XML error: %s at line %d", $message, $lineNumber));
}
\xml_parser_free($this->resParser);
return MarkupObjectModel::FromArray($this->mvarOutput);
}
private function tagOpen($parser, $name, $attrs)
{
$tag = array("Type" => "MarkupTagElement", "Name" => $name, "Attributes" => $attrs);
array_push($this->mvarOutput,$tag);
}
private function tagData($parser, $value)
{
if ($this->RemoveWhitespace && trim($value) == "") return;
$value = htmlentities($value);
$tag = array("Type" => "MarkupLiteralElement", "Value" => $value);
array_push($this->mvarOutput, $tag);
$this->mvarOutput[count($this->mvarOutput) - 2]['Elements'][] = $this->mvarOutput[count($this->mvarOutput) - 1];
array_pop($this->mvarOutput);
}
function tagClosed($parser, $name)
{
$this->mvarOutput[count($this->mvarOutput) - 2]['Elements'][] = $this->mvarOutput[count($this->mvarOutput) - 1];
array_pop($this->mvarOutput);
}
}
?>