Package cssutils :: Package css :: Module selector
[hide private]
[frames] | no frames]

Source Code for Module cssutils.css.selector

  1  """Selector is a single Selector of a CSSStyleRule SelectorList. 
  2   
  3  Partly implements 
  4      http://www.w3.org/TR/css3-selectors/ 
  5   
  6  TODO 
  7      - .contains(selector) 
  8      - .isSubselector(selector) 
  9  """ 
 10  __all__ = ['Selector'] 
 11  __docformat__ = 'restructuredtext' 
 12  __author__ = '$LastChangedBy: cthedot $' 
 13  __date__ = '$LastChangedDate: 2008-02-02 23:54:52 +0100 (Sa, 02 Feb 2008) $' 
 14  __version__ = '$LastChangedRevision: 977 $' 
 15   
 16  import xml.dom 
 17  import cssutils 
 18  from cssutils.util import _SimpleNamespaces 
 19   
20 -class Selector(cssutils.util.Base2):
21 """ 22 (cssutils) a single selector in a SelectorList of a CSSStyleRule 23 24 Properties 25 ========== 26 element 27 Effective element target of this selector 28 parentList: of type SelectorList, readonly 29 The SelectorList that contains this selector or None if this 30 Selector is not attached to a SelectorList. 31 selectorText 32 textual representation of this Selector 33 seq 34 sequence of Selector parts including comments 35 specificity (READONLY) 36 tuple of (a, b, c, d) where: 37 38 a 39 presence of style in document, always 0 if not used on a document 40 b 41 number of ID selectors 42 c 43 number of .class selectors 44 d 45 number of Element (type) selectors 46 47 wellformed 48 if this selector is wellformed regarding the Selector spec 49 50 Format 51 ====== 52 :: 53 54 # implemented in SelectorList 55 selectors_group 56 : selector [ COMMA S* selector ]* 57 ; 58 59 selector 60 : simple_selector_sequence [ combinator simple_selector_sequence ]* 61 ; 62 63 combinator 64 /* combinators can be surrounded by white space */ 65 : PLUS S* | GREATER S* | TILDE S* | S+ 66 ; 67 68 simple_selector_sequence 69 : [ type_selector | universal ] 70 [ HASH | class | attrib | pseudo | negation ]* 71 | [ HASH | class | attrib | pseudo | negation ]+ 72 ; 73 74 type_selector 75 : [ namespace_prefix ]? element_name 76 ; 77 78 namespace_prefix 79 : [ IDENT | '*' ]? '|' 80 ; 81 82 element_name 83 : IDENT 84 ; 85 86 universal 87 : [ namespace_prefix ]? '*' 88 ; 89 90 class 91 : '.' IDENT 92 ; 93 94 attrib 95 : '[' S* [ namespace_prefix ]? IDENT S* 96 [ [ PREFIXMATCH | 97 SUFFIXMATCH | 98 SUBSTRINGMATCH | 99 '=' | 100 INCLUDES | 101 DASHMATCH ] S* [ IDENT | STRING ] S* 102 ]? ']' 103 ; 104 105 pseudo 106 /* '::' starts a pseudo-element, ':' a pseudo-class */ 107 /* Exceptions: :first-line, :first-letter, :before and :after. */ 108 /* Note that pseudo-elements are restricted to one per selector and */ 109 /* occur only in the last simple_selector_sequence. */ 110 : ':' ':'? [ IDENT | functional_pseudo ] 111 ; 112 113 functional_pseudo 114 : FUNCTION S* expression ')' 115 ; 116 117 expression 118 /* In CSS3, the expressions are identifiers, strings, */ 119 /* or of the form "an+b" */ 120 : [ [ PLUS | '-' | DIMENSION | NUMBER | STRING | IDENT ] S* ]+ 121 ; 122 123 negation 124 : NOT S* negation_arg S* ')' 125 ; 126 127 negation_arg 128 : type_selector | universal | HASH | class | attrib | pseudo 129 ; 130 131 """
132 - def __init__(self, selectorText=None, parentList=None, 133 readonly=False):
134 """ 135 :Parameters: 136 selectorText 137 initial value of this selector 138 parentList 139 a SelectorList 140 readonly 141 default to False 142 """ 143 super(Selector, self).__init__() 144 145 self.__namespaces = _SimpleNamespaces() 146 self._element = None 147 self._parent = parentList 148 self._specificity = (0, 0, 0, 0) 149 self.wellformed = False 150 151 if selectorText: 152 self.selectorText = selectorText 153 154 self._readonly = readonly
155
156 - def __getNamespaces(self):
157 "uses own namespaces if not attached to a sheet, else the sheet's ones" 158 try: 159 return self._parent.parentRule.parentStyleSheet.namespaces 160 except AttributeError: 161 return self.__namespaces
162 163 _namespaces = property(__getNamespaces, doc="""if this Selector is attached 164 to a CSSStyleSheet the namespaces of that sheet are mirrored here. 165 While the Selector (or parent SelectorList or parentRule(s) of that are 166 not attached a own dict of {prefix: namespaceURI} is used.""") 167 168 169 element = property(lambda self: self._element, 170 doc=u"Effective element target of this selector.") 171 172 parentList = property(lambda self: self._parent, 173 doc="(DOM) The SelectorList that contains this Selector or\ 174 None if this Selector is not attached to a SelectorList.") 175
176 - def _getSelectorText(self):
177 """ 178 returns serialized format 179 """ 180 return cssutils.ser.do_css_Selector(self)
181
182 - def _setSelectorText(self, selectorText):
183 """ 184 :param selectorText: 185 parsable string or a tuple of (selectorText, dict-of-namespaces). 186 Given namespaces are ignored if this object is attached to a 187 CSSStyleSheet! 188 189 :Exceptions: 190 - `NAMESPACE_ERR`: (self) 191 Raised if the specified selector uses an unknown namespace 192 prefix. 193 - `SYNTAX_ERR`: (self) 194 Raised if the specified CSS string value has a syntax error 195 and is unparsable. 196 - `NO_MODIFICATION_ALLOWED_ERR`: (self) 197 Raised if this rule is readonly. 198 """ 199 self._checkReadonly() 200 201 # might be (selectorText, namespaces) 202 selectorText, namespaces = self._splitNamespacesOff(selectorText) 203 try: 204 # uses parent stylesheets namespaces if available, otherwise given ones 205 namespaces = self.parentList.parentRule.parentStyleSheet.namespaces 206 except AttributeError: 207 pass 208 tokenizer = self._tokenize2(selectorText) 209 if not tokenizer: 210 self._log.error(u'Selector: No selectorText given.') 211 else: 212 # prepare tokenlist: 213 # "*" -> type "universal" 214 # "*"|IDENT + "|" -> combined to "namespace_prefix" 215 # "|" -> type "namespace_prefix" 216 # "." + IDENT -> combined to "class" 217 # ":" + IDENT, ":" + FUNCTION -> pseudo-class 218 # FUNCTION "not(" -> negation 219 # "::" + IDENT, "::" + FUNCTION -> pseudo-element 220 tokens = [] 221 for t in tokenizer: 222 typ, val, lin, col = t 223 if val == u':' and tokens and\ 224 self._tokenvalue(tokens[-1]) == ':': 225 # combine ":" and ":" 226 tokens[-1] = (typ, u'::', lin, col) 227 228 elif typ == 'IDENT' and tokens\ 229 and self._tokenvalue(tokens[-1]) == u'.': 230 # class: combine to .IDENT 231 tokens[-1] = ('class', u'.'+val, lin, col) 232 elif typ == 'IDENT' and tokens and \ 233 self._tokenvalue(tokens[-1]).startswith(u':') and\ 234 not self._tokenvalue(tokens[-1]).endswith(u'('): 235 # pseudo-X: combine to :IDENT or ::IDENT but not ":a(" + "b" 236 if self._tokenvalue(tokens[-1]).startswith(u'::'): 237 t = 'pseudo-element' 238 else: 239 t = 'pseudo-class' 240 tokens[-1] = (t, self._tokenvalue(tokens[-1])+val, lin, col) 241 242 elif typ == 'FUNCTION' and val == u'not(' and tokens and \ 243 u':' == self._tokenvalue(tokens[-1]): 244 tokens[-1] = ('negation', u':' + val, lin, tokens[-1][3]) 245 elif typ == 'FUNCTION' and tokens\ 246 and self._tokenvalue(tokens[-1]).startswith(u':'): 247 # pseudo-X: combine to :FUNCTION( or ::FUNCTION( 248 if self._tokenvalue(tokens[-1]).startswith(u'::'): 249 t = 'pseudo-element' 250 else: 251 t = 'pseudo-class' 252 tokens[-1] = (t, self._tokenvalue(tokens[-1])+val, lin, col) 253 254 elif val == u'*' and tokens and\ 255 self._type(tokens[-1]) == 'namespace_prefix' and\ 256 self._tokenvalue(tokens[-1]).endswith(u'|'): 257 # combine prefix|* 258 tokens[-1] = ('universal', self._tokenvalue(tokens[-1])+val, 259 lin, col) 260 elif val == u'*': 261 # universal: "*" 262 tokens.append(('universal', val, lin, col)) 263 264 elif val == u'|' and tokens and\ 265 self._type(tokens[-1]) in ('IDENT', 'universal') and\ 266 self._tokenvalue(tokens[-1]).find(u'|') == -1: 267 # namespace_prefix: "IDENT|" or "*|" 268 tokens[-1] = ('namespace_prefix', 269 self._tokenvalue(tokens[-1])+u'|', lin, col) 270 elif val == u'|': 271 # namespace_prefix: "|" 272 tokens.append(('namespace_prefix', val, lin, col)) 273 274 else: 275 tokens.append(t) 276 277 # TODO: back to generator but not elegant at all! 278 tokenizer = (t for t in tokens) 279 280 # for closures: must be a mutable 281 new = {'context': [''], # stack of: 'attrib', 'negation', 'pseudo' 282 'element': None, 283 '_PREFIX': None, 284 'specificity': [0, 0, 0, 0], # mutable, finally a tuple! 285 'wellformed': True 286 } 287 # used for equality checks and setting of a space combinator 288 S = u' ' 289 290 def append(seq, val, typ=None, line=-1, col=0, context=None): 291 """ 292 appends to seq 293 294 namespace_prefix, IDENT will be combined to a tuple 295 (prefix, name) where prefix might be None, the empty string 296 or a prefix. 297 298 Saved are also: 299 - specificity definition: style, id, class, type 300 - element: the element this Selector is for 301 """ 302 if typ == '_PREFIX': 303 # SPECIAL TYPE: save prefix for combination with next 304 new['_PREFIX'] = val[:-1] 305 return 306 307 if new['_PREFIX'] is not None: 308 # as saved from before 309 prefix = new['_PREFIX'] 310 new['_PREFIX'] = None # reset 311 elif typ == 'universal' and '|' in val: 312 # val == *|* or prefix|* 313 prefix, val = val.split('|') 314 else: 315 prefix = None 316 317 # TODO: CHECK IF THIS IS REALLY OK! 318 if typ.endswith('-selector') or typ == 'universal': 319 # val is (namespaceprefix, name) tuple 320 if prefix == u'*': 321 # *|name 322 namespaceURI = cssutils._ANYNS 323 elif prefix is None: 324 # name which has effectively namespace u'' (?) 325 namespaceURI = namespaces.get(u'', None) 326 elif prefix == u'': 327 # |name or |* 328 namespaceURI = namespaces.get(prefix, u'') 329 else: 330 try: 331 namespaceURI = namespaces[prefix] 332 except KeyError: 333 new['wellformed'] = False 334 self._log.error(u'Selector: No namespaceURI found for prefix %r' % 335 prefix, token=(typ, val, line, col), 336 error=xml.dom.NamespaceErr) 337 return 338 339 val = (namespaceURI, val) 340 341 if not context or context == 'negation': 342 # define specificity 343 if 'id' == typ: 344 new['specificity'][1] += 1 345 elif 'class' == typ or '[' == val: 346 new['specificity'][2] += 1 347 elif typ in ('type-selector', 'negation-type-selector', 348 'pseudo-element'): 349 new['specificity'][3] += 1 350 if not context and typ in ('type-selector', 'universal'): 351 # define element 352 new['element'] = val 353 354 seq.append(val, typ)
355 356 # expected constants 357 simple_selector_sequence = 'type_selector universal HASH class attrib pseudo negation ' 358 simple_selector_sequence2 = 'HASH class attrib pseudo negation ' 359 360 element_name = 'element_name' 361 362 negation_arg = 'type_selector universal HASH class attrib pseudo' 363 negationend = ')' 364 365 attname = 'prefix attribute' 366 attname2 = 'attribute' 367 attcombinator = 'combinator ]' # optional 368 attvalue = 'value' # optional 369 attend = ']' 370 371 expressionstart = 'PLUS - DIMENSION NUMBER STRING IDENT' 372 expression = expressionstart + ' )' 373 374 combinator = ' combinator' 375 376 def _COMMENT(expected, seq, token, tokenizer=None): 377 "special implementation for comment token" 378 append(seq, cssutils.css.CSSComment([token]), 'comment') 379 return expected
380 381 def _S(expected, seq, token, tokenizer=None): 382 # S 383 context = new['context'][-1] 384 val, typ = self._tokenvalue(token), self._type(token) 385 if context.startswith('pseudo-'): 386 append(seq, S, 'descendant', context=context) 387 return expected 388 389 elif context != 'attrib' and 'combinator' in expected: 390 append(seq, S, 'descendant', context=context) 391 return simple_selector_sequence + combinator 392 393 else: 394 return expected 395 396 def _universal(expected, seq, token, tokenizer=None): 397 # *|* or prefix|* 398 context = new['context'][-1] 399 val, typ = self._tokenvalue(token), self._type(token) 400 if 'universal' in expected: 401 append(seq, val, 'universal', context=context) 402 403 if 'negation' == context: 404 return negationend 405 else: 406 return simple_selector_sequence2 + combinator 407 408 else: 409 new['wellformed'] = False 410 self._log.error( 411 u'Selector: Unexpected universal.', token=token) 412 return expected 413 414 def _namespace_prefix(expected, seq, token, tokenizer=None): 415 # prefix| => element_name 416 # or prefix| => attribute_name if attrib 417 context = new['context'][-1] 418 val, typ = self._tokenvalue(token), self._type(token) 419 if 'attrib' == context and 'prefix' in expected: 420 # [PREFIX|att] 421 append(seq, val, '_PREFIX', context=context) 422 return attname2 423 elif 'type_selector' in expected: 424 # PREFIX|* 425 append(seq, val, '_PREFIX', context=context) 426 return element_name 427 else: 428 new['wellformed'] = False 429 self._log.error( 430 u'Selector: Unexpected namespace prefix.', token=token) 431 return expected 432 433 def _pseudo(expected, seq, token, tokenizer=None): 434 # pseudo-class or pseudo-element :a ::a :a( ::a( 435 """ 436 /* '::' starts a pseudo-element, ':' a pseudo-class */ 437 /* Exceptions: :first-line, :first-letter, :before and :after. */ 438 /* Note that pseudo-elements are restricted to one per selector and */ 439 /* occur only in the last simple_selector_sequence. */ 440 """ 441 context = new['context'][-1] 442 val, typ = self._tokenvalue(token, normalize=True), self._type(token) 443 if 'pseudo' in expected: 444 if val in (':first-line', ':first-letter', ':before', ':after'): 445 # always pseudo-element ??? 446 typ = 'pseudo-element' 447 append(seq, val, typ, context=context) 448 449 if val.endswith(u'('): 450 # function 451 new['context'].append(typ) # "pseudo-" "class" or "element" 452 return expressionstart 453 elif 'negation' == context: 454 return negationend 455 elif 'pseudo-element' == typ: 456 # only one per element, check at ) also! 457 return combinator 458 else: 459 return simple_selector_sequence2 + combinator 460 461 else: 462 new['wellformed'] = False 463 self._log.error( 464 u'Selector: Unexpected start of pseudo.', token=token) 465 return expected 466 467 def _expression(expected, seq, token, tokenizer=None): 468 # [ [ PLUS | '-' | DIMENSION | NUMBER | STRING | IDENT ] S* ]+ 469 context = new['context'][-1] 470 val, typ = self._tokenvalue(token), self._type(token) 471 if context.startswith('pseudo-'): 472 append(seq, val, typ, context=context) 473 return expression 474 else: 475 new['wellformed'] = False 476 self._log.error( 477 u'Selector: Unexpected %s.' % typ, token=token) 478 return expected 479 480 def _attcombinator(expected, seq, token, tokenizer=None): 481 # context: attrib 482 # PREFIXMATCH | SUFFIXMATCH | SUBSTRINGMATCH | INCLUDES | 483 # DASHMATCH 484 context = new['context'][-1] 485 val, typ = self._tokenvalue(token), self._type(token) 486 if 'attrib' == context and 'combinator' in expected: 487 # combinator in attrib 488 append(seq, val, typ.lower(), context=context) 489 return attvalue 490 else: 491 new['wellformed'] = False 492 self._log.error( 493 u'Selector: Unexpected %s.' % typ, token=token) 494 return expected 495 496 def _string(expected, seq, token, tokenizer=None): 497 # identifier 498 context = new['context'][-1] 499 val, typ = self._tokenvalue(token), self._type(token) 500 501 # context: attrib 502 if 'attrib' == context and 'value' in expected: 503 # attrib: [...=VALUE] 504 append(seq, val, 'string', context=context) 505 return attend 506 507 # context: pseudo 508 elif context.startswith('pseudo-'): 509 # :func(...) 510 append(seq, val, 'string', context=context) 511 return expression 512 513 else: 514 new['wellformed'] = False 515 self._log.error( 516 u'Selector: Unexpected STRING.', token=token) 517 return expected 518 519 def _ident(expected, seq, token, tokenizer=None): 520 # identifier 521 context = new['context'][-1] 522 val, typ = self._tokenvalue(token), self._type(token) 523 524 # context: attrib 525 if 'attrib' == context and 'attribute' in expected: 526 # attrib: [...|ATT...] 527 append(seq, val, 'attribute-selector', context=context) 528 return attcombinator 529 530 elif 'attrib' == context and 'value' in expected: 531 # attrib: [...=VALUE] 532 append(seq, val, 'attribute-value', context=context) 533 return attend 534 535 # context: negation 536 elif 'negation' == context: 537 # negation: (prefix|IDENT) 538 append(seq, val, 'negation-type-selector', context=context) 539 return negationend 540 541 # context: pseudo 542 elif context.startswith('pseudo-'): 543 # :func(...) 544 append(seq, val, typ, context=context) 545 return expression 546 547 elif 'type_selector' in expected or element_name == expected: 548 # element name after ns or complete type_selector 549 append(seq, val, 'type-selector', context=context) 550 return simple_selector_sequence2 + combinator 551 552 else: 553 new['wellformed'] = False 554 self._log.error( 555 u'Selector: Unexpected IDENT.', 556 token=token) 557 return expected 558 559 def _class(expected, seq, token, tokenizer=None): 560 # .IDENT 561 context = new['context'][-1] 562 val, typ = self._tokenvalue(token), self._type(token) 563 if 'class' in expected: 564 append(seq, val, typ, context=context) 565 566 if 'negation' == context: 567 return negationend 568 else: 569 return simple_selector_sequence2 + combinator 570 571 else: 572 new['wellformed'] = False 573 self._log.error( 574 u'Selector: Unexpected class.', token=token) 575 return expected 576 577 def _hash(expected, seq, token, tokenizer=None): 578 # #IDENT 579 context = new['context'][-1] 580 val, typ = self._tokenvalue(token), self._type(token) 581 if 'HASH' in expected: 582 append(seq, val, 'id', context=context) 583 584 if 'negation' == context: 585 return negationend 586 else: 587 return simple_selector_sequence2 + combinator 588 589 else: 590 new['wellformed'] = False 591 self._log.error( 592 u'Selector: Unexpected HASH.', token=token) 593 return expected 594 595 def _char(expected, seq, token, tokenizer=None): 596 # + > ~ ) [ ] + - 597 context = new['context'][-1] 598 val, typ = self._tokenvalue(token), self._type(token) 599 600 # context: attrib 601 if u']' == val and 'attrib' == context and ']' in expected: 602 # end of attrib 603 append(seq, val, 'attribute-end', context=context) 604 context = new['context'].pop() # attrib is done 605 context = new['context'][-1] 606 if 'negation' == context: 607 return negationend 608 else: 609 return simple_selector_sequence2 + combinator 610 611 elif u'=' == val and 'attrib' == context and 'combinator' in expected: 612 # combinator in attrib 613 append(seq, val, 'equals', context=context) 614 return attvalue 615 616 # context: negation 617 elif u')' == val and 'negation' == context and u')' in expected: 618 # not(negation_arg)" 619 append(seq, val, 'negation-end', context=context) 620 new['context'].pop() # negation is done 621 context = new['context'][-1] 622 return simple_selector_sequence + combinator 623 624 # context: pseudo (at least one expression) 625 elif val in u'+-' and context.startswith('pseudo-'): 626 # :func(+ -)" 627 append(seq, val, {'+': 'plus', '-': 'minus'}[val], context=context) 628 return expression 629 630 elif u')' == val and context.startswith('pseudo-') and\ 631 expression == expected: 632 # :func(expression)" 633 append(seq, val, 'function-end', context=context) 634 new['context'].pop() # pseudo is done 635 if 'pseudo-element' == context: 636 return combinator 637 else: 638 return simple_selector_sequence + combinator 639 640 # context: ROOT 641 elif u'[' == val and 'attrib' in expected: 642 # start of [attrib] 643 new['context'].append('attrib') 644 append(seq, val, 'attribute-start', context=context) 645 return attname 646 647 elif val in u'+>~' and 'combinator' in expected: 648 # no other combinator except S may be following 649 _names = { 650 '>': 'child', 651 '+': 'adjacent-sibling', 652 '~': 'following-sibling'} 653 if seq and seq[-1].value == S: 654 seq.replace(-1, val, _names[val]) 655 else: 656 append(seq, val, _names[val], context=context) 657 return simple_selector_sequence 658 659 elif u',' == val: 660 # not a selectorlist 661 new['wellformed'] = False 662 self._log.error( 663 u'Selector: Single selector only.', 664 error=xml.dom.InvalidModificationErr, 665 token=token) 666 667 else: 668 new['wellformed'] = False 669 self._log.error( 670 u'Selector: Unexpected CHAR.', token=token) 671 return expected 672 673 def _negation(expected, seq, token, tokenizer=None): 674 # not( 675 context = new['context'][-1] 676 val = self._tokenvalue(token, normalize=True) 677 if 'negation' in expected: 678 new['context'].append('negation') 679 append(seq, val, 'negation-start', context=context) 680 return negation_arg 681 else: 682 new['wellformed'] = False 683 self._log.error( 684 u'Selector: Unexpected negation.', token=token) 685 return expected 686 687 # expected: only|not or mediatype, mediatype, feature, and 688 newseq = self._tempSeq() 689 690 wellformed, expected = self._parse(expected=simple_selector_sequence, 691 seq=newseq, tokenizer=tokenizer, 692 productions={'CHAR': _char, 693 'class': _class, 694 'HASH': _hash, 695 'STRING': _string, 696 'IDENT': _ident, 697 'namespace_prefix': _namespace_prefix, 698 'negation': _negation, 699 'pseudo-class': _pseudo, 700 'pseudo-element': _pseudo, 701 'universal': _universal, 702 # pseudo 703 'NUMBER': _expression, 704 'DIMENSION': _expression, 705 # attribute 706 'PREFIXMATCH': _attcombinator, 707 'SUFFIXMATCH': _attcombinator, 708 'SUBSTRINGMATCH': _attcombinator, 709 'DASHMATCH': _attcombinator, 710 'INCLUDES': _attcombinator, 711 712 'S': _S, 713 'COMMENT': _COMMENT}) 714 wellformed = wellformed and new['wellformed'] 715 716 # post condition 717 if len(new['context']) > 1: 718 wellformed = False 719 self._log.error(u'Selector: Incomplete selector: %s' % 720 self._valuestr(selectorText)) 721 722 if expected == 'element_name': 723 wellformed = False 724 self._log.error(u'Selector: No element name found: %s' % 725 self._valuestr(selectorText)) 726 727 if expected == simple_selector_sequence: 728 wellformed = False 729 self._log.error(u'Selector: Cannot end with combinator: %s' % 730 self._valuestr(selectorText)) 731 732 if newseq and hasattr(newseq[-1].value, 'strip') and \ 733 newseq[-1].value.strip() == u'': 734 del newseq[-1] 735 736 # set 737 if wellformed: 738 self.__namespaces = namespaces 739 self._element = new['element'] 740 self._specificity = tuple(new['specificity']) 741 self.seq = newseq 742 self.wellformed = True 743 # filter that only used ones are kept 744 self.__namespaces = self._getUsedNamespaces() 745 746 selectorText = property(_getSelectorText, _setSelectorText, 747 doc="(DOM) The parsable textual representation of the selector.") 748 749 750 specificity = property(lambda self: self._specificity, 751 doc="Specificity of this selector (READONLY).") 752
753 - def __repr__(self):
754 if self.__getNamespaces(): 755 st = (self.selectorText, self._getUsedNamespaces()) 756 else: 757 st = self.selectorText 758 return u"cssutils.css.%s(selectorText=%r)" % ( 759 self.__class__.__name__, st)
760
761 - def __str__(self):
762 return u"<cssutils.css.%s object selectorText=%r specificity=%r _namespaces=%r at 0x%x>" % ( 763 self.__class__.__name__, self.selectorText, self.specificity, 764 self._getUsedNamespaces(), id(self))
765
766 - def _getUsedUris(self):
767 "returns list of actually used URIs in this Selector" 768 uris = set() 769 for item in self.seq: 770 type_, val = item.type, item.value 771 if type_.endswith(u'-selector') or type_ == u'universal' and \ 772 type(val) == tuple and val[0] not in (None, u'*'): 773 uris.add(val[0]) 774 return uris
775
776 - def _getUsedNamespaces(self):
777 "returns actually used namespaces only" 778 useduris = self._getUsedUris() 779 namespaces = _SimpleNamespaces() 780 for p, uri in self._namespaces.items(): 781 if uri in useduris: 782 namespaces[p] = uri 783 return namespaces
784