1<?php
2	function var2xml($name, $data)
3	{
4		$doc = new xmltool('root','','');
5		return $doc->import_var($name,$data,True,True);
6	}
7
8	class xmltool
9	{
10		/* for root nodes */
11		var $xmlversion = '1.0';
12		var $doctype = Array();
13		/* shared */
14		var $node_type = '';
15		var $name = '';
16		var $data_type;
17		var $data;
18		/* for nodes */
19		var $attributes = Array();
20		var $comments = Array();
21		var $indentstring = "\t";
22
23		/* start the class as either a root or a node */
24		function xmltool ($node_type = 'root', $name='',$indentstring="\t")
25		{
26			$this->node_type = $node_type;
27			$this->indentstring = $indentstring;
28			if ($this->node_type == 'node')
29			{
30				if($name != '')
31				{
32					$this->name = $name;
33				}
34				else
35				{
36					echo 'You must name node type objects<br>';
37					exit;
38				}
39			}
40		}
41
42		function set_version ($version = '1.0')
43		{
44			$this->xmlversion = $version;
45			return True;
46		}
47
48		function set_doctype ($name, $uri = '')
49		{
50			if ($this->node_type == 'root')
51			{
52				$this->doctype[$name] = $uri;
53				return True;
54			}
55			else
56			{
57				return False;
58			}
59		}
60
61		function add_node ($node_object, $name = '')
62		{
63			switch ($this->node_type)
64			{
65				case 'root':
66					if (is_object($node_object))
67					{
68						$this->data = $node_object;
69					}
70					else
71					{
72						$this->data = $this->import_var($name, $node_object);
73					}
74					break;
75				case 'node':
76					if(!is_array($this->data))
77					{
78						$this->data = Array();
79						$this->data_type = 'node';
80					}
81					if (is_object($node_object))
82					{
83						if ($name != '')
84						{
85							$this->data[$name] = $node_object;
86						}
87						else
88						{
89							$this->data[] = $node_object;
90						}
91					}
92					else
93					{
94						$this->data[$name] = $this->import_var($name, $node_object);
95					}
96					return True;
97					break;
98			}
99		}
100
101		function get_node ($name = '')	// what is that function doing: NOTHING !!!
102		{
103			switch	($this->data_type)
104			{
105				case 'root':
106					break;
107				case 'node':
108					break;
109				case 'object':
110					break;
111			}
112
113		}
114
115		function set_value ($string)
116		{
117			$this->data = $string;
118			$this->data_type = 'value';
119			return True;
120		}
121
122		function get_value ()
123		{
124			if($this->data_type == 'value')
125			{
126				return $this->data;
127			}
128			else
129			{
130				return False;
131			}
132		}
133
134		function set_attribute ($name, $value = '')
135		{
136			$this->attributes[$name] = $value;
137			return True;
138		}
139
140		function get_attribute ($name)
141		{
142			return $this->attributes[$name];
143		}
144
145		function get_attributes ()
146		{
147			return $this->attributes;
148		}
149
150		function add_comment ($comment)
151		{
152			$this->comments[] = $comment;
153			return True;
154		}
155
156		function import_var($name, $value,$is_root=False,$export_xml=False)
157		{
158			echo "<p>import_var: this->indentstring='$this->indentstring'</p>\n";
159			$node = new xmltool('node',$name,$this->indentstring);
160			switch (gettype($value))
161			{
162				case 'string':
163				case 'integer':
164				case 'double':
165				case 'NULL':
166					$node->set_value($value);
167					break;
168				case 'boolean':
169					if($value == True)
170					{
171						$node->set_value('1');
172					}
173					else
174					{
175						$node->set_value('0');
176					}
177					break;
178				case 'array':
179					$new_index = False;
180					while (list ($idxkey, $idxval) = each ($value))
181					{
182						if(is_array($idxval))
183						{
184							while (list ($k, $i) = each ($idxval))
185							{
186								if (is_int($k))
187								{
188									$new_index = True;
189								}
190							}
191						}
192					}
193					reset($value);
194					while (list ($key, $val) = each ($value))
195					{
196						if($new_index)
197						{
198							$keyname = $name;
199							$nextkey = $key;
200						}
201						else
202						{
203							$keyname = $key;
204							$nextkey = $key;
205						}
206						switch (gettype($val))
207						{
208							case 'string':
209							case 'integer':
210							case 'double':
211							case 'NULL':
212								$subnode = new xmltool('node', $nextkey,$this->indentstring);
213								$subnode->set_value($val);
214								$node->add_node($subnode);
215								break;
216							case 'boolean':
217								$subnode = new xmltool('node', $nextkey,$this->indentstring);
218								if($val == True)
219								{
220									$subnode->set_value('1');
221								}
222								else
223								{
224									$subnode->set_value('0');
225								}
226								$node->add_node($subnode);
227								break;
228							case 'array':
229								if($new_index)
230								{
231									while (list ($subkey, $subval) = each ($val))
232									{
233										$node->add_node($this->import_var($nextkey, $subval));
234									}
235								}
236								else
237								{
238									$subnode = $this->import_var($nextkey, $val);
239									$node->add_node($subnode);
240								}
241								break;
242							case 'object':
243								$subnode = new xmltool('node', $nextkey,$this->indentstring);
244								$subnode->set_value('PHP_SERIALIZED_OBJECT&:'.serialize($val));
245								$node->add_node($subnode);
246								break;
247							case 'resource':
248								echo 'Halt: Cannot package PHP resource pointers into XML<br>';
249								exit;
250							default:
251								echo 'Halt: Invalid or unknown data type<br>';
252								exit;
253						}
254					}
255					break;
256				case 'object':
257					$node->set_value('PHP_SERIALIZED_OBJECT&:'.serialize($value));
258					break;
259				case 'resource':
260					echo 'Halt: Cannot package PHP resource pointers into XML<br>';
261					exit;
262				default:
263					echo 'Halt: Invalid or unknown data type<br>';
264					exit;
265			}
266
267			if($is_root)
268			{
269				$this->add_node($node);
270				if($export_xml)
271				{
272					$xml = $this->export_xml();
273					return $xml;
274				}
275				else
276				{
277					return True;
278				}
279			}
280			else
281			{
282				$this->add_node($node);
283				return $node;
284			}
285		}
286
287		function export_var()
288		{
289			if($this->node_type == 'root')
290			{
291				return $this->data->export_var();
292			}
293
294			if($this->data_type != 'node')
295			{
296				$found_at = strstr($this->data,'PHP_SERIALIZED_OBJECT&:');
297				if($found_at != False)
298				{
299					return unserialize(str_replace ('PHP_SERIALIZED_OBJECT&:', '', $this->data));
300				}
301				return $this->data;
302			}
303			else
304			{
305				$new_index = False;
306				reset($this->data);
307				while(list($key,$val) = each($this->data))
308				{
309					if(!isset($found_keys[$val->name]))
310					{
311						$found_keys[$val->name] = True;
312					}
313					else
314					{
315						$new_index = True;
316					}
317				}
318
319				if($new_index)
320				{
321					reset($this->data);
322					while(list($key,$val) = each($this->data))
323					{
324
325						$return_array[$val->name][] = $val->export_var();
326					}
327				}
328				else
329				{
330					reset($this->data);
331					while(list($key,$val) = each($this->data))
332					{
333						$return_array[$val->name] = $val->export_var();
334					}
335				}
336				return $return_array;
337			}
338		}
339
340		function export_struct()
341		{
342			if($this->node_type == 'root')
343			{
344				return $this->data->export_struct();
345			}
346
347			$retval['tag'] = $this->name;
348			$retval['attributes'] = $this->attributes;
349			if($this->data_type != 'node')
350			{
351				$found_at = strstr($this->data,'PHP_SERIALIZED_OBJECT&:');
352				if($found_at != False)
353				{
354					$retval['value'] = unserialize(str_replace ('PHP_SERIALIZED_OBJECT&:', '', $this->data));
355				}
356				else
357				{
358					$retval['value'] = $this->data;
359				}
360				return $retval;
361			}
362			else
363			{
364				reset($this->data);
365				while(list($key,$val) = each($this->data))
366				{
367					$retval['children'][] = $val->export_struct();
368				}
369				return $retval;
370			}
371		}
372
373
374		function import_xml_children($data, &$i, $parent_node)
375		{
376			while (++$i < count($data))
377			{
378				switch ($data[$i]['type'])
379				{
380					case 'cdata':
381					case 'complete':
382						$node = new xmltool('node',$data[$i]['tag'],$this->indentstring);
383						if(is_array($data[$i]['attributes']) && count($data[$i]['attributes']) > 0)
384						{
385							while(list($k,$v)=each($data[$i]['attributes']))
386							{
387								$node->set_attribute($k,$v);
388							}
389						}
390						$node->set_value($data[$i]['value']);
391						$parent_node->add_node($node);
392						break;
393					case 'open':
394						$node = new xmltool('node',$data[$i]['tag'],$this->indentstring);
395						if(is_array($data[$i]['attributes']) && count($data[$i]['attributes']) > 0)
396						{
397							while(list($k,$v)=each($data[$i]['attributes']))
398							{
399								$node->set_attribute($k,$v);
400							}
401						}
402
403						$node = $this->import_xml_children($data, $i, $node);
404						$parent_node->add_node($node);
405						break;
406					case 'close':
407						return $parent_node;
408				}
409			}
410		}
411
412		function import_xml($xmldata)
413		{
414			$parser = xml_parser_create();
415			xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
416			xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE,   1);
417			xml_parse_into_struct($parser, $xmldata, $vals, $index);
418			xml_parser_free($parser);
419			unset($index);
420			$node = new xmltool('node',$vals[0]['tag'],$this->indentstring);
421			if(isset($vals[0]['attributes']))
422			{
423				while(list($key,$value) = each($vals[0]['attributes']))
424				{
425					$node->set_attribute($key, $value);
426				}
427			}
428			switch ($vals[0]['type'])
429			{
430				case 'complete':
431					$node->set_value($vals[0]['value']);
432					break;
433				case 'cdata':
434					$node->set_value($vals[0]['value']);
435					break;
436				case 'open':
437					$node = $this->import_xml_children($vals, $i = 0, $node);
438					break;
439				case 'closed':
440					exit;
441			}
442			$this->add_node($node);
443		}
444
445		function export_xml($indent = 1)
446		{
447			if ($this->node_type == 'root')
448			{
449				$result = '<?xml version="'.$this->xmlversion.'"?>'."\n";
450				if(count($this->doctype) == 1)
451				{
452					list($doctype_name,$doctype_uri) = each($this->doctype);
453					$result .= '<!DOCTYPE '.$doctype_name.' SYSTEM "'.$doctype_uri.'">'."\n";
454				}
455				if(count($this->comments) > 0 )
456				{
457					//reset($this->comments);
458					while(list($key,$val) = each ($this->comments))
459					{
460						$result .= "<!-- $val -->\n";
461					}
462				}
463				if(is_object($this->data))
464				{
465					$indent = 0;
466					$result .= $this->data->export_xml($indent);
467				}
468				return $result;
469			}
470			else /* For node objects */
471			{
472				for ($i = 0; $i < $indent; $i++)
473				{
474					$indentstring .= $this->indentstring;
475				}
476
477				$result = $indentstring.'<'.$this->name;
478				if(count($this->attributes) > 0 )
479				{
480					reset($this->attributes);
481					while(list($key,$val) = each ($this->attributes))
482					{
483						$result .= ' '.$key.'="'.htmlspecialchars($val).'"';
484					}
485				}
486
487				$endtag_indent = $indentstring;
488				if (empty($this->data_type))
489				{
490					$result .= '/>'."\n";
491				}
492				else
493				{
494					$result .= '>';
495
496					switch ($this->data_type)
497					{
498						case 'value':
499							if(is_array($this->data))
500							{
501								$type_error = True;
502								break;
503							}
504
505							/*if(preg_match("(&|<)", $this->data))	// this is unnecessary with htmlspecialchars($this->data)
506							{
507								$result .= '<![CDATA['.$this->data.']]>';
508								$endtag_indent = '';
509							}
510							else*/if(strlen($this->data) > 30 && !empty($this->indentstring))
511							{
512								$result .= "\n".$indentstring.$this->indentstring.htmlspecialchars($this->data)."\n";
513								$endtag_indent = $indentstring;
514							}
515							else
516							{
517								$result .= htmlspecialchars($this->data);
518								$endtag_indent = '';
519							}
520							break;
521						case 'node':
522							$result .= "\n";
523							if(!is_array($this->data))
524							{
525								$type_error = True;
526								break;
527							}
528
529							$subindent = $indent+1;
530							reset($this->data);
531							while(list($key,$val) = each ($this->data))
532							{
533								if(is_object($val))
534								{
535									$result .= $val->export_xml($subindent);
536								}
537							}
538							break;
539						default:
540						if($this->data != '')
541						{
542							echo 'Invalid or unset data type ('.$this->data_type.'). This should not be possible if using the class as intended<br>';
543						}
544					}
545
546					if ($type_error)
547					{
548						echo 'Invalid data type. Tagged as '.$this->data_type.' but data is '.gettype($this->data).'<br>';
549					}
550
551					$result .= $endtag_indent.'</'.$this->name.'>';
552					if($indent != 0)
553					{
554						$result .= "\n";
555					}
556				}
557				if(count($this->comments) > 0 )
558				{
559					reset($this->comments);
560					while(list($key,$val) = each ($this->comments))
561					{
562						$result .= $endtag_indent."<!-- $val -->\n";
563					}
564				}
565				return $result;
566			}
567		}
568	}
569
570	class xmlnode extends xmltool
571	{
572		function xmlnode($name)
573		{
574			$this->xmltool('node',$name);
575		}
576	}
577
578	class xmldoc extends xmltool
579	{
580		function xmldoc($version = '1.0')
581		{
582			$this->xmltool('root');
583			$this->set_version($version);
584		}
585
586		function add_root($root_node)
587		{
588			return $this->add_node($root_node);
589		}
590	}
591?>
592