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