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. if ( ! function_exists( 'xml_parser_create_ns' ) ) { 
  56. trigger_error( __( "PHP's XML extension is not available. Please contact your hosting provider to enable PHP's XML extension." ) ); 
  57. return false; 
  58.  
  59. $parser = xml_parser_create_ns(); 
  60. xml_set_object($parser, $this); 
  61. xml_set_element_handler($parser, "start_element", "end_element"); 
  62. xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0); 
  63. xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 0); 
  64. xml_set_character_data_handler($parser, "cdata"); 
  65. xml_set_default_handler($parser, "_default"); 
  66. xml_set_start_namespace_decl_handler($parser, "start_ns"); 
  67. xml_set_end_namespace_decl_handler($parser, "end_ns"); 
  68.  
  69. $this->content = ''; 
  70.  
  71. $ret = true; 
  72.  
  73. $fp = fopen($this->FILE, "r"); 
  74. while ($data = fread($fp, 4096)) { 
  75. if($this->debug) $this->content .= $data; 
  76.  
  77. if(!xml_parse($parser, $data, feof($fp))) { 
  78. /** translators: 1: error message, 2: line number */ 
  79. trigger_error(sprintf(__('XML Error: %1$s at line %2$s')."\n",  
  80. xml_error_string(xml_get_error_code($parser)),  
  81. xml_get_current_line_number($parser))); 
  82. $ret = false; 
  83. break; 
  84. fclose($fp); 
  85.  
  86. xml_parser_free($parser); 
  87.  
  88. restore_error_handler(); 
  89.  
  90. return $ret; 
  91.  
  92. function start_element($parser, $name, $attrs) { 
  93.  
  94. $tag = array_pop(explode(":", $name)); 
  95.  
  96. switch($name) { 
  97. case $this->NS . ':feed': 
  98. $this->current = $this->feed; 
  99. break; 
  100. case $this->NS . ':entry': 
  101. $this->current = new AtomEntry(); 
  102. break; 
  103. }; 
  104.  
  105. $this->_p("start_element('$name')"); 
  106. #$this->_p(print_r($this->ns_contexts, true)); 
  107. #$this->_p('current(' . $this->current . ')'); 
  108.  
  109. array_unshift($this->ns_contexts, $this->ns_decls); 
  110.  
  111. $this->depth++; 
  112.  
  113. if(!empty($this->in_content)) { 
  114.  
  115. $this->content_ns_decls = array(); 
  116.  
  117. if($this->is_html || $this->is_text) 
  118. trigger_error("Invalid content in element found. Content must not be of type text or html if it contains markup."); 
  119.  
  120. $attrs_prefix = array(); 
  121.  
  122. // resolve prefixes for attributes 
  123. foreach($attrs as $key => $value) { 
  124. $with_prefix = $this->ns_to_prefix($key, true); 
  125. $attrs_prefix[$with_prefix[1]] = $this->xml_escape($value); 
  126.  
  127. $attrs_str = join(' ', array_map($this->map_attrs_func, array_keys($attrs_prefix), array_values($attrs_prefix))); 
  128. if(strlen($attrs_str) > 0) { 
  129. $attrs_str = " " . $attrs_str; 
  130.  
  131. $with_prefix = $this->ns_to_prefix($name); 
  132.  
  133. if(!$this->is_declared_content_ns($with_prefix[0])) { 
  134. array_push($this->content_ns_decls, $with_prefix[0]); 
  135.  
  136. $xmlns_str = ''; 
  137. if(count($this->content_ns_decls) > 0) { 
  138. array_unshift($this->content_ns_contexts, $this->content_ns_decls); 
  139. $xmlns_str .= join(' ', array_map($this->map_xmlns_func, array_keys($this->content_ns_contexts[0]), array_values($this->content_ns_contexts[0]))); 
  140. if(strlen($xmlns_str) > 0) { 
  141. $xmlns_str = " " . $xmlns_str; 
  142.  
  143. array_push($this->in_content, array($tag, $this->depth, "<". $with_prefix[1] ."{$xmlns_str}{$attrs_str}" . ">")); 
  144.  
  145. } else if(in_array($tag, $this->ATOM_CONTENT_ELEMENTS) || in_array($tag, $this->ATOM_SIMPLE_ELEMENTS)) { 
  146. $this->in_content = array(); 
  147. $this->is_xhtml = $attrs['type'] == 'xhtml'; 
  148. $this->is_html = $attrs['type'] == 'html' || $attrs['type'] == 'text/html'; 
  149. $this->is_text = !in_array('type', array_keys($attrs)) || $attrs['type'] == 'text'; 
  150. $type = $this->is_xhtml ? 'XHTML' : ($this->is_html ? 'HTML' : ($this->is_text ? 'TEXT' : $attrs['type'])); 
  151.  
  152. if(in_array('src', array_keys($attrs))) { 
  153. $this->current->$tag = $attrs; 
  154. } else { 
  155. array_push($this->in_content, array($tag, $this->depth, $type)); 
  156. } else if($tag == 'link') { 
  157. array_push($this->current->links, $attrs); 
  158. } else if($tag == 'category') { 
  159. array_push($this->current->categories, $attrs); 
  160.  
  161. $this->ns_decls = array(); 
  162.  
  163. function end_element($parser, $name) { 
  164.  
  165. $tag = array_pop(explode(":", $name)); 
  166.  
  167. $ccount = count($this->in_content); 
  168.  
  169. # if we are *in* content, then let's proceed to serialize it 
  170. if(!empty($this->in_content)) { 
  171. # if we are ending the original content element 
  172. # then let's finalize the content 
  173. if($this->in_content[0][0] == $tag && 
  174. $this->in_content[0][1] == $this->depth) { 
  175. $origtype = $this->in_content[0][2]; 
  176. array_shift($this->in_content); 
  177. $newcontent = array(); 
  178. foreach($this->in_content as $c) { 
  179. if(count($c) == 3) { 
  180. array_push($newcontent, $c[2]); 
  181. } else { 
  182. if($this->is_xhtml || $this->is_text) { 
  183. array_push($newcontent, $this->xml_escape($c)); 
  184. } else { 
  185. array_push($newcontent, $c); 
  186. if(in_array($tag, $this->ATOM_CONTENT_ELEMENTS)) { 
  187. $this->current->$tag = array($origtype, join('', $newcontent)); 
  188. } else { 
  189. $this->current->$tag = join('', $newcontent); 
  190. $this->in_content = array(); 
  191. } else if($this->in_content[$ccount-1][0] == $tag && 
  192. $this->in_content[$ccount-1][1] == $this->depth) { 
  193. $this->in_content[$ccount-1][2] = substr($this->in_content[$ccount-1][2], 0, -1) . "/>"; 
  194. } else { 
  195. # else, just finalize the current element's content 
  196. $endtag = $this->ns_to_prefix($name); 
  197. array_push($this->in_content, array($tag, $this->depth, "</$endtag[1]>")); 
  198.  
  199. array_shift($this->ns_contexts); 
  200.  
  201. $this->depth--; 
  202.  
  203. if($name == ($this->NS . ':entry')) { 
  204. array_push($this->feed->entries, $this->current); 
  205. $this->current = null; 
  206.  
  207. $this->_p("end_element('$name')"); 
  208.  
  209. function start_ns($parser, $prefix, $uri) { 
  210. $this->_p("starting: " . $prefix . ":" . $uri); 
  211. array_push($this->ns_decls, array($prefix, $uri)); 
  212.  
  213. function end_ns($parser, $prefix) { 
  214. $this->_p("ending: #" . $prefix . "#"); 
  215.  
  216. function cdata($parser, $data) { 
  217. $this->_p("data: #" . str_replace(array("\n"), array("\\n"), trim($data)) . "#"); 
  218. if(!empty($this->in_content)) { 
  219. array_push($this->in_content, $data); 
  220.  
  221. function _default($parser, $data) { 
  222. # when does this gets called? 
  223.  
  224.  
  225. function ns_to_prefix($qname, $attr=false) { 
  226. # split 'http://www.w3.org/1999/xhtml:div' into ('http', '//www.w3.org/1999/xhtml', 'div') 
  227. $components = explode(":", $qname); 
  228.  
  229. # grab the last one (e.g 'div') 
  230. $name = array_pop($components); 
  231.  
  232. if(!empty($components)) { 
  233. # re-join back the namespace component 
  234. $ns = join(":", $components); 
  235. foreach($this->ns_contexts as $context) { 
  236. foreach($context as $mapping) { 
  237. if($mapping[1] == $ns && strlen($mapping[0]) > 0) { 
  238. return array($mapping, "$mapping[0]:$name"); 
  239.  
  240. if($attr) { 
  241. return array(null, $name); 
  242. } else { 
  243. foreach($this->ns_contexts as $context) { 
  244. foreach($context as $mapping) { 
  245. if(strlen($mapping[0]) == 0) { 
  246. return array($mapping, $name); 
  247.  
  248. function is_declared_content_ns($new_mapping) { 
  249. foreach($this->content_ns_contexts as $context) { 
  250. foreach($context as $mapping) { 
  251. if($new_mapping == $mapping) { 
  252. return true; 
  253. return false; 
  254.  
  255. function xml_escape($string) 
  256. return str_replace(array('&', '"', "'", '<', '>'),  
  257. array('&', '"', ''', '<', '>'),  
  258. $string );