PageRenderTime 54ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/third_party/adodb_xml/class.xml.php

https://github.com/testlinkjp/testlink-japanese-localization
PHP | 442 lines | 228 code | 38 blank | 176 comment | 28 complexity | 929b136da1318bdca65066378dacbf5b MD5 | raw file
  1. <?php
  2. # XMLFile -- Initial version June 1, 2000
  3. # May 29, 2002
  4. # Fixed to work with later versions of PHP that have deprecated the call-time
  5. # pass by reference syntax. This may break versions of PHP older than 3, so
  6. # if you are using this on those versions, go with an earlier version.
  7. # Also added some more comments on how to use it to create XML files. Some
  8. # people (a surprising number of them, in fact) were having difficulty
  9. # understanding the recursive nature of XML files, and that each tag has
  10. # subtags, each of which can have subtags, each of which....
  11. # July 12, 2001
  12. # Fixed an oops in the find_subtags_by_name function.
  13. # July 11, 2001
  14. # Incorporated Kevin Howe's read_xml_string function.
  15. # Incorporated Mike Konkov's find_subtags_by_name function (with some changes).
  16. # Fixed an errant documentation comment (open instead of fopen -- oops).
  17. #
  18. # September 29, 2000
  19. # by Chris Monson -- e408345b17be3ce90059d01d96be0599@orangatango.com This PHP module is licensed under the GNU LGPL (www.gnu.org)
  20. # Please become familiar with this license before sending this thing all over
  21. # the place! I would like to have any changes submitted back to me, and this
  22. # comment must be included with any distribution of this component.
  23. #
  24. # The purpose of this module was to provide a simple interface for dealing with
  25. # small to medium sized XML files. It is probably not suitable for very large
  26. # files since it reads the entire file into a structure in memory. For very
  27. # large files, the XML parsing functions should be used more or less directly
  28. # so that pieces of the file can be dealt with as they are read in.
  29. #
  30. # The basic idea is this: Read the XML file into an internal tree structure
  31. # that is easy to traverse. This module also allows you to create such a
  32. # structure in memory and then write it out to disk. The output is formatted
  33. # in a nice, readable way, using whitespace to delimit tag containment, etc.
  34. # It makes it very easy to write nice-looking XML files.
  35. #
  36. # I have included some usage comments. They are almost certainly incomplete.
  37. # If you get stumped, first use the source, then email me.
  38. #
  39. # July 22, 2004
  40. # by Olavo Alexandrino <oalexandrino@yahoo.com.br>
  41. # Small adaptation so that it is configured the version and codification of the file xml
  42. # Usage:
  43. # $xmlFile = new XMLFile($version, $encoding);
  44. #------------------------------------------------------------------------------
  45. ### USAGE ###
  46. #------------------------------------------------------------------------------
  47. # Reading an XML file:
  48. #------------------------------------------------------------------------------
  49. #
  50. # $xml = new XMLFile();
  51. # $fh = fopen( 'myxmlfile.xml', 'r' );
  52. # $xml->read_file_handle( $fh );
  53. # close( $fh );
  54. #
  55. # Now the tags can be accessed via the root node of $xml:
  56. #
  57. # $root = &$xml->roottag;
  58. # $tagname = $root->name;
  59. # $tagdata = $root->cdata;
  60. #
  61. # Note that a tag is of the following form:
  62. # <NAME attribute=value>CDATA</NAME>
  63. # Each tag contains an attributes array, which is associative by nature. In
  64. # other words, you would access the value of "attribute" as follows:
  65. #
  66. # $value = $root->attributes['attribute'];
  67. #
  68. # Also, each tag has a 'tags' proprerty, which is an ordered array (integer
  69. # indices, not associative!) which has the tags that were contained within
  70. # this tag in their order of appearance. The reason that this is not
  71. # associative is that there can be multiple tags of the same name. There is
  72. # nothing in the XML spec (barring a DTD) that declares the uniqueness of tag
  73. # names. For example:
  74. #
  75. # <OUTER>
  76. # <INNER>CDATA</INNER>
  77. # <INNER name="hello"/>
  78. # </OUTER>
  79. #
  80. # In the above example, the outer tag would have a tags array that has two
  81. # entries, each of which has a tag name of "INNER". The one with CDATA wrapped
  82. # inside would be at index 0, and the other would be at index 1.
  83. #
  84. # Once you have finished with the XMLFile object, you need to call the cleanup
  85. # method. If you don't, you will get a memory leak, since PHP is reference
  86. # counted and each element in the tree refers to its parent. 'cleanup' simply
  87. # traverses the tree and disconnects the parent pointers. The PHP cleans up
  88. # everything else.
  89. #
  90. # $xml->cleanup();
  91. #
  92. # Note that you can change the elements, delete tags, and do other things
  93. # to the tree once it has been read from the file. After it has been changed,
  94. # you can write it back out and the file will reflect your changes.
  95. #------------------------------------------------------------------------------
  96. # Writing a new file:
  97. #
  98. # $xml = new XMLFile();
  99. # $xml->create_root(); # necessary -- no root is created until requested
  100. # $xml->roottag->name = 'ROOT';
  101. # $xml->roottag->add_subtag( 'INNER', array() );
  102. # $innertag = &$xml->roottag->curtag;
  103. # $innertag->add_subtag( 'REALLYINNER', array() );
  104. # # Or, you can do this:
  105. # $xml->roottag->curtag->add_subtag( 'INNER2', array() );
  106. # # The point is that each tag can have subtags. The most recently added
  107. # # subtag is always the curtag of its parent.
  108. # $xml->roottag->add_subtag( 'INNER', array( 'name' => 'value' ) );
  109. # $xml->roottag->curtag->cdata = "Hello!"; # curtag is the most recent addition
  110. # $fh = fopen( 'myxmlfile.xml', 'w' );
  111. # $xml->write_file_handle( $fh );
  112. # close( $fh );
  113. #
  114. # The file will look like this: (no space between ? and >)
  115. #
  116. # <?xml version="1.0" encoding="UTF-8" ? >
  117. # <ROOT>
  118. # <INNER>
  119. # <REALLYINNER/>
  120. # <INNER2/>
  121. # </INNER>
  122. # <INNER name="value">Hello!</INNER>
  123. # </ROOT>
  124. #
  125. #------------------------------------------------------------------------------
  126. #------------------------------------------------------------------------------
  127. #
  128. if (!isset($XMLFile_Included) || !$XMLFile_Included) {
  129. $XMLFile_Included = 1;
  130. ###############################################################################
  131. class XMLTag
  132. {
  133. var $cdata;
  134. var $attributes;
  135. var $name;
  136. var $tags;
  137. var $parent;
  138. var $curtag;
  139. function XMLTag(&$parent)
  140. {
  141. if (is_object( $parent ))
  142. {
  143. $this->parent = &$parent;
  144. }
  145. $this->_init();
  146. }
  147. /**
  148. * @description It initiates the attributes of the XML
  149. * @author Olavo Alexandrino <oalexandrino@yahoo.com.br>
  150. * @copyright oalexandrino.com
  151. * @access private
  152. * @since july / 2004
  153. */
  154. function _init()
  155. {
  156. $this->attributes = array();
  157. $this->cdata = '';
  158. $this->name = '';
  159. $this->tags = array();
  160. }
  161. function add_subtag($name, $attributes=0)
  162. {
  163. $tag = new XMLTag( $this );
  164. $tag->set_name( $name );
  165. if (is_array($attributes)) {
  166. $tag->set_attributes( $attributes );
  167. }
  168. $this->tags[] = &$tag;
  169. $this->curtag = &$tag;
  170. }
  171. function find_subtags_by_name( $name )
  172. {
  173. $result = array();
  174. $found=false;
  175. for($i=0;$i<$this->num_subtags();$i++) {
  176. if(strtoupper($this->tags[$i]->name)==strtoupper($name)) {
  177. $found=true;
  178. $array2return[]=&$this->tags[$i];
  179. }
  180. }
  181. if($found) {
  182. return $array2return;
  183. }
  184. else {
  185. return false;
  186. }
  187. }
  188. function clear_subtags()
  189. {
  190. # Traverse the structure, removing the parent pointers
  191. $numtags = sizeof($this->tags);
  192. $keys = array_keys( $this->tags );
  193. foreach( $keys as $k ) {
  194. $this->tags[$k]->clear_subtags();
  195. unset($this->tags[$k]->parent);
  196. }
  197. # Clear the tags array
  198. $this->tags = array();
  199. unset( $this->curtag );
  200. }
  201. function remove_subtag($index)
  202. {
  203. if (is_object($this->tags[$index])) {
  204. unset($this->tags[$index]->parent);
  205. unset($this->tags[$index]);
  206. }
  207. }
  208. function num_subtags()
  209. {
  210. return sizeof( $this->tags );
  211. }
  212. function add_attribute( $name, $val )
  213. {
  214. //$this->attributes[strtoupper($name)] = $val;
  215. $this->attributes[$name] = $val;
  216. }
  217. function clear_attributes()
  218. {
  219. $this->attributes = array();
  220. }
  221. function set_name( $name )
  222. {
  223. //$this->name = strtoupper($name);
  224. $this->name = $name;
  225. }
  226. function set_attributes( $attributes )
  227. {
  228. $this->attributes = (is_array($attributes)) ? $attributes : array();
  229. }
  230. function add_cdata( $data )
  231. {
  232. $this->cdata .= $data;
  233. }
  234. function clear_cdata()
  235. {
  236. $this->cdata = "";
  237. }
  238. function write_file_handle( $fh, $prepend_str='' )
  239. {
  240. # Get the attribute string
  241. $attrs = array();
  242. $attr_str = '';
  243. foreach( $this->attributes as $key => $val )
  244. {
  245. $attrs[] = strtoupper($key) . "=\"$val\"";
  246. }
  247. if ($attrs) {
  248. $attr_str = join( " ", $attrs );
  249. }
  250. # Write out the start element
  251. $tagstr = "$prepend_str<{$this->name}";
  252. if ($attr_str) {
  253. $tagstr .= " $attr_str";
  254. }
  255. $keys = array_keys( $this->tags );
  256. $numtags = sizeof( $keys );
  257. #
  258. # If there are subtags and no data (only whitespace),
  259. # then go ahead and add a carriage
  260. # return. Otherwise the tag should be of this form:
  261. # <tag>val</tag>
  262. # If there are no subtags and no data, then the tag should be
  263. # closed: <tag attrib="val"/>
  264. #
  265. # 20080921 - francisco.mancardi@gmail.com
  266. # $trimmeddata = "![CDATA[" . trim( $this->cdata ) . "]]";
  267. $trimmeddata = trim( $this->cdata );
  268. if ($numtags && ($trimmeddata == "")) {
  269. $tagstr .= ">\n";
  270. }
  271. elseif (!$numtags && ($trimmeddata == "")) {
  272. $tagstr .= "/>\n";
  273. }
  274. else {
  275. $tagstr .= ">";
  276. }
  277. fwrite( $fh, $tagstr );
  278. # Write out the data if it is not purely whitespace
  279. if ($trimmeddata != "") {
  280. fwrite( $fh, $trimmeddata );
  281. }
  282. # Write out each subtag
  283. foreach( $keys as $k ) {
  284. $this->tags[$k]->write_file_handle( $fh, "$prepend_str\t" );
  285. }
  286. # Write out the end element if necessary
  287. if ($numtags || ($trimmeddata != "")) {
  288. $tagstr = "</{$this->name}>\n";
  289. if ($numtags) {
  290. $tagstr = "$prepend_str$tagstr";
  291. }
  292. fwrite( $fh, $tagstr );
  293. }
  294. }
  295. }
  296. ###############################################################################
  297. class XMLFile
  298. {
  299. var $parser;
  300. var $roottag;
  301. var $curtag;
  302. var $encoding;
  303. var $version;
  304. /**
  305. * @description Constructor
  306. * @author Olavo Alexandrino <oalexandrino@yahoo.com.br>
  307. * @copyright oalexandrino.com
  308. * @access public
  309. * @since july / 2004
  310. */
  311. function XMLFile($version = "1.0", $encoding = "UTF-8")
  312. {
  313. $this->version = $version;
  314. $this->encoding = $encoding;
  315. $this->init();
  316. }
  317. # Until there is a suitable destructor mechanism, this needs to be
  318. # called when the file is no longer needed. This calls the clear_subtags
  319. # method of the root node, which eliminates all circular references
  320. # in the xml tree.
  321. function cleanup()
  322. {
  323. if (is_object( $this->roottag )) {
  324. $this->roottag->clear_subtags();
  325. }
  326. }
  327. function init()
  328. {
  329. $this->roottag = "";
  330. $this->curtag = &$this->roottag;
  331. }
  332. function create_root()
  333. {
  334. $null = 0;
  335. $this->roottag = new XMLTag($null);
  336. $this->curtag = &$this->roottag;
  337. }
  338. # read_xml_string
  339. # Same as read_file_handle, but you pass it a string. Note that
  340. # depending on the size of the XML, this could be rather memory intensive.
  341. # Contributed July 06, 2001 by Kevin Howe
  342. function read_xml_string( $str )
  343. {
  344. $this->init();
  345. $this->parser = xml_parser_create($this->encoding);
  346. xml_set_object( $this->parser, $this );
  347. xml_set_element_handler( $this->parser, "_tag_open", "_tag_close" );
  348. xml_set_character_data_handler( $this->parser, "_cdata" );
  349. xml_parse( $this->parser, $str );
  350. xml_parser_free( $this->parser );
  351. }
  352. function read_file_handle( $fh )
  353. {
  354. $this->init();
  355. $this->parser = xml_parser_create($this->encoding);
  356. xml_set_object( $this->parser, $this );
  357. xml_set_element_handler( $this->parser, "_tag_open", "_tag_close" );
  358. xml_set_character_data_handler( $this->parser, "_cdata" );
  359. while( $data = fread( $fh, 4096 )) {
  360. if (!xml_parse( $this->parser, $data, feof( $fh ) )) {
  361. die(sprintf("XML error: %s at line %d",
  362. xml_error_string(xml_get_error_code($this->parser)),
  363. xml_get_current_line_number($this->parser)));
  364. }
  365. }
  366. xml_parser_free( $this->parser );
  367. }
  368. function write_file_handle( $fh, $write_header=1 )
  369. {
  370. if ($write_header) {
  371. fwrite( $fh, "<?xml version='". $this->version . "' encoding='". $this->encoding . "'?>\n" );
  372. }
  373. # Start at the root and write out all of the tags
  374. $this->roottag->write_file_handle( $fh );
  375. }
  376. ###### UTIL #######
  377. function _tag_open( $parser, $tag, $attributes )
  378. {
  379. #print "tag_open: $parser, $tag, $attributes\n";
  380. # If the current tag is not set, then we are at the root
  381. if (!is_object($this->curtag)) {
  382. $null = 0;
  383. $this->curtag = new XMLTag($null);
  384. $this->curtag->set_name( $tag );
  385. $this->curtag->set_attributes( $attributes );
  386. }
  387. else { # otherwise, add it to the tag list and move curtag
  388. $this->curtag->add_subtag( $tag, $attributes );
  389. $this->curtag = &$this->curtag->curtag;
  390. }
  391. }
  392. function _tag_close( $parser, $tag )
  393. {
  394. # Move the current pointer up a level
  395. $this->curtag = &$this->curtag->parent;
  396. }
  397. function _cdata( $parser, $data )
  398. {
  399. $this->curtag->add_cdata( $data );
  400. }
  401. }
  402. ###############################################################################
  403. } // included
  404. ###############################################################################