PageRenderTime 51ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/saf/lib/XML/RelaxNG/Parser.php

https://github.com/wokkie/sitellite
PHP | 238 lines | 192 code | 34 blank | 12 comment | 61 complexity | 5e9a425125f89e130421d2f3efecc1c7 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, Apache-2.0
  1. <?php
  2. $loader->import ('saf.XML.RelaxNG.Rule');
  3. /**
  4. * @package XML
  5. */
  6. class RNGParser {
  7. var $rules;
  8. var $current;
  9. var $schema;
  10. var $nodes;
  11. var $tags;
  12. var $types = array ('text', 'empty', 'data'); //, 'choice', 'list', 'value');
  13. var $parser;
  14. var $encoding;
  15. var $rule = 'required';
  16. var $error = false;
  17. var $err_line;
  18. var $err_code;
  19. var $err_byte;
  20. var $err_colnum;
  21. function parse ($schema) {
  22. $this->parser = xml_parser_create ($this->encoding);
  23. if (! $this->parser) {
  24. $this->error = 'Relax Error: Failed to create an XML parser!';
  25. return false;
  26. }
  27. if (! xml_parser_set_option ($this->parser, XML_OPTION_CASE_FOLDING, false)) {
  28. xml_parser_free ($this->parser);
  29. $this->error = 'Relax Error: Failed to disable case folding!';
  30. return false;
  31. }
  32. $this->schema = $schema;
  33. //$this->elements = array ();
  34. //$this->parents = array ();
  35. //$this->attrs = array ();
  36. $this->attrOpen = false;
  37. $this->definitions = array ();
  38. $this->addUntil = false;
  39. $this->error = false;
  40. $this->rule = 'required';
  41. if (xml_parse_into_struct ($this->parser, $schema, $this->nodes, $this->tags)) {
  42. xml_parser_free ($this->parser);
  43. foreach ($this->nodes as $node) {
  44. $this->{$this->makeMethod ($node['tag'], $node['type'])} ($node);
  45. }
  46. return $this->rules;
  47. } else {
  48. $this->err_code = xml_get_error_code ($this->parser);
  49. $this->err_line = xml_get_current_line_number ($this->parser);
  50. $this->err_byte = xml_get_current_byte_index ($this->parser);
  51. $this->err_colnum = xml_get_current_column_number ($this->parser);
  52. $this->error = 'Relax Error: ' . xml_error_string ($this->err_code);
  53. xml_parser_free ($this->parser);
  54. return false;
  55. }
  56. }
  57. function makeMethod ($tag, $type) {
  58. if ($tag == 'element' && $type == 'open') {
  59. return '_element';
  60. } elseif ($tag == 'element' && $type == 'close') {
  61. return '_close_element';
  62. } elseif ($tag == 'attribute' && $type == 'open') {
  63. return '_attribute';
  64. } elseif ($tag == 'attribute' && $type == 'close') {
  65. return '_close_attribute';
  66. } elseif ($tag == 'zeroOrMore' && $type == 'open') {
  67. return '_zeroOrMore';
  68. } elseif ($tag == 'oneOrMore' && $type == 'open') {
  69. return '_oneOrMore';
  70. } elseif ($tag == 'optional' && $type == 'open') {
  71. return '_optional';
  72. } elseif ($tag == 'ref') {
  73. return '_ref';
  74. } elseif (in_array ($tag, $this->types)) {
  75. return '_type';
  76. }
  77. return '_default';
  78. }
  79. function _default ($node) {
  80. if ($node['tag'] == 'define' && $node['type'] == 'open') { // define tag
  81. $this->definitions[$node['attributes']['name']] = array ();
  82. $this->addUntil = $node['level'];
  83. return;
  84. } elseif ($node['level'] == $this->addUntil) { // close define tag
  85. $this->addUntil = false;
  86. return;
  87. } elseif ($this->addUntil) { // add to definition
  88. $this->definitions[array_pop (array_keys ($this->definitions))][] = $node;
  89. return;
  90. }
  91. }
  92. function _element ($node) {
  93. if ($this->addUntil) {
  94. $this->definitions[array_pop (array_keys ($this->definitions))][] = $node;
  95. return;
  96. }
  97. // set default datatypeLibrary value
  98. if (isset ($node['attributes']['datatypeLibrary'])) {
  99. $this->typeNS = $node['attributes']['datatypeLibrary'];
  100. $this->keepTypeNSUntil = $node['level'];
  101. }
  102. if (is_object ($this->rules)) {
  103. $this->current =& $this->current->addChild ($node['attributes']['name'], $this->rule);
  104. } else {
  105. $this->rules = new RNGRule ($node['attributes']['name'], $this->rule);
  106. $this->current =& $this->rules;
  107. }
  108. $this->rule = 'required';
  109. }
  110. function _close_element ($node) {
  111. if ($this->addUntil) {
  112. $this->definitions[ array_pop (array_keys ($this->definitions)) ][] = $node;
  113. return;
  114. }
  115. // keep datatypeLibrary value until appropriate level
  116. if ($this->keepTypeNSUntil && $node['level'] == $this->typeNS) {
  117. $this->typeNS = '';
  118. $this->keepTypeNSUntil = false;
  119. }
  120. if (is_object ($this->current->parent)) {
  121. $this->current =& $this->current->parent;
  122. } else {
  123. // we're done, no more elements
  124. //unset ($this->current);
  125. }
  126. }
  127. function _attribute ($node) {
  128. if ($this->addUntil) {
  129. $this->definitions[array_pop (array_keys ($this->definitions))][] = $node;
  130. return;
  131. }
  132. // set default datatypeLibrary value
  133. if (isset ($node['attributes']['datatypeLibrary'])) {
  134. $this->typeNS = $node['attributes']['datatypeLibrary'];
  135. $this->keepTypeNSUntil = $node['level'];
  136. }
  137. $this->current->setAttribute ($node['attributes']['name'], $this->rule);
  138. $this->attrOpen = $node['attributes']['name'];
  139. $this->rule = 'required';
  140. }
  141. function _close_attribute ($node) {
  142. if ($this->addUntil) {
  143. $this->definitions[ array_pop (array_keys ($this->definitions)) ][] = $node;
  144. return;
  145. }
  146. // keep datatypeLibrary value until appropriate level
  147. if ($this->keepTypeNSUntil && $node['level'] == $this->typeNS) {
  148. $this->typeNS = '';
  149. $this->keepTypeNSUntil = false;
  150. }
  151. $this->attrOpen = false;
  152. }
  153. function _zeroOrMore ($node) { // * rule
  154. if ($this->addUntil) {
  155. $this->definitions[ array_pop (array_keys ($this->definitions)) ][] = $node;
  156. return;
  157. }
  158. $this->rule = 'zero or more';
  159. }
  160. function _oneOrMore ($node) { // + rule
  161. if ($this->addUntil) {
  162. $this->definitions[ array_pop (array_keys ($this->definitions)) ][] = $node;
  163. return;
  164. }
  165. $this->rule = 'one or more';
  166. }
  167. function _optional ($node) { // ? rule
  168. if ($this->addUntil) {
  169. $this->definitions[ array_pop (array_keys ($this->definitions)) ][] = $node;
  170. return;
  171. }
  172. $this->rule = 'optional';
  173. }
  174. function _ref ($node) {
  175. if (is_array ($this->definitions[ $node['attributes']['name'] ]) && count ($this->definitions[ $node['attributes']['name'] ]) > 0) {
  176. foreach ($this->definitions[ $node['attributes']['name'] ] as $n) {
  177. $n['level'] = $node['level'] + ($n['level'] - 3);
  178. $this->{$this->makeMethod ($n['tag'], $n['type'])} ($n);
  179. }
  180. }
  181. }
  182. function _type ($node) {
  183. if ($this->addUntil) {
  184. $this->definitions[ array_pop (array_keys ($this->definitions)) ][] = $node;
  185. return;
  186. }
  187. if ($node['tag'] == 'data') {
  188. $type = $node['attributes']['type'];
  189. } else {
  190. $type = $node['tag'];
  191. }
  192. if (isset ($node['attributes']['datatypeLibrary'])) {
  193. $ns = $node['attributes']['datatypeLibrary'];
  194. } else {
  195. $ns = $this->typeNS;
  196. }
  197. if ($this->attrOpen) {
  198. $this->current->setType ($type, $ns, $this->attrOpen);
  199. } else {
  200. $this->current->setType ($type, $ns);
  201. }
  202. }
  203. }
  204. ?>