1<?php
2/**
3 * Classes and functions for manipulating XML templates.
4 *
5 * @author The phpLDAPadmin development team
6 * @package phpLDAPadmin
7 */
8
9/**
10 * XML Parser
11 *
12 * This will read our XML file and convert it into variables for us to parse.
13 *
14 * @package phpLDAPadmin
15 * @subpackage XML
16 */
17class xml2array {
18	var $stack = array();
19	var $stack_ref;
20	var $arrOutput = array();
21	var $resParser;
22	var $strXmlData;
23
24	private function push_pos(&$pos) {
25		$this->stack[count($this->stack)] = &$pos;
26		$this->stack_ref = &$pos;
27	}
28
29	private function pop_pos() {
30		unset($this->stack[count($this->stack) - 1]);
31		$this->stack_ref = &$this->stack[count($this->stack) - 1];
32	}
33
34	public function parseXML($strInputXML,$filename) {
35		$this->resParser = xml_parser_create();
36		xml_set_object($this->resParser,$this);
37		xml_set_element_handler($this->resParser,'tagOpen','tagClosed');
38
39		xml_set_character_data_handler($this->resParser,'tagData');
40
41		$this->push_pos($this->arrOutput);
42
43		$this->strXmlData = xml_parse($this->resParser,$strInputXML);
44
45		if (! $this->strXmlData)
46			die(sprintf('XML error: %s at line %d in file %s',
47				xml_error_string(xml_get_error_code($this->resParser)),
48				xml_get_current_line_number($this->resParser),
49				$filename));
50
51		xml_parser_free($this->resParser);
52
53		$output = array();
54		foreach ($this->arrOutput as $key => $values)
55			$output[$key] = $this->cleanXML($values);
56
57		#return $this->arrOutput;
58		return $output;
59	}
60
61	private function tagOpen($parser,$name,$attrs) {
62		$name = strtolower($name);
63
64		if (isset($this->stack_ref[$name])) {
65			if (! isset($this->stack_ref[$name][0])) {
66				$tmp = $this->stack_ref[$name];
67				unset($this->stack_ref[$name]);
68				$this->stack_ref[$name][0] = $tmp;
69			}
70
71			$cnt = count($this->stack_ref[$name]);
72			$this->stack_ref[$name][$cnt] = array();
73			if (isset($attrs))
74				$this->stack_ref[$name][$cnt] = $attrs;
75
76			$this->push_pos($this->stack_ref[$name][$cnt]);
77
78		} else {
79			$this->stack_ref[$name]=array();
80
81			if (isset($attrs))
82				$this->stack_ref[$name]=$attrs;
83
84			$this->push_pos($this->stack_ref[$name]);
85		}
86	}
87
88	private function tagData($parser,$tagData) {
89		if (trim($tagData) != '') {
90
91			if (isset($this->stack_ref['#text']))
92				$this->stack_ref['#text'] .= $tagData;
93			else
94				$this->stack_ref['#text'] = $tagData;
95		}
96	}
97
98	private function tagClosed($parser,$name) {
99		$this->pop_pos();
100	}
101
102	/**
103	 * This function will parse an XML array and make a normal array.
104	 *
105	 * @return array - Clean XML data
106	 */
107	private function cleanXML($details) {
108		# Quick processing for the final branch of the XML array.
109		if (is_array($details) && isset($details['#text']))
110			return $details['#text'];
111
112		elseif (is_array($details) && isset($details['ID']) && count($details) == 1)
113			return $details['ID'];
114
115		$cleanXML = array();
116
117		# Quick processing for the final branch, when it holds the ID and values.
118		if (is_array($details) && isset($details['ID']) && count($details) > 1) {
119				$key = $details['ID'];
120				unset($details['ID']);
121				$cleanXML[$key] = $this->cleanXML($details);
122				$details = array();
123		}
124
125		# More detailed processing...
126		if (is_array($details))
127			foreach ($details as $key => $values)
128				if (is_numeric($key) && isset($values['ID']) && count($values) > 1) {
129					$key = $values['ID'];
130					unset($values['ID']);
131					$cleanXML[$key] = $this->cleanXML($values);
132
133				} elseif (isset($values['#text']))
134					$cleanXML[$key] = $this->cleanXML($values);
135
136				elseif (is_array($values))
137					$cleanXML[$key] = $this->cleanXML($values);
138
139		if (! $cleanXML)
140			return $details;
141		else
142			return $cleanXML;
143	}
144}
145