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