OSDN Git Service

Creación y administración de documentos basados en DOM mediante PHP
[dombasic/DOMbasic.git] / DOM_element.php
1 <?php
2 //PUNTO DE ENTRADA DE TODOS LOS ELEMENTOS DEL DOM CREADOS:
3 //CONSTANTES A TRAVES DE INI [solo deben conocerse ruta al ini y nombre de la seccion del ini para las constantes]
4 $config = parse_ini_file('config.ini'); //RUTA AL ARCHIVO INI DE CONFIGURACION
5 $seccConsts = $config['_SECC_CONSTS_INI_DOM'];  //SECCION DEL INI DONDE SE ENCUENTRAN LAS CONSTANTES
6 //echo '<div style="background:green;">'.$seccConsts.'</div>';
7 $config = parse_ini_file('config.ini', true);   //AHORA POR SECCIONES
8 //ESTABLECIENDO LAS CONSTANTES DEL PAKETE
9 foreach($config as $key => $value) {
10         if($key==$seccConsts){
11                 foreach($value as $k => $v) {
12                         //echo "[".$seccConsts."] ".$k." = ".$v."<br />";
13                         if(! defined($k)) define($k, $v);
14                 }
15         }
16 }
17 if(! defined('QUOTE')) define('QUOTE', '"');    //Permite utilizar " en el archivo ini mediante QUOTE
18 if(! defined("_PATH_CLASS_DOM_")) define("_PATH_CLASS_DOM_", realpath( dirname(__FILE__) ));//"."
19 /*
20 //TODO: BORRAR: LAS SIGUIENTES DEFINICIONES SE MANTIENEN POR COMODIDAD EN EL DESARROLLO CON ECLIPSE
21 if(! defined("_PATH_EXCEPTION_DOM_")) define("_PATH_EXCEPTION_DOM_", "/exceptions");
22 if(! defined("_PATH_UTIL_DOM_")) define("_PATH_UTIL_DOM_", "/util");
23 if(! defined("_CONF_INI_FILE_DOM_")) define("_CONF_INI_FILE_DOM_", "config.ini");
24 if(! defined("_SECC_CONF_INI_DOM")) define("_SECC_CONF_INI_DOM", "[CONF_SECC]");
25 if(! defined('QUOTE')) define('QUOTE', '"');    //Permite utilizar " en el archivo ini mediante QUOTE
26 */
27
28         //define("TAG", "LinkClass");
29 // we've writen this code where we need
30 function __autoload($classname) {
31         $ruta=_PATH_CLASS_DOM_;
32         if(substr($classname, -9)=="Exception") $ruta .= _PATH_EXCEPTION_DOM_;
33         //if(substr($classname, -9)=="Configuration") $ruta .= "/conf";
34         if(substr($classname, 3)=="INI") $ruta .= _PATH_UTIL_DOM_;
35         $filename = $ruta."/". $classname .".php";
36         try{
37                 include_once($filename);
38                 //parent::__autoload($classname);
39         } catch (Exception $e){
40                 throw new Exception("Imposible cargar $classname desde el directorio $ruta. ERROR: ".$e->getMessage().PHP_EOL);
41         }
42 }
43         /**
44          * Clase padre para crear cualquier elemento del DOM. Admite CONCATENACION DE METODOS mediante el retorno de la construccion '$this'
45          * en todos los metodos 'NO-GETTER': &hellip; <code>$this->setText('text')->removeChild($child)->importConfINI();</code> &hellip;
46          **/
47         class DOM_element extends DOM_attribs implements DOM_Interface {
48                 /**
49                  * <h1>Name Class</h1>
50                  * Constante de cadena que representa el nombre de esta Clase, util para labores de Depuracion 
51                  * (agregandola a las sentencias del log o de trade...)
52                  * @var String constant
53                  * @access public
54                  */
55                 const N_C = __CLASS__;
56                 
57                 //------------  BEGIN: CONFIGURACION  -----------------
58                 /**
59                  * ¿ Permitir el patron SINGLETON ?
60                  **/
61                 const PATRON_SINGLETON=true;
62                 /**
63                  * <h1>Boolean indicando si los atributos de este elemento son DE SOLO LECTURA O ESCRIBIBLES.</h1>
64                  * @var String
65                  * @access protected
66                  */
67                 protected $_READ_ONLY=false;//=boolean;
68
69                 /**
70                  * Variable de cadena indicando la etiqueta DOM (HTML) de este elemento
71                  * @var String
72                  * @access protected
73                  */
74                 protected $TAG = "";
75                 /**
76                  * Variable de cadena indicando el tipo DOM de este elemento
77                  * @var String
78                  * @access protected
79                  */
80                 protected $TYPE = "container";
81                 /**
82                  * Variable de cadena indicando la descripcion de este elemento
83                  * @var String
84                  * @access protected
85                  */
86                 protected $DESC = "DOM's container element";
87                 //CONSTANTES QUE REPRESENTAN LAS APERTURA Y CIERRE DE ETIQUETAS DE LOS ELEMENTOS DOM.
88                 //Algunos elementos autocontendidos (como '<img />') pueden modificarlas, o incluso anularlas (como 'textNode')
89                 /**
90                  * Variable de cadena indicando la apertura de la etiqueta HTML de este elemento
91                  * <p style="background:yellow; color: navy">Algunos elementos autocontendidos (como '&lt;img />')
92                  * pueden modificarlas, o incluso anularlas (como 'textNode')</p>
93                  * @var String
94                  * @access protected
95                  */
96                 protected $OPEN_TAG_LEFT="<";
97                 /**
98                  * Variable de cadena indicando el cierre de la etiqueta HTML de apertura de este elemento
99                  * <p style="background:yellow; color: navy">Algunos elementos autocontendidos (como '&lt;img />')
100                  * pueden modificarlas, o incluso anularlas (como 'textNode')</p>
101                  * @var String
102                  * @access protected
103                  */
104                 protected $OPEN_TAG_RIGHT=">";
105                 /**
106                  * Variable de cadena indicando la apertura de la etiqueta HTML de cierre de este elemento
107                  * <p style="background:yellow; color: navy">Algunos elementos autocontendidos (como '&lt;img />')
108                  * pueden modificarlas, o incluso anularlas (como 'textNode')</p>
109                  * @var String
110                  * @access protected
111                  */
112                 protected $CLOSE_TAG_LEFT="</";
113                 /**
114                  * Variable de cadena indicando el cierre de la etiqueta HTML de este elemento
115                  * <p style="background:yellow; color: navy">Algunos elementos autocontendidos (como '&lt;img />')
116                  * pueden modificarlas, o incluso anularlas (como 'textNode')</p>
117                  * @var String
118                  * @access protected
119                  */
120                 protected $CLOSE_TAG_RIGHT=">";
121
122                 //---- BEGIN: AVISOS ------
123                 /**
124                  * ¿ Lanzar Aviso cuando se intenta tomar una instancia estatica mediante el 'Patron SINGLETON' sin estar permitida por
125                  * '<a href="DOM_attribs::PATRON_SINGLETON" title="PATRON_SINGLETON">'PATRON SINGLETON'</a> ?
126                  **/
127                 const AVISO_SINGLETON=true;
128                 /**
129                  * ¿ Lanzar Aviso cuando se lee un atributo que no existe ?
130                  **/
131                 protected $AVISO_GET=false;
132                 //---- END: AVISOS ------
133                 
134
135                 /*
136                 protected static final $DTD_DOCTYPE_HTML=0;
137                 protected static final $DTD_DOCTYPE_XHTML_TRANSITIONAL=10;
138                 protected static final $DTD_DOCTYPE_XHTML_STRICT=10;
139                 protected static final $DTD_XML_1_0=20;*/
140                 protected static $DTD_DOCTYPE_HTML=0;
141                 protected static $DTD_DOCTYPE_XHTML_TRANSITIONAL=10;
142                 protected static $DTD_DOCTYPE_XHTML_STRICT=10;
143                 protected static $DTD_XML_1_0=20;
144                 protected static $LINE_BREAK="\n";
145                 //------------ END: CONFIGURACION ------------------------
146                 
147                 /**
148                  * Clave de este elemento
149                  * @var String
150                  * @access protected
151                  */
152                 protected $_key="";
153                 /**
154                  * Texto que contiene este elemento.
155                  * @var String
156                  * @access protected
157                  */
158                 protected $_text="";
159                 /**
160                  * Array de elementos del DOM hijos de este
161                  * @var Array DOM_element
162                  * @access protected
163                  */
164                 protected $_children=array();
165
166                 //---------------------  BEGIN: PATRON SINGLETON  -------------------
167                 /**
168                  * PATRON ESTATICO SINGLETON
169                  * @var DOM_attribs
170                  * @access protected
171                  */
172                 protected static $instance;
173                 /**
174                  * PATRON SINGLETON. Tomar una instancia de forma estatica.<br />
175                  * $attrbs = DOM_attribs::getInstance();
176                  **/
177                 public static function getInstance() {
178                         if(self::PATRON_SINGLETON){
179                                         //if (!isset(self::$instance)) {
180                                         if (is_null(self::$instance)) {
181                                                 $c = __CLASS__; //self::TAG
182                                                 //$instance = new $c;
183                                                 self::$instance = new $c();
184                                         }
185                                         return self::$instance;
186                         }else{
187                                 try {
188                                         if(self::AVISO_SINGLETON) throw new DOMBasicSingletonException();
189                                 }catch (Exception $e){
190                                         self::writeLog($e->getMessage(), $e->getTrace());
191                                 }
192                         }
193                 }
194                 private function setInstance() {
195                         try{    
196                                         $this->tryingWrite("INSTANCE");
197                                         self::$instance=$this;
198                          }catch(Exception $e){
199                                         $this::writeLog($e->getMessage(), $e->getTrace());
200                          }
201                 }
202                 //----------------------  END: PATRON SINGLETON  --------------------
203
204                 //----------------------  BEGIN: MAGICS METHODS  --------------------
205                         //CONSTRUCTOR
206                 public function __construct($key=null){
207                         if($key != null) $this->_key=$key;
208                         $this->importConfINI();
209                         $this->reinicializar();
210                         $this::$instance=$this;
211                         //return $this;
212                 }
213                         //DESTRUCTOR
214                 public function __destruct(){
215                         parent::__destruct();
216                         //echo "<h1>DESTRUYENDO ".$this->getKey()."</h1>";
217                         $this::$instance=null;
218                         $this->_children=null;
219                 }
220                         //CLONE
221                 public function __clone(){
222                         //return self::getInstance();
223                         $clase=__CLASS__;       //self::TAG;
224                         $clon=new $clase($this->_key);
225                         $clon->setReadOnly(false);
226                         $clon->setChildren($this->_children);
227                         $clon->setAttribs($this->getAttribs());
228                         $clon->setConfiguration($this->getConfiguration());
229                         $clon->setReadOnly($this->getReadOnly());
230                         return $clon;   //DA ERRORES EN PHP 4.0
231                 }
232                         //UNSET
233                 /**
234                  * <h1>Desde PHP 5.1.0</h1>
235                  * @throws DOMBasicElementReadOnlyException If 'Read Only' ON.
236                  * @throws DOMBasicElementNotFoundException
237                  *         If $attrib is not a key in the $_attribs array.
238                  * @param DOM_element $child The element to unset.
239                  */
240                 public function __unset($child) {
241                         //echo "Eliminando '$child'\n";
242                         try{
243                                 $this->tryingWrite($child);
244                                 if(in_array($child,$this->_children)){
245                                         $index=array_search($child, $this->_children);
246                                         unset($this->_children[$index]);
247                                 }
248                         }catch(Exception $e){
249                                 $this->writeLog($e->getMessage(), $e->getTrace());
250                         }
251                 }
252
253                 public function __toString() {
254                         //return $this->_text;
255                         return $this->getOpenTag() . $this->_text . $this->getCloseTag();
256                 }
257                 
258                 /*
259                  public static function __set_state($an_array) // A partir de PHP 5.1.0
260                 {
261                 $obj = new self($an_array['_key']);
262                 $obj->setReadOnly($an_array['_READ_ONLY']);
263                 $obj->setTag($an_array['TAG']+"_22");
264                 $obj->TYPE = $an_array['TYPE'];
265                 $obj->DESC = $an_array['DESC'];
266                 $obj->OPEN_TAG_LEFT = $an_array['OPEN_TAG_LEFT'];
267                 $obj->OPEN_TAG_RIGHT = $an_array['OPEN_TAG_RIGHT'];
268                 $obj->CLOSE_TAG_LEFT = $an_array['CLOSE_TAG_LEFT'];
269                 $obj->CLOSE_TAG_RIGHT = $an_array['CLOSE_TAG_RIGHT'];
270                 $obj->AVISO_GET = $an_array['AVISO_GET'];
271                 //$obj->_key = $an_array['_key'];
272                 $obj->setText( $an_array['_text'] );
273                 $obj->_children = $an_array['_children'];
274                 
275                 return $obj;
276                 }
277                 */
278                 //-----------------  END: MAGICS METHODS  -----------------------------
279                 
280                 //-----------------  BEGIN: ABSTRACT METHODS IN PARENT  ----------------
281                 public function reinicializar(){
282                         //$this->_attribs=array();
283                         try{
284                                 $this->tryingWrite("[".$this->_key."]".$this->TAG);
285                                 $this->_children=array();
286                         }catch(Exception $e){
287                                 $this->writeLog($e->getMessage(), $e->getTrace());
288                         }
289                         //TODO: ¡¡OJO NO ACTIVAR!! PUEDE PROVOCAR UNA EXCEPCION AL SER LLAMADA DESDE UN CONSTRUCTOR.
290                         //register_shutdown_function(array($this, '__destruct'));       //para evitar un bug en PHP 5.3.10 con la destruccion de objetos
291                         return $this;
292                 }
293                 //ABSTRACT METHOD IN PARENT
294                 public function setReadOnly($readOnly){
295                         $this->_READ_ONLY=$readOnly;
296                         return $this;
297                 }
298                 public function getReadOnly(){
299                         return $this->_READ_ONLY;
300                         return $this;
301                 }
302                                                 //------------ OVERRIDE  -------------
303                 /**
304                  * <p><b>:OVERRIDE-PARENT:</b></p>
305                  * <p>Notifica una accion de escritura al objeto; Si es de solo-lectura lanzara una Excepcion.</p>
306                  * @return boolean TRUE=OK, FALSE=throw DOMBasicElementReadOnlyException()
307                  * @throws DOMBasicElementReadOnlyException;
308                  **/
309                 protected function tryingWrite($arg="") {
310                         //parent::tryingWrite($arg);
311                         if($this->_READ_ONLY){
312                                 //$mensaje="Intentando escribir en un Objeto de Solo-Lectura!!";
313                                 throw new DOMBasicElementReadOnlyException($arg, DOMBasicElementReadOnlyException::READ);
314                                 return false;
315                         }
316                         return true;
317                 }
318                 //-----------------  END: ABSTRACT METHODS IN PARENT  ----------------
319                 
320                 //-----------------  BEGIN: GETTER & SETTER  -------------------------
321                 public function setKey(string $key=null){
322                         try{
323                                 $this->tryingWrite("[".$this->_key."]".$this->TAG);
324                                 if(! is_null($key))$this->_key=$key;
325                         }catch(Exception $e){
326                                 $this->writeLog($e->getMessage(), $e->getTrace());
327                         }
328                         return $this;
329                 }
330                 public function getKey(){
331                         return $this->_key;
332                 }
333                 public function getTag(){
334                         return $this->TAG;
335                 }
336                 public function setTag($tag){
337                         $this->TAG=$tag;
338                         return $this;
339                 }
340                 public function getOpenTag(){
341                         return ($this->OPEN_TAG_LEFT . $this->TAG . parent::getAttribsStr() . $this->OPEN_TAG_RIGHT);
342                 }
343                 public function getCloseTag(){
344                         if(strlen( $this->CLOSE_TAG_LEFT . $this->CLOSE_TAG_RIGHT ) == 0){
345                                 return "";
346                         }else{
347                                 return ($this->CLOSE_TAG_LEFT . $this->TAG . $this->CLOSE_TAG_RIGHT);
348                         }
349                 }
350                 public function getType(){
351                         return $this->TYPE;
352                 }
353                 public function getDesc(){
354                         return $this->DESC;
355                 }
356                 //--------------------  END: GETTER & SETTER  -------------
357                 
358                 //--------------------  BEGIN: TEXT  ----------------------
359                 public function clearText(){
360                         //$textoAnterior="";
361                         try{
362                                 $this->tryingWrite("[".$this->_key."]".$this->TAG);
363                                 $textoAnterior=$this->getText();
364                                 $objTxt=new DOM_textNode();
365                                 $this->removeChildrenByType($objTxt->getType(), false);
366                         }catch(Exception $e){
367                                 $this->writeLog($e->getMessage(), $e->getTrace());
368                         }
369                         //return $textoAnterior;
370                         return $this;
371                 }
372                 
373                 /**
374                  * Agreaga un hijo de texto (textNode) a este elemento DOM, eliminando los hijos tipo 'textNode' que tubiese
375                  * @param string $text para este elemento.
376                  * @return string con el texto anterior.
377                  **/
378                 public function setText($text){
379                         //$textoAnterior=$this->getText();
380                         try{
381                                 //$this->tryingWrite("[".$this->_key."]".$this->TAG);
382                                 $this->clearText();
383                                 //$this->_text=$text;
384                                 $txt=new DOM_textNode();
385                                 $txt->setText($text);
386                                 $this->addChild($txt);
387                         }catch(Exception $e){
388                                 $this->writeLog($e->getMessage(), $e->getTrace());
389                         }
390                         //return $textoAnterior;
391                         return $this;
392                 }
393                 
394                 public function addText($text){
395                         try{
396                                 $this->tryingWrite("[".$this->_key."]".$this->TAG);
397                                 $txt=new DOM_textNode();
398                                 $txt->setText($text);
399                                 $this->addChild($txt);
400                         }catch(Exception $e){
401                                 $this->writeLog($e->getMessage(), $e->getTrace());
402                         }
403                         return $this;
404                 }
405                 
406                 /** Retorna todo el texto encontrado en este elemento y en sus hijos. 
407                  * @param $filter [boolean] Permite especificar si el texto se retorna filtrado mediante 'htmlspecialchars_decode(...)' y 
408                  * 'stripcslashes(...)' o no. [Por defecto NO] 
409                  * @return string con el texto de todos los nodos tipo 'textNode' de este elemento y sus hijos. 
410                  **/
411                 public function getTextAll($filter=false){
412                         $texto = $filter ? htmlspecialchars_decode(stripslashes( $this->_text )) : $this->_text;
413                         if( is_null($this->getChildren()) )     return $texto;
414                         foreach ($this->getChildren() as $child){
415                                         if( is_null($child) ) continue;
416                                         $texto .= $filter ? htmlspecialchars_decode(stripslashes( $child->getText($filter) )) : $this->getText($filter);
417                         }
418                         return $texto;
419                 }
420                 /**
421                  * Metodo para retornar el texto de este elemento DOM (la concatenacion de los textos de todos los elementos textNode).
422                  * @param $filter [boolean] Permite especificar si el texto se retorna filtrado mediante 'htmlspecialchars_decode(...)' y 
423                  * 'stripcslashes(...)' o no. [Por defecto NO]
424                  * @return string con el texto de todos los nodos tipo 'textNode' de este elemento.
425                  **/
426                 public function getText($filter=false){
427                         $texto = $filter ? htmlspecialchars_decode(stripslashes( $this->_text )) : $this->_text;
428                         if( is_null($this->getChildren()) )     return $texto;
429                         foreach ($this->getChildren() as $child){
430                                 //echo "<div>".$child->TYPE."</div>";
431                                         if( is_null($child) || ($child->TYPE != "textNode") ) continue;
432                                         //$texto =" :: " . $child->TYPE ." :: ";
433                                         $texto .= $filter ? htmlspecialchars_decode(stripslashes( $child->_text )) : $this->_text;
434                                         //htmlspecialchars_decode(stripslashes( $child->getText($grandchildren) ));
435                         }
436                         return $texto;
437                 }
438                 //-----------------  END: TEXT  -----------------------
439                 
440                 //----------------- BEGIN: CHILDREN HANDLER  ----------
441                 public function addChild(DOM_element $child=null){
442                         try{
443                                 $this->tryingWrite("[".$this->_key."]".$this->TAG);
444                                 if(! is_null($child)){
445                                         $this->_children[]=$child;
446                                 }
447                         }catch(Exception $e){
448                                 $this->writeLog($e->getMessage(), $e->getTrace());
449                         }
450                         //return count($this->_children);
451                         return $this;
452                 }
453                 
454                 public function addChildren(array $children=null){
455                         try{
456                                 $this->tryingWrite("[".$this->_key."]".$this->TAG);
457                                 if( is_null($this->_children) ) $this->_children=array();
458                                 if(is_array($children)){
459                                         foreach ($children as $child){
460                                                 $this->_children[]=$child;
461                                         }
462                                 }
463                         }catch(Exception $e){
464                                 $this->writeLog($e->getMessage(), $e->getTrace());
465                         }
466                         //return count($this->_children);
467                         return $this;
468                 }
469                 
470                 public function setChildren(array $children=null){
471                         try{
472                                 $this->tryingWrite("[".$this->_key."]".$this->TAG);
473                                 $this->_children=$children;
474                         }catch(Exception $e){
475                                 $this->writeLog($e->getMessage(), $e->getTrace());
476                         }
477                         return $this;
478                 }
479                 
480                                 //CHILD's GETTER
481                 public function getChildren(){
482                         return $this->_children;
483                 }
484                 
485                 public function getChildrenAll(){
486                         $children = array();
487                         foreach ($this->getChildren() as $child){
488                                 $children[]=$child;
489                                 if( count($child->getChildren())>0 ) $children[]=$child->getChildrenAll();
490                         }
491                         return $children;
492                 }
493                 
494                 public function getChildByKey($key, $grandchildren=true){
495                         if( is_null($this->getChildren()) ) return null;
496                         foreach ($this->getChildren() as $child){
497                                 if($child->getKey()==$key) return $child;
498                                 if($grandchildren){
499                                         $childOfChild = $child->getChildByKey($key);
500                                         if( ! is_null($childOfChild) ) return $childOfChild;
501                                 }
502                         }
503                         return null;
504                 }
505                 
506                 public function getChildrenByTag($tag, $grandchildren=true){
507                         $children = array();
508                         foreach ($this->getChildren() as $child){
509                                 if($child->getTag()==$tag) $children[]= $child;
510                                 if($grandchildren){
511                                         $childrenOfChild = $child->getChildrenByTag($tag);
512                                         if( ! is_null($childrenOfChild) ) {
513                                                 foreach ($childrenOfChild as $c){
514                                                         //echo "ENCONTRADO [".$c->getKey()."] EN [".$child->getKey()."]";
515                                                         $children[]= $c;
516                                                 }
517                                         }
518                                 }
519                         }
520                         return $children;
521                 }
522                 public function getChildrenByType($type, $grandchildren=true){
523                         $children = array();
524                         foreach ($this->getChildren() as $child){
525                                 if($child->getType()==$type) $children[]= $child;
526                                 if($grandchildren){
527                                         $childrenOfChild = $child->getChildrenByType($type);
528                                         if( ! is_null($childrenOfChild) ) {
529                                                 foreach ($childrenOfChild as $c){
530                                                         //echo "ENCONTRADO [".$c->getKey()."] EN [".$child->getKey()."]";
531                                                         $children[]= $c;
532                                                 }
533                                         }
534                                 }
535                         }
536                         return $children;
537                 }
538                         //CHILD's ERASER
539                 public function removeChild($child, $grandchildren=true){
540                         $exito=false;
541                         foreach ($this->getChildren() as $hijo){
542                                 //if($hijo->equalsExacts($child)) {
543                                 if($hijo->equals($child)) {
544                                         $exito=true;
545                                         $this->__unset($child);
546                                 }else{  //RECURSIVIDAD
547                                         if($grandchildren) $exito = $exito || $hijo->removeChild($child, $grandchildren);
548                                 }
549                         }
550                         //return $exito;
551                         return $this;
552                 }
553                 
554                 public function removeChildrenAll(){
555                         //ELIMINAR TODOS
556                         foreach ($this->getChildren() as $child){
557                                 $this->__unset($child);
558                         }
559                         return $this;
560                 }
561                 public function removeChildByKey($key, $grandchildren=true){
562                         $contador=0;
563                         foreach ($this->getChildren() as $child){
564                                 if($child->getKey()==$key){
565                                         $contador++;
566                                         $this->__unset($child);
567                                 }else{  //RECURSIVIDAD
568                                         if($grandchildren) $contador +=$child->removeChildByKey($key, $grandchildren);
569                                 }
570                         }
571                         //return $contador;
572                         return $this;
573                 }
574                 
575                 public function removeChildrenByTag($tag, $grandchildren=true){
576                         $contador=0;
577                         foreach ($this->getChildren() as $child){
578                                 if($child->getTag()==$tag){
579                                         $contador++;
580                                         $this->__unset($child);
581                                 }else{  //RECURSIVIDAD
582                                         if($grandchildren) $contador +=$child->removeChildrenByTag($tag, $grandchildren);
583                                 }
584                         }
585                         //return $contador;
586                         return $this;
587                 }
588                 
589                 public function removeChildrenByType($type, $grandchildren=true){
590                         $contador=0;
591                         foreach ($this->getChildren() as $child){
592                                 if($child->getType()==$type){
593                                         $contador++;
594                                         $this->__unset($child);
595                                 }else{  //RECURSIVIDAD
596                                         if($grandchildren) $contador +=$child->removeChildrenByType($type, $grandchildren);
597                                 }
598                         }
599                         //return $contador;
600                         return $this;
601                 }
602                 //----------------- END: CHILDREN HANDLER  ----------
603
604                 //----------------- BEGIN: COMPARATOR  --------------
605                 /** <p>Compara si otro objeto es igual (comparable no clonable) a este (no si es el mismo); para esto se tienen que cumplir las 
606                  * siguientes normas: </p>
607                  * <ul>
608                  *      <li>Que los dos sean instancias de la misma Clase (el mismo tipo de elemento y etiqueta).</li>
609                  *      <li>Que los dos tengan definidos el mismo numero de atributos y con los mismos valores.</li>
610                  *      <li>Que los dos tengan definidos el mismo numero de hijos y con los mismos valores.</li>
611                  *      <li>Tambien que los dos tengan definida la misma clave.</li>
612                  *  <li>Incluso que los dos contengan el mismo texto como contenido.</li>
613                  * </ul>
614                  * @param DOM_element $objDOM Algun objeto instancia de esta Clase
615                  * @return boolean **/
616                 public function equals($objDOM) {
617                         $equal=true;
618                         //1º COMPARACION SI NO ES NULO
619                         if(is_null($objDOM)) return false;
620                         //if(! parent::equals($objDOM->getDOM_attrib())) return false;
621                         if(is_null($objDOM->_children)) $objDOM->_children=array();
622                         if(is_null($this->_children)) $this->_children=array();
623                         //2º COMPARACION SI ES UNA INSTACIA DE ESTA CLASE
624                         if( !($objDOM instanceof $this) ) return false; //is_a(), get_class();
625                         //if(! is_subclass_of($objAttribs, self::TAG, false) ) return false;
626                         //3º COMPARACION VARIABLES
627                         //if($equal) $equal = ($this->_key == $objDOM->_key); //SE ADMITE DISTINTA
628                         if($equal) $equal = ($this->TAG == $objDOM->TAG);
629                         //if($equal) $equal = $equal && ($this->DESC == $objDOM->DESC); //SE ADMITE DISTINTA
630                         if($equal) $equal = ($this->OPEN_TAG_LEFT == $objDOM->OPEN_TAG_LEFT);
631                         if($equal) $equal = ($this->OPEN_TAG_RIGHT == $objDOM->OPEN_TAG_RIGHT);
632                         if($equal) $equal = ($this->CLOSE_TAG_LEFT == $objDOM->CLOSE_TAG_LEFT);
633                         if($equal) $equal = ($this->CLOSE_TAG_RIGHT == $objDOM->CLOSE_TAG_RIGHT);
634                         if($equal) $equal = ($this->_text == $objDOM->_text);
635                                 //echo "3º / ".($equal?"TRUE":"FALSE")."<br />";
636                         //4º COMPARACION RAPIDA. IGUAL NUMERO DE HIJOS
637                         if($equal) $equal = (count($objDOM->_children) == count($this->_children));
638                                 //echo "4º / ".($equal?"TRUE":"FALSE")."<br />";
639                         //5º COMPARACION HIJO A HIJO
640                         if($equal){
641                                 $contador=0;
642                                 foreach($objDOM->_children as $clave=>$valor) {
643                                         foreach($this->_children as $clave2=>$valor2) {
644                                                 if(($clave==$clave2) && ($valor==$valor2)) $contador++;
645                                         }
646                                 }
647                                 $equal = ( (count($this->_children) == $contador) && (count($objDOM->_children) == $contador) );
648                                 //echo "5º / ".($equal?"TRUE":"FALSE")."<br />";
649                         }
650                         //6º COMPARACION ATRIBUTO A ATRIBUTO
651                         if($equal) $equal = parent::equals($objDOM);
652                                 //echo "6º / ".($equal?"TRUE":"FALSE")."<br /> - EQUAL=-|"; print_r($equal);echo "|-<br />";
653                         return $equal;
654                 }
655                 
656                 public function equalsType($objDOM) {
657                         return ( ($objDOM instanceof $this) && ($this->TYPE == $objDOM->TYPE ) );
658                 }
659                 //----------------  END: COMPARATOR  ------------------------
660                 
661                 //----------------  BEGIN: HTML  ----------------------------
662                 public function toHTML() {
663                         $HTML = $this->getOpenTag();
664                         if($this->getCloseTag() != "") $HTML .= self::$LINE_BREAK;
665                         $HTML .= ($this->TYPE == "textNode") ?  $this->getText(true) : ""; //$this->_text;
666                         foreach($this->getChildren() as $child){
667                           $HTML .= $child->toHTML();
668                         }
669                         $HTML .= $this->getCloseTag() . self::$LINE_BREAK;
670                         //if($this->getCloseTag() == "") $HTML .= self::$LINE_BREAK;
671                         return $HTML;
672                         //return '<a '.parent::__toString().'>'.$this->_key.'</a>';
673                 }
674
675                 /**
676                  * Metodo para obtener una etiqueta de definicion DTD que especifique el tipo de documento que estamos
677                  * tratando. (HTML, XHTML, XML, ...)
678                  * @param int $dtd Un entero identificando el tipo de DTD a retornar. Puede ser una de las constantes de
679                  * esta clase que comienzan con DTD_
680                  * @return string La cadena con el DTD solicitado.
681                  **/
682                 public static function getDTD(int $dtd){
683                         //<?xml version="1.0" encoding="UTF-8"? >
684                         //<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
685                         //Copyright © 2014 W3C <sup>®</sup> (<a href="http://www.csail.mit.edu/"><acronym title="Massachusetts Institute of Technology">MIT</acronym></a>
686                         //<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
687                         //<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
688                         //HTML 2.0 :
689                                 //<!DOCTYPE html PUBLIC "-//IETF//DTD HTML 2.0//EN">
690                         //HTML 3.2 :
691                                 //<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
692                         //HTML 4.01 :
693                                 //      (STRICT)
694                                 //<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
695                                 //      (TRANSITIONAL)
696                                 //<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
697                                 //      (FRAMSET)
698                                 //<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">
699                         //XHTML 1.0 :
700                                 //      (STRICT)
701                                 //<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
702                                 //      (TRANSITIONAL)
703                                 //<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
704                                 //      (FRAMSET)
705                                 //<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
706                         //XHTML Basic 1.0 :
707                                 //<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.0//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic10.dtd">
708                         //XHTML Basic 1.1 :
709                                 //<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">
710                         //HTML 5 :
711                                 //<!DOCTYPE HTML>
712                         switch ($dtd){
713                                 case self::$DTD_DOCTYPE_HTML:
714                                         return '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">';
715                                 case self::$DTD_DOCTYPE_XHTML_TRANSITIONAL:
716                                         return '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">';
717                                 case self::$DTD_DOCTYPE_XHTML_STRICT:
718                                         return'<?xml version="1.0" encoding="iso-8859-1"?>
719                                                                  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
720                                 case self::$DTD_XML_1_0:
721                                         return '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">';
722                                 default:
723                                         ;
724                         }
725                 }
726                 //----------------  END: HTML  ------------------------------
727                 
728                 //----------------  BEGIN: JSON  ----------------------------
729                 public function toJSON($return=true, $base64values=true) {
730                         $id =$this->getKey()?('-'.$this->getKey()):'';
731                         $id .=$this->getType()?('-'.$this->getType()):'';
732                         $id .='-' . rand(5, 1000);
733                         //$result ='"'.__CLASS__ . $id .'":{';
734                         $result ='{"_base64":"'.($base64values?'true':'false').'",';
735                         $array = array ();
736                         //PROPIEDADES:
737                         foreach (get_object_vars($this) as $clave=>$valor){
738                                 if( !is_array($valor) && !is_object($valor)){
739                                         //$clave = htmlentities(htmlspecialchars(utf8_encode($clave)));
740                                         if($clave != "_text"){  //PARA TEXT YA OCURRE EL ESCAPE EN SU PROPIO METODO setText();
741                                                 $clave = addslashes( htmlspecialchars( utf8_encode($clave) ) );
742                                                 $valor = addslashes( htmlspecialchars( utf8_encode($valor) ) );
743                                         }
744                                         $clave=parent::filtrarStrJSON($clave);
745                                         $valor=parent::filtrarStrJSON($valor);
746                                         if($base64values) {
747                                                 $array[] = '"'.$clave.'":"'.base64_encode($valor).'"';
748                                         }else{
749                                                 $array[] = '"'.$clave.'":"'.$valor.'"';
750                                         }
751                                 }
752                         }
753                         $result .= implode(',', $array).',';
754                         //$result .='"_children":'.json_encode($this->_children).",";
755                         //ATTRIBS
756                         $result .= '"_attribs":'.parent::toJSON($return, $base64values).',';
757                         //CHILDREN
758                         $array=array();
759                         foreach ($this->getChildren() as $key => $value) {
760                                 if ( is_object($value) ){ //OBJETOS DOM (NO ATTRIBS NI PROPIEDADES)
761                                         $array[] = $value->toJSON($return,$base64values);
762                                 }
763                         }
764                         $result .= '"_children":['.implode(',', $array).']';
765                 
766                         $result .='}';
767                                 
768                         if ($return) {
769                                 return $result;
770                         } else {
771                                 echo "<pre>";
772                                 print $result;
773                                 echo "</pre>";
774                                 return null;
775                         }
776                 }
777
778                 public function fromJSON($json) {
779                         //DECODIFICAR LA CADENA JSON Y OBTENER EL OBJETO
780                         $result = json_decode(utf8_decode(htmlspecialchars_decode(stripslashes($json))));
781                         //DETECTAR AUTOMATICAMENTE SI HA SIDO CODIFICADO EN BASE64
782                         $base64values = key_exists("_base64", get_object_vars($result))? ($result->_base64=="true") : false;
783                         //CONVIERTO EL OBJ-JSON A OBJ-DOM_ELEMENT
784                         $object=self::objJSON2DOM_element( $result, true, $base64values );
785                         //ASIGNA Y RETORNA THIS COMO EL NUEVO OBJETO...
786                         return $this->fromDOM_element($object);
787                 }
788                 
789                 /**
790                  * <p>Metodo estatico para construir un objeto DOM a la imagen y semejanza del objeto JSON entregado que deberia representar 
791                  * otro DOM_element con hijos, atributos, y caracteristicas propias.</p>
792                  * <p>NI QUE DECIR TIENE QUE EL OBJETO JSON ENTREGADO DEBE SER UN FIEL REFLEJO DE ALGUN ELEMENTO DE ESTA CLASE, 
793                  * NORMALMENTE SE OBTENDRA DECODIFICANDO EL RETORNO DE LA FUNCION toJSON(); (json_decode(...->toJSON();))</p>
794                  * @param JSON $objectJSON Es un objeto creado con una cadena JSON.
795                  * @param boolean $return Expresa si retornar (TRUE) el objeto creado o imprimirlo (FALSE).
796                  * @param boolean $base64values Indica si codificar los textos en 'base64' o no.
797                  * @return DOM_element El elemento (DOM_element) creado equivalente al objeto entregado o NULL en caso de impresion.
798                  **/
799                 public static function objJSON2DOM_element($objectJSON, $return=true, $base64values=true){
800                         //$object es un 'Objeto stdClass' convertido de una cadena valida JSON 
801                         $object=null;
802                         if(is_object($objectJSON)){
803                                 $object=new DOM_element();
804                                 foreach (get_object_vars($objectJSON) as $clave=>$valor){
805                                         if(is_array($valor)){   //OBJECT
806                                                 //$object->setAttribs($valor);
807                                                 //$object->addChildren($valor);
808                                                 foreach ($valor as $key=>$value){
809                                                         $object->addChild( $object->objJSON2DOM_element( $value , $return, $base64values ) );
810                                                 }
811                                         }elseif(is_object($valor)){     //ATTRIBS
812                                                 //$object->setAttribs($valor);
813                                                 foreach (get_object_vars($valor) as $key=>$value){
814                                                         $object->addAttrib($key, ($base64values ? base64_decode( $value ) : $value));
815                                                 }
816                                         }else {//if( !is_array($valor) && !is_object($valor)){ //PARAM
817                                                 if($clave=="_base64") continue;
818                                                 //if($clave=="TYPE") echo "<p>TYPE:".$valor."</p>";
819                                                 $object->$clave = $base64values ? base64_decode( $valor ) : $valor;
820                                                 //if($clave=="TYPE") echo "<p>".$clave.":".$valor." || ".$object->$clave."</p>";
821                                         }
822                                 }
823                         }
824                         
825                         if ($return) {
826                                 return $object;
827                         } else {
828                                 echo "<pre>";
829                                 print_r ($object);
830                                 echo "</pre>";
831                                 return null;
832                         }
833                 }
834                 //----------------  END: JSON  ------------------------------
835                 
836                 /**
837                  * <p>Metodo para reconstruir este objeto a la imagen y semejanza del objeto DOM_element entregado, con hijos, atributos,
838                  * y caracteristicas propias.</p>
839                  * @param DOM_element $dom Un objeto de esta clase.
840                  * @return DOM_element Este elemento (this) recreado equivalente (pero no el mismo) al objeto entregado.
841                  **/
842                 public function fromDOM_element(DOM_element $dom){
843                         //$this=new $dom($dom->_key);
844                         $this->setReadOnly(false);
845                         $this->_Key = $dom->getKey();
846                         $this->setConfiguration($dom->getConfiguration());
847                         $this->setChildren($dom->getChildren());
848                         $this->setAttribs($dom->getAttribs());
849                         $this->setReadOnly($dom->getReadOnly());
850                         return $this;   //DA ERRORES EN PHP 4.0
851                 }
852                 
853                 //----------------  BEGIN URL  ------------------------------
854                 /** 
855                  * <p>Retorna una cadena con el formato de las URL's, construida con los Atributos de este Objeto.<br />
856                  * Contiene un parametro $encode indicando el tipo de codificacion a aplicar: 'RFC_1738' (espacios=+) o 'RFC_3986' (espacions=%20),
857                  * las cuales estan implementadas como cadenas staticas de la clase DOM_attribs.</p>
858                  * @param $encode Cadena indicando el tipo de codificacion (alguna de las dos constantes indicadas
859                  * {@link DOM_attribs->ENCODE_RFC_1738 RFC_1738} o {@link DOM_attribs#ENCODE_RFC_3986 RFC_3986}).
860                  * @return Cadena con formato de codificacion URL. 
861                  **/
862                 public function attribsToURL($encode = self::ENCODE_RFC_1738){
863                         return parent::toURL($encode);
864                 }
865                 /**
866                  * <p>Establece y retorna un array de atributos con sus correspondientes valores extraidos de una cadena con el formato de las URL's, 
867                  * para construir Atributos de este Objeto.</p>
868                  * <p>El parametro es la cadena desde la que se extraeran los atributos y sus valores, esta cadena tendra el formato entregado en
869                  * las URL's como parte de su 'queryString' (entre '?' y '#'), Igual a la generada por el metodo toURL().</p>
870                  * @param $encode Cadena indicando el tipo de codificacion (alguna de las dos constantes indicadas
871                  * {@link DOM_attribs->ENCODE_RFC_1738 RFC_1738} o {@link DOM_attribs#ENCODE_RFC_3986 RFC_3986}).
872                  * @return Array de atributos extraidos de la queryString.
873                  **/
874                 public function attribsFromURL($strURL){
875                         return parent::fromURL($strURL);
876                 }
877                 //-----------------  END URL ----------------------------
878                 
879                 //-----------------  BEGIN: CONFIGURACION  --------------
880                 public function getConfiguration(){
881                         /*$conf=array($this->_READ_ONLY, $this->AVISO_GET, 
882                                                                         $this->TAG, $this->TYPE, $this->DESC, $this->_text,
883                                                                         $this->OPEN_TAG_LEFT, $this->OPEN_TAG_RIGHT, $this->CLOSE_TAG_LEFT, $this->CLOSE_TAG_RIGHT );*/
884                         $conf=array("_READ_ONLY"=>$this->_READ_ONLY, "AVISO_GET"=>$this->AVISO_GET,
885                                                                         "TAG"=>$this->TAG, "TYPE"=>$this->TYPE, "DESC"=>$this->DESC, "_text"=>$this->_text,
886                                                                         "OPEN_TAG_LEFT"=>$this->OPEN_TAG_LEFT, "OPEN_TAG_RIGHT"=>$this->OPEN_TAG_RIGHT, 
887                                                                         "CLOSE_TAG_LEFT"=>$this->CLOSE_TAG_LEFT, "CLOSE_TAG_RIGHT"=>$this->CLOSE_TAG_RIGHT );
888                         return $conf;
889                 }
890
891                 public function setConfiguration(array $conf){
892                         try{
893                                 $this->tryingWrite("[".$this->_key."]".$this->TAG);
894
895                                 if( ! is_null($conf) ){
896                                         /*$conf=array($this->_READ_ONLY, $this->AVISO_GET,
897                                                         $this->TAG, $this->TYPE, $this->DESC, $this->_text,
898                                                         $this->OPEN_TAG_LEFT, $this->OPEN_TAG_RIGHT, $this->CLOSE_TAG_LEFT, $this->CLOSE_TAG_RIGHT );
899                                         */
900                                         foreach ($conf as $clave=>$valor){
901                                                 //echo $clave." = ".$value."<br />";
902                                                 $this->$clave=$valor;
903                                                 //if($clave=="TYPE") echo "<p>TYPE:".$valor."</p>";
904                                                 //echo (is_array($conf)?"true":"false")." :: ".$clave."-".$valor."<br />";
905                                         }
906                                 }
907
908                         }catch(Exception $e){
909                                 $this->writeLog($e->getMessage(), $e->getTrace());
910                         }
911                         //return $conf;
912                         return $this;
913                 }
914                 
915                 public function importConfINI($confFile=null){
916                         // Analizar con secciones
917                         $seccIni = parse_ini_file(_PATH_CLASS_DOM_."/"._CONF_INI_FILE_DOM_, true);
918                         foreach ($seccIni as $secc=>$items){
919                                 if($secc==_SECC_CONF_INI_DOM){
920                                         /*
921                                         foreach ($items as $key=>$value){
922                                                 echo $key." = ".$value."<br />";
923                                         }
924                                         */
925                                         $this->setConfiguration($items);
926                                 }
927                         }
928                         return $this;
929                 }
930                 //---------------  END: CONFIGURACION  ----------------
931
932         }
933 ?>