FluentDOM Package
Current file: /fluentdom/releases/release_2.0/FluentDOM/FluentDOM.php
Legend: executed not executed dead code

  Coverage
  Classes Functions / Methods Lines
Total
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 79 / 79
99.88%99.88%
99.88% 835 / 836
 
FluentDOM
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 78 / 78
99.88%99.88%
99.88% 831 / 832
 public function __construct()
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 2 / 2
 public function load($source, $contentType = 'text/xml')
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 28 / 28
 protected function _initLoaders()
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 18 / 18
 public function setLoaders($loaders)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 6 / 6
 private function _setContentType($value)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 19 / 19
 public function __get($name)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 11 / 11
 public function __set($name, $value)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 12 / 12
 public function __isset($name)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 6 / 6
 public function __call($name, $arguments)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 8 / 8
 public function __toString()
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 7 / 7
 public function item($position)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 3 / 3
 public function getIterator()
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 1 / 1
 public function count()
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 1 / 1
 public function offsetSet($offset, $value)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 1 / 1
 public function offsetExists($offset)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 1 / 1
 public function offsetUnset($offset)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 1 / 1
 public function offsetGet($offset)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 1 / 1
 protected function _spawn()
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 3 / 3
 private function _xpath()
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 13 / 13
 private function _match($expr, $context = NULL)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 3 / 3
 private function _test($expr, $context)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 4 / 4
 private function _push($elements, $unique = false)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 24 / 24
 private function _inList($node)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 5 / 5
 private function _isQName($name)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 6 / 6
 private function _isNode($node)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 8 / 8
 protected function _isCallback($callback)
100.00%100.00%
100.00% 1 / 1
90.91%90.91%
90.91% 10 / 11
 private function _getContentNodes($content, $includeTextNodes = true, $limit = 0)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 41 / 41
 private function _getTargetNodes($selector)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 10 / 10
 private function _removeNodes($selector)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 9 / 9
 private function _getContentElement($content)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 4 / 4
 public function each($function)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 6 / 6
 public function formatOutput($contentType = NULL)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 11 / 11
 public function eq($position)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 5 / 5
 public function filter($expr)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 13 / 13
 public function is($expr)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 4 / 4
 public function map($function)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 20 / 20
 public function not($expr)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 13 / 13
 public function slice($start, $end = NULL)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 10 / 10
 public function add($expr)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 9 / 9
 public function children($expr = NULL)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 12 / 12
 public function find($expr, $useDocumentContext = false)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 9 / 9
 public function next($expr = NULL)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 13 / 13
 public function nextAll($expr = NULL)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 13 / 13
 public function parent()
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 7 / 7
 public function parents($expr = NULL)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 11 / 11
 public function prev($expr = NULL)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 13 / 13
 public function prevAll($expr = NULL)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 13 / 13
 public function siblings($expr = NULL)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 15 / 15
 public function andSelf()
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 4 / 4
 public function end()
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 3 / 3
 public function xml($xml = NULL)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 20 / 20
 public function text($text = NULL)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 10 / 10
 public function append($content)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 1 / 1
 public function appendTo($expr)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 1 / 1
 public function prepend($content)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 1 / 1
 public function prependTo($expr)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 1 / 1
 private function _insertChild($content, $first)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 22 / 22
 private function _insertChildTo($selector, $first)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 19 / 19
 public function after($content)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 16 / 16
 public function before($content)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 15 / 15
 public function insertAfter($selector)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 18 / 18
 public function insertBefore($selector)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 17 / 17
 private function _wrap($elements, $content)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 22 / 22
 public function wrap($content)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 3 / 3
 public function wrapAll($content)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 41 / 41
 public function wrapInner($content)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 11 / 11
 public function replaceWith($content)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 12 / 12
 public function replaceAll($selector)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 16 / 16
 private function _emptyNodes()
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 7 / 7
 public function remove($expr = NULL)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 9 / 9
 public function node($content)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 3 / 3
 private function _cloneNodes()
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 5 / 5
 public function attr($attribute, $value = NULL)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 39 / 39
 public function removeAttr($name)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 9 / 9
 public function addClass($class)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 1 / 1
 public function hasClass($class)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 9 / 9
 public function removeClass($class)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 1 / 1
 public function toggleClass($class, $switch = NULL)
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 32 / 32
Functions
  
   
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 0 / 0
 function FluentDOM($source = NULL, $contentType = 'text/xml')
100.00%100.00%
100.00% 1 / 1
100.00%100.00%
100.00% 4 / 4


       1                 : <?php                                                                                                           
       2                 : /**                                                                                                             
       3                 : * FluentDOM implements a jQuery like replacement for DOMNodeList                                                
       4                 : *                                                                                                               
       5                 : * @version $Id: FluentDOM.php 305 2009-07-24 18:03:59Z subjective $                                             
       6                 : * @license http://www.opensource.org/licenses/mit-license.php The MIT License                                   
       7                 : * @copyright Copyright (c) 2009 Bastian Feder, Thomas Weinert                                                   
       8                 : *                                                                                                               
       9                 : * @package FluentDOM                                                                                            
      10                 : */                                                                                                              
      11                 :                                                                                                                 
      12                 : require_once(dirname(__FILE__).'/FluentDOMIterator.php');                                                       
      13                 :                                                                                                                 
      14                 : /**                                                                                                             
      15                 : * Function to create a new FluentDOM instance                                                                   
      16                 : *                                                                                                               
      17                 : * This is a shortcut for "new FluentDOM($source)"                                                               
      18                 : *                                                                                                               
      19                 : * @param mixed $source                                                                                          
      20                 : * @param string $contentType optional, default value 'text/xml'                                                 
      21                 : * @access public                                                                                                
      22                 : * @return object FluentDOM                                                                                      
      23                 : */                                                                                                              
      24                 : function FluentDOM($source = NULL, $contentType = 'text/xml') {                                                 
      25               2 :   $result = new FluentDOM();                                                                                    
      26               2 :   if (isset($source)) {                                                                                         
      27               1 :     return $result->load($source, $contentType);                                                                
      28                 :   } else {                                                                                                      
      29               1 :     return $result;                                                                                             
      30                 :   }                                                                                                             
      31                 : }                                                                                                               
      32                 :                                                                                                                 
      33                 : /**                                                                                                             
      34                 : * FluentDOM implements a jQuery like replacement for DOMNodeList                                                
      35                 : *                                                                                                               
      36                 : * @property-read int $length the amount of elements found by selector                                           
      37                 : * @property-read DOMDocument $document An instance of the current DOMDocument                                   
      38                 : * @property-read DOMXPath $xpath An Instance of the current DOMXPath object                                     
      39                 : *                                                                                                               
      40                 : * @method bool empty() clears the current node list identified by a selector                                    
      41                 : * @method DOMDocument clone() clones the items of the current node list identified by a selector                
      42                 : *                                                                                                               
      43                 : * @package FluentDOM                                                                                            
      44                 : */                                                                                                              
      45                 : class FluentDOM implements IteratorAggregate, Countable, ArrayAccess {                                          
      46                 :                                                                                                                 
      47                 :   /**                                                                                                           
      48                 :   * document object                                                                                             
      49                 :   * @var object DOMDocument                                                                                     
      50                 :   * @access private                                                                                             
      51                 :   */                                                                                                            
      52                 :   private $_document = NULL;                                                                                    
      53                 :                                                                                                                 
      54                 :   /**                                                                                                           
      55                 :   * use document context for expression                                                                         
      56                 :   * @var boolean                                                                                                
      57                 :   * @access private                                                                                             
      58                 :   */                                                                                                            
      59                 :   private $_useDocumentContext = TRUE;                                                                          
      60                 :                                                                                                                 
      61                 :   /**                                                                                                           
      62                 :   * content type for output (xml, text/xml, html, text/html)                                                    
      63                 :   * @var string                                                                                                 
      64                 :   * @access private                                                                                             
      65                 :   */                                                                                                            
      66                 :   private $_contentType = 'text/xml';                                                                           
      67                 :                                                                                                                 
      68                 :   /**                                                                                                           
      69                 :   * parent node list (last selection in chain)                                                                  
      70                 :   * @var object FluentDOM                                                                                       
      71                 :   * @access private                                                                                             
      72                 :   */                                                                                                            
      73                 :   private $_parent = NULL;                                                                                      
      74                 :                                                                                                                 
      75                 :   /**                                                                                                           
      76                 :   * element nodes                                                                                               
      77                 :   * @var array                                                                                                  
      78                 :   * @access protected                                                                                           
      79                 :   */                                                                                                            
      80                 :   protected $_array = array();                                                                                  
      81                 :                                                                                                                 
      82                 :   /**                                                                                                           
      83                 :   * internal xpath instance                                                                                     
      84                 :   * @var object DOMXPath                                                                                        
      85                 :   * @access private                                                                                             
      86                 :   */                                                                                                            
      87                 :   private $_xpath = NULL;                                                                                       
      88                 :                                                                                                                 
      89                 :   /**                                                                                                           
      90                 :   * document loader objects                                                                                     
      91                 :   * @var array                                                                                                  
      92                 :   * @access private                                                                                             
      93                 :   */                                                                                                            
      94                 :   private $_loaders = NULL;                                                                                     
      95                 :                                                                                                                 
      96                 :   /**                                                                                                           
      97                 :   * Constructor                                                                                                 
      98                 :   *                                                                                                             
      99                 :   * @access public                                                                                              
     100                 :   * @return FluentDOM                                                                                           
     101                 :   */                                                                                                            
     102                 :   public function __construct() {                                                                               
     103             149 :     $this->_document = new DOMDocument();                                                                       
     104             149 :   }                                                                                                             
     105                 :                                                                                                                 
     106                 :   /**                                                                                                           
     107                 :   * Load a $source string. This can be content (contains <) or an URL.                                          
     108                 :   *                                                                                                             
     109                 :   * @param $source                                                                                              
     110                 :   * @param string $contentType optional, default value 'text/xml'                                               
     111                 :   * @access public                                                                                              
     112                 :   *                                                                                                             
     113                 :   * @see DOMDocument::loadHTML()                                                                                
     114                 :   * @see DOMDocument::loadHTMLFile()                                                                            
     115                 :   * @see DOMDocument::loadXML()                                                                                 
     116                 :   * @see DOMDocument::load()                                                                                    
     117                 :   */                                                                                                            
     118                 :   public function load($source, $contentType = 'text/xml') {                                                    
     119             127 :     $this->_array = array();                                                                                    
     120             127 :     $this->_setContentType($contentType);                                                                       
     121             127 :     if ($source instanceof FluentDOM) {                                                                         
     122             114 :       $this->_useDocumentContext = FALSE;                                                                       
     123             114 :       $this->_document = $source->document;                                                                     
     124             114 :       $this->_xpath = $source->_xpath;                                                                          
     125             114 :       $this->_contentType = $source->_contentType;                                                              
     126             114 :       $this->_parent = $source;                                                                                 
     127             114 :       return $this;                                                                                             
     128                 :     } else {                                                                                                    
     129             124 :       $this->_parent = NULL;                                                                                    
     130             124 :       $this->_initLoaders();                                                                                    
     131             124 :       foreach ($this->_loaders as $loader) {                                                                    
     132             124 :         if ($loaded = $loader->load($source, $this->_contentType)) {                                            
     133             123 :           if ($loaded instanceof DOMDocument) {                                                                 
     134             120 :             $this->_useDocumentContext = TRUE;                                                                  
     135             120 :             $this->_document = $loaded;                                                                         
     136             123 :           } elseif (is_array($loaded) &&                                                                        
     137               6 :                     isset($loaded[0]) &&                                                                        
     138               6 :                     isset($loaded[1]) &&                                                                        
     139               6 :                     $loaded[0] instanceof DOMDocument &&                                                        
     140               6 :                     is_array($loaded[1])) {                                                                     
     141               6 :             $this->_document = $loaded[0];                                                                      
     142               6 :             $this->_push($loaded[1]);                                                                           
     143               6 :             $this->_useDocumentContext = FALSE;                                                                 
     144               6 :           }                                                                                                     
     145             123 :           return $this;                                                                                         
     146                 :         }                                                                                                       
     147               2 :       }                                                                                                         
     148               1 :       throw new InvalidArgumentException('Invalid source object.');                                             
     149                 :     }                                                                                                           
     150                 :     return $this;                                                                                               
     151                 :   }                                                                                                             
     152                 :                                                                                                                 
     153                 :   /**                                                                                                           
     154                 :   * Initialize loaders if they are not already initialized                                                      
     155                 :   *                                                                                                             
     156                 :   * @access protected                                                                                           
     157                 :   * @return void                                                                                                
     158                 :   */                                                                                                            
     159                 :   protected function _initLoaders() {                                                                           
     160             124 :     if (!is_array($this->_loaders)) {                                                                           
     161               6 :       $path = dirname(__FILE__);                                                                                
     162               6 :       include_once($path.'/FluentDOMLoader.php');                                                               
     163               6 :       include_once($path.'/Loader/DOMNode.php');                                                                
     164               6 :       include_once($path.'/Loader/DOMDocument.php');                                                            
     165               6 :       include_once($path.'/Loader/StringXML.php');                                                              
     166               6 :       include_once($path.'/Loader/FileXML.php');                                                                
     167               6 :       include_once($path.'/Loader/StringHTML.php');                                                             
     168               6 :       include_once($path.'/Loader/FileHTML.php');                                                               
     169               6 :       $this->_loaders = array(                                                                                  
     170               6 :         new FluentDOMLoaderDOMNode(),                                                                           
     171               6 :         new FluentDOMLoaderDOMDocument(),                                                                       
     172               6 :         new FluentDOMLoaderStringXML(),                                                                         
     173               6 :         new FluentDOMLoaderFileXML(),                                                                           
     174               6 :         new FluentDOMLoaderStringHTML(),                                                                        
     175               6 :         new FluentDOMLoaderFileHTML(),                                                                          
     176                 :       );                                                                                                        
     177               6 :     }                                                                                                           
     178             124 :   }                                                                                                             
     179                 :                                                                                                                 
     180                 :   /**                                                                                                           
     181                 :   * Define own loading handlers                                                                                 
     182                 :   *                                                                                                             
     183                 :   * @param $loaders                                                                                             
     184                 :   * @access public                                                                                              
     185                 :   * @return object FluentDOM                                                                                    
     186                 :   */                                                                                                            
     187                 :   public function setLoaders($loaders) {                                                                        
     188             122 :     foreach ($loaders as $loader) {                                                                             
     189             122 :       if (!($loader instanceof FluentDOMLoader)) {                                                              
     190               1 :         throw new InvalidArgumentException('Array contains invalid loader object');                             
     191                 :       }                                                                                                         
     192             121 :     }                                                                                                           
     193             121 :     $this->_loaders = $loaders;                                                                                 
     194             121 :     return $this;                                                                                               
     195                 :   }                                                                                                             
     196                 :                                                                                                                 
     197                 :   /**                                                                                                           
     198                 :   * setter for contentType property                                                                             
     199                 :   *                                                                                                             
     200                 :   * @param string $value                                                                                        
     201                 :   * @access private                                                                                             
     202                 :   * @return void                                                                                                
     203                 :   */                                                                                                            
     204                 :   private function _setContentType($value) {                                                                    
     205             136 :     switch (strtolower($value)) {                                                                               
     206             136 :     case 'xml' :                                                                                                
     207             136 :     case 'text/xml' :                                                                                           
     208             130 :       $newContentType = 'text/xml';                                                                             
     209             130 :       break;                                                                                                    
     210               7 :     case 'html' :                                                                                               
     211               7 :     case 'text/html' :                                                                                          
     212               6 :       $newContentType = 'text/html';                                                                            
     213               6 :       break;                                                                                                    
     214               1 :     default :                                                                                                   
     215               1 :       throw new UnexpectedValueException('Invalid content type value');                                         
     216             136 :     }                                                                                                           
     217             135 :     if ($this->_contentType != $newContentType) {                                                               
     218               6 :       $this->_contentType = $newContentType;                                                                    
     219               6 :       if (isset($this->_parent)) {                                                                              
     220               1 :         $this->_parent->contentType = $newContentType;                                                          
     221               1 :       }                                                                                                         
     222               6 :     }                                                                                                           
     223             135 :   }                                                                                                             
     224                 :                                                                                                                 
     225                 :   /**                                                                                                           
     226                 :   * implement dynamic properties using magic methods                                                            
     227                 :   *                                                                                                             
     228                 :   * @param string $name                                                                                         
     229                 :   * @access public                                                                                              
     230                 :   * @return mixed                                                                                               
     231                 :   */                                                                                                            
     232                 :   public function __get($name) {                                                                                
     233                 :     switch ($name) {                                                                                            
     234             129 :     case 'contentType' :                                                                                        
     235               8 :       return $this->_contentType;                                                                               
     236             121 :     case 'document' :                                                                                           
     237             118 :       return $this->_document;                                                                                  
     238              16 :     case 'length' :                                                                                             
     239              13 :       return count($this->_array);                                                                              
     240               3 :     case 'xpath' :                                                                                              
     241               2 :       return $this->_xpath();                                                                                   
     242               1 :     default :                                                                                                   
     243               1 :       return NULL;                                                                                              
     244               1 :     }                                                                                                           
     245                 :   }                                                                                                             
     246                 :                                                                                                                 
     247                 :   /**                                                                                                           
     248                 :   * block changes of dynamic readonly property length                                                           
     249                 :   *                                                                                                             
     250                 :   * @param $name                                                                                                
     251                 :   * @param $value                                                                                               
     252                 :   * @access public                                                                                              
     253                 :   * @return void                                                                                                
     254                 :   */                                                                                                            
     255                 :   public function __set($name, $value) {                                                                        
     256                 :     switch ($name) {                                                                                            
     257              18 :     case 'contentType' :                                                                                        
     258              10 :       $this->_setContentType($value);                                                                           
     259               9 :       break;                                                                                                    
     260               9 :     case 'document' :                                                                                           
     261               9 :     case 'length' :                                                                                             
     262               9 :     case 'xpath' :                                                                                              
     263               3 :       throw new BadMethodCallException('Can not set readonly value.');                                          
     264               6 :     default :                                                                                                   
     265               6 :       $this->$name = $value;                                                                                    
     266               6 :       break;                                                                                                    
     267               6 :     }                                                                                                           
     268              14 :   }                                                                                                             
     269                 :                                                                                                                 
     270                 :   /**                                                                                                           
     271                 :   * support isset for dynamic properties length and document                                                    
     272                 :   *                                                                                                             
     273                 :   * @param $name                                                                                                
     274                 :   * @access public                                                                                              
     275                 :   * @return boolean                                                                                             
     276                 :   */                                                                                                            
     277                 :   public function __isset($name) {                                                                              
     278                 :     switch ($name) {                                                                                            
     279               4 :     case 'length' :                                                                                             
     280               4 :     case 'xpath' :                                                                                              
     281               2 :       return TRUE;                                                                                              
     282               2 :     case 'document' :                                                                                           
     283               1 :       return isset($this->_document);                                                                           
     284                 :     }                                                                                                           
     285               1 :     return FALSE;                                                                                               
     286                 :   }                                                                                                             
     287                 :                                                                                                                 
     288                 :   /**                                                                                                           
     289                 :   * declaring an empty() or clone() method will crash the parser so we use some magic                           
     290                 :   *                                                                                                             
     291                 :   * @param string $name                                                                                         
     292                 :   * @param array $arguments                                                                                     
     293                 :   * @access public                                                                                              
     294                 :   * @return mixed                                                                                               
     295                 :   */                                                                                                            
     296                 :   public function __call($name, $arguments) {                                                                   
     297               3 :     switch (strtolower($name)) {                                                                                
     298               3 :     case 'empty' :                                                                                              
     299               1 :       return $this->_emptyNodes();                                                                              
     300               2 :     case 'clone' :                                                                                              
     301               1 :       return $this->_cloneNodes();                                                                              
     302               1 :     default :                                                                                                   
     303               1 :       throw new BadMethodCallException('Unknown method '.get_class($this).'::'.$name);                          
     304               1 :     }                                                                                                           
     305                 :   }                                                                                                             
     306                 :                                                                                                                 
     307                 :   /**                                                                                                           
     308                 :   * Return the XML output of the internal dom document                                                          
     309                 :   *                                                                                                             
     310                 :   * @access public                                                                                              
     311                 :   * @return string                                                                                              
     312                 :   */                                                                                                            
     313                 :   public function __toString() {                                                                                
     314              49 :     switch ($this->_contentType) {                                                                              
     315              49 :     case 'html' :                                                                                               
     316              49 :     case 'text/html' :                                                                                          
     317               2 :       return $this->_document->saveHTML();                                                                      
     318              47 :     default :                                                                                                   
     319              47 :       return $this->_document->saveXML();                                                                       
     320              47 :     }                                                                                                           
     321                 :   }                                                                                                             
     322                 :                                                                                                                 
     323                 :   /**                                                                                                           
     324                 :   * the item() method is used to access elements in the node list                                               
     325                 :   *                                                                                                             
     326                 :   * @param $position                                                                                            
     327                 :   * @access public                                                                                              
     328                 :   * @return object DOMNode                                                                                      
     329                 :   */                                                                                                            
     330                 :   public function item($position) {                                                                             
     331              17 :     if (isset($this->_array[$position])) {                                                                      
     332              16 :       return $this->_array[$position];                                                                          
     333                 :     }                                                                                                           
     334              11 :     return NULL;                                                                                                
     335                 :   }                                                                                                             
     336                 :                                                                                                                 
     337                 :   /*                                                                                                            
     338                 :   * Interface - IteratorAggregate                                                                               
     339                 :   */                                                                                                            
     340                 :                                                                                                                 
     341                 :   public function getIterator() {                                                                               
     342              11 :     return new FluentDOMIterator($this);                                                                        
     343                 :   }                                                                                                             
     344                 :                                                                                                                 
     345                 :   /*                                                                                                            
     346                 :   * Interface - Countable                                                                                       
     347                 :   */                                                                                                            
     348                 :                                                                                                                 
     349                 :   /**                                                                                                           
     350                 :   * get element count (Countable)                                                                               
     351                 :   *                                                                                                             
     352                 :   * @access public                                                                                              
     353                 :   * @return integer                                                                                             
     354                 :   */                                                                                                            
     355                 :   public function count() {                                                                                     
     356               6 :     return count($this->_array);                                                                                
     357                 :   }                                                                                                             
     358                 :                                                                                                                 
     359                 :   /*                                                                                                            
     360                 :   * Interface - ArrayAccess                                                                                     
     361                 :   */                                                                                                            
     362                 :                                                                                                                 
     363                 :   /**                                                                                                           
     364                 :   * If somebody tries to modify the internal array throw an exception.                                          
     365                 :   *                                                                                                             
     366                 :   * @param integer $offset                                                                                      
     367                 :   * @param mixed $value                                                                                         
     368                 :   * @access public                                                                                              
     369                 :   * @return void                                                                                                
     370                 :   */                                                                                                            
     371                 :   public function offsetSet($offset, $value) {                                                                  
     372               1 :     throw new BadMethodCallException('List is read only');                                                      
     373                 :   }                                                                                                             
     374                 :                                                                                                                 
     375                 :   /**                                                                                                           
     376                 :   * Check if index exists in internal array                                                                     
     377                 :   *                                                                                                             
     378                 :   * @param integer $offset                                                                                      
     379                 :   * @access public                                                                                              
     380                 :   * @return boolean                                                                                             
     381                 :   */                                                                                                            
     382                 :   public function offsetExists($offset) {                                                                       
     383               1 :     return isset($this->_array[$offset]);                                                                       
     384                 :   }                                                                                                             
     385                 :                                                                                                                 
     386                 :   /**                                                                                                           
     387                 :   * If somebody tries to remove an element from the internal array throw an exception.                          
     388                 :   *                                                                                                             
     389                 :   * @param integer $offset                                                                                      
     390                 :   * @access public                                                                                              
     391                 :   * @return void                                                                                                
     392                 :   */                                                                                                            
     393                 :   public function offsetUnset($offset) {                                                                        
     394               1 :     throw new BadMethodCallException('List is read only');                                                      
     395                 :   }                                                                                                             
     396                 :                                                                                                                 
     397                 :   /**                                                                                                           
     398                 :   * Get element from internal array                                                                             
     399                 :   *                                                                                                             
     400                 :   * @param $offset                                                                                              
     401                 :   * @access public                                                                                              
     402                 :   * @return void                                                                                                
     403                 :   */                                                                                                            
     404                 :   public function offsetGet($offset) {                                                                          
     405              12 :     return isset($this->_array[$offset]) ? $this->_array[$offset] : null;                                       
     406                 :   }                                                                                                             
     407                 :                                                                                                                 
     408                 :   /*                                                                                                            
     409                 :   * Core functions                                                                                              
     410                 :   */                                                                                                            
     411                 :                                                                                                                 
     412                 :   /**                                                                                                           
     413                 :   * Create a new instance of the same class with the $this as the parent.                                       
     414                 :   *                                                                                                             
     415                 :   * This is used for the chaining and needs to be overloaded in child classes.                                  
     416                 :   *                                                                                                             
     417                 :   * @access private                                                                                             
     418                 :   * @return  object FluentDOM                                                                                   
     419                 :   */                                                                                                            
     420                 :   protected function _spawn() {                                                                                 
     421             114 :     $className = get_class($this);                                                                              
     422             114 :     $result = new $className();                                                                                 
     423             114 :     return $result->load($this);                                                                                
     424                 :   }                                                                                                             
     425                 :                                                                                                                 
     426                 :   /**                                                                                                           
     427                 :   * create a new xpath object an register default namespaces from the current document                          
     428                 :   *                                                                                                             
     429                 :   * @access private                                                                                             
     430                 :   * @return object DOMXPath                                                                                     
     431                 :   */                                                                                                            
     432                 :   private function _xpath() {                                                                                   
     433             108 :     if (empty($this->_xpath) || $this->_xpath->document != $this->_document) {                                  
     434             108 :       $this->_xpath = new DOMXPath($this->_document);                                                           
     435             108 :       if ($this->_document->documentElement) {                                                                  
     436             108 :         $uri = $this->_document->documentElement->lookupnamespaceURI('_');                                      
     437             108 :         if (!isset($uri)) {                                                                                     
     438             108 :           $uri = $this->_document->documentElement->lookupnamespaceURI(NULL);                                   
     439             108 :           if (isset($uri)) {                                                                                    
     440               1 :             $this->_xpath->registerNamespace('_', $uri);                                                        
     441               1 :           }                                                                                                     
     442             108 :         }                                                                                                       
     443             108 :       }                                                                                                         
     444             108 :     }                                                                                                           
     445             108 :     return $this->_xpath;                                                                                       
     446                 :   }                                                                                                             
     447                 :                                                                                                                 
     448                 :   /**                                                                                                           
     449                 :   * match xpath expression agains context and return matched elements                                           
     450                 :   *                                                                                                             
     451                 :   * @param string$expr                                                                                          
     452                 :   * @param DOMElement $context optional, default value NULL                                                     
     453                 :   * @access private                                                                                             
     454                 :   * @return DOMNodeList                                                                                         
     455                 :   */                                                                                                            
     456                 :   private function _match($expr, $context = NULL) {                                                             
     457             107 :     if (isset($context)) {                                                                                      
     458              12 :       return $this->_xpath()->query($expr, $context);                                                           
     459                 :     } else {                                                                                                    
     460             107 :       return $this->_xpath()->query($expr);                                                                     
     461                 :     }                                                                                                           
     462                 :   }                                                                                                             
     463                 :                                                                                                                 
     464                 :   /**                                                                                                           
     465                 :   * test xpath expression against context and return true/false                                                 
     466                 :   *                                                                                                             
     467                 :   * @param string$expr                                                                                          
     468                 :   * @param DOMElement $context optional, default value NULL                                                     
     469                 :   * @access private                                                                                             
     470                 :   * @return boolean                                                                                             
     471                 :   */                                                                                                            
     472                 :   private function _test($expr, $context) {                                                                     
     473               5 :     $check = $this->_xpath()->evaluate($expr, $context);                                                        
     474               5 :     if ($check instanceof DOMNodeList) {                                                                        
     475               1 :       return $check->length > 0;                                                                                
     476                 :     } else {                                                                                                    
     477               4 :       return (bool)$check;                                                                                      
     478                 :     }                                                                                                           
     479                 :   }                                                                                                             
     480                 :                                                                                                                 
     481                 :   /**                                                                                                           
     482                 :   * push new elements an the list                                                                               
     483                 :   *                                                                                                             
     484                 :   * @param object DOMElement | object DOMNodeList | object FluentDOM $elements                                  
     485                 :   * @access private                                                                                             
     486                 :   * @return void                                                                                                
     487                 :   */                                                                                                            
     488                 :   private function _push($elements, $unique = FALSE) {                                                          
     489             115 :     if ($this->_isNode($elements)) {                                                                            
     490              46 :       if ($elements->ownerDocument === $this->_document) {                                                      
     491              45 :         if (!$unique || !$this->_inList($elements, $this->_array)) {                                            
     492              45 :           $this->_array[] = $elements;                                                                          
     493              45 :         }                                                                                                       
     494              45 :       } else {                                                                                                  
     495               1 :         throw new OutOfBoundsException('Node is not a part of this document');                                  
     496                 :       }                                                                                                         
     497             115 :     } elseif ($elements instanceof DOMNodeList ||                                                               
     498              28 :               $elements instanceof DOMDocumentFragment ||                                                       
     499              28 :               $elements instanceof Iterator ||                                                                  
     500              28 :               $elements instanceof IteratorAggregate ||                                                         
     501             113 :               is_array($elements)) {                                                                            
     502             113 :       foreach ($elements as $node) {                                                                            
     503             111 :         if ($this->_isNode($node)) {                                                                            
     504             111 :           if ($node->ownerDocument === $this->_document) {                                                      
     505             111 :             if (!$unique || !$this->_inList($node, $this->_array)) {                                            
     506             111 :               $this->_array[] = $node;                                                                          
     507             111 :             }                                                                                                   
     508             111 :           } else {                                                                                              
     509               1 :             throw new OutOfBoundsException('Node is not a part of this document');                              
     510                 :           }                                                                                                     
     511             111 :         }                                                                                                       
     512             113 :       }                                                                                                         
     513             113 :     }                                                                                                           
     514             115 :   }                                                                                                             
     515                 :                                                                                                                 
     516                 :   /**                                                                                                           
     517                 :   * check if object is already in internal list                                                                 
     518                 :   *                                                                                                             
     519                 :   * @param object DOMElement $node                                                                              
     520                 :   * @access private                                                                                             
     521                 :   * @return boolean                                                                                             
     522                 :   */                                                                                                            
     523                 :   private function _inList($node) {                                                                             
     524              12 :     foreach ($this->_array as $compareNode) {                                                                   
     525               8 :       if ($compareNode === $node) {                                                                             
     526               2 :         return TRUE;                                                                                            
     527                 :       }                                                                                                         
     528              12 :     }                                                                                                           
     529              12 :     return FALSE;                                                                                               
     530                 :   }                                                                                                             
     531                 :                                                                                                                 
     532                 :   /**                                                                                                           
     533                 :   * validate string as qualified tag name                                                                       
     534                 :   *                                                                                                             
     535                 :   * @param string $name                                                                                         
     536                 :   * @access private                                                                                             
     537                 :   * @return boolean                                                                                             
     538                 :   */                                                                                                            
     539                 :   private function _isQName($name) {                                                                            
     540              18 :     $nameStartChar = '[A-Za-z_|]';                                                                              
     541              18 :     $nameChar = '(?:'.$nameStartChar.'|[-.\d])';                                                                
     542              18 :     $pattern = '(^('.$nameStartChar.$nameChar.'*:)?('.$nameStartChar.$nameChar.'+)$)Diu';                       
     543              18 :     if (preg_match($pattern, $name)) {                                                                          
     544              13 :       return TRUE;                                                                                              
     545                 :     } else {                                                                                                    
     546               5 :       throw new UnexpectedValueException('Invalid QName');                                                      
     547                 :     }                                                                                                           
     548                 :   }                                                                                                             
     549                 :                                                                                                                 
     550                 :   /**                                                                                                           
     551                 :   * Check if the DOMNode is DOMElement or DOMText with content                                                  
     552                 :   *                                                                                                             
     553                 :   * @param DOMNode $node                                                                                        
     554                 :   * @access private                                                                                             
     555                 :   * @return boolean                                                                                             
     556                 :   */                                                                                                            
     557                 :   private function _isNode($node) {                                                                             
     558             117 :     if (is_object($node)) {                                                                                     
     559             115 :       if ($node instanceof DOMElement) {                                                                        
     560             111 :         return TRUE;                                                                                            
     561             108 :       } elseif ($node instanceof DOMText &&                                                                     
     562             108 :                 !$node->isWhitespaceInElementContent()) {                                                       
     563              13 :         return TRUE;                                                                                            
     564                 :       }                                                                                                         
     565             107 :     }                                                                                                           
     566             115 :     return FALSE;                                                                                               
     567                 :   }                                                                                                             
     568                 :                                                                                                                 
     569                 :   /**                                                                                                           
     570                 :   * check if parameter is a valid callback function                                                             
     571                 :   *                                                                                                             
     572                 :   * @param $callback                                                                                            
     573                 :   * @access protected                                                                                           
     574                 :   * @return boolean                                                                                             
     575                 :   */                                                                                                            
     576                 :   protected function _isCallback($callback) {                                                                   
     577              10 :     if ($callback instanceof Closure) {                                                                         
     578               0 :       return TRUE;                                                                                              
     579              10 :     } elseif (is_string($callback) &&                                                                           
     580              10 :               function_exists($callback)) {                                                                     
     581               5 :       return is_callable($callback);                                                                            
     582               5 :     } elseif (is_array($callback) &&                                                                            
     583               3 :               count($callback) == 2 &&                                                                          
     584               3 :               (is_object($callback[0]) || is_string($callback[0])) &&                                           
     585               5 :               is_string($callback[1])) {                                                                        
     586               3 :       return is_callable($callback);                                                                            
     587                 :     } else {                                                                                                    
     588               2 :       throw new BadFunctionCallException('Invalid callback argument');                                          
     589                 :     }                                                                                                           
     590                 :   }                                                                                                             
     591                 :                                                                                                                 
     592                 :   /**                                                                                                           
     593                 :   * Convert a given content into and array of nodes                                                             
     594                 :   *                                                                                                             
     595                 :   * @param string | object DOMElement | object DOMText | object Iterator $content                               
     596                 :   * @param boolean $includeTextNodes                                                                            
     597                 :   * @param integer $limit                                                                                       
     598                 :   * @access private                                                                                             
     599                 :   * @return array                                                                                               
     600                 :   */                                                                                                            
     601                 :   private function _getContentNodes($content, $includeTextNodes = TRUE, $limit = 0) {                           
     602              30 :     $result = array();                                                                                          
     603              30 :     if ($content instanceof DOMElement) {                                                                       
     604               1 :       $result = array($content);                                                                                
     605              30 :     } elseif ($includeTextNodes && $this->_isNode($content)) {                                                  
     606               2 :       $result = array($content);                                                                                
     607              29 :     } elseif (is_string($content)) {                                                                            
     608              20 :       $fragment = $this->_document->createDocumentFragment();                                                   
     609              20 :       if ($fragment->appendXML($content)) {                                                                     
     610              19 :         foreach ($fragment->childNodes as $element) {                                                           
     611              19 :           if ($element instanceof DOMElement ||                                                                 
     612              19 :               ($includeTextNodes && $this->_isNode($element))) {                                                
     613              19 :             $element->parentNode->removeChild($element);                                                        
     614              19 :             $result[] = $element;                                                                               
     615              19 :             if ($limit > 0 && count($result) >= $limit) {                                                       
     616               7 :               break;                                                                                            
     617                 :             }                                                                                                   
     618              12 :           }                                                                                                     
     619              19 :         }                                                                                                       
     620              19 :         return $result;                                                                                         
     621                 :       } else {                                                                                                  
     622               1 :         throw new UnexpectedValueException('Invalid document fragment');                                        
     623                 :       }                                                                                                         
     624               7 :     } elseif ($content instanceof DOMNodeList ||                                                                
     625               6 :               $content instanceof Iterator ||                                                                   
     626               6 :               $content instanceof IteratorAggregate ||                                                          
     627               7 :               is_array($content)) {                                                                             
     628               5 :       foreach ($content as $element) {                                                                          
     629               4 :         if ($element instanceof DOMElement ||                                                                   
     630               4 :             ($includeTextNodes && $this->_isNode($element))) {                                                  
     631               4 :           $result[] = $element;                                                                                 
     632               4 :           if ($limit > 0 && count($result) >= $limit) {                                                         
     633               2 :             break;                                                                                              
     634                 :           }                                                                                                     
     635               2 :         }                                                                                                       
     636               5 :       }                                                                                                         
     637               5 :     } else {                                                                                                    
     638               2 :       throw new InvalidArgumentException('Invalid content parameter');                                          
     639                 :     }                                                                                                           
     640               8 :     if (empty($result)) {                                                                                       
     641               1 :       throw new UnexpectedValueException('No element found');                                                   
     642                 :     } else {                                                                                                    
     643                 :       //if a node is not in the current document import it                                                      
     644               7 :       foreach ($result as $index => $node) {                                                                    
     645               7 :         if ($node->ownerDocument !== $this->_document) {                                                        
     646               1 :           $result[$index] = $this->_document->importNode($node, TRUE);                                          
     647               1 :         }                                                                                                       
     648               7 :       }                                                                                                         
     649                 :     }                                                                                                           
     650               7 :     return $result;                                                                                             
     651                 :   }                                                                                                             
     652                 :                                                                                                                 
     653                 :   private function _getTargetNodes($selector) {                                                                 
     654              13 :     if ($this->_isNode($selector)) {                                                                            
     655               1 :       return array($selector);                                                                                  
     656              13 :     } elseif (is_string($selector)) {                                                                           
     657              10 :       return $this->_match($selector);                                                                          
     658              13 :     } elseif (is_array($selector) ||                                                                            
     659               7 :               $selector instanceof Iterator ||                                                                  
     660               7 :               $selector instanceof IteratorAggregate ||                                                         
     661              13 :               $selector instanceof DOMNodeList) {                                                               
     662              12 :       return $selector;                                                                                         
     663                 :     } else {                                                                                                    
     664               1 :       throw new InvalidArgumentException('Invalid selector');                                                   
     665                 :     }                                                                                                           
     666                 :   }                                                                                                             
     667                 :                                                                                                                 
     668                 :   /**                                                                                                           
     669                 :   * Remove nodes from document tree                                                                             
     670                 :   *                                                                                                             
     671                 :   * @param $selector                                                                                            
     672                 :   * @access private                                                                                             
     673                 :   * @return array removed nodes                                                                                 
     674                 :   */                                                                                                            
     675                 :   private function _removeNodes($selector) {                                                                    
     676              12 :     $targetNodes = $this->_getTargetNodes($selector);                                                           
     677              12 :     $result = array();                                                                                          
     678              12 :     foreach ($targetNodes as $node) {                                                                           
     679              12 :       if ($node instanceof DOMNode &&                                                                           
     680              12 :           isset($node->parentNode)) {                                                                           
     681              12 :         $result[] = $node->parentNode->removeChild($node);                                                      
     682              12 :       }                                                                                                         
     683              12 :     }                                                                                                           
     684              12 :     return $result;                                                                                             
     685                 :   }                                                                                                             
     686                 :                                                                                                                 
     687                 :   /**                                                                                                           
     688                 :   * Convert content to DOMElement                                                                               
     689                 :   *                                                                                                             
     690                 :   * @param string | array | object DOMElement | object FluentDOM $content                                       
     691                 :   * @access private                                                                                             
     692                 :   * @return object DOMElement                                                                                   
     693                 :   */                                                                                                            
     694                 :   private function _getContentElement($content) {                                                               
     695              11 :     if ($content instanceof DOMElement) {                                                                       
     696               1 :       return $content;                                                                                          
     697                 :     } else {                                                                                                    
     698              10 :       $contentNodes = $this->_getContentNodes($content, FALSE, 1);                                              
     699               9 :       return $contentNodes[0];                                                                                  
     700                 :     }                                                                                                           
     701                 :   }                                                                                                             
     702                 :                                                                                                                 
     703                 :   /*                                                                                                            
     704                 :   * Object Accessors                                                                                            
     705                 :   */                                                                                                            
     706                 :                                                                                                                 
     707                 :   /**                                                                                                           
     708                 :   * Execute a function within the context of every matched element.                                             
     709                 :   *                                                                                                             
     710                 :   * @param callback | object Closure $function                                                                  
     711                 :   * @access public                                                                                              
     712                 :   * @return object FluentDOM                                                                                    
     713                 :   */                                                                                                            
     714                 :   public function each($function) {                                                                             
     715               3 :     if ($this->_isCallback($function)) {                                                                        
     716               2 :       foreach ($this->_array as $index => $node) {                                                              
     717               2 :         call_user_func($function, $node, $index);                                                               
     718               2 :       }                                                                                                         
     719               2 :     }                                                                                                           
     720               2 :     return $this;                                                                                               
     721                 :   }                                                                                                             
     722                 :                                                                                                                 
     723                 :   /**                                                                                                           
     724                 :   * Formats the current document, resets internal node array and other properties.                              
     725                 :   *                                                                                                             
     726                 :   * The document is saved and reloaded, all variables with DOMNodes of this document will get invalid.          
     727                 :   *                                                                                                             
     728                 :   * @access public                                                                                              
     729                 :   * @return object FluentDOM                                                                                    
     730                 :   */                                                                                                            
     731                 :   public function formatOutput($contentType = NULL) {                                                           
     732               5 :     if (isset($contentType)) {                                                                                  
     733               1 :       $this->_setContentType($contentType);                                                                     
     734               1 :     }                                                                                                           
     735               5 :     $this->_array = array();                                                                                    
     736               5 :     $this->_position = 0;                                                                                       
     737               5 :     $this->_useDocumentContext = TRUE;                                                                          
     738               5 :     $this->_parent = NULL;                                                                                      
     739               5 :     $this->_document->preserveWhiteSpace = FALSE;                                                               
     740               5 :     $this->_document->formatOutput = TRUE;                                                                      
     741               5 :     $this->_document->loadXML($this->_document->saveXML());                                                     
     742               5 :     return $this;                                                                                               
     743                 :   }                                                                                                             
     744                 :                                                                                                                 
     745                 :   /*                                                                                                            
     746                 :   * Traversing - Filtering                                                                                      
     747                 :   */                                                                                                            
     748                 :                                                                                                                 
     749                 :   /**                                                                                                           
     750                 :   * Reduce the set of matched elements to a single element.                                                     
     751                 :   *                                                                                                             
     752                 :   * @param integer $position Element index (start with 0)                                                       
     753                 :   * @access public                                                                                              
     754                 :   * @return object FluentDOM                                                                                    
     755                 :   */                                                                                                            
     756                 :   public function eq($position) {                                                                               
     757               5 :     $result = $this->_spawn();                                                                                  
     758               5 :     if (isset($this->_array[$position])) {                                                                      
     759               5 :       $result->_push($this->_array[$position]);                                                                 
     760               5 :     }                                                                                                           
     761               5 :     return $result;                                                                                             
     762                 :   }                                                                                                             
     763                 :                                                                                                                 
     764                 :   /**                                                                                                           
     765                 :   * Removes all elements from the set of matched elements that do not match the specified expression(s).        
     766                 :   *                                                                                                             
     767                 :   * @param string $expr | callback | object Closure XPath expression or callback function                       
     768                 :   * @access public                                                                                              
     769                 :   * @return object FluentDOM                                                                                    
     770                 :   */                                                                                                            
     771                 :   public function filter($expr) {                                                                               
     772               2 :     $result = $this->_spawn();                                                                                  
     773               2 :     foreach ($this->_array as $index => $node) {                                                                
     774               2 :       $check = TRUE;                                                                                            
     775               2 :       if (is_string($expr)) {                                                                                   
     776               1 :         $check = $this->_test($expr, $node, $index);                                                            
     777               2 :       } elseif ($this->_isCallback($expr)) {                                                                    
     778               1 :         $check = call_user_func($expr, $node, $index);                                                          
     779               1 :       }                                                                                                         
     780               2 :       if ($check) {                                                                                             
     781               2 :         $result->_push($node);                                                                                  
     782               2 :       }                                                                                                         
     783               2 :     }                                                                                                           
     784               2 :     return $result;                                                                                             
     785                 :   }                                                                                                             
     786                 :                                                                                                                 
     787                 :   /**                                                                                                           
     788                 :   * Checks the current selection against an expression and returns true,                                        
     789                 :   * if at least one element of the selection fits the given expression.                                         
     790                 :   *                                                                                                             
     791                 :   * @param string $expr XPath expression                                                                        
     792                 :   * @access public                                                                                              
     793                 :   * @return boolean                                                                                             
     794                 :   */                                                                                                            
     795                 :   public function is($expr) {                                                                                   
     796               2 :     foreach ($this->_array as $node) {                                                                          
     797               1 :       return $this->_test($expr, $node);                                                                        
     798               1 :     }                                                                                                           
     799               1 :     return FALSE;                                                                                               
     800                 :   }                                                                                                             
     801                 :                                                                                                                 
     802                 :   /**                                                                                                           
     803                 :   * Translate a set of elements in the FluentDOM object into                                                    
     804                 :   * another set of values in an array (which may, or may not contain elements).                                 
     805                 :   *                                                                                                             
     806                 :   * @param callback | object Closure $function                                                                  
     807                 :   * @access public                                                                                              
     808                 :   * @return array                                                                                               
     809                 :   */                                                                                                            
     810                 :   public function map($function) {                                                                              
     811               4 :     $result = array();                                                                                          
     812               4 :     foreach ($this->_array as $index => $node) {                                                                
     813               4 :       if ($this->_isCallback($function)) {                                                                      
     814               3 :         $mapped = call_user_func($function, $node, $index);                                                     
     815               3 :       }                                                                                                         
     816               3 :       if ($mapped === NULL) {                                                                                   
     817               1 :         continue;                                                                                               
     818               3 :       } elseif ($mapped instanceof DOMNodeList ||                                                               
     819               3 :                 $mapped instanceof Iterator ||                                                                  
     820               3 :                 $mapped instanceof IteratorAggregate ||                                                         
     821               3 :                 is_array($mapped)) {                                                                            
     822               1 :         foreach ($mapped as $element) {                                                                         
     823               1 :           if ($element !== NULL) {                                                                              
     824               1 :             $result[] = $element;                                                                               
     825               1 :           }                                                                                                     
     826               1 :         }                                                                                                       
     827               1 :       } else {                                                                                                  
     828               3 :         $result[] = $mapped;                                                                                    
     829                 :       }                                                                                                         
     830               3 :     }                                                                                                           
     831               3 :     return $result;                                                                                             
     832                 :   }                                                                                                             
     833                 :                                                                                                                 
     834                 :   /**                                                                                                           
     835                 :   * Removes elements matching the specified expression from the set of matched elements.                        
     836                 :   *                                                                                                             
     837                 :   * @param string $expr | callback | object Closure XPath expression or callback function                       
     838                 :   * @access public                                                                                              
     839                 :   * @return object FluentDOM                                                                                    
     840                 :   */                                                                                                            
     841                 :   public function not($expr) {                                                                                  
     842               2 :     $result = $this->_spawn();                                                                                  
     843               2 :     foreach ($this->_array as $index => $node) {                                                                
     844               2 :       $check = FALSE;                                                                                           
     845               2 :       if (is_string($expr)) {                                                                                   
     846               1 :         $check = $this->_test($expr, $node, $index);                                                            
     847               2 :       } elseif ($this->_isCallback($expr)) {                                                                    
     848               1 :         $check = call_user_func($expr, $node, $index);                                                          
     849               1 :       }                                                                                                         
     850               2 :       if (!$check) {                                                                                            
     851               2 :         $result->_push($node);                                                                                  
     852               2 :       }                                                                                                         
     853               2 :     }                                                                                                           
     854               2 :     return $result;                                                                                             
     855                 :   }                                                                                                             
     856                 :                                                                                                                 
     857                 :   /**                                                                                                           
     858                 :   * Selects a subset of the matched elements.                                                                   
     859                 :   *                                                                                                             
     860                 :   * @param integer $start                                                                                       
     861                 :   * @param integer $end                                                                                         
     862                 :   * @access public                                                                                              
     863                 :   * @return object FluentDOM                                                                                    
     864                 :   */                                                                                                            
     865                 :   public function slice($start, $end = NULL) {                                                                  
     866               4 :     $result = $this->_spawn();                                                                                  
     867               4 :     if ($end === NULL) {                                                                                        
     868               1 :       $result->_push(array_slice($this->_array, $start));                                                       
     869               4 :     } elseif ($end < 0) {                                                                                       
     870               1 :       $result->_push(array_slice($this->_array, $start, $end));                                                 
     871               3 :     } elseif ($end > $start) {                                                                                  
     872               1 :       $result->_push(array_slice($this->_array, $start, $end - $start));                                        
     873               1 :     } else {                                                                                                    
     874               1 :       $result->_push(array_slice($this->_array, $end, $start - $end));                                          
     875                 :     }                                                                                                           
     876               4 :     return $result;                                                                                             
     877                 :   }                                                                                                             
     878                 :                                                                                                                 
     879                 :   /*                                                                                                            
     880                 :   * Traversing - Finding                                                                                        
     881                 :   */                                                                                                            
     882                 :                                                                                                                 
     883                 :   /**                                                                                                           
     884                 :   * Adds more elements, matched by the given expression, to the set of matched elements.                        
     885                 :   *                                                                                                             
     886                 :   * @param string $expr XPath expression                                                                        
     887                 :   * @access public                                                                                              
     888                 :   * @return object FluentDOM                                                                                    
     889                 :   */                                                                                                            
     890                 :   public function add($expr) {                                                                                  
     891               5 :     $result = $this->_spawn();                                                                                  
     892               5 :     $result->_push($this->_array);                                                                              
     893               5 :     if (is_object($expr)) {                                                                                     
     894               3 :       $result->_push($expr);                                                                                    
     895               3 :     } elseif (isset($this->_parent)) {                                                                          
     896               1 :       $result->_push($this->_parent->find($expr));                                                              
     897               1 :     } else {                                                                                                    
     898               1 :       $result->_push($this->find($expr));                                                                       
     899                 :     }                                                                                                           
     900               3 :     return $result;                                                                                             
     901                 :   }                                                                                                             
     902                 :                                                                                                                 
     903                 :   /**                                                                                                           
     904                 :   * Get a set of elements containing all of the unique immediate                                                
     905                 :   * children of each of the matched set of elements.                                                            
     906                 :   *                                                                                                             
     907                 :   * @param string $expr XPath expression                                                                        
     908                 :   * @access public                                                                                              
     909                 :   * @return object FluentDOM                                                                                    
     910                 :   */                                                                                                            
     911                 :   public function children($expr = NULL) {                                                                      
     912               3 :     $result = $this->_spawn();                                                                                  
     913               3 :     foreach ($this->_array as $node) {                                                                          
     914               3 :       if (empty($expr)) {                                                                                       
     915               2 :         $result->_push($node->childNodes, TRUE);                                                                
     916               2 :       } else {                                                                                                  
     917               1 :         foreach ($node->childNodes as $childNode) {                                                             
     918               1 :           if ($this->_test($expr, $childNode)) {                                                                
     919               1 :             $result->_push($childNode, TRUE);                                                                   
     920               1 :           }                                                                                                     
     921               1 :         }                                                                                                       
     922                 :       }                                                                                                         
     923               3 :     }                                                                                                           
     924               3 :     return $result;                                                                                             
     925                 :   }                                                                                                             
     926                 :                                                                                                                 
     927                 :   /**                                                                                                           
     928                 :   * Searches for descendent elements that match the specified expression.                                       
     929                 :   *                                                                                                             
     930                 :   * @param string $expr XPath expression                                                                        
     931                 :   * @param boolean $useDocumentContext ignore current node list                                                 
     932                 :   * @access public                                                                                              
     933                 :   * @return object FluentDOM                                                                                    
     934                 :   */                                                                                                            
     935                 :   public function find($expr, $useDocumentContext = FALSE) {                                                    
     936             106 :     $result = $this->_spawn();                                                                                  
     937             106 :     if ($useDocumentContext ||                                                                                  
     938             106 :         $this->_useDocumentContext) {                                                                           
     939             106 :       $result->_push($this->_match($expr));                                                                     
     940             106 :     } else {                                                                                                    
     941               4 :       foreach ($this->_array as $contextNode) {                                                                 
     942               4 :         $result->_push($this->_match($expr, $contextNode));                                                     
     943               4 :       }                                                                                                         
     944                 :     }                                                                                                           
     945             106 :     return $result;                                                                                             
     946                 :   }                                                                                                             
     947                 :                                                                                                                 
     948                 :   /**                                                                                                           
     949                 :   * Get a set of elements containing the unique next siblings of each of the given set of elements.             
     950                 :   *                                                                                                             
     951                 :   * Like jQuerys next() method but renamed because of a conflict with Iterator                                  
     952                 :   *                                                                                                             
     953                 :   * @param string $expr XPath expression                                                                        
     954                 :   * @access public                                                                                              
     955                 :   * @return FluentDOM                                                                                           
     956                 :   */                                                                                                            
     957                 :   public function next($expr = NULL) {                                                                          
     958               1 :     $result = $this->_spawn();                                                                                  
     959               1 :     foreach ($this->_array as $node) {                                                                          
     960               1 :       $next = $node->nextSibling;                                                                               
     961               1 :       while ($next instanceof DOMNode && !$this->_isNode($next)) {                                              
     962               1 :         $next = $next->nextSibling;                                                                             
     963               1 :       }                                                                                                         
     964               1 :       if (!empty($next)) {                                                                                      
     965               1 :         if (empty($expr) || $this->_test($expr, $next)) {                                                       
     966               1 :           $result->_push($next, TRUE);                                                                          
     967               1 :         }                                                                                                       
     968               1 :       }                                                                                                         
     969               1 :     }                                                                                                           
     970               1 :     return $result;                                                                                             
     971                 :   }                                                                                                             
     972                 :                                                                                                                 
     973                 :   /**                                                                                                           
     974                 :   * Find all sibling elements after the current element.                                                        
     975                 :   *                                                                                                             
     976                 :   * Like jQuerys nextAll() method but renamed for consistency with nextSiblings()                               
     977                 :   *                                                                                                             
     978                 :   * @param string $expr XPath expression                                                                        
     979                 :   * @access public                                                                                              
     980                 :   * @return FluentDOM                                                                                           
     981                 :   */                                                                                                            
     982                 :   public function nextAll($expr = NULL) {                                                                       
     983               1 :     $result = $this->_spawn();                                                                                  
     984               1 :     foreach ($this->_array as $node) {                                                                          
     985               1 :       $next = $node->nextSibling;                                                                               
     986               1 :       while ($next instanceof DOMNode) {                                                                        
     987               1 :         if ($this->_isNode($next)) {                                                                            
     988               1 :           if (empty($expr) || $this->_test($expr, $next)) {                                                     
     989               1 :             $result->_push($next, TRUE);                                                                        
     990               1 :           }                                                                                                     
     991               1 :         }                                                                                                       
     992               1 :         $next = $next->nextSibling;                                                                             
     993               1 :       }                                                                                                         
     994               1 :     }                                                                                                           
     995               1 :     return $result;                                                                                             
     996                 :   }                                                                                                             
     997                 :                                                                                                                 
     998                 :   /**                                                                                                           
     999                 :   * Get a set of elements containing the unique parents of the matched set of elements.                         
    1000                 :   *                                                                                                             
    1001                 :   * @access public                                                                                              
    1002                 :   * @return FluentDOM                                                                                           
    1003                 :   */                                                                                                            
    1004                 :   public function parent() {                                                                                    
    1005               1 :     $result = $this->_spawn();                                                                                  
    1006               1 :     foreach ($this->_array as $node) {                                                                          
    1007               1 :       if (isset($node->parentNode)) {                                                                           
    1008               1 :         $result->_push($node->parentNode, TRUE);                                                                
    1009               1 :       }                                                                                                         
    1010               1 :     }                                                                                                           
    1011               1 :     return $result;                                                                                             
    1012                 :   }                                                                                                             
    1013                 :                                                                                                                 
    1014                 :   /**                                                                                                           
    1015                 :   * Get a set of elements containing the unique ancestors of the matched set of elements.                       
    1016                 :   *                                                                                                             
    1017                 :   * @param string $expr XPath expression                                                                        
    1018                 :   * @access public                                                                                              
    1019                 :   * @return FluentDOM                                                                                           
    1020                 :   */                                                                                                            
    1021                 :   public function parents($expr = NULL) {                                                                       
    1022               1 :     $result = $this->_spawn();                                                                                  
    1023               1 :     foreach ($this->_array as $node) {                                                                          
    1024               1 :       $parents = $this->_match('ancestor::*', $node);                                                           
    1025               1 :       for ($i = $parents->length - 1; $i >= 0; --$i) {                                                          
    1026               1 :         $parentNode = $parents->item($i);                                                                       
    1027               1 :         if (empty($expr) || $this->_test($expr, $parentNode)) {                                                 
    1028               1 :           $result->_push($parentNode, TRUE);                                                                    
    1029               1 :         }                                                                                                       
    1030               1 :       }                                                                                                         
    1031               1 :     }                                                                                                           
    1032               1 :     return $result;                                                                                             
    1033                 :   }                                                                                                             
    1034                 :                                                                                                                 
    1035                 :   /**                                                                                                           
    1036                 :   * Get a set of elements containing the unique previous siblings of each of the matched set of elements.       
    1037                 :   *                                                                                                             
    1038                 :   * Like jQuerys prev() method but renamed for consistency with nextSiblings()                                  
    1039                 :   *                                                                                                             
    1040                 :   * @param string $expr XPath expression                                                                        
    1041                 :   * @access public                                                                                              
    1042                 :   * @return object FluentDOM                                                                                    
    1043                 :   */                                                                                                            
    1044                 :   public function prev($expr = NULL) {                                                                          
    1045               3 :     $result = $this->_spawn();                                                                                  
    1046               3 :     foreach ($this->_array as $node) {                                                                          
    1047               3 :       $previous = $node->previousSibling;                                                                       
    1048               3 :       while ($previous instanceof DOMNode && !$this->_isNode($previous)) {                                      
    1049               3 :         $previous = $previous->previousSibling;                                                                 
    1050               3 :       }                                                                                                         
    1051               3 :       if (!empty($previous)) {                                                                                  
    1052               3 :         if (empty($expr) || $this->_test($expr, $previous)) {                                                   
    1053               3 :           $result->_push($previous, TRUE);                                                                      
    1054               3 :         }                                                                                                       
    1055               3 :       }                                                                                                         
    1056               3 :     }                                                                                                           
    1057               3 :     return $result;                                                                                             
    1058                 :   }                                                                                                             
    1059                 :                                                                                                                 
    1060                 :   /**                                                                                                           
    1061                 :   * Find all sibling elements in front of the current element.                                                  
    1062                 :   *                                                                                                             
    1063                 :   * Like jQuerys prevAll() method but renamed for consistency with nextSiblings()                               
    1064                 :   *                                                                                                             
    1065                 :   * @param string $expr XPath expression                                                                        
    1066                 :   * @access public                                                                                              
    1067                 :   * @return object FluentDOM                                                                                    
    1068                 :   */                                                                                                            
    1069                 :   public function prevAll($expr = NULL) {                                                                       
    1070               1 :     $result = $this->_spawn();                                                                                  
    1071               1 :     foreach ($this->_array as $node) {                                                                          
    1072               1 :       $previous = $node->previousSibling;                                                                       
    1073               1 :       while ($previous instanceof DOMNode) {                                                                    
    1074               1 :         if ($this->_isNode($previous)) {                                                                        
    1075               1 :           if (empty($expr) || $this->_test($expr, $previous)) {                                                 
    1076               1 :             $result->_push($previous, TRUE);                                                                    
    1077               1 :           }                                                                                                     
    1078               1 :         }                                                                                                       
    1079               1 :         $previous = $previous->previousSibling;                                                                 
    1080               1 :       }                                                                                                         
    1081               1 :     }                                                                                                           
    1082               1 :     return $result;                                                                                             
    1083                 :   }                                                                                                             
    1084                 :                                                                                                                 
    1085                 :   /**                                                                                                           
    1086                 :   * Get a set of elements containing all of the unique siblings of each of the matched set of elements.         
    1087                 :   *                                                                                                             
    1088                 :   * @param string $expr XPath expression                                                                        
    1089                 :   * @access public                                                                                              
    1090                 :   * @return object FluentDOM                                                                                    
    1091                 :   */                                                                                                            
    1092                 :   public function siblings($expr = NULL) {                                                                      
    1093               1 :     $result = $this->_spawn();                                                                                  
    1094               1 :     foreach ($this->_array as $node) {                                                                          
    1095               1 :       if (isset($node->parentNode)) {                                                                           
    1096               1 :         $siblings = $node->parentNode->childNodes;                                                              
    1097               1 :         foreach ($node->parentNode->childNodes as $childNode) {                                                 
    1098               1 :           if ($this->_isNode($childNode) &&                                                                     
    1099               1 :               $childNode !== $node) {                                                                           
    1100               1 :             if (empty($expr) || $this->_test($expr, $childNode)) {                                              
    1101               1 :               $result->_push($childNode, TRUE);                                                                 
    1102               1 :             }                                                                                                   
    1103               1 :           }                                                                                                     
    1104               1 :         }                                                                                                       
    1105               1 :       }                                                                                                         
    1106               1 :     }                                                                                                           
    1107               1 :     return $result;                                                                                             
    1108                 :   }                                                                                                             
    1109                 :                                                                                                                 
    1110                 :   /*                                                                                                            
    1111                 :   * Traversing - Chaining                                                                                       
    1112                 :   */                                                                                                            
    1113                 :                                                                                                                 
    1114                 :   /**                                                                                                           
    1115                 :   * Add the previous selection to the current selection.                                                        
    1116                 :   *                                                                                                             
    1117                 :   * @access public                                                                                              
    1118                 :   * @return object FluentDOM                                                                                    
    1119                 :   */                                                                                                            
    1120                 :   public function andSelf() {                                                                                   
    1121               2 :     $result = $this->_spawn();                                                                                  
    1122               2 :     $result->_push($this->_array);                                                                              
    1123               2 :     $result->_push($this->_parent);                                                                             
    1124               2 :     return $result;                                                                                             
    1125                 :   }                                                                                                             
    1126                 :                                                                                                                 
    1127                 :   /**                                                                                                           
    1128                 :   * Revert the most recent traversing operation,                                                                
    1129                 :   * changing the set of matched elements to its previous state.                                                 
    1130                 :   *                                                                                                             
    1131                 :   * @access public                                                                                              
    1132                 :   * @return object FluentDOM                                                                                    
    1133                 :   */                                                                                                            
    1134                 :   public function end() {                                                                                       
    1135               1 :     if ($this->_parent instanceof FluentDOM) {                                                                  
    1136               1 :       return $this->_parent;                                                                                    
    1137                 :     } else {                                                                                                    
    1138               1 :       return $this;                                                                                             
    1139                 :     }                                                                                                           
    1140                 :   }                                                                                                             
    1141                 :                                                                                                                 
    1142                 :   /*                                                                                                            
    1143                 :   * Manipulation - Changing Contents                                                                            
    1144                 :   */                                                                                                            
    1145                 :                                                                                                                 
    1146                 :   /**                                                                                                           
    1147                 :   * Get or set the xml contents of the first matched element.                                                   
    1148                 :   *                                                                                                             
    1149                 :   * @param string $xml XML fragment                                                                             
    1150                 :   * @access public                                                                                              
    1151                 :   * @return string | object FluentDOM                                                                           
    1152                 :   */                                                                                                            
    1153                 :   public function xml($xml = NULL) {                                                                            
    1154               2 :     if (isset($xml)) {                                                                                          
    1155               1 :       if (!empty($xml)) {                                                                                       
    1156               1 :         $fragment = $this->_document->createDocumentFragment();                                                 
    1157               1 :         if ($fragment->appendXML($xml)) {                                                                       
    1158               1 :           foreach ($this->_array as $node) {                                                                    
    1159               1 :             $node->nodeValue = '';                                                                              
    1160               1 :             $node->appendChild($fragment->cloneNode(TRUE));                                                     
    1161               1 :           }                                                                                                     
    1162               1 :         }                                                                                                       
    1163               1 :       }                                                                                                         
    1164               1 :       return $this;                                                                                             
    1165                 :     } else {                                                                                                    
    1166               1 :       $result = '';                                                                                             
    1167               1 :       if (isset($this->_array[0])) {                                                                            
    1168               1 :         foreach ($this->_array[0]->childNodes as $childNode) {                                                  
    1169               1 :           if ($this->_isNode($childNode)) {                                                                     
    1170               1 :             $result .= $this->_document->saveXML($childNode);                                                   
    1171               1 :           }                                                                                                     
    1172               1 :         }                                                                                                       
    1173               1 :       }                                                                                                         
    1174               1 :       return $result;                                                                                           
    1175                 :     }                                                                                                           
    1176                 :   }                                                                                                             
    1177                 :                                                                                                                 
    1178                 :   /**                                                                                                           
    1179                 :   * Get the combined text contents of all matched elements or                                                   
    1180                 :   * set the text contents of all matched elements.                                                              
    1181                 :   *                                                                                                             
    1182                 :   * @param string $text                                                                                         
    1183                 :   * @access public                                                                                              
    1184                 :   * @return string | object FluentDOM                                                                           
    1185                 :   */                                                                                                            
    1186                 :   public function text($text = NULL) {                                                                          
    1187               4 :     if (isset($text)) {                                                                                         
    1188               2 :       foreach ($this->_array as $node) {                                                                        
    1189               2 :         $node->nodeValue = $text;                                                                               
    1190               2 :       }                                                                                                         
    1191               2 :       return $this;                                                                                             
    1192                 :     } else {                                                                                                    
    1193               2 :       $result = '';                                                                                             
    1194               2 :       foreach ($this->_array as $node) {                                                                        
    1195               2 :         $result .= $node->textContent;                                                                          
    1196               2 :       }                                                                                                         
    1197               2 :       return $result;                                                                                           
    1198                 :     }                                                                                                           
    1199                 :   }                                                                                                             
    1200                 :                                                                                                                 
    1201                 :   /*                                                                                                            
    1202                 :   * Manipulation - Inserting Inside                                                                             
    1203                 :   */                                                                                                            
    1204                 :                                                                                                                 
    1205                 :   /**                                                                                                           
    1206                 :   * Append content to the inside of every matched element.                                                      
    1207                 :   *                                                                                                             
    1208                 :   * @param string | object DOMNode | object FluentDOM $content DOMNode or DOMNodeList or xml fragment string    
    1209                 :   * @access public                                                                                              
    1210                 :   * @return string | object FluentDOM                                                                           
    1211                 :   */                                                                                                            
    1212                 :   public function append($content) {                                                                            
    1213               8 :     return $this->_insertChild($content, FALSE);                                                                
    1214                 :   }                                                                                                             
    1215                 :                                                                                                                 
    1216                 :   /**                                                                                                           
    1217                 :   * Append all of the matched elements to another, specified, set of elements.                                  
    1218                 :   * Returns all of the inserted elements.                                                                       
    1219                 :   *                                                                                                             
    1220                 :   * @param string | object DOMElement | object FluentDOM $expr XPath expression, element or list of elements    
    1221                 :   * @access public                                                                                              
    1222                 :   * @return object FluentDOM                                                                                    
    1223                 :   */                                                                                                            
    1224                 :   public function appendTo($expr) {                                                                             
    1225               1 :     return $this->_insertChildTo($expr, FALSE);                                                                 
    1226                 :   }                                                                                                             
    1227                 :                                                                                                                 
    1228                 :   /**                                                                                                           
    1229                 :   * Prepend content to the inside of every matched element.                                                     
    1230                 :   *                                                                                                             
    1231                 :   * @param string | object DOMNode | object FluentDOM $content DOMNode or DOMNodeList or xml fragment string    
    1232                 :   * @access public                                                                                              
    1233                 :   * @return string | object FluentDOM                                                                           
    1234                 :   */                                                                                                            
    1235                 :   public function prepend($content) {                                                                           
    1236               3 :     return $this->_insertChild($content, TRUE);                                                                 
    1237                 :   }                                                                                                             
    1238                 :                                                                                                                 
    1239                 :   /**                                                                                                           
    1240                 :   * Prepend all of the matched elements to another, specified, set of elements.                                 
    1241                 :   * Returns all of the inserted elements.                                                                       
    1242                 :   *                                                                                                             
    1243                 :   * @param string | object DOMElement | object FluentDOM $expr XPath expression, element or list of elements    
    1244                 :   * @access public                                                                                              
    1245                 :   * @return object FluentDOM list of all new elements                                                           
    1246                 :   */                                                                                                            
    1247                 :   public function prependTo($expr) {                                                                            
    1248               1 :     return $this->_insertChildTo($expr, TRUE);                                                                  
    1249                 :   }                                                                                                             
    1250                 :                                                                                                                 
    1251                 :   /**                                                                                                           
    1252                 :   * Insert content to the inside of every matched element.                                                      
    1253                 :   *                                                                                                             
    1254                 :   * @param string | object DOMNode | object FluentDOM $content DOMNode or DOMNodeList or xml fragment string    
    1255                 :   * @param boolean $first insert at first position (or last)                                                    
    1256                 :   * @access private                                                                                             
    1257                 :   * @return object FluentDOM                                                                                    
    1258                 :   */                                                                                                            
    1259                 :   private function _insertChild($content, $first) {                                                             
    1260              11 :     $result = $this->_spawn();                                                                                  
    1261              11 :     if (empty($this->_array) &&                                                                                 
    1262               3 :         $this->_useDocumentContext &&                                                                           
    1263              11 :         !isset($this->_document->documentElement)) {                                                            
    1264               3 :       $contentNode = $this->_getContentElement($content);                                                       
    1265               3 :       $result->_push(                                                                                           
    1266               3 :         $this->_document->appendChild(                                                                          
    1267                 :           $contentNode                                                                                          
    1268               3 :         )                                                                                                       
    1269               3 :       );                                                                                                        
    1270               3 :     } else {                                                                                                    
    1271               8 :       $contentNodes = $this->_getContentNodes($content, TRUE);                                                  
    1272               8 :       foreach ($this->_array as $node) {                                                                        
    1273               8 :         foreach ($contentNodes as $contentNode) {                                                               
    1274               8 :           $result->_push(                                                                                       
    1275               8 :             $node->insertBefore(                                                                                
    1276               8 :               $contentNode->cloneNode(TRUE),                                                                    
    1277               8 :               ($first && $node->hasChildNodes()) ? $node->childNodes->item(0) : NULL                            
    1278               8 :             )                                                                                                   
    1279               8 :           );                                                                                                    
    1280               8 :         }                                                                                                       
    1281               8 :       }                                                                                                         
    1282                 :     }                                                                                                           
    1283              11 :     return $result;                                                                                             
    1284                 :   }                                                                                                             
    1285                 :                                                                                                                 
    1286                 :   /**                                                                                                           
    1287                 :   * Insert all of the matched elements to another, specified, set of elements.                                  
    1288                 :   * Returns all of the inserted elements.                                                                       
    1289                 :   *                                                                                                             
    1290                 :   * @param string | object DOMElement | object FluentDOM $selector XPath expression, element or list of elements
    1291                 :   * @param boolean $first insert at first position (or last)                                                    
    1292                 :   * @access public                                                                                              
    1293                 :   * @return object FluentDOM                                                                                    
    1294                 :   */                                                                                                            
    1295                 :   private function _insertChildTo($selector, $first) {                                                          
    1296               2 :     $result = $this->_spawn();                                                                                  
    1297               2 :     $targets = $this->_getTargetNodes($selector);                                                               
    1298               2 :     if (!empty($targets)) {                                                                                     
    1299               2 :       foreach ($targets as $targetNode) {                                                                       
    1300               2 :         if ($targetNode instanceof DOMElement) {                                                                
    1301               2 :           foreach ($this->_array as $node) {                                                                    
    1302               2 :             $result->_push(                                                                                     
    1303               2 :               $targetNode->insertBefore(                                                                        
    1304               2 :                 $node->cloneNode(TRUE),                                                                         
    1305               1 :                 ($first && $targetNode->hasChildNodes())                                                        
    1306               2 :                   ? $targetNode->childNodes->item(0) : NULL                                                     
    1307               2 :               )                                                                                                 
    1308               2 :             );                                                                                                  
    1309               2 :           }                                                                                                     
    1310               2 :         }                                                                                                       
    1311               2 :         $this->_removeNodes($this->_array);                                                                     
    1312               2 :       }                                                                                                         
    1313               2 :     }                                                                                                           
    1314               2 :     return $result;                                                                                             
    1315                 :   }                                                                                                             
    1316                 :                                                                                                                 
    1317                 :   /*                                                                                                            
    1318                 :   * Manipulation - Inserting Outside                                                                            
    1319                 :   */                                                                                                            
    1320                 :                                                                                                                 
    1321                 :   /**                                                                                                           
    1322                 :   * Insert content after each of the matched elements.                                                          
    1323                 :   *                                                                                                             
    1324                 :   * @param $content                                                                                             
    1325                 :   * @access public                                                                                              
    1326                 :   * @return  object FluentDOM                                                                                   
    1327                 :   */                                                                                                            
    1328                 :   public function after($content) {                                                                             
    1329               1 :     $result = $this->_spawn();                                                                                  
    1330               1 :     if ($contentNodes = $this->_getContentNodes($content, TRUE)) {                                              
    1331               1 :       foreach ($this->_array as $node) {                                                                        
    1332               1 :         $beforeNode = $node->nextSibling;                                                                       
    1333               1 :         if (isset($node->parentNode)) {                                                                         
    1334               1 :           foreach ($contentNodes as $contentNode) {                                                             
    1335               1 :             $result->_push(                                                                                     
    1336               1 :               $node->parentNode->insertBefore(                                                                  
    1337               1 :                 $contentNode->cloneNode(TRUE),                                                                  
    1338                 :                 $beforeNode                                                                                     
    1339               1 :               )                                                                                                 
    1340               1 :             );                                                                                                  
    1341               1 :           }                                                                                                     
    1342               1 :         }                                                                                                       
    1343               1 :       }                                                                                                         
    1344               1 :     }                                                                                                           
    1345               1 :     return $result;                                                                                             
    1346                 :   }                                                                                                             
    1347                 :                                                                                                                 
    1348                 :   /**                                                                                                           
    1349                 :   * Insert content before each of the matched elements.                                                         
    1350                 :   *                                                                                                             
    1351                 :   * @param $content                                                                                             
    1352                 :   * @access public                                                                                              
    1353                 :   * @return object FluentDOM                                                                                    
    1354                 :   */                                                                                                            
    1355                 :   public function before($content) {                                                                            
    1356               1 :     $result = $this->_spawn();                                                                                  
    1357               1 :     if ($contentNodes = $this->_getContentNodes($content, TRUE)) {                                              
    1358               1 :       foreach ($this->_array as $node) {                                                                        
    1359               1 :         if (isset($node->parentNode)) {                                                                         
    1360               1 :           foreach ($contentNodes as $contentNode) {                                                             
    1361               1 :             $result->_push(                                                                                     
    1362               1 :               $node->parentNode->insertBefore(                                                                  
    1363               1 :                 $contentNode->cloneNode(TRUE),                                                                  
    1364                 :                 $node                                                                                           
    1365               1 :               )                                                                                                 
    1366               1 :             );                                                                                                  
    1367               1 :           }                                                                                                     
    1368               1 :         }                                                                                                       
    1369               1 :       }                                                                                                         
    1370               1 :     }                                                                                                           
    1371               1 :     return $result;                                                                                             
    1372                 :   }                                                                                                             
    1373                 :                                                                                                                 
    1374                 :   /**                                                                                                           
    1375                 :   * Insert all of the matched elements after another, specified, set of elements.                               
    1376                 :   *                                                                                                             
    1377                 :   * @param $selector                                                                                            
    1378                 :   * @access public                                                                                              
    1379                 :   * @return object FluentDOM                                                                                    
    1380                 :   */                                                                                                            
    1381                 :   public function insertAfter($selector) {                                                                      
    1382               1 :     $result = $this->_spawn();                                                                                  
    1383               1 :     $targets = $this->_getTargetNodes($selector);                                                               
    1384               1 :     if (!empty($targets)) {                                                                                     
    1385               1 :       foreach ($targets as $targetNode) {                                                                       
    1386               1 :         if ($this->_isNode($targetNode) && isset($targetNode->parentNode)) {                                    
    1387               1 :           $beforeNode = $targetNode->nextSibling;                                                               
    1388               1 :           foreach ($this->_array as $node) {                                                                    
    1389               1 :             $result->_push(                                                                                     
    1390               1 :               $targetNode->parentNode->insertBefore(                                                            
    1391               1 :                 $node->cloneNode(TRUE),                                                                         
    1392                 :                 $beforeNode                                                                                     
    1393               1 :               )                                                                                                 
    1394               1 :             );                                                                                                  
    1395               1 :           }                                                                                                     
    1396               1 :         }                                                                                                       
    1397               1 :         $this->_removeNodes($this->_array);                                                                     
    1398               1 :       }                                                                                                         
    1399               1 :     }                                                                                                           
    1400               1 :     return $result;                                                                                             
    1401                 :   }                                                                                                             
    1402                 :                                                                                                                 
    1403                 :   /**                                                                                                           
    1404                 :   * Insert all of the matched elements before another, specified, set of elements.                              
    1405                 :   *                                                                                                             
    1406                 :   * @param $selector                                                                                            
    1407                 :   * @access public                                                                                              
    1408                 :   * @return object FluentDOM                                                                                    
    1409                 :   */                                                                                                            
    1410                 :   public function insertBefore($selector) {                                                                     
    1411               1 :     $result = $this->_spawn();                                                                                  
    1412               1 :     $targets = $this->_getTargetNodes($selector);                                                               
    1413               1 :     if (!empty($targets)) {                                                                                     
    1414               1 :       foreach ($targets as $targetNode) {                                                                       
    1415               1 :         if ($this->_isNode($targetNode) && isset($targetNode->parentNode)) {                                    
    1416               1 :           foreach ($this->_array as $node) {                                                                    
    1417               1 :             $result->_push(                                                                                     
    1418               1 :               $targetNode->parentNode->insertBefore(                                                            
    1419               1 :                 $node->cloneNode(TRUE),                                                                         
    1420                 :                 $targetNode                                                                                     
    1421               1 :               )                                                                                                 
    1422               1 :             );                                                                                                  
    1423               1 :           }                                                                                                     
    1424               1 :         }                                                                                                       
    1425               1 :         $this->_removeNodes($this->_array);                                                                     
    1426               1 :       }                                                                                                         
    1427               1 :     }                                                                                                           
    1428               1 :     return $result;                                                                                             
    1429                 :   }                                                                                                             
    1430                 :                                                                                                                 
    1431                 :   /*                                                                                                            
    1432                 :   * Manipulation - Inserting Around                                                                             
    1433                 :   */                                                                                                            
    1434                 :                                                                                                                 
    1435                 :   /**                                                                                                           
    1436                 :   * Wrap $content around a set of elements                                                                      
    1437                 :   *                                                                                                             
    1438                 :   * @param array $elements                                                                                      
    1439                 :   * @param string | array | object DOMElement | object FluentDOM $content                                       
    1440                 :   * @access private                                                                                             
    1441                 :   * @return object FluentDOM                                                                                    
    1442                 :   */                                                                                                            
    1443                 :   private function _wrap($elements, $content) {                                                                 
    1444               6 :     $wrapperTemplate = $this->_getContentElement($content);                                                     
    1445               5 :     $result = array();                                                                                          
    1446               5 :     if ($wrapperTemplate instanceof DOMElement) {                                                               
    1447               5 :       $simple = FALSE;                                                                                          
    1448               5 :       foreach ($elements as $node) {                                                                            
    1449               5 :         $wrapper = $wrapperTemplate->cloneNode(TRUE);                                                           
    1450               5 :         if (!$simple) {                                                                                         
    1451               5 :           $targets = $this->_match('.//*[count(*) = 0]', $wrapper);                                             
    1452               5 :         }                                                                                                       
    1453               5 :         if ($simple || $targets->length == 0) {                                                                 
    1454               4 :           $target = $wrapper;                                                                                   
    1455               4 :           $simple = TRUE;                                                                                       
    1456               4 :         } else {                                                                                                
    1457               1 :           $target = $targets->item(0);                                                                          
    1458                 :         }                                                                                                       
    1459               5 :         if (isset($node->parentNode)) {                                                                         
    1460               5 :           $node->parentNode->insertBefore($wrapper, $node);                                                     
    1461               5 :         }                                                                                                       
    1462               5 :         $target->appendChild($node);                                                                            
    1463               5 :         $result[] = $node;                                                                                      
    1464               5 :       }                                                                                                         
    1465               5 :     }                                                                                                           
    1466               5 :     return $result;                                                                                             
    1467                 :   }                                                                                                             
    1468                 :                                                                                                                 
    1469                 :   /**                                                                                                           
    1470                 :   * Wrap each matched element with the specified content.                                                       
    1471                 :   *                                                                                                             
    1472                 :   * If $content contains several elements the first one is used                                                 
    1473                 :   *                                                                                                             
    1474                 :   * @param string | array | object DOMElement | object FluentDOM $content                                       
    1475                 :   * @access public                                                                                              
    1476                 :   * @return object FluentDOM                                                                                    
    1477                 :   */                                                                                                            
    1478                 :   public function wrap($content) {                                                                              
    1479               5 :     $result = $this->_spawn();                                                                                  
    1480               5 :     $result->_push($this->_wrap($this->_array, $content));                                                      
    1481               4 :     return $result;                                                                                             
    1482                 :   }                                                                                                             
    1483                 :                                                                                                                 
    1484                 :   /**                                                                                                           
    1485                 :   * Wrap al matched elements with the specified content                                                         
    1486                 :   *                                                                                                             
    1487                 :   * If the matched elemetns are not siblings, wrap each group of siblings.                                      
    1488                 :   *                                                                                                             
    1489                 :   * @param string | array | object DOMElement | object FluentDOM $content                                       
    1490                 :   * @access public                                                                                              
    1491                 :   * @return object FluentDOM                                                                                    
    1492                 :   */                                                                                                            
    1493                 :   public function wrapAll($content) {                                                                           
    1494               2 :     $result = $this->_spawn();                                                                                  
    1495               2 :     $current = NULL;                                                                                            
    1496               2 :     $counter = 0;                                                                                               
    1497               2 :     $groups = array();                                                                                          
    1498                 :     //group elements by previous node - ignore whitespace text nodes                                            
    1499               2 :     foreach ($this->_array as $node) {                                                                          
    1500               2 :       $previous = $node->previousSibling;                                                                       
    1501               2 :       while ($previous instanceof DOMText && $previous->isWhitespaceInElementContent()) {                       
    1502               2 :         $previous = $previous->previousSibling;                                                                 
    1503               2 :       }                                                                                                         
    1504               2 :       if ($previous !== $current) {                                                                             
    1505               2 :         $counter++;                                                                                             
    1506               2 :       }                                                                                                         
    1507               2 :       $groups[$counter][] = $node;                                                                              
    1508               2 :       $current = $node;                                                                                         
    1509               2 :     }                                                                                                           
    1510               2 :     if (count($groups) > 0) {                                                                                   
    1511               2 :       $wrapperTemplate = $this->_getContentElement($content);                                                   
    1512               2 :       $simple = FALSE;                                                                                          
    1513               2 :       foreach ($groups as $group) {                                                                             
    1514               2 :         if (isset($group[0])) {                                                                                 
    1515               2 :           $node = $group[0];                                                                                    
    1516               2 :           $wrapper = $wrapperTemplate->cloneNode(TRUE);                                                         
    1517               2 :           if (!$simple) {                                                                                       
    1518               2 :             $targets = $this->_match('.//*[count(*) = 0]', $wrapper);                                           
    1519               2 :           }                                                                                                     
    1520               2 :           if ($simple || $targets->length == 0) {                                                               
    1521               1 :             $target = $wrapper;                                                                                 
    1522               1 :             $simple = TRUE;                                                                                     
    1523               1 :           } else {                                                                                              
    1524               1 :             $target = $targets->item(0);                                                                        
    1525                 :           }                                                                                                     
    1526               2 :           if (isset($node->parentNode)) {                                                                       
    1527               2 :             $node->parentNode->insertBefore($wrapper, $node);                                                   
    1528               2 :           }                                                                                                     
    1529               2 :           foreach ($group as $node) {                                                                           
    1530               2 :             $target->appendChild($node);                                                                        
    1531               2 :           }                                                                                                     
    1532               2 :           $result->_push($node);                                                                                
    1533               2 :         }                                                                                                       
    1534               2 :       }                                                                                                         
    1535               2 :     }                                                                                                           
    1536               2 :     return $result;                                                                                             
    1537                 :   }                                                                                                             
    1538                 :                                                                                                                 
    1539                 :   /**                                                                                                           
    1540                 :   * Wrap the inner child contents of each matched element                                                       
    1541                 :   * (including text nodes) with an XML structure.                                                               
    1542                 :   *                                                                                                             
    1543                 :   * @param string | array | object DOMElement | object FluentDOM $content                                       
    1544                 :   * @access public                                                                                              
    1545                 :   * @return FluentDOM                                                                                           
    1546                 :   */                                                                                                            
    1547                 :   public function wrapInner($content) {                                                                         
    1548               1 :     $result = $this->_spawn();                                                                                  
    1549               1 :     $elements = array();                                                                                        
    1550               1 :     foreach ($this->_array as $node) {                                                                          
    1551               1 :       foreach ($node->childNodes as $childNode) {                                                               
    1552               1 :         if ($this->_isNode($childNode)) {                                                                       
    1553               1 :           $elements[] = $childNode;                                                                             
    1554               1 :         }                                                                                                       
    1555               1 :       }                                                                                                         
    1556               1 :     }                                                                                                           
    1557               1 :     $result->_push($this->_wrap($elements, $content));                                                          
    1558               1 :     return $result;                                                                                             
    1559                 :   }                                                                                                             
    1560                 :                                                                                                                 
    1561                 :   /*                                                                                                            
    1562                 :   * Manipulation - Replacing                                                                                    
    1563                 :   */                                                                                                            
    1564                 :                                                                                                                 
    1565                 :   /**                                                                                                           
    1566                 :   * Replaces all matched elements with the specified HTML or DOM elements.                                      
    1567                 :   * This returns the JQuery element that was just replaced,                                                     
    1568                 :   * which has been removed from the DOM.                                                                        
    1569                 :   *                                                                                                             
    1570                 :   * @param $content                                                                                             
    1571                 :   * @access public                                                                                              
    1572                 :   * @return object FluentDOM                                                                                    
    1573                 :   */                                                                                                            
    1574                 :   public function replaceWith($content) {                                                                       
    1575               1 :     $contentNodes = $this->_getContentNodes($content);                                                          
    1576               1 :     foreach ($this->_array as $node) {                                                                          
    1577               1 :       if (isset($node->parentNode)) {                                                                           
    1578               1 :         foreach ($contentNodes as $contentNode) {                                                               
    1579               1 :           $node->parentNode->insertBefore(                                                                      
    1580               1 :             $contentNode->cloneNode(TRUE),                                                                      
    1581                 :             $node                                                                                               
    1582               1 :           );                                                                                                    
    1583               1 :         }                                                                                                       
    1584               1 :       }                                                                                                         
    1585               1 :     }                                                                                                           
    1586               1 :     $this->_removeNodes($this->_array);                                                                         
    1587               1 :     return $this;                                                                                               
    1588                 :   }                                                                                                             
    1589                 :                                                                                                                 
    1590                 :   /**                                                                                                           
    1591                 :   * Replaces the elements matched by the specified selector with the matched elements.                          
    1592                 :   *                                                                                                             
    1593                 :   * @param $selector                                                                                            
    1594                 :   * @access public                                                                                              
    1595                 :   * @return object FluentDOM                                                                                    
    1596                 :   */                                                                                                            
    1597                 :   public function replaceAll($selector) {                                                                       
    1598               8 :     $result = $this->_spawn();                                                                                  
    1599               8 :     $targetNodes = $this->_getTargetNodes($selector);                                                           
    1600               7 :     foreach ($targetNodes as $targetNode) {                                                                     
    1601               7 :       if (isset($targetNode->parentNode)) {                                                                     
    1602               7 :         foreach ($this->_array as $node) {                                                                      
    1603               7 :           $result->_push(                                                                                       
    1604               7 :             $targetNode->parentNode->insertBefore(                                                              
    1605               7 :               $node->cloneNode(TRUE),                                                                           
    1606                 :               $targetNode                                                                                       
    1607               7 :             )                                                                                                   
    1608               7 :           );                                                                                                    
    1609               7 :         }                                                                                                       
    1610               7 :       }                                                                                                         
    1611               7 :     }                                                                                                           
    1612               7 :     $this->_removeNodes($targetNodes);                                                                          
    1613               7 :     $this->_removeNodes($this->_array);                                                                         
    1614               7 :     return $result;                                                                                             
    1615                 :   }                                                                                                             
    1616                 :                                                                                                                 
    1617                 :   /*                                                                                                            
    1618                 :   * Manipulation - Removing                                                                                     
    1619                 :   */                                                                                                            
    1620                 :                                                                                                                 
    1621                 :   /**                                                                                                           
    1622                 :   * this is the empty() method - but because empty                                                              
    1623                 :   * is a reserved word we can no declare it directly                                                            
    1624                 :   * @see __call                                                                                                 
    1625                 :   *                                                                                                             
    1626                 :   * @access private                                                                                             
    1627                 :   * @return object FluentDOM                                                                                    
    1628                 :   */                                                                                                            
    1629                 :   private function _emptyNodes() {                                                                              
    1630               1 :     foreach ($this->_array as $node) {                                                                          
    1631               1 :       if ($node instanceof DOMElement ||                                                                        
    1632               1 :           $node instanceof DOMText) {                                                                           
    1633               1 :         $node->nodeValue = '';                                                                                  
    1634               1 :       }                                                                                                         
    1635               1 :     }                                                                                                           
    1636               1 :     return $this;                                                                                               
    1637                 :   }                                                                                                             
    1638                 :                                                                                                                 
    1639                 :   /**                                                                                                           
    1640                 :   * Removes all matched elements from the DOM.                                                                  
    1641                 :   *                                                                                                             
    1642                 :   * @param string $expr XPath expression                                                                        
    1643                 :   * @access public                                                                                              
    1644                 :   * @return object FluentDOM removed elements                                                                   
    1645                 :   */                                                                                                            
    1646                 :   public function remove($expr = NULL) {                                                                        
    1647               1 :     $result = $this->_spawn();                                                                                  
    1648               1 :     foreach ($this->_array as $node) {                                                                          
    1649               1 :       if (isset($node->parentNode)) {                                                                           
    1650               1 :         if (empty($expr) || $this->test($expr, $node)) {                                                        
    1651               1 :           $result->_push($node->parentNode->removeChild($node));                                                
    1652               1 :         }                                                                                                       
    1653               1 :       }                                                                                                         
    1654               1 :     }                                                                                                           
    1655               1 :     return $result;                                                                                             
    1656                 :   }                                                                                                             
    1657                 :                                                                                                                 
    1658                 :   /*                                                                                                            
    1659                 :   * Manipulation - Creation                                                                                     
    1660                 :   */                                                                                                            
    1661                 :                                                                                                                 
    1662                 :   /**                                                                                                           
    1663                 :   * create nodes list from content, if $content contains node(s)                                                
    1664                 :   * from another document the are imported.                                                                     
    1665                 :   *                                                                                                             
    1666                 :   * @param $content                                                                                             
    1667                 :   * @access public                                                                                              
    1668                 :   * @return object FluentDOM                                                                                    
    1669                 :   */                                                                                                            
    1670                 :   public function node($content) {                                                                              
    1671               9 :     $result = $this->_spawn();                                                                                  
    1672               9 :     $result->_push($this->_getContentNodes($content));                                                          
    1673               6 :     return $result;                                                                                             
    1674                 :   }                                                                                                             
    1675                 :                                                                                                                 
    1676                 :   /*                                                                                                            
    1677                 :   * Manipulation - Copying                                                                                      
    1678                 :   */                                                                                                            
    1679                 :                                                                                                                 
    1680                 :   /**                                                                                                           
    1681                 :   * Clone matched DOM Elements and select the clones.                                                           
    1682                 :   *                                                                                                             
    1683                 :   * @access private                                                                                             
    1684                 :   * @return object FluentDOM                                                                                    
    1685                 :   */                                                                                                            
    1686                 :   private function _cloneNodes() {                                                                              
    1687               1 :     $result = $this->_spawn();                                                                                  
    1688               1 :     foreach ($this->_array as $node) {                                                                          
    1689               1 :       $result->_push($node->cloneNode(TRUE));                                                                   
    1690               1 :     }                                                                                                           
    1691               1 :     return $result;                                                                                             
    1692                 :   }                                                                                                             
    1693                 :                                                                                                                 
    1694                 :   /*                                                                                                            
    1695                 :   * Attributes - General                                                                                        
    1696                 :   */                                                                                                            
    1697                 :                                                                                                                 
    1698                 :   /**                                                                                                           
    1699                 :   * Access a property on the first matched element or set the attribute(s) of all matched elements              
    1700                 :   *                                                                                                             
    1701                 :   * @param string | array $expr attribute name or attribute list                                                
    1702                 :   * @param callback | string $value function callback or value                                                  
    1703                 :   * @access public                                                                                              
    1704                 :   * @return string | object FluentDOM attribute value or $this                                                  
    1705                 :   */                                                                                                            
    1706                 :   public function attr($attribute, $value = NULL) {                                                             
    1707              18 :     if (is_array($attribute) && count($attribute) > 0) {                                                        
    1708                 :       //expr is an array of attributes and values - set on each element                                         
    1709               1 :       foreach ($attribute as $key => $value) {                                                                  
    1710               1 :         if ($this->_isQName($key)) {