<?php
/**
XML parser & validator
@author Andrey Nikishaev
If parent node tag name equal children tag name but ends with 's' then
it will be an array.
For example:
<tournaments>
<tournament></tournament>
</tournaments>
Else it will be an associative array and duplicated tags will be deleted.
If node has no elements and ends with "s" like "<pages></pages>" then it will
be empty array.
Example of use:
$xmltools = new XMLTools();
$isvalid = $xmltools->ValidateXML('test.xml','test.xsd');
if($isvalid)
// return True
$data = $xmltools->XML2Array('test.xml')
else
// returned array of errors
print_r($isvalid);
XML like:
<tournaments>
<tournament>
<options>
<resultType>maxWeight|maxSumWeight|totalCount</resultType>
<startType>weekly|monthly</startType>
<startDay>2</startDay>
<fishtypes>
<fishtype>1</fishtype>
<fishtype>2</fishtype>
</fishtypes>
<pages>
</pages>
<map_pid>1</map_pid>
<location_pid>1</location_pid>
</options>
<variants>
<variant timeStart="01:50" timeEnd="02:50" name="Canadian losos" />
<variant timeStart="02:50" timeEnd="03:50" name="Canadian losos" />
<variant timeStart="03:50" timeEnd="04:50" name="Canadian losos" />
</variants>
</tournament>
</tournaments>
Will be parsed as:
Array
(
[0] => Array
(
[options] => Array
(
[resultType] => maxWeight|maxSumWeight|totalCount
[startType] => weekly|monthly
[startDay] => 2
[fishtypes] => Array
(
[0] => 1
[1] => 2
)
[pages] => Array()
[map_pid] => 1
[location_pid] => 1
)
[variants] => Array
(
[0] => Array
(
[timeStart] => 01:52
[timeEnd] => 02:50
[name] => Canadian losos
)
)
)
)
*/
class XMLTools {
public function XML2Array($file) {
if (!($fp = fopen($file, "r"))) {
die("could not open XML input");
}
$contents = fread($fp, filesize($file));
fclose($fp);
if(!$contents) return array();
if(!function_exists('xml_parser_create')) {
throw new Exception("'xml_parser_create()' function not found!");
return null;
}
//Get the XML parser of PHP - PHP must have this module for the parser to work
$parser = xml_parser_create('');
xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, "UTF-8");
xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
xml_parse_into_struct($parser, trim($contents), $xml_values);
xml_parser_free($parser);
if(!$xml_values) return;//Hmm...
//Initializations
$xml_array = array();
$parents = array();
$level = 0;
$is_array = array();
$current = &$xml_array; //Refference
$dc = count($xml_values);
for($i=0;$i<$dc;$i++) {
$data = $xml_values[$i];
if(!isset($is_array[$data['level']]) && ($data['level'] > 1) && ($data['tag'].'s' == $xml_values[$i-1]['tag'] || $data['tag'].'es' == $xml_values[$i-1]['tag'])) {
$is_array[$data['level']] = true;
}
$level = $data['level'];
if($data['type'] == 'open') {
$c = array();
if(isset($data['attributes'])) $c = $data['attributes'];
if(!isset($is_array[$level])) {
$current[$data['tag']] = $c;
$parents[$level] = &$current;
$current = &$current[$data['tag']];
} else {
$current[] = $c;
$parents[$level] = &$current;
$current = &$current[count($current)-1];
}
} else if($data['type'] == 'complete') {
$c = (substr($data['tag'], -1)=="s")?array():null;
if(isset($data['attributes'])) $c = $data['attributes'];
if(isset($data['value']) && isset($data['attributes'])) $c = array_merge($c,array('value'=>trim($data['value'])));
if(isset($data['value']) && !isset($data['attributes'])) $c = trim($data['value']);
if(isset($is_array[$level])) {
$current[] = $c;
} else {
$current[$data['tag']] = $c;
}
} else {
unset($is_array[$level+1]);
$current = &$parents[$level];
}
}
return $xml_array;
}
private function _libxml_display_error($error) {
$return = "Error in $error->file (Line:{$error->line}):";
$return .= trim($error->message);
return $return;
}
private function _libxml_display_errors() {
$errors = libxml_get_errors();
$res = array();
foreach ($errors as $error) {
$res[] = $this->_libxml_display_error($error);
}
libxml_clear_errors();
return $res;
}
public function ValidateXML($xml,$schema) {
if(!class_exists('DOMDocument')) {
throw new Exception("'DOMDocument' class not found!");
return False;
}
libxml_use_internal_errors(true);
if (!($fp = fopen($xml, "r"))) {
die("could not open XML input");
}
$contents = fread($fp, filesize($xml));
fclose($fp);
$xml = new DOMDocument();
$xml->loadXML($contents);
if (!$xml->schemaValidate($schema)) {
return $this->_libxml_display_errors();
} else {
return True;
}
}
}
|