AtomParser

AtomLib Atom Parser API.

Defined (1)

The class is defined in the following location(s).

/wp-includes/atomlib.php  
  1. class AtomParser { 
  2.  
  3. var $NS = 'http://www.w3.org/2005/Atom'; 
  4. var $ATOM_CONTENT_ELEMENTS = array('content', 'summary', 'title', 'subtitle', 'rights'); 
  5. var $ATOM_SIMPLE_ELEMENTS = array('id', 'updated', 'published', 'draft'); 
  6.  
  7. var $debug = false; 
  8.  
  9. var $depth = 0; 
  10. var $indent = 2; 
  11. var $in_content; 
  12. var $ns_contexts = array(); 
  13. var $ns_decls = array(); 
  14. var $content_ns_decls = array(); 
  15. var $content_ns_contexts = array(); 
  16. var $is_xhtml = false; 
  17. var $is_html = false; 
  18. var $is_text = true; 
  19. var $skipped_div = false; 
  20.  
  21. var $FILE = "php://input"; 
  22.  
  23. var $feed; 
  24. var $current; 
  25.  
  26. /** 
  27. * PHP5 constructor. 
  28. */ 
  29. function __construct() { 
  30.  
  31. $this->feed = new AtomFeed(); 
  32. $this->current = null; 
  33. $this->map_attrs_func = create_function('$k, $v', 'return "$k=\"$v\"";'); 
  34. $this->map_xmlns_func = create_function('$p, $n', '$xd = "xmlns"; if(strlen($n[0])>0) $xd .= ":{$n[0]}"; return "{$xd}=\"{$n[1]}\"";'); 
  35.  
  36. /** 
  37. * PHP4 constructor. 
  38. */ 
  39. public function AtomParser() { 
  40. self::__construct(); 
  41.  
  42. function _p($msg) { 
  43. if($this->debug) { 
  44. print str_repeat(" ", $this->depth * $this->indent) . $msg ."\n"; 
  45.  
  46. function error_handler($log_level, $log_text, $error_file, $error_line) { 
  47. $this->error = $log_text; 
  48.  
  49. function parse() { 
  50.  
  51. set_error_handler(array(&$this, 'error_handler')); 
  52.  
  53. array_unshift($this->ns_contexts, array()); 
  54.  
  55. $parser = xml_parser_create_ns(); 
  56. xml_set_object($parser, $this); 
  57. xml_set_element_handler($parser, "start_element", "end_element"); 
  58. xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0); 
  59. xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 0); 
  60. xml_set_character_data_handler($parser, "cdata"); 
  61. xml_set_default_handler($parser, "_default"); 
  62. xml_set_start_namespace_decl_handler($parser, "start_ns"); 
  63. xml_set_end_namespace_decl_handler($parser, "end_ns"); 
  64.  
  65. $this->content = ''; 
  66.  
  67. $ret = true; 
  68.  
  69. $fp = fopen($this->FILE, "r"); 
  70. while ($data = fread($fp, 4096)) { 
  71. if($this->debug) $this->content .= $data; 
  72.  
  73. if(!xml_parse($parser, $data, feof($fp))) { 
  74. /** translators: 1: error message, 2: line number */ 
  75. trigger_error(sprintf(__('XML Error: %1$s at line %2$s')."\n",  
  76. xml_error_string(xml_get_error_code($parser)),  
  77. xml_get_current_line_number($parser))); 
  78. $ret = false; 
  79. break; 
  80. fclose($fp); 
  81.  
  82. xml_parser_free($parser); 
  83.  
  84. restore_error_handler(); 
  85.  
  86. return $ret; 
  87.  
  88. function start_element($parser, $name, $attrs) { 
  89.  
  90. $tag = array_pop(split(":", $name)); 
  91.  
  92. switch($name) { 
  93. case $this->NS . ':feed': 
  94. $this->current = $this->feed; 
  95. break; 
  96. case $this->NS . ':entry': 
  97. $this->current = new AtomEntry(); 
  98. break; 
  99. }; 
  100.  
  101. $this->_p("start_element('$name')"); 
  102. #$this->_p(print_r($this->ns_contexts, true)); 
  103. #$this->_p('current(' . $this->current . ')'); 
  104.  
  105. array_unshift($this->ns_contexts, $this->ns_decls); 
  106.  
  107. $this->depth++; 
  108.  
  109. if(!empty($this->in_content)) { 
  110.  
  111. $this->content_ns_decls = array(); 
  112.  
  113. if($this->is_html || $this->is_text) 
  114. trigger_error("Invalid content in element found. Content must not be of type text or html if it contains markup."); 
  115.  
  116. $attrs_prefix = array(); 
  117.  
  118. // resolve prefixes for attributes 
  119. foreach($attrs as $key => $value) { 
  120. $with_prefix = $this->ns_to_prefix($key, true); 
  121. $attrs_prefix[$with_prefix[1]] = $this->xml_escape($value); 
  122.  
  123. $attrs_str = join(' ', array_map($this->map_attrs_func, array_keys($attrs_prefix), array_values($attrs_prefix))); 
  124. if(strlen($attrs_str) > 0) { 
  125. $attrs_str = " " . $attrs_str; 
  126.  
  127. $with_prefix = $this->ns_to_prefix($name); 
  128.  
  129. if(!$this->is_declared_content_ns($with_prefix[0])) { 
  130. array_push($this->content_ns_decls, $with_prefix[0]); 
  131.  
  132. $xmlns_str = ''; 
  133. if(count($this->content_ns_decls) > 0) { 
  134. array_unshift($this->content_ns_contexts, $this->content_ns_decls); 
  135. $xmlns_str .= join(' ', array_map($this->map_xmlns_func, array_keys($this->content_ns_contexts[0]), array_values($this->content_ns_contexts[0]))); 
  136. if(strlen($xmlns_str) > 0) { 
  137. $xmlns_str = " " . $xmlns_str; 
  138.  
  139. array_push($this->in_content, array($tag, $this->depth, "<". $with_prefix[1] ."{$xmlns_str}{$attrs_str}" . ">")); 
  140.  
  141. } else if(in_array($tag, $this->ATOM_CONTENT_ELEMENTS) || in_array($tag, $this->ATOM_SIMPLE_ELEMENTS)) { 
  142. $this->in_content = array(); 
  143. $this->is_xhtml = $attrs['type'] == 'xhtml'; 
  144. $this->is_html = $attrs['type'] == 'html' || $attrs['type'] == 'text/html'; 
  145. $this->is_text = !in_array('type', array_keys($attrs)) || $attrs['type'] == 'text'; 
  146. $type = $this->is_xhtml ? 'XHTML' : ($this->is_html ? 'HTML' : ($this->is_text ? 'TEXT' : $attrs['type'])); 
  147.  
  148. if(in_array('src', array_keys($attrs))) { 
  149. $this->current->$tag = $attrs; 
  150. } else { 
  151. array_push($this->in_content, array($tag, $this->depth, $type)); 
  152. } else if($tag == 'link') { 
  153. array_push($this->current->links, $attrs); 
  154. } else if($tag == 'category') { 
  155. array_push($this->current->categories, $attrs); 
  156.  
  157. $this->ns_decls = array(); 
  158.  
  159. function end_element($parser, $name) { 
  160.  
  161. $tag = array_pop(split(":", $name)); 
  162.  
  163. $ccount = count($this->in_content); 
  164.  
  165. # if we are *in* content, then let's proceed to serialize it 
  166. if(!empty($this->in_content)) { 
  167. # if we are ending the original content element 
  168. # then let's finalize the content 
  169. if($this->in_content[0][0] == $tag && 
  170. $this->in_content[0][1] == $this->depth) { 
  171. $origtype = $this->in_content[0][2]; 
  172. array_shift($this->in_content); 
  173. $newcontent = array(); 
  174. foreach($this->in_content as $c) { 
  175. if(count($c) == 3) { 
  176. array_push($newcontent, $c[2]); 
  177. } else { 
  178. if($this->is_xhtml || $this->is_text) { 
  179. array_push($newcontent, $this->xml_escape($c)); 
  180. } else { 
  181. array_push($newcontent, $c); 
  182. if(in_array($tag, $this->ATOM_CONTENT_ELEMENTS)) { 
  183. $this->current->$tag = array($origtype, join('', $newcontent)); 
  184. } else { 
  185. $this->current->$tag = join('', $newcontent); 
  186. $this->in_content = array(); 
  187. } else if($this->in_content[$ccount-1][0] == $tag && 
  188. $this->in_content[$ccount-1][1] == $this->depth) { 
  189. $this->in_content[$ccount-1][2] = substr($this->in_content[$ccount-1][2], 0, -1) . "/>"; 
  190. } else { 
  191. # else, just finalize the current element's content 
  192. $endtag = $this->ns_to_prefix($name); 
  193. array_push($this->in_content, array($tag, $this->depth, "</$endtag[1]>")); 
  194.  
  195. array_shift($this->ns_contexts); 
  196.  
  197. $this->depth--; 
  198.  
  199. if($name == ($this->NS . ':entry')) { 
  200. array_push($this->feed->entries, $this->current); 
  201. $this->current = null; 
  202.  
  203. $this->_p("end_element('$name')"); 
  204.  
  205. function start_ns($parser, $prefix, $uri) { 
  206. $this->_p("starting: " . $prefix . ":" . $uri); 
  207. array_push($this->ns_decls, array($prefix, $uri)); 
  208.  
  209. function end_ns($parser, $prefix) { 
  210. $this->_p("ending: #" . $prefix . "#"); 
  211.  
  212. function cdata($parser, $data) { 
  213. $this->_p("data: #" . str_replace(array("\n"), array("\\n"), trim($data)) . "#"); 
  214. if(!empty($this->in_content)) { 
  215. array_push($this->in_content, $data); 
  216.  
  217. function _default($parser, $data) { 
  218. # when does this gets called? 
  219.  
  220.  
  221. function ns_to_prefix($qname, $attr=false) { 
  222. # split 'http://www.w3.org/1999/xhtml:div' into ('http', '//www.w3.org/1999/xhtml', 'div') 
  223. $components = split(":", $qname); 
  224.  
  225. # grab the last one (e.g 'div') 
  226. $name = array_pop($components); 
  227.  
  228. if(!empty($components)) { 
  229. # re-join back the namespace component 
  230. $ns = join(":", $components); 
  231. foreach($this->ns_contexts as $context) { 
  232. foreach($context as $mapping) { 
  233. if($mapping[1] == $ns && strlen($mapping[0]) > 0) { 
  234. return array($mapping, "$mapping[0]:$name"); 
  235.  
  236. if($attr) { 
  237. return array(null, $name); 
  238. } else { 
  239. foreach($this->ns_contexts as $context) { 
  240. foreach($context as $mapping) { 
  241. if(strlen($mapping[0]) == 0) { 
  242. return array($mapping, $name); 
  243.  
  244. function is_declared_content_ns($new_mapping) { 
  245. foreach($this->content_ns_contexts as $context) { 
  246. foreach($context as $mapping) { 
  247. if($new_mapping == $mapping) { 
  248. return true; 
  249. return false; 
  250.  
  251. function xml_escape($string) 
  252. return str_replace(array('&', '"', "'", '<', '>'),  
  253. array('&', '"', ''', '<', '>'),  
  254. $string );