[ Index ] |
|
Code source de Symfony 1.0.0 |
1 <?php 2 3 /* 4 * This file is part of the symfony package. 5 * (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com> 6 * 7 * For the full copyright and license information, please view the LICENSE 8 * file that was distributed with this source code. 9 */ 10 11 /** 12 * sfDomCssSelector allows to navigate a DOM with CSS selector. 13 * 14 * based on getElementsBySelector version 0.4 - Simon Willison, March 25th 2003 15 * http://simon.incutio.com/archive/2003/03/25/getElementsBySelector 16 * 17 * @package symfony 18 * @subpackage util 19 * @author Fabien Potencier <fabien.potencier@symfony-project.com> 20 * @version SVN: $Id: sfDomCssSelector.class.php 3053 2006-12-16 16:01:30Z fabien $ 21 */ 22 class sfDomCssSelector 23 { 24 protected $dom = null; 25 26 public function __construct($dom) 27 { 28 $this->dom = $dom; 29 } 30 31 public function getTexts($selector) 32 { 33 $texts = array(); 34 foreach ($this->getElements($selector) as $element) 35 { 36 $texts[] = $element->nodeValue; 37 } 38 39 return $texts; 40 } 41 42 public function getElements($selector) 43 { 44 $all_nodes = array(); 45 foreach ($this->tokenize_selectors($selector) as $selector) 46 { 47 $nodes = array($this->dom); 48 foreach ($this->tokenize($selector) as $token) 49 { 50 $combinator = $token['combinator']; 51 $token = trim($token['name']); 52 $pos = strpos($token, '#'); 53 if (false !== $pos && preg_match('/^[A-Za-z0-9]*$/', substr($token, 0, $pos))) 54 { 55 // Token is an ID selector 56 $tagName = substr($token, 0, $pos); 57 $id = substr($token, $pos + 1); 58 $xpath = new DomXPath($this->dom); 59 $element = $xpath->query(sprintf("//*[@id = '%s']", $id))->item(0); 60 if (!$element || ($tagName && strtolower($element->nodeName) != $tagName)) 61 { 62 // tag with that ID not found 63 return array(); 64 } 65 66 // Set nodes to contain just this element 67 $nodes = array($element); 68 69 continue; // Skip to next token 70 } 71 72 $pos = strpos($token, '.'); 73 if (false !== $pos && preg_match('/^[A-Za-z0-9]*$/', substr($token, 0, $pos))) 74 { 75 // Token contains a class selector 76 $tagName = substr($token, 0, $pos); 77 if (!$tagName) 78 { 79 $tagName = '*'; 80 } 81 $className = substr($token, $pos + 1); 82 83 // Get elements matching tag, filter them for class selector 84 $founds = $this->getElementsByTagName($nodes, $tagName, $combinator); 85 $nodes = array(); 86 foreach ($founds as $found) 87 { 88 if (preg_match('/\b'.$className.'\b/', $found->getAttribute('class'))) 89 { 90 $nodes[] = $found; 91 } 92 } 93 94 continue; // Skip to next token 95 } 96 97 // Code to deal with attribute selectors 98 if (preg_match('/^(\w*)(\[.+\])$/', $token, $matches)) 99 { 100 $tagName = $matches[1] ? $matches[1] : '*'; 101 preg_match_all('/ 102 \[ 103 (\w+) # attribute 104 ([=~\|\^\$\*]?) # modifier (optional) 105 =? # equal (optional) 106 ( 107 "([^"]*)" # quoted value (optional) 108 | 109 ([^\]]*) # non quoted value (optional) 110 ) 111 \] 112 /x', $matches[2], $matches, PREG_SET_ORDER); 113 114 // Grab all of the tagName elements within current node 115 $founds = $this->getElementsByTagName($nodes, $tagName, $combinator); 116 $nodes = array(); 117 foreach ($founds as $found) 118 { 119 $ok = false; 120 foreach ($matches as $match) 121 { 122 $attrName = $match[1]; 123 $attrOperator = $match[2]; 124 $attrValue = $match[4]; 125 126 switch ($attrOperator) 127 { 128 case '=': // Equality 129 $ok = $found->getAttribute($attrName) == $attrValue; 130 break; 131 case '~': // Match one of space seperated words 132 $ok = preg_match('/\b'.preg_quote($attrValue, '/').'\b/', $found->getAttribute($attrName)); 133 break; 134 case '|': // Match start with value followed by optional hyphen 135 $ok = preg_match('/^'.preg_quote($attrValue, '/').'-?/', $found->getAttribute($attrName)); 136 break; 137 case '^': // Match starts with value 138 $ok = 0 === strpos($found->getAttribute($attrName), $attrValue); 139 break; 140 case '$': // Match ends with value 141 $ok = $attrValue == substr($found->getAttribute($attrName), -strlen($attrValue)); 142 break; 143 case '*': // Match ends with value 144 $ok = false !== strpos($found->getAttribute($attrName), $attrValue); 145 break; 146 default : 147 // Just test for existence of attribute 148 $ok = $found->hasAttribute($attrName); 149 } 150 151 if (false == $ok) 152 { 153 break; 154 } 155 } 156 157 if ($ok) 158 { 159 $nodes[] = $found; 160 } 161 } 162 163 continue; // Skip to next token 164 } 165 166 // If we get here, token is JUST an element (not a class or ID selector) 167 $nodes = $this->getElementsByTagName($nodes, $token, $combinator); 168 } 169 170 foreach ($nodes as $node) 171 { 172 if (!$node->getAttribute('sf_matched')) 173 { 174 $node->setAttribute('sf_matched', true); 175 $all_nodes[] = $node; 176 } 177 } 178 } 179 180 foreach ($all_nodes as $node) 181 { 182 $node->removeAttribute('sf_matched'); 183 } 184 185 return $all_nodes; 186 } 187 188 protected function getElementsByTagName($nodes, $tagName, $combinator = ' ') 189 { 190 $founds = array(); 191 foreach ($nodes as $node) 192 { 193 switch ($combinator) 194 { 195 case ' ': 196 foreach ($node->getElementsByTagName($tagName) as $element) 197 { 198 $founds[] = $element; 199 } 200 break; 201 case '>': 202 foreach ($node->childNodes as $element) 203 { 204 if ($tagName == $element->nodeName) 205 { 206 $founds[] = $element; 207 } 208 } 209 break; 210 case '+': 211 $element = $node->childNodes->item(0); 212 if ($element && $tagName == $element->nodeName) 213 { 214 $founds[] = $element; 215 } 216 break; 217 } 218 } 219 220 return $founds; 221 } 222 223 protected function tokenize_selectors($selector) 224 { 225 // split tokens by , except in an attribute selector 226 $tokens = array(); 227 $quoted = false; 228 $token = ''; 229 for ($i = 0, $max = strlen($selector); $i < $max; $i++) 230 { 231 if (',' == $selector[$i] && !$quoted) 232 { 233 $tokens[] = trim($token); 234 $token = ''; 235 } 236 else if ('"' == $selector[$i]) 237 { 238 $token .= $selector[$i]; 239 $quoted = $quoted ? false : true; 240 } 241 else 242 { 243 $token .= $selector[$i]; 244 } 245 } 246 if ($token) 247 { 248 $tokens[] = trim($token); 249 } 250 251 return $tokens; 252 } 253 254 protected function tokenize($selector) 255 { 256 // split tokens by space except if space is in an attribute selector 257 $tokens = array(); 258 $combinators = array(' ', '>', '+'); 259 $quoted = false; 260 $token = array('combinator' => ' ', 'name' => ''); 261 for ($i = 0, $max = strlen($selector); $i < $max; $i++) 262 { 263 if (in_array($selector[$i], $combinators) && !$quoted) 264 { 265 // remove all whitespaces around the combinator 266 $combinator = $selector[$i]; 267 while (in_array($selector[$i + 1], $combinators)) 268 { 269 if (' ' != $selector[++$i]) 270 { 271 $combinator = $selector[$i]; 272 } 273 } 274 275 $tokens[] = $token; 276 $token = array('combinator' => $combinator, 'name' => ''); 277 } 278 else if ('"' == $selector[$i]) 279 { 280 $token['name'] .= $selector[$i]; 281 $quoted = $quoted ? false : true; 282 } 283 else 284 { 285 $token['name'] .= $selector[$i]; 286 } 287 } 288 if ($token['name']) 289 { 290 $tokens[] = $token; 291 } 292 293 return $tokens; 294 } 295 }
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Fri Mar 16 22:42:14 2007 | par Balluche grâce à PHPXref 0.7 |