ead8bbc78eb504a7e6f59b0cce8d486d1c9b6fbe
[pear] / XML / Tree / Morph.php
1 <?php
2 /* vim: set expandtab tabstop=4 shiftwidth=4: */
3 // +----------------------------------------------------------------------+
4 // | PHP Version 4                                                        |
5 // +----------------------------------------------------------------------+
6 // | Copyright (c) 1997-2002 The PHP Group                                |
7 // +----------------------------------------------------------------------+
8 // | This source file is subject to version 2.02 of the PHP license,      |
9 // | that is bundled with this package in the file LICENSE, and is        |
10 // | available at through the world-wide-web at                           |
11 // | http://www.php.net/license/2_02.txt.                                 |
12 // | If you did not receive a copy of the PHP license and are unable to   |
13 // | obtain it through the world-wide-web, please send a note to          |
14 // | license@php.net so we can mail you a copy immediately.               |
15 // +----------------------------------------------------------------------+
16 // | Authors:  Alan Knowles <alan@akbkhome.com>                           |
17 // +----------------------------------------------------------------------+
18 //
19 // $Id: php_pear_headers,v 1.1 2002/04/22 09:51:27 alan_k Exp $
20 //
21 // This is a wrapper class for XML_Tree to lets you add callbacks to xml tags
22 // to enable data morphing (so you can get associative arrays and the like from 
23 // Trees.
24 // 
25 //
26
27 require_once 'XML/Tree.php';
28
29 /**
30 * The Morpher..
31 *
32 * Usage:
33 *
34 *
35 *
36 *
37 * require_once 'XML/Tree/Morph.php';
38 *
39 *
40 * $x = new XML_Tree_Morph(
41 *    'somefile.glade',
42 *    array(
43 *       'debug' => 0,
44 *       'filter' => array(
45 *            //tag      // either toObject/toArray or your function/method etc.
46 *           'project' => 'toObject',
47 *           'widget'  => 'toObject',
48 *           'child'   => 'toObject',
49 *
50 *         )
51 *     )
52 * );
53 * $tree = $x->getTreeFromFile();
54 * print_r($tree->children[0]['project']);
55 * print_r($tree->children[1]['widget']);
56
57 * Results in...
58 *
59 *stdClass Object
60 *(
61 *    [name] => validatemanager
62 *    [program_name] => validatemanage 
63 *    [directory] =>
64 *    [source_directory] => src
65 *    [pixmaps_directory] => pixmaps
66 *    [language] => C
67 *    [gnome_support] => False
68 *    [gettext_support] => False
69 *)
70 *stdClass Object
71 *(
72 *    [class] => GtkWindow
73 *    [name] => window
74 *    [title] => Gtk_ValidateManager
75 *    [type] => GTK_WINDOW_TOPLEVEL
76 *    [position] => GTK_WIN_POS_CENTER
77 *    [modal] => False
78 *    [default_width] => 600
79 *    [default_height] => 400
80 *    [allow_shrink] => False
81 *    [allow_grow] => True
82 *    [auto_shrink] => False
83 *    [widget] => stdClass Object
84 *        ( ......
85 *
86 *
87 * @version    $Id: php_phpdoc_class,v 1.1 2002/04/22 10:20:29 alan_k Exp $
88 */
89 class XML_Tree_Morph extends XML_Tree {
90
91     var $cdata;
92     var $_morphOptions;
93
94     /**
95     * Constructor
96     *
97     * 
98     * 
99     * 
100     * @param   string               Filename
101     * @param   array $options
102     *                   valid options:
103     *               debug = 0/1
104     *               filter => array(
105     *                   tagname => callback
106     *   
107     *           where callback can be
108     *               - toObject|toArary = built in converters
109     *               - 'function', array($object,'method') or
110     *                 array('class','staticMethod');
111     * 
112     *
113     * @access   public
114     */
115   
116     function __construct($filename,$options) {
117        
118         parent::__construct($filename,'1.0');
119         
120         $this->_morphOptions = $options;
121     }
122     
123
124     /**
125     * Overridden endHandler which relays into callbacks..
126     *
127     * @see      XML_Tree:endHandler();
128     */
129       
130   
131     
132     function endHandler($xp, $elem)  {
133         $this->i--;
134         if ($this->i > 1) {
135             $obj_id = 'obj' . $this->i;
136             // recover the node created in StartHandler
137             $node   =  $this->$obj_id;
138             // mixed contents
139             if (count($node->children) > 0) {
140                 if (trim($this->cdata)) {
141                     $node->children[] =  new XML_Tree_Node(null, $this->cdata);
142                 }
143             } else {
144                 $node->setContent($this->cdata);
145             }
146             $parent_id = 'obj' . ($this->i - 1);
147             $parent    = $this->$parent_id;
148             // attach the node to its parent node children array
149             
150             if (isset($this->_morphOptions['filter'][$node->name])) {
151                 $f = &$this->_morphOptions['filter'][$node->name];
152                 if (is_string($f) && method_exists($this,'morph'.$f)) {
153                     $parent->children[] = $this->{'morph'.$this->_morphOptions['filter'][$node->name]}($node);
154                     $this->cdata = null;
155                     return null;
156                 }
157                 if (is_callable($f)) {
158                     $parent->children[] = call_user_func($f, $node);
159                     $this->cdata = null;
160                     return null;
161                 }
162                  
163                 
164                 
165             }
166             if (@$this->_morphOptions['debug']) {
167                 echo "SKIP: {$node->name}\n";\r
168             }
169             
170             $parent->children[] = $node;
171         }
172         $this->cdata = null;
173         return null;
174         
175          
176     }
177     
178     /**
179     * morph to an array
180     *
181     * Converts standard <xxx>vvvv</xxxx> into
182     *   [xxxx] => vvvvv
183     * 
184     * 
185     * @param   object XML_Tree_Node
186     * 
187     *
188     * @return   array (name => array(keys=>values)
189     * @access   public
190     */
191     function morphToArray($node) {
192         $ret = array();
193         foreach($node->children as $cnode)  {
194             // is cnode a node?
195             if (is_a($cnode,'xml_tree_node')) {
196                 $ret[$cnode->name] = $cnode->content;
197                 continue;
198             }
199             // otherwise it's an array...
200              
201             
202             foreach($cnode as $k=>$o) {
203                 if (empty($ret[$k])) {
204                     $ret[$k]= array();
205                 }
206                 if (!is_array($ret[$k])) {
207                     echo "OPPS: $k already in array ";print_r($ret);
208                     echo "TRYING TO ADD "; print_r($cnode);
209                     exit;
210                 }
211                 $ret[$k][] = $o;
212             }
213             
214         }
215         foreach($ret as $k=>$v) {
216             if (is_array($v) && count($v) == 1 ) {
217                 $ret[$k] = $v[0];
218             }
219         }
220         
221         //print_r($ret);
222         return array($node->name => $ret);
223     }
224       /**
225     * morph to an object
226     *
227     * Converts standard <xxx>vvvv</xxxx> into
228     *   $obj->xxx = vvvvv
229     * 
230     * 
231     * @param   object XML_Tree_Node
232     * 
233     *
234     * @return   array   ($node->name => $object);
235     * @access   public
236     */
237     function morphToObject($node) {
238         $ret = new StdClass;
239         foreach($node->children as $cnode)  {
240             // is cnode a node?
241             if (is_a($cnode,'xml_tree_node')) {
242                 $ret->{$cnode->name} = $cnode->content;
243                 continue;
244             }
245             // otherwise it's an array...
246              
247             
248             foreach($cnode as $k=>$o) {
249                 if (empty($ret->{$k})) {
250                     $ret->{$k}= array();
251                 }
252                 if (!is_array($ret->{$k})) {
253                     echo "OPPS: $k already in array ";print_r($ret);
254                     echo "TRYING TO ADD "; print_r($cnode);
255                     exit;
256                 }
257                 $ret->{$k}[] = $o;
258             }
259             
260         }
261         foreach($ret as $k=>$v) {
262             if (is_array($v) && count($v) == 1 ) {
263                 $ret->{$k} = $v[0];
264             }
265         }
266         
267         //print_r($ret);
268         return array($node->name => $ret);
269     }
270 }
271