]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/XmlParser.php
- Atom Parser and Feed Plugin
[SourceForge/phpwiki.git] / lib / XmlParser.php
1 <?php // -*-php-*-
2 // rcs_id('$Id$');
3 /**
4  * Base XmlParser Class.
5  * Requires the expat.so/.dll, usually enabled by default.
6  * Used by HtmlParser and RssParser.
7  *
8  * @author: Reini Urban
9  *
10  * TODO: Convert more perl Html::Element style to our XmlElement style
11  * Needed additions to XmlElement: 
12  *   Html::Element::parent() <=> XmlElement::parent
13  *   Html::Element::attr()   <=> XmlElement::getAttr()
14  *   Html::Element::tag      <=> XmlElement::_tag
15  *   Html::Element::content_list() <=> ->getContent() ??? or ->_children[]
16  *   all_external_attr_names() <=> 
17  *
18  * Problems:
19  * The HtmlParser object set by xml_parse() doesn't keep its parameters, 
20  * esp. $this->root is lost. So we have to this into a global.
21  */
22
23 /*
24  This file is part of PhpWiki.
25
26  PhpWiki is free software; you can redistribute it and/or modify
27  it under the terms of the GNU General Public License as published by
28  the Free Software Foundation; either version 2 of the License, or
29  (at your option) any later version.
30
31  PhpWiki is distributed in the hope that it will be useful,
32  but WITHOUT ANY WARRANTY; without even the implied warranty of
33  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
34  GNU General Public License for more details.
35
36  You should have received a copy of the GNU General Public License
37  along with PhpWiki; if not, write to the Free Software
38  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
39  */
40
41 /**
42  * class XmlParser - Parse into a tree of XmlElement nodes.
43  * 
44  * PHP Problems:
45  *   inside the handlers no globals are transported, only class vars.
46  *   when leaving the handler class all class vars are destroyed, so we 
47  *   have to copy the root to a global.
48  *
49  */
50 class XmlParser {
51
52     var $_parser, $root, $current, $previous, $parent;
53
54     function XmlParser($encoding = '') { //  "ISO-8859-1"
55         if ($encoding)
56             $this->_parser = xml_parser_create($encoding);
57         else
58             $this->_parser = xml_parser_create(); 
59
60         if (isset($GLOBALS['charset']))
61             xml_parser_set_option($this->_parser, XML_OPTION_TARGET_ENCODING, $GLOBALS['charset']);
62
63         xml_set_element_handler($this->_parser,
64                                 array(&$this, 'tag_open'),
65                                 array(&$this, 'tag_close' ));
66         xml_set_character_data_handler($this->_parser,
67                                        array(&$this, 'cdata'));
68         //xml_set_element_handler($this->_parser, "tag_open", "tag_close");
69         //xml_set_character_data_handler($this->_parser, "cdata");
70
71         // Hack: workaround php OO bug
72         unset($GLOBALS['xml_parser_root']);
73     }
74
75     function __destruct() {
76         global $xml_parser_root, $xml_parser_current;
77
78         if (!empty($this->_parser)) xml_parser_free($this->_parser);
79         unset($this->_parser);
80         
81         if (isset($xml_parser_root)) {
82             $xml_parser_root->_destruct();
83             unset($xml_parser_root); // nested parsing forbidden!
84         }
85         unset($xml_parser_current);
86     }
87
88     function tag_open($parser, $name, $attrs='') {
89         $this->_tag = strtolower($name);
90         $node = new XmlElement($this->_tag);
91         if (is_string($attrs) and !empty($attrs)) {
92             // lowercase attr names
93             foreach(split(' ',$attrs) as $pair) {
94                 if (strstr($pair,"=")) {
95                     list($key,$val) = split('=',$pair);
96                     $key = strtolower(trim($key));
97                     $val = str_replace(array('"',"'"),'',trim($val));
98                     $node->_attr[$key] = $val;
99                 } else {
100                     $key = str_replace(array('"',"'"),'',strtolower(trim($pair)));
101                     $node->_attr[$key] = $key;
102                 }
103             }
104         } elseif (!empty($attrs) and is_array($attrs)) {
105             foreach ($attrs as $key => $val) {  
106                 $key = strtolower(trim($key));
107                 $val = str_replace(array('"',"'"),'',trim($val));
108                 $node->_attr[$key] = $val;
109             }
110         }
111         if (!is_null($this->current)) {
112             $this->current->_content[] =& $node;    // copy or ref?
113             $node->previous =& $this->current;      // ref to parallel prev
114         }
115         $this->current =& $node;                        // ref 
116         if (empty($this->root)) {
117             $this->root =& $node;                       // ref for === test below
118             $GLOBALS['xml_parser_root'] =& $this->root;  // copy
119         }
120     }
121
122     function tag_close($parser, $name, $attrs='') {
123         $this->current->parent = $this->current;    // copy!
124         $this->current =& $this->current->parent;   // ref!
125         //unset($this->current);
126     }
127
128     function cdata($parser, $data) {
129         if (isset($this->current)) {
130             $this->current->_content[] = $data;
131         } else {
132             trigger_error(sprintf("unparsed content outside tags: %s",$data), E_USER_WARNING);
133         }
134         if ($this->current === $this->root) {   // workaround php OO bug: ref => copy
135             $GLOBALS['xml_parser_root'] =& $this->root; // copy!
136             //$this->root = $this->current;       // copy?
137         }
138     }
139
140     function parse($content, $is_final = true) {
141         xml_parse($this->_parser, $content, $is_final) or 
142             trigger_error(sprintf("XML error: %s at line %d", 
143                                   xml_error_string(xml_get_error_code($this->_parser)), 
144                                   xml_get_current_line_number($this->_parser)),
145                           E_USER_WARNING);
146     }
147
148     function parse_url($file, $debug=false)   {
149         if (get_cfg_var('allow_url_fopen')) {
150             if (!($fp = fopen("$file","r"))) {
151                 trigger_error("Error parse url $file");
152                 return;
153             }
154             $content = "";
155             while ($data = fread($fp, 4096))  {
156                 $content .= $data;
157             }
158             fclose($fp);
159             $this->parse($content);
160         } else {
161             // other url_fopen workarounds: curl, socket (http 80 only)
162             $data = url_get_contents($file);
163             if (empty($data)) {
164                 trigger_error("Error parse url $file");
165                 return;
166             }
167             $this->parse($data);
168         }
169     }
170 }
171
172 // For emacs users
173 // Local Variables:
174 // mode: php
175 // tab-width: 8
176 // c-basic-offset: 4
177 // c-hanging-comment-ender-p: nil
178 // indent-tabs-mode: nil
179 // End:
180 ?>