]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/XmlParser.php
updated RssParser for XmlParser quirks (store parser object params in globals)
[SourceForge/phpwiki.git] / lib / XmlParser.php
1 <?php // -*-php-*-
2 rcs_id('$Id: XmlParser.php,v 1.4 2004-06-08 21:03:20 rurban Exp $');
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;
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         xml_parser_set_option($this->_parser, XML_OPTION_TARGET_ENCODING, $GLOBALS['charset']);
60         //xml_set_object($this->_parser, &$this);
61         xml_set_element_handler($this->_parser,
62                                 array(&$this, 'tag_open'),
63                                 array(&$this, 'tag_close' ));
64         xml_set_character_data_handler($this->_parser,
65                                        array(&$this, 'cdata'));
66         //xml_set_element_handler($this->_parser, "tag_open", "tag_close");
67         //xml_set_character_data_handler($this->_parser, "cdata");
68
69         // Hack: workaround php OO bug
70         unset($GLOBALS['xml_parser_root']);
71     }
72
73     function __destruct() {
74         global $xml_parser_root, $xml_parser_current;
75
76         if (!empty($this->_parser)) xml_parser_free($this->_parser);
77         unset($this->_parser);
78         
79         if (isset($xml_parser_root)) {
80             $xml_parser_root->__destruct();
81             unset($xml_parser_root); // nested parsing forbidden!
82         }
83         unset($xml_parser_current);
84     }
85
86     function tag_open($parser, $name, $attrs='') {
87         $this->_tag = strtolower($name);
88         $node = new XmlElement($this->_tag);
89         if (is_string($attrs) and !empty($attrs)) {
90             // lowercase attr names
91             foreach(split(' ',$attrs) as $pair) {
92                 if (strstr($pair,"=")) {
93                     list($key,$val) = split('=',$pair);
94                     $key = strtolower(trim($key));
95                     $val = str_replace(array('"',"'"),'',trim($val));
96                     $node->_attr[$key] = $val;
97                 } else {
98                     $key = str_replace(array('"',"'"),'',strtolower(trim($pair)));
99                     $node->_attr[$key] = $key;
100                 }
101             }
102         } elseif (!empty($attrs) and is_array($attrs)) {
103             foreach ($attrs as $key => $val) {  
104                 $key = strtolower(trim($key));
105                 $val = str_replace(array('"',"'"),'',trim($val));
106                 $node->_attr[$key] = $val;
107             }
108         }
109         if (!is_null($this->current)) {
110             $this->current->_content[] =& $node;    // copy or ref?
111             $node->parent =& $this->current;       // ref
112         }
113         $this->current =& $node;                        // ref 
114         if (empty($this->root)) {
115             $this->root =& $node;                       // ref for === test below
116             $GLOBALS['xml_parser_root'] =& $this->root;  // copy
117         }
118     }
119
120     function tag_close($parser, $name, $attrs='') {
121         //$this->parent = $this->current;   // copy!
122         //unset($this->current);
123     }
124
125     function cdata($parser, $data) {
126         if (isset($this->current)) {
127             $this->current->_content[] = $data;
128         } else {
129             trigger_error(sprintf("unparsed content outside tags: %s",$data), E_USER_WARNING);
130         }
131         if ($this->current === $this->root) {   // workaround php OO bug: ref => copy
132             $GLOBALS['xml_parser_root'] =& $this->root; // copy!
133             //$this->root = $this->current;       // copy?
134         }
135     }
136
137     function parse($content, $is_final = true) {
138         xml_parse($this->_parser, $content, $is_final) or 
139             trigger_error(sprintf("XML error: %s at line %d", 
140                                   xml_error_string(xml_get_error_code($this->_parser)), 
141                                   xml_get_current_line_number($this->_parser)),
142                           E_USER_WARNING);
143     }
144
145     function parse_url($file, $debug=false)   {
146         if (get_cfg_var('allow_url_fopen')) {
147             $fp = fopen("$file","r") or die("Error reading XML file, $file");
148             while ($data = fread($fp, 4096))  {
149                 $this->parse($data, feof($fp));
150             }
151             fclose($fp);
152         } else {
153             // other url_fopen workarounds: curl, socket (http 80 only)
154             $data = url_get_contents($file);
155             if (empty($data)) return;
156             $this->parse($data);
157         }
158     }
159 }
160
161 // $Log: not supported by cvs2svn $
162 // Revision 1.3  2004/06/03 18:06:29  rurban
163 // fix file locking issues (only needed on write)
164 // fixed immediate LANG and THEME in-session updates if not stored in prefs
165 // advanced editpage toolbars (search & replace broken)
166 //
167 // Revision 1.2  2004/06/01 15:28:00  rurban
168 // AdminUser only ADMIN_USER not member of Administrators
169 // some RateIt improvements by dfrankow
170 // edit_toolbar buttons
171 //
172 // Revision 1.1  2004/05/24 17:31:31  rurban
173 // new XmlParser and HtmlParser, RssParser based on that.
174 //
175 //
176 // 2004-04-09 16:30:50 rurban: 
177 //  added fsockopen allow_url_fopen = Off workaround
178
179 // For emacs users
180 // Local Variables:
181 // mode: php
182 // tab-width: 8
183 // c-basic-offset: 4
184 // c-hanging-comment-ender-p: nil
185 // indent-tabs-mode: nil
186 // End:
187 ?>