Ticket #2502: xpath.diff

File xpath.diff, 22.1 KB (added by jack, 15 years ago)

new operators for xpath

  • TwistedWords-0.5.0/twisted/words/test/test_xpath.py

     
    2626        #          <gar>ABC</gar>
    2727        #        </bar>
    2828        #     <bar/>
     29        #     <bar attrib4='value4' attrib5='value5'>
     30        #        <foo/>
     31        #        <gar>JKL</gar>
     32        #     </bar>
     33        #     <bar attrib4='value4' attrib5='value4'>
     34        #        <foo/>
     35        #        <gar>MNO</gar>
     36        #     </bar>
     37        #     <bar attrib4='value4' attrib5='value6'/>
    2938        # </foo>
    3039        self.e = Element(("testns", "foo"))
    3140        self.e["attrib1"] = "value1"
     
    4352        self.gar2 = self.bar3.addElement("gar")
    4453        self.gar2.addContent("ABC")
    4554        self.bar4 = self.e.addElement("bar")
     55        self.bar5 = self.e.addElement("bar")
     56        self.bar5["attrib4"] = "value4"
     57        self.bar5["attrib5"] = "value5"
     58        self.subfoo3 = self.bar5.addElement("foo")
     59        self.gar3 = self.bar5.addElement("gar")
     60        self.gar3.addContent("JKL")
     61        self.bar6 = self.e.addElement("bar")
     62        self.bar6["attrib4"] = "value4"
     63        self.bar6["attrib5"] = "value4"
     64        self.subfoo4 = self.bar6.addElement("foo")
     65        self.gar4 = self.bar6.addElement("gar")
     66        self.gar4.addContent("MNO")
     67        self.bar7 = self.e.addElement("bar")
     68        self.bar7["attrib4"] = "value4"
     69        self.bar7["attrib5"] = "value6"
    4670
    4771   
    4872    def testStaticMethods(self):
    4973        self.assertEquals(xpath.matches("/foo/bar", self.e),
    5074                          True)
    5175        self.assertEquals(xpath.queryForNodes("/foo/bar", self.e),
    52                           [self.bar1, self.bar2, self.bar4])
     76                          [self.bar1, self.bar2, self.bar4, self.bar5, self.bar6, self.bar7])
    5377        self.assertEquals(xpath.queryForString("/foo", self.e),
    5478                          "somecontent")
    5579        self.assertEquals(xpath.queryForStringList("/foo", self.e),
     
    6185
    6286        xp = XPathQuery("/foo/bar/foo")
    6387        self.assertEquals(xp.matches(self.e), 1)
    64         self.assertEquals(xp.queryForNodes(self.e), [self.subfoo])
     88        self.assertEquals(xp.queryForNodes(self.e), [self.subfoo, self.subfoo3, self.subfoo4])
    6589       
    6690        xp = XPathQuery("/foo/bar3")
    6791        self.assertEquals(xp.matches(self.e), 0)
    6892
    6993        xp = XPathQuery("/foo/*")
    7094        self.assertEquals(xp.matches(self.e), True)
    71         self.assertEquals(xp.queryForNodes(self.e), [self.bar1, self.bar2, self.bar4])
     95        self.assertEquals(xp.queryForNodes(self.e), [self.bar1, self.bar2, self.bar4, self.bar5, self.bar6, self.bar7])
    7296
    7397        xp = XPathQuery("/foo[@attrib1]")
    7498        self.assertEquals(xp.matches(self.e), True)
     
    96120        self.assertEquals(xp.queryForStringList(self.e), ["somecontent", "somemorecontent"])
    97121
    98122        xp = XPathQuery("/foo/bar")
    99         self.assertEquals(xp.queryForNodes(self.e), [self.bar1, self.bar2, self.bar4])
     123        self.assertEquals(xp.queryForNodes(self.e), [self.bar1, self.bar2, self.bar4, self.bar5, self.bar6, self.bar7])
    100124
    101125        xp = XPathQuery("/foo[text() = 'somecontent']")
    102126        self.assertEquals(xp.matches(self.e), True)
     
    106130
    107131        xp = XPathQuery("//gar")
    108132        self.assertEquals(xp.matches(self.e), True)
    109         self.assertEquals(xp.queryForNodes(self.e), [self.gar1, self.gar2])
    110         self.assertEquals(xp.queryForStringList(self.e), ["DEF", "ABC"])
     133        self.assertEquals(xp.queryForNodes(self.e), [self.gar1, self.gar2, self.gar3, self.gar4])
     134        self.assertEquals(xp.queryForStringList(self.e), ["DEF", "ABC", "JKL", "MNO"])
    111135
    112136        xp = XPathQuery("//bar")
    113137        self.assertEquals(xp.matches(self.e), True)
    114         self.assertEquals(xp.queryForNodes(self.e), [self.bar1, self.bar2, self.bar3, self.bar4])
     138        self.assertEquals(xp.queryForNodes(self.e), [self.bar1, self.bar2, self.bar3, self.bar4, self.bar5, self.bar6, self.bar7])
    115139
     140        xp = XPathQuery("//bar[@attrib4='value4' and @attrib5='value5']")
     141        self.assertEquals(xp.matches(self.e), True)
     142        self.assertEquals(xp.queryForNodes(self.e), [self.bar5])
    116143
     144        xp = XPathQuery("//bar[@attrib5='value4' or @attrib5='value5']")
     145        self.assertEquals(xp.matches(self.e), True)
     146        self.assertEquals(xp.queryForNodes(self.e), [self.bar5, self.bar6])
    117147
     148        xp = XPathQuery("//bar[@attrib4='value4' and (@attrib5='value4' or @attrib5='value6')]")
     149        self.assertEquals(xp.matches(self.e), True)
     150        self.assertEquals(xp.queryForNodes(self.e), [self.bar6, self.bar7])
     151
     152        xp = XPathQuery("//bar[@attrib5='value4' or @attrib5='value5' or @attrib5='value6']")
     153        self.assertEquals(xp.matches(self.e), True)
     154        self.assertEquals(xp.queryForNodes(self.e), [self.bar5, self.bar6, self.bar7])
  • TwistedWords-0.5.0/twisted/words/xish/xpathparser.g

     
    1 
    2 # Copyright (c) 2001-2004 Twisted Matrix Laboratories.
     1# -*- test-case-name: twisted.words.test -*-
     2# Copyright (c) 2001-2007 Twisted Matrix Laboratories.
    33# See LICENSE for details.
    44
    55
     
    5555    """
    5656   
    5757    def __init__(self, patterns, ignore, input):
    58         """Initialize the scanner.
     58        """ Initialize the scanner.
    5959
    60         Parameters:
    61           patterns : [(terminal, uncompiled regex), ...] or None
    62           ignore : [terminal,...]
    63           input : string
    6460
    65         If patterns is None, we assume that the subclass has
    66         defined self.patterns : [(terminal, compiled regex), ...].
     61        @param patterns: [(terminal, uncompiled regex), ...] or C{None}
     62        @param ignore: [terminal,...]
     63        @param input: string
     64
     65        If patterns is C{None}, we assume that the subclass has
     66        defined C{self.patterns} : [(terminal, compiled regex), ...].
    6767        Note that the patterns parameter expects uncompiled regexes,
    68         whereas the self.patterns field expects compiled regexes.
     68        whereas the C{self.patterns} field expects compiled regexes.
    6969        """
    7070        self.tokens = [] # [(begin char pos, end char pos, token name, matched text), ...]
    7171        self.restrictions = []
     
    116116    def token(self, i, restrict=None):
    117117        """Get the i'th token in the input.
    118118
    119         If i is one past the end, then scan for another token.
     119        If L{i} is one past the end, then scan for another token.
    120120       
    121         Args:
     121        @param i: token index
    122122
    123         restrict : [token, ...] or None; if restrict is None, then any
    124         token is allowed.  You may call token(i) more than once.
    125         However, the restrict set may never be larger than what was
    126         passed in on the first call to token(i).
    127        
     123        @param restrict: [token, ...] or C{None}; if restrict is
     124               C{None}, then any token is allowed.  You may call
     125               token(i) more than once.  However, the restrict set may
     126               never be larger than what was passed in on the first
     127               call to token(i).
    128128        """
    129129        if i == len(self.tokens):
    130130            self.scan(restrict)
     
    222222    def __init__(self, parent, scanner, tokenpos, rule, args=()):
    223223        """Create a new context.
    224224
    225         Args:
    226         parent: Context object or None
    227         scanner: Scanner object
    228         pos: integer (scanner token position)
    229         rule: string (name of the rule)
    230         args: tuple listing parameters to the rule
     225        @param parent: Context object or C{None}
     226        @param scanner: Scanner object
     227        @param tokenpos: scanner token position
     228        @type tokenpos: L{int}
     229        @param rule: name of the rule
     230        @type rule: L{str}
     231        @param args: tuple listing parameters to the rule
    231232
    232233        """
    233234        self.parent = parent
     
    309310
    310311
    311312
    312 from twisted.words.xish.xpath import _Location, _AnyLocation, IndexValue, CompareValue, AttribValue, LiteralValue, Function
     313from twisted.words.xish.xpath import _Location, _AnyLocation, IndexValue, CompareValue, BooleanValue, AttribValue, LiteralValue, Function
    313314
    314315%%
    315316parser XPathParser:
     
    323324        token CMP_NE:       "\!\="
    324325        token STR_DQ:       '"([^"]|(\\"))*?"'
    325326        token STR_SQ:       "'([^']|(\\'))*?'"
     327        token OP_AND:       "and"
     328        token OP_OR:        "or"
    326329        token END:          "$"
    327330
    328331        rule XPATH:    PATH {{ result = PATH; current = result }}
     
    337340        rule PREDICATE:  EXPR  {{ return EXPR }} |
    338341                         INDEX {{ return IndexValue(INDEX) }}
    339342
    340         rule EXPR:       VALUE            {{ e = VALUE }}
    341                            [ CMP VALUE  {{ e = CompareValue(e, CMP, VALUE) }} ] 
    342                                           {{ return e }}
     343        rule EXPR:       FACTOR {{ e = FACTOR }}
     344                           ( BOOLOP FACTOR {{ e = BooleanValue(e, BOOLOP, FACTOR) }} )*
     345                             {{ return e }}
    343346
     347        rule BOOLOP:     ( OP_AND {{ return OP_AND }} | OP_OR {{ return OP_OR }} )
     348
     349        rule FACTOR:    TERM {{ return TERM }}
     350                           | "\(" EXPR "\)" {{ return EXPR }}
     351
     352        rule TERM:       VALUE            {{ t = VALUE }}
     353                           [ CMP VALUE  {{ t = CompareValue(t, CMP, VALUE) }} ] 
     354                                          {{ return t }}
     355
    344356        rule VALUE:      "@" IDENTIFIER   {{ return AttribValue(IDENTIFIER) }} |
    345357                         FUNCNAME         {{ f = Function(FUNCNAME); args = [] }}
    346                            "\("[ VALUE      {{ args.append(VALUE) }}
     358                           "\(" [ VALUE      {{ args.append(VALUE) }}
    347359                             (
    348360                               "," VALUE     {{ args.append(VALUE) }}
    349361                             )*   
  • TwistedWords-0.5.0/twisted/words/xish/xpathparser.py

     
    11# -*- test-case-name: twisted.words.test -*-
    2 # Copyright (c) 2001-2005 Twisted Matrix Laboratories.
     2# Copyright (c) 2001-2007 Twisted Matrix Laboratories.
    33# See LICENSE for details.
    44
    55
     
    99
    1010# HOWTO Generate me:
    1111# 1.) Grab a copy of yapps2: http://theory.stanford.edu/~amitp/Yapps/
     12#     (available on debian by "apt-get install -t unstable yapps2")
    1213# 2.) Hack it to not add a "import yappsrt" in the output file
    1314# 3.) Generate the grammar as usual
    1415
     
    5657    def __init__(self, patterns, ignore, input):
    5758        """ Initialize the scanner.
    5859
    59         @param patterns: [(terminal, uncompiled regex), ...] or C{None}
    60         @param ignore: [terminal,...]
    61         @param input: string
    6260
    63         If patterns is C{None}, we assume that the subclass has defined
    64         C{self.patterns} : [(terminal, compiled regex), ...]. Note that the
    65         patterns parameter expects uncompiled regexes, whereas the
    66         C{self.patterns} field expects compiled regexes.
     61        @param patterns: [(terminal, uncompiled regex), ...] or C{None}
     62        @param ignore: [terminal,...]
     63        @param input: string
     64
     65        If patterns is C{None}, we assume that the subclass has
     66        defined C{self.patterns} : [(terminal, compiled regex), ...].
     67        Note that the patterns parameter expects uncompiled regexes,
     68        whereas the C{self.patterns} field expects compiled regexes.
    6769        """
    6870        self.tokens = [] # [(begin char pos, end char pos, token name, matched text), ...]
    6971        self.restrictions = []
     
    114116    def token(self, i, restrict=None):
    115117        """Get the i'th token in the input.
    116118
     119        If L{i} is one past the end, then scan for another token.
     120       
     121        @param i: token index
    117122
    118         If L{i} is one past the end, then scan for another token.
    119        
    120         @param i: token index
    121         @param restrict: [token, ...] or C{None}; if restrict is C{None},
    122                          then any token is allowed. You may call token(i) more
    123                          than once.  However, the restrict set may never be
    124                          larger than what was passed in on the first call to
    125                          token(i).
     123        @param restrict: [token, ...] or C{None}; if restrict is
     124               C{None}, then any token is allowed.  You may call
     125               token(i) more than once.  However, the restrict set may
     126               never be larger than what was passed in on the first
     127               call to token(i).
    126128        """
    127129        if i == len(self.tokens):
    128130            self.scan(restrict)
     
    223225        @param parent: Context object or C{None}
    224226        @param scanner: Scanner object
    225227        @param tokenpos: scanner token position
    226         @type tokenpos: L{int}
    227         @param rule: name of the rule
     228        @type tokenpos: L{int}
     229        @param rule: name of the rule
    228230        @type rule: L{str}
    229231        @param args: tuple listing parameters to the rule
    230232
     
    308310
    309311
    310312
    311 from twisted.words.xish.xpath import _Location, _AnyLocation, IndexValue, CompareValue, AttribValue, LiteralValue, Function
     313from twisted.words.xish.xpath import _Location, _AnyLocation, IndexValue, CompareValue, BooleanValue, AttribValue, LiteralValue, Function
    312314
    313315
    314 # Begin -- grammar generated by Yapps
    315 import sys, re
    316316
    317317class XPathParserScanner(Scanner):
    318318    patterns = [
     319        ('","', re.compile(',')),
     320        ('"@"', re.compile('@')),
    319321        ('"\\)"', re.compile('\\)')),
    320         ('","', re.compile(',')),
    321322        ('"\\("', re.compile('\\(')),
    322         ('"@"', re.compile('@')),
    323323        ('"\\]"', re.compile('\\]')),
    324324        ('"\\["', re.compile('\\[')),
    325325        ('"//"', re.compile('//')),
     
    334334        ('CMP_NE', re.compile('\\!\\=')),
    335335        ('STR_DQ', re.compile('"([^"]|(\\"))*?"')),
    336336        ('STR_SQ', re.compile("'([^']|(\\'))*?'")),
     337        ('OP_AND', re.compile('and')),
     338        ('OP_OR', re.compile('or')),
    337339        ('END', re.compile('$')),
    338340    ]
    339341    def __init__(self, str):
    340342        Scanner.__init__(self,None,['\\s+'],str)
    341343
    342344class XPathParser(Parser):
    343     Context = Context
    344     def XPATH(self, _parent=None):
    345         _context = self.Context(_parent, self._scanner, self._pos, 'XPATH', [])
    346         PATH = self.PATH(_context)
     345    def XPATH(self):
     346        PATH = self.PATH()
    347347        result = PATH; current = result
    348348        while self._peek('END', '"/"', '"//"') != 'END':
    349             PATH = self.PATH(_context)
     349            PATH = self.PATH()
    350350            current.childLocation = PATH; current = current.childLocation
    351         if self._peek() not in ['END', '"/"', '"//"']:
    352             raise SyntaxError(charpos=self._scanner.get_prev_char_pos(), context=_context, msg='Need one of ' + ', '.join(['END', '"/"', '"//"']))
    353351        END = self._scan('END')
    354352        return  result
    355353
    356     def PATH(self, _parent=None):
    357         _context = self.Context(_parent, self._scanner, self._pos, 'PATH', [])
    358         _token = self._peek('"/"', '"//"')
    359         if _token == '"/"':
     354    def PATH(self):
     355        _token_ = self._peek('"/"', '"//"')
     356        if _token_ == '"/"':
    360357            self._scan('"/"')
    361358            result = _Location()
    362         else: # == '"//"'
     359        else:# == '"//"'
    363360            self._scan('"//"')
    364361            result = _AnyLocation()
    365         _token = self._peek('IDENTIFIER', 'WILDCARD')
    366         if _token == 'IDENTIFIER':
     362        _token_ = self._peek('IDENTIFIER', 'WILDCARD')
     363        if _token_ == 'IDENTIFIER':
    367364            IDENTIFIER = self._scan('IDENTIFIER')
    368365            result.elementName = IDENTIFIER
    369         else: # == 'WILDCARD'
     366        else:# == 'WILDCARD'
    370367            WILDCARD = self._scan('WILDCARD')
    371368            result.elementName = None
    372369        while self._peek('"\\["', 'END', '"/"', '"//"') == '"\\["':
    373370            self._scan('"\\["')
    374             PREDICATE = self.PREDICATE(_context)
     371            PREDICATE = self.PREDICATE()
    375372            result.predicates.append(PREDICATE)
    376373            self._scan('"\\]"')
    377         if self._peek() not in ['"\\["', 'END', '"/"', '"//"']:
    378             raise SyntaxError(charpos=self._scanner.get_prev_char_pos(), context=_context, msg='Need one of ' + ', '.join(['"\\["', 'END', '"/"', '"//"']))
    379374        return result
    380375
    381     def PREDICATE(self, _parent=None):
    382         _context = self.Context(_parent, self._scanner, self._pos, 'PREDICATE', [])
    383         _token = self._peek('INDEX', '"@"', 'FUNCNAME', 'STR_DQ', 'STR_SQ')
    384         if _token != 'INDEX':
    385             EXPR = self.EXPR(_context)
     376    def PREDICATE(self):
     377        _token_ = self._peek('INDEX', '"\\("', '"@"', 'FUNCNAME', 'STR_DQ', 'STR_SQ')
     378        if _token_ != 'INDEX':
     379            EXPR = self.EXPR()
    386380            return EXPR
    387         else: # == 'INDEX'
     381        else:# == 'INDEX'
    388382            INDEX = self._scan('INDEX')
    389383            return IndexValue(INDEX)
    390384
    391     def EXPR(self, _parent=None):
    392         _context = self.Context(_parent, self._scanner, self._pos, 'EXPR', [])
    393         VALUE = self.VALUE(_context)
    394         e = VALUE
    395         if self._peek('CMP_EQ', 'CMP_NE', '"\\]"') != '"\\]"':
    396             CMP = self.CMP(_context)
    397             VALUE = self.VALUE(_context)
    398             e = CompareValue(e, CMP, VALUE)
     385    def EXPR(self):
     386        FACTOR = self.FACTOR()
     387        e = FACTOR
     388        while self._peek('OP_AND', 'OP_OR', '"\\)"', '"\\]"') in ['OP_AND', 'OP_OR']:
     389            BOOLOP = self.BOOLOP()
     390            FACTOR = self.FACTOR()
     391            e = BooleanValue(e, BOOLOP, FACTOR)
    399392        return e
    400393
    401     def VALUE(self, _parent=None):
    402         _context = self.Context(_parent, self._scanner, self._pos, 'VALUE', [])
    403         _token = self._peek('"@"', 'FUNCNAME', 'STR_DQ', 'STR_SQ')
    404         if _token == '"@"':
     394    def BOOLOP(self):
     395        _token_ = self._peek('OP_AND', 'OP_OR')
     396        if _token_ == 'OP_AND':
     397            OP_AND = self._scan('OP_AND')
     398            return OP_AND
     399        else:# == 'OP_OR'
     400            OP_OR = self._scan('OP_OR')
     401            return OP_OR
     402
     403    def FACTOR(self):
     404        _token_ = self._peek('"\\("', '"@"', 'FUNCNAME', 'STR_DQ', 'STR_SQ')
     405        if _token_ != '"\\("':
     406            TERM = self.TERM()
     407            return TERM
     408        else:# == '"\\("'
     409            self._scan('"\\("')
     410            EXPR = self.EXPR()
     411            self._scan('"\\)"')
     412            return EXPR
     413
     414    def TERM(self):
     415        VALUE = self.VALUE()
     416        t = VALUE
     417        if self._peek('CMP_EQ', 'CMP_NE', 'OP_AND', 'OP_OR', '"\\)"', '"\\]"') in ['CMP_EQ', 'CMP_NE']:
     418            CMP = self.CMP()
     419            VALUE = self.VALUE()
     420            t = CompareValue(t, CMP, VALUE)
     421        return t
     422
     423    def VALUE(self):
     424        _token_ = self._peek('"@"', 'FUNCNAME', 'STR_DQ', 'STR_SQ')
     425        if _token_ == '"@"':
    405426            self._scan('"@"')
    406427            IDENTIFIER = self._scan('IDENTIFIER')
    407428            return AttribValue(IDENTIFIER)
    408         elif _token == 'FUNCNAME':
     429        elif _token_ == 'FUNCNAME':
    409430            FUNCNAME = self._scan('FUNCNAME')
    410431            f = Function(FUNCNAME); args = []
    411432            self._scan('"\\("')
    412             if self._peek('"\\)"', '"@"', 'FUNCNAME', '","', 'STR_DQ', 'STR_SQ') not in ['"\\)"', '","']:
    413                 VALUE = self.VALUE(_context)
     433            if self._peek('","', '"\\)"', '"@"', 'FUNCNAME', 'STR_DQ', 'STR_SQ') not in ['","', '"\\)"']:
     434                VALUE = self.VALUE()
    414435                args.append(VALUE)
    415436                while self._peek('","', '"\\)"') == '","':
    416437                    self._scan('","')
    417                     VALUE = self.VALUE(_context)
     438                    VALUE = self.VALUE()
    418439                    args.append(VALUE)
    419                 if self._peek() not in ['","', '"\\)"']:
    420                     raise SyntaxError(charpos=self._scanner.get_prev_char_pos(), context=_context, msg='Need one of ' + ', '.join(['","', '"\\)"']))
    421440            self._scan('"\\)"')
    422441            f.setParams(*args); return f
    423         else: # in ['STR_DQ', 'STR_SQ']
    424             STR = self.STR(_context)
     442        else:# in ['STR_DQ', 'STR_SQ']
     443            STR = self.STR()
    425444            return LiteralValue(STR[1:len(STR)-1])
    426445
    427     def CMP(self, _parent=None):
    428         _context = self.Context(_parent, self._scanner, self._pos, 'CMP', [])
    429         _token = self._peek('CMP_EQ', 'CMP_NE')
    430         if _token == 'CMP_EQ':
     446    def CMP(self):
     447        _token_ = self._peek('CMP_EQ', 'CMP_NE')
     448        if _token_ == 'CMP_EQ':
    431449            CMP_EQ = self._scan('CMP_EQ')
    432450            return CMP_EQ
    433         else: # == 'CMP_NE'
     451        else:# == 'CMP_NE'
    434452            CMP_NE = self._scan('CMP_NE')
    435453            return CMP_NE
    436454
    437     def STR(self, _parent=None):
    438         _context = self.Context(_parent, self._scanner, self._pos, 'STR', [])
    439         _token = self._peek('STR_DQ', 'STR_SQ')
    440         if _token == 'STR_DQ':
     455    def STR(self):
     456        _token_ = self._peek('STR_DQ', 'STR_SQ')
     457        if _token_ == 'STR_DQ':
    441458            STR_DQ = self._scan('STR_DQ')
    442459            return STR_DQ
    443         else: # == 'STR_SQ'
     460        else:# == 'STR_SQ'
    444461            STR_SQ = self._scan('STR_SQ')
    445462            return STR_SQ
    446463
     
    457474        else:
    458475            f = stdin
    459476        print parse(argv[1], f.read())
    460     else: print >>sys.stderr, 'Args:  <rule> [<filename>]'
    461 # End -- grammar generated by Yapps
     477    else: print 'Args:  <rule> [<filename>]'
  • TwistedWords-0.5.0/twisted/words/xish/xpath.py

     
    5050    def _compareNotEqual(self, elem):
    5151        return self.lhs.value(elem) != self.rhs.value(elem)
    5252
     53class BooleanValue:
     54    def __init__(self, lhs, op, rhs):
     55        self.lhs = lhs
     56        self.rhs = rhs
     57        if op == "and":
     58            self.value = self._booleanAnd
     59        else:
     60            self.value = self._booleanOr
     61
     62    def _booleanAnd(self, elem):
     63        return self.lhs.value(elem) and self.rhs.value(elem)
     64   
     65    def _booleanOr(self, elem):
     66        return self.lhs.value(elem) or self.rhs.value(elem)
     67
    5368def Function(fname):
    5469    """ Internal method which selects the function object """
    5570    klassname = "_%s_Function" % fname
     
    8297    def matchesPredicates(self, elem):
    8398        if self.elementName != None and self.elementName != elem.name:
    8499            return 0
    85                
     100
    86101        for p in self.predicates:
    87102            if not p.value(elem):
    88103                return 0