/mod/wiki/xml/classxml.php

https://github.com/jarednipper/HSU-common-code · PHP · 292 lines · 225 code · 38 blank · 29 comment · 28 complexity · 46a5afdcfe387584f8429c3638116195 MD5 · raw file

  1. <?php
  2. if (!isset($XMLFile_Included) || !$XMLFile_Included) {
  3. $XMLFile_Included = 1;
  4. class XMLTag
  5. {
  6. var $cdata;
  7. var $attributes;
  8. var $name;
  9. var $tags;
  10. var $parent;
  11. var $curtag;
  12. function XMLTag(&$parent)
  13. {
  14. if (is_object( $parent ))
  15. {
  16. $this->parent = &$parent;
  17. }
  18. $this->_init();
  19. }
  20. function _init()
  21. {
  22. $this->attributes = array();
  23. $this->cdata = '';
  24. $this->name = '';
  25. $this->tags = array();
  26. }
  27. function add_subtag($name, $attributes=0)
  28. {
  29. $tag = new XMLTag( $this );
  30. $tag->set_name( $name );
  31. if (is_array($attributes)) {
  32. $tag->set_attributes( $attributes );
  33. }
  34. $this->tags[] = &$tag;
  35. $this->curtag = &$tag;
  36. }
  37. function find_subtags_by_name( $name )
  38. {
  39. $result = array();
  40. $found=false;
  41. for($i=0;$i<$this->num_subtags();$i++) {
  42. if(strtoupper($this->tags[$i]->name)==strtoupper($name)) {
  43. $found=true;
  44. $array2return[]=&$this->tags[$i];
  45. }
  46. }
  47. if($found) {
  48. return $array2return;
  49. }
  50. else {
  51. return false;
  52. }
  53. }
  54. function clear_subtags()
  55. {
  56. # Traverse the structure, removing the parent pointers
  57. $numtags = sizeof($this->tags);
  58. $keys = array_keys( $this->tags );
  59. foreach( $keys as $k ) {
  60. $this->tags[$k]->clear_subtags();
  61. unset($this->tags[$k]->parent);
  62. }
  63. # Clear the tags array
  64. $this->tags = array();
  65. unset( $this->curtag );
  66. }
  67. function remove_subtag($index)
  68. {
  69. if (is_object($this->tags[$index])) {
  70. unset($this->tags[$index]->parent);
  71. unset($this->tags[$index]);
  72. }
  73. }
  74. function num_subtags()
  75. {
  76. return sizeof( $this->tags );
  77. }
  78. function add_attribute( $name, $val )
  79. {
  80. $this->attributes[strtoupper($name)] = $val;
  81. }
  82. function clear_attributes()
  83. {
  84. $this->attributes = array();
  85. }
  86. function set_name( $name )
  87. {
  88. $this->name = strtoupper($name);
  89. }
  90. function set_attributes( $attributes )
  91. {
  92. $this->attributes = (is_array($attributes)) ? $attributes : array();
  93. }
  94. function add_cdata( $data )
  95. {
  96. $this->cdata .= $data;
  97. }
  98. function clear_cdata()
  99. {
  100. $this->cdata = "";
  101. }
  102. function write_file_handle( $fh, $prepend_str='' )
  103. {
  104. # Get the attribute string
  105. $attrs = array();
  106. $attr_str = '';
  107. foreach( $this->attributes as $key => $val )
  108. {
  109. $attrs[] = strtoupper($key) . "=\"$val\"";
  110. }
  111. if ($attrs) {
  112. $attr_str = join( " ", $attrs );
  113. }
  114. # Write out the start element
  115. $tagstr = "$prepend_str<{$this->name}";
  116. if ($attr_str) {
  117. $tagstr .= " $attr_str";
  118. }
  119. $keys = array_keys( $this->tags );
  120. $numtags = sizeof( $keys );
  121. # If there are subtags and no data (only whitespace),
  122. # then go ahead and add a carriage
  123. # return. Otherwise the tag should be of this form:
  124. # <tag>val</tag>
  125. # If there are no subtags and no data, then the tag should be
  126. # closed: <tag attrib="val"/>
  127. $trimmeddata = trim( $this->cdata );
  128. if ($numtags && ($trimmeddata == "")) {
  129. $tagstr .= ">\n";
  130. }
  131. elseif (!$numtags && ($trimmeddata == "")) {
  132. $tagstr .= "/>\n";
  133. }
  134. else {
  135. $tagstr .= ">";
  136. }
  137. fwrite( $fh, $tagstr );
  138. # Write out the data if it is not purely whitespace
  139. if ($trimmeddata != "") {
  140. fwrite( $fh, $trimmeddata );
  141. }
  142. # Write out each subtag
  143. foreach( $keys as $k ) {
  144. $this->tags[$k]->write_file_handle( $fh, "$prepend_str\t" );
  145. }
  146. # Write out the end element if necessary
  147. if ($numtags || ($trimmeddata != "")) {
  148. $tagstr = "</{$this->name}>\n";
  149. if ($numtags) {
  150. $tagstr = "$prepend_str$tagstr";
  151. }
  152. fwrite( $fh, $tagstr );
  153. }
  154. }
  155. }
  156. ###############################################################################
  157. class XMLFile
  158. {
  159. var $parser;
  160. var $roottag;
  161. var $curtag;
  162. function XMLFile()
  163. {
  164. $this->init();
  165. }
  166. # Until there is a suitable destructor mechanism, this needs to be
  167. # called when the file is no longer needed. This calls the clear_subtags
  168. # method of the root node, which eliminates all circular references
  169. # in the xml tree.
  170. function cleanup()
  171. {
  172. if (is_object( $this->roottag )) {
  173. $this->roottag->clear_subtags();
  174. }
  175. }
  176. function init()
  177. {
  178. $this->roottag = "";
  179. $this->curtag = &$this->roottag;
  180. }
  181. function create_root()
  182. {
  183. $null = 0;
  184. $this->roottag = new XMLTag($null);
  185. $this->curtag = &$this->roottag;
  186. }
  187. # read_xml_string
  188. # Same as read_file_handle, but you pass it a string. Note that
  189. # depending on the size of the XML, this could be rather memory intensive.
  190. # Contributed July 06, 2001 by Kevin Howe
  191. function read_xml_string( $str )
  192. {
  193. $this->init();
  194. $this->parser = xml_parser_create("UTF-8");
  195. xml_set_object( $this->parser, $this );
  196. xml_set_element_handler( $this->parser, "_tag_open", "_tag_close" );
  197. xml_set_character_data_handler( $this->parser, "_cdata" );
  198. xml_parse( $this->parser, $str );
  199. xml_parser_free( $this->parser );
  200. }
  201. function read_file_handle( $fh )
  202. {
  203. $this->init();
  204. $this->parser = xml_parser_create("UTF-8");
  205. xml_set_object( $this->parser, $this );
  206. xml_set_element_handler( $this->parser, "_tag_open", "_tag_close" );
  207. xml_set_character_data_handler( $this->parser, "_cdata" );
  208. while( $data = fread( $fh, 4096 )) {
  209. if (!xml_parse( $this->parser, $data, feof( $fh ) )) {
  210. die(sprintf("XML error: %s at line %d",
  211. xml_error_string(xml_get_error_code($this->parser)),
  212. xml_get_current_line_number($this->parser)));
  213. }
  214. }
  215. xml_parser_free( $this->parser );
  216. }
  217. function write_file_handle( $fh, $write_header=1 )
  218. {
  219. if ($write_header) {
  220. fwrite( $fh, "<?xml version='1.0' encoding='UTF-8'?>\n" );
  221. }
  222. # Start at the root and write out all of the tags
  223. $this->roottag->write_file_handle( $fh );
  224. }
  225. ###### UTIL #######
  226. function _tag_open( $parser, $tag, $attributes )
  227. {
  228. #print "tag_open: $parser, $tag, $attributes\n";
  229. # If the current tag is not set, then we are at the root
  230. if (!is_object($this->curtag)) {
  231. $null = 0;
  232. $this->curtag = new XMLTag($null);
  233. $this->curtag->set_name( $tag );
  234. $this->curtag->set_attributes( $attributes );
  235. }
  236. else { # otherwise, add it to the tag list and move curtag
  237. $this->curtag->add_subtag( $tag, $attributes );
  238. $this->curtag = &$this->curtag->curtag;
  239. }
  240. }
  241. function _tag_close( $parser, $tag )
  242. {
  243. # Move the current pointer up a level
  244. $this->curtag = &$this->curtag->parent;
  245. }
  246. function _cdata( $parser, $data )
  247. {
  248. $this->curtag->add_cdata( $data );
  249. }
  250. }
  251. ###############################################################################
  252. } // included
  253. ###############################################################################
  254. ?>