1: <?php
2:
3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21:
22:
23: namespace picon;
24:
25: 26: 27: 28: 29: 30: 31: 32: 33:
34: class XMLParser
35: {
36: private $parser;
37: private $stack = array();
38: private $depth = 0;
39: private $root;
40: protected $xmlFile;
41: private $data;
42:
43: 44: 45: 46:
47: public function __construct()
48: {
49: $this->parser = xml_parser_create('UTF-8');
50: xml_parser_set_option($this->parser, XML_OPTION_TARGET_ENCODING, 'UTF-8');
51: xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, 0);
52: xml_parser_set_option($this->parser, XML_OPTION_SKIP_WHITE, 1);
53:
54: xml_set_object($this->parser, $this);
55: xml_set_element_handler($this->parser, "startElement", "endElement");
56: xml_set_character_data_handler($this->parser, "characterData");
57: }
58:
59: 60: 61: 62: 63:
64: public function parse($xmlFile)
65: {
66: $this->xmlFile = $xmlFile;
67: if (!($fp = @fopen($xmlFile, "r")))
68: {
69: throw new \FileException("Could not open XML input");
70: }
71: while ($data = fread($fp, 4096))
72: {
73: $this->data = $this->prepare($data);
74: if (!xml_parse($this->parser, $this->data, feof($fp)))
75: {
76: $this->onXmlError(xml_error_string(xml_get_error_code($this->parser)), xml_get_current_line_number($this->parser));
77: }
78: }
79: return $this->root;
80: }
81:
82: protected function prepare($data)
83: {
84: return $data;
85: }
86:
87: 88: 89: 90: 91: 92:
93: private function startElement($parser, $name, $attributes)
94: {
95: $tag = $this->newElement($name, $attributes);
96: $this->stack[$this->depth] = $tag;
97:
98: $close = $this->data[$this->getPreceedingCharacter($parser)];
99:
100: if($close=='/')
101: {
102: $tag->setTagType(new XmlTagType(XmlTagType::OPENCLOSE));
103: }
104:
105: if($this->depth==0)
106: {
107:
108: $this->root = $tag;
109: }
110: else
111: {
112: $this->stack[$this->depth-1]->addChild($tag);
113: }
114:
115: $this->depth++;
116: }
117:
118: protected function newElement($name, $attributes)
119: {
120: return new XMLTag($name, $attributes);
121: }
122:
123: protected function onXmlError($errorCode, $errorMessage)
124: {
125: throw new \XMLException(sprintf("XML error: %s at line %d of file %s", $errorCode,$errorMessage, $this->xmlFile));
126: }
127:
128: 129: 130: 131: 132:
133: private function endElement($parser, $name)
134: {
135: $this->depth--;
136: }
137:
138: 139: 140: 141: 142: 143:
144: private function characterData($parser, $data)
145: {
146: $this->onCharacterData($data, $this->stack[$this->depth-1]);
147: }
148:
149: protected function onCharacterData($data, XMLTag $element)
150: {
151: $data = trim($data);
152: if(!empty($data))
153: {
154: $element->addChild(new TextElement($data));
155: }
156: }
157:
158: 159: 160: 161: 162: 163: 164: 165: 166:
167: private function getPreceedingCharacter($parser)
168: {
169: $index = xml_get_current_byte_index($parser);
170: if (isset($this->data[$index]))
171: {
172: if($this->data[$index]=='<')
173: {
174: return strpos(substr($this->data, $index), '>')+$index-1;
175: }
176: else
177: {
178: return $index;
179: }
180: }
181: else
182: {
183: $length = strlen($this->data);
184: return $length-1;
185: }
186: }
187: }
188:
189: ?>
190: