/administrator/components/com_csvimproved/helpers/ods/ods.php

https://bitbucket.org/dreamriks/gift · PHP · 193 lines · 115 code · 15 blank · 63 comment · 23 complexity · dea127a142694df47fba36843e36ee73 MD5 · raw file

  1. <?php
  2. /**
  3. * XML parser for ODS files
  4. *
  5. * Parses the content.xml file
  6. *
  7. * @package CSVImproved
  8. * @subpackage Helpers
  9. * @author Roland Dalmulder
  10. * @link http://www.csvimproved.com
  11. * @copyright Copyright (C) 2006 - 2012 RolandD Cyber Produksi
  12. * @license GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html
  13. * @version $Id: ods.php 754 2009-02-14 10:53:32Z Suami $
  14. *
  15. * @todo add support for zip file
  16. * @todo add multiple sheet processing
  17. */
  18. /**
  19. * Parse ODS files
  20. *
  21. * @package CSVImproved
  22. * @subpackage Helpers
  23. */
  24. class ODSParser {
  25. /* Set private variables */
  26. /** @var string filename */
  27. private $_file = null;
  28. /** @var string tag */
  29. private $_tag = null;
  30. /** @var object the xml parser */
  31. private $_xml_parser = null;
  32. /** @var bool set if inside a tag */
  33. private $_insideitem = false;
  34. /** @var array tags to process */
  35. private $_tagprocess = array('TABLE:TABLE-CELL', 'TABLE:TABLE-ROW');
  36. /** @var array holds the data per node */
  37. private $_data = array();
  38. /** @var integer counts the positions */
  39. private $_poscount = 0;
  40. /** @var integer counts the number of times a string is repeated */
  41. private $_columns_repeated = 0;
  42. /* Set public variables */
  43. /** @var array holds the parsed data */
  44. public $fulldata = array();
  45. /** @var int holds the number of rows */
  46. public $rows = null;
  47. /** @var int holds the number of columns */
  48. public $cols = null;
  49. /**
  50. * Start to process the XML file
  51. *
  52. * @todo change die to a proper return result
  53. * @todo add support for <table:table-cell/>
  54. */
  55. public function read($filename) {
  56. $this->_file = $filename;
  57. list($this->_xml_parser, $fp) = $this->new_xml_parser($this->_file);
  58. if (!$this->_xml_parser) {
  59. die("could not open XML input");
  60. }
  61. $data = '';
  62. while (!feof($fp)) {
  63. $data .= fread($fp, 4096);
  64. }
  65. fclose($fp);
  66. /* Regex to find data elements */
  67. $regex = "#<text:p>(.*?)</text:p>#s";
  68. /* Find the content links */
  69. $matches = array();
  70. $result = preg_match_all($regex, $data, $matches);
  71. /* Loop through the links to link them */
  72. foreach ($matches[1] as $key => $value) {
  73. if (!stristr($value, '<![CDATA[')) {
  74. $find = $matches[0][$key];
  75. $replace = '<text:p><![CDATA['.$value.']]></text:p>';
  76. $data = str_replace($find, $replace, $data);
  77. }
  78. }
  79. if (!xml_parse($this->_xml_parser, $data, true)) {
  80. die(sprintf("XML error: %s at line %d\n",
  81. xml_error_string(xml_get_error_code($this->_xml_parser)),
  82. xml_get_current_line_number($this->_xml_parser)));
  83. }
  84. xml_parser_free($this->_xml_parser);
  85. $this->cols = count($this->fulldata[0]);
  86. $this->rows = count($this->fulldata);
  87. return true;
  88. }
  89. /**
  90. * Handle the opening element
  91. */
  92. private function startElement($parser, $tagname, $attribs) {
  93. if ($this->_insideitem) {
  94. $this->_tag = $tagname;
  95. }
  96. elseif (in_array($tagname, $this->_tagprocess)) {
  97. $this->_insideitem = true;
  98. if (isset($attribs['TABLE:NUMBER-COLUMNS-REPEATED'])) {
  99. $this->_columns_repeated = $attribs['TABLE:NUMBER-COLUMNS-REPEATED'];
  100. $this->_poscount += $this->_columns_repeated;
  101. }
  102. else $this->_poscount++;
  103. }
  104. }
  105. /**
  106. * Handle the closing element
  107. */
  108. private function endElement($parser, $name) {
  109. /* Add empty fields */
  110. if ($this->_poscount > count($this->_data)) {
  111. $addfields = $this->_poscount - count($this->_data);
  112. for ($addempty = 0; $addempty < $addfields; $addempty++) {
  113. $this->_data[] = '';
  114. }
  115. }
  116. /* Empty the data array otherwise all data gets put into 1 array */
  117. if ($name == 'TABLE:TABLE-ROW') {
  118. /* Check for empty sheets */
  119. if (count($this->_data) <> 1 && !empty($this->_data[1])) {
  120. $this->fulldata[] = $this->_data;
  121. }
  122. $this->_data = array();
  123. $this->_poscount = 0;
  124. }
  125. /* Reset everything */
  126. $this->_tag = null;
  127. $this->_insideitem = false;
  128. }
  129. /**
  130. * Handle the data
  131. *
  132. * @todo parse <text:s text:c="2"/>
  133. */
  134. private function characterData($parser, $data) {
  135. if ($this->_insideitem) {
  136. switch ($this->_tag) {
  137. case 'TEXT:P':
  138. /* Replace single spaces */
  139. $data = str_replace('<text:s/>', ' ', $data);
  140. if (stristr($data, '<text:s')) {
  141. /* Regex to find data elements */
  142. $regex = "#<text:s text:c=\"(.*?)\"/>#s";
  143. /* Find the spaces */
  144. $matches = array();
  145. $result = preg_match_all($regex, $data, $matches);
  146. /* Replace the spaces */
  147. foreach ($matches[1] as $key => $value) {
  148. $find = '<text:s text:c="'.$value.'"/>';
  149. $replace = str_repeat(" ", $value);
  150. $data = str_replace($find, $replace, $data);
  151. }
  152. }
  153. if (!isset($this->_data[1])) $this->_data[1] = $data;
  154. else {
  155. if ($this->_columns_repeated >= 2) {
  156. for ($print = 0; $print < $this->_columns_repeated; $print++) {
  157. $this->_data[] = $data;
  158. }
  159. $this->_columns_repeated = 0;
  160. }
  161. else $this->_data[] = $data;
  162. }
  163. break;
  164. }
  165. }
  166. }
  167. private function new_xml_parser($file) {
  168. $this->_xml_parser = xml_parser_create("UTF-8");
  169. xml_parser_set_option($this->_xml_parser, XML_OPTION_CASE_FOLDING, 1);
  170. xml_set_object($this->_xml_parser, $this);
  171. xml_set_element_handler($this->_xml_parser, "startElement", "endElement");
  172. xml_set_character_data_handler($this->_xml_parser, "characterData");
  173. $fp = fopen($file, "rb");
  174. if (!$fp) return false;
  175. else return array($this->_xml_parser, $fp);
  176. }
  177. }
  178. ?>