Logo Search packages:      
Sourcecode: calibre version File versions

def calibre::utils::genshi::path::Path::test (   self,
  ignore_context = False 
)

Returns a function that can be used to track whether the path matches
a specific stream event.

The function returned expects the positional arguments ``event``,
``namespaces`` and ``variables``. The first is a stream event, while the
latter two are a mapping of namespace prefixes to URIs, and a mapping
of variable names to values, respectively. In addition, the function
accepts an ``updateonly`` keyword argument that default to ``False``. If
it is set to ``True``, the function only updates its internal state,
but does not perform any tests or return a result.

If the path matches the event, the function returns the match (for
example, a `START` or `TEXT` event.) Otherwise, it returns ``None``.

>>> from genshi.input import XML
>>> xml = XML('<root><elem><child id="1"/></elem><child id="2"/></root>')
>>> test = Path('child').test()
>>> for event in xml:
...     if test(event, {}, {}):
...         print event[0], repr(event[1])
START (QName(u'child'), Attrs([(QName(u'id'), u'2')]))

:param ignore_context: if `True`, the path is interpreted like a pattern
               in XSLT, meaning for example that it will match
               at any depth
:return: a function that can be used to test individual events in a
 stream against the path
:rtype: ``function``

Definition at line 154 of file path.py.

00154                                         :
        """Returns a function that can be used to track whether the path matches
        a specific stream event.
        
        The function returned expects the positional arguments ``event``,
        ``namespaces`` and ``variables``. The first is a stream event, while the
        latter two are a mapping of namespace prefixes to URIs, and a mapping
        of variable names to values, respectively. In addition, the function
        accepts an ``updateonly`` keyword argument that default to ``False``. If
        it is set to ``True``, the function only updates its internal state,
        but does not perform any tests or return a result.
        
        If the path matches the event, the function returns the match (for
        example, a `START` or `TEXT` event.) Otherwise, it returns ``None``.
        
        >>> from genshi.input import XML
        >>> xml = XML('<root><elem><child id="1"/></elem><child id="2"/></root>')
        >>> test = Path('child').test()
        >>> for event in xml:
        ...     if test(event, {}, {}):
        ...         print event[0], repr(event[1])
        START (QName(u'child'), Attrs([(QName(u'id'), u'2')]))
        
        :param ignore_context: if `True`, the path is interpreted like a pattern
                               in XSLT, meaning for example that it will match
                               at any depth
        :return: a function that can be used to test individual events in a
                 stream against the path
        :rtype: ``function``
        """
        paths = [(p, len(p), [0], [], [0] * len(p)) for p in [
            (ignore_context and [_DOTSLASHSLASH] or []) + p for p in self.paths
        ]]

        def _test(event, namespaces, variables, updateonly=False):
            kind, data, pos = event[:3]
            retval = None
            for steps, size, cursors, cutoff, counter in paths:
                # Manage the stack that tells us "where we are" in the stream
                if kind is END:
                    if cursors:
                        cursors.pop()
                    continue
                elif kind is START:
                    cursors.append(cursors and cursors[-1] or 0)
                elif kind is START_NS or kind is END_NS \
                        or kind is START_CDATA or kind is END_CDATA:
                    continue

                if updateonly or retval or not cursors:
                    continue
                cursor = cursors[-1]
                depth = len(cursors)

                if cutoff and depth + int(kind is not START) > cutoff[0]:
                    continue

                ctxtnode = not ignore_context and kind is START \
                                              and depth == 2
                matched = None
                while 1:
                    # Fetch the next location step
                    axis, nodetest, predicates = steps[cursor]

                    # If this is the start event for the context node, and the
                    # axis of the location step doesn't include the current
                    # element, skip the test
                    if ctxtnode and (axis is CHILD or axis is DESCENDANT):
                        break

                    # Is this the last step of the location path?
                    last_step = cursor + 1 == size

                    # Perform the actual node test
                    matched = nodetest(kind, data, pos, namespaces, variables)

                    # The node test matched
                    if matched:

                        # Check all the predicates for this step
                        if predicates:
                            for predicate in predicates:
                                pretval = predicate(kind, data, pos, namespaces,
                                                    variables)
                                if type(pretval) is float: # FIXME <- need to
                                                           # check this for
                                                           # other types that
                                                           # can be coerced to
                                                           # float
                                    counter[cursor] += 1
                                    if counter[cursor] != int(pretval):
                                        pretval = False
                                if not pretval:
                                    matched = None
                                    break

                        # Both the node test and the predicates matched
                        if matched:
                            if last_step:
                                if not ctxtnode or kind is not START \
                                        or axis is ATTRIBUTE or axis is SELF:
                                    retval = matched
                            elif not ctxtnode or axis is SELF \
                                              or axis is DESCENDANT_OR_SELF:
                                cursor += 1
                                cursors[-1] = cursor
                            cutoff[:] = []

                    if kind is START:
                        if last_step and not (axis is DESCENDANT or
                                              axis is DESCENDANT_OR_SELF):
                            cutoff[:] = [depth]

                        elif steps[cursor][0] is ATTRIBUTE:
                            # If the axis of the next location step is the
                            # attribute axis, we need to move on to processing
                            # that step without waiting for the next markup
                            # event
                            continue

                    # We're done with this step if it's the last step or the
                    # axis isn't "self"
                    if not matched or last_step or not (
                            axis is SELF or axis is DESCENDANT_OR_SELF):
                        break
                    if ctxtnode and axis is DESCENDANT_OR_SELF:
                        ctxtnode = False

                if (retval or not matched) and kind is START and \
                        not (axis is DESCENDANT or axis is DESCENDANT_OR_SELF):
                    # If this step is not a closure, it cannot be matched until
                    # the current element is closed... so we need to move the
                    # cursor back to the previous closure and retest that
                    # against the current element
                    backsteps = [(i, k, d, p) for i, (k, d, p)
                                 in enumerate(steps[:cursor])
                                 if k is DESCENDANT or k is DESCENDANT_OR_SELF]
                    backsteps.reverse()
                    for cursor, axis, nodetest, predicates in backsteps:
                        if nodetest(kind, data, pos, namespaces, variables):
                            cutoff[:] = []
                            break
                    cursors[-1] = cursor

            return retval

        return _test


class PathSyntaxError(Exception):


Generated by  Doxygen 1.6.0   Back to index