Util.py :  » XML » 4Suite » 4Suite-XML-1.0.2 » Ft » Xml » XPath » Python Open Source

Home
Python Open Source
1.3.1.2 Python
2.Ajax
3.Aspect Oriented
4.Blog
5.Build
6.Business Application
7.Chart Report
8.Content Management Systems
9.Cryptographic
10.Database
11.Development
12.Editor
13.Email
14.ERP
15.Game 2D 3D
16.GIS
17.GUI
18.IDE
19.Installer
20.IRC
21.Issue Tracker
22.Language Interface
23.Log
24.Math
25.Media Sound Audio
26.Mobile
27.Network
28.Parser
29.PDF
30.Project Management
31.RSS
32.Search
33.Security
34.Template Engines
35.Test
36.UML
37.USB Serial
38.Web Frameworks
39.Web Server
40.Web Services
41.Web Unit
42.Wiki
43.Windows
44.XML
Python Open Source » XML » 4Suite 
4Suite » 4Suite XML 1.0.2 » Ft » Xml » XPath » Util.py
########################################################################
# $Header: /var/local/cvsroot/4Suite/Ft/Xml/XPath/Util.py,v 1.23 2006/01/15 00:55:53 jkloth Exp $
"""
General utilities for XPath applications

Copyright 2005 Fourthought, Inc. (USA).
Detailed license and copyright information: http://4suite.org/COPYRIGHT
Project home, documentation, distributions: http://4suite.org/
"""

import os
from xml.dom import Node

from Ft.Xml import EMPTY_NAMESPACE
from Ft.Xml.Domlette import GetAllNs
from Ft.Xml.Lib.XmlString import SplitQName

# NOTE: XPathParser and Context are added to this module by __init__.py

__all__ = [# XPath expression parser:
           #'XPathParser', #is this necessary to expose?
           # XPath expression processing:
           'Compile', 'Evaluate', 'SimpleEvaluate',
           # DOM preparation for XPath processing:
           'NormalizeNode',
           # misc XPath related utilities:
           'ExpandQName',
           ]


def ExpandQName(qname, refNode=None, namespaces=None):
    """
    Expand the given QName in the context of the given node,
    or in the given namespace dictionary.

    Returns a 2-tuple consisting of the namespace URI and local name.
    """
    nss = {}
    if refNode:
        nss = GetAllNs(refNode)
    elif namespaces:
        nss = namespaces
    (prefix, local) = SplitQName(qname)
    #We're not to use the default namespace
    if prefix:
        try:
            split_name = (nss[prefix], local)
        except KeyError:
            from Ft.Xml.XPath import RuntimeException
            raise RuntimeException(RuntimeException.UNDEFINED_PREFIX,
                                   prefix)
    else:
        split_name = (EMPTY_NAMESPACE, local)
    return split_name


def NormalizeNode(node):
    """
    NormalizeNode is used to prepare a DOM for XPath evaluation.

    1.  Convert CDATA Sections to Text Nodes.
    2.  Normalize all text nodes (adjacent nodes are merged into the first one).
    """
    node = node.firstChild
    while node:
        if node.nodeType == Node.CDATA_SECTION_NODE:
            # If followed by a text node, add this data to it
            if node.nextSibling and node.nextSibling.nodeType == Node.TEXT_NODE:
                node.nextSibling.insertData(0, node.data)
            elif node.data:
                # Replace this node with a new text node
                text = node.ownerDocument.createTextNode(node.data)
                node.parentNode.replaceChild(text, node)
                node = text
            else:
                # It is empty, get rid of it
                next = node.nextSibling
                node.parentNode.removeChild(node)
                node = next
                # Just in case it is None
                continue
        elif node.nodeType == Node.TEXT_NODE:
            next = node.nextSibling
            while next and next.nodeType in [Node.TEXT_NODE,
                                             Node.CDATA_SECTION_NODE]:
                node.appendData(next.data)
                node.parentNode.removeChild(next)
                next = node.nextSibling
            if not node.data:
                # Remove any empty text nodes
                next = node.nextSibling
                node.parentNode.removeChild(node)
                node = next
                # Just in case it is None
                continue
        elif node.nodeType == Node.ELEMENT_NODE:
            for attr in node.attributes.values():
                if len(attr.childNodes) > 1:
                    NormalizeNode(attr)
            NormalizeNode(node)
        node = node.nextSibling
    return


# -- Core XPath API ---------------------------------------------------------


def SimpleEvaluate(expr, node, explicitNss=None):
    """
    Designed to be the most simple/brain-dead interface to using XPath
    Usually invoked through Node objects using:
      node.xpath(expr[, explicitNss])

    expr - XPath expression in string or compiled form
    node - the node to be used as core of the context for evaluating the XPath
    explicitNss - (optional) any additional or overriding namespace mappings
                  in the form of a dictionary of prefix: namespace
                  the base namespace mappings are taken from in-scope
                  declarations on the given node.  This explicit dictionary
                  is suprimposed on the base mappings
    """
    if 'EXTMODULES' in os.environ:
        ext_modules = os.environ["EXTMODULES"].split(':')
    else:
        ext_modules = []
    explicitNss = explicitNss or {}

    nss = GetAllNs(node)
    nss.update(explicitNss)
    context = Context.Context(node, 0, 0, processorNss=nss,
                              extModuleList=ext_modules)

    if hasattr(expr, "evaluate"):
        retval = expr.evaluate(context)
    else:
        retval = XPathParser.new().parse(expr).evaluate(context)
    return retval


def Evaluate(expr, contextNode=None, context=None):
    """
    Evaluates the given XPath expression.

    Two arguments are required: the expression (as a string or compiled
    expression object), and a context. The context can be given as a
    Domlette node via the 'contextNode' named argument, or can be given as
    an Ft.Xml.XPath.Context.Context object via the 'context' named
    argument.

    If namespace bindings or variable bindings are needed, use a
    Context object. If extension functions are needed, either use a
    Context object, or set the EXTMODULES environment variable to be a
    ':'-separated list of names of Python modules that implement
    extension functions.

    The return value will be one of the following:
    node-set: list of Domlette node objects (xml.dom.Node based);
    string: Unicode string type;
    number: float type;
    boolean: Ft.Lib.boolean C extension object;
    or a non-XPath object (i.e. as returned by an extension function).
    """
    if 'EXTMODULES' in os.environ:
        ext_modules = os.environ["EXTMODULES"].split(':')
    else:
        ext_modules = []

    if contextNode and context:
        con = context.clone()
        con.node = contextNode
    elif context:
        con = context
    elif contextNode:
        #contextNode should be a node, not a context obj,
        #but this is a common error.  Be forgiving?
        if isinstance(contextNode, Context.Context):
            con = contextNode
        else:
            con = Context.Context(contextNode, 0, 0, extModuleList=ext_modules)
    else:
        # import here to avoid circularity
        from Ft.Xml.XPath import RuntimeException
        raise RuntimeException(RuntimeException.NO_CONTEXT)

    if hasattr(expr, "evaluate"):
        retval = expr.evaluate(con)
    else:
        retval = XPathParser.new().parse(expr).evaluate(con)
    return retval


def Compile(expr):
    """
    Given an XPath expression as a string, returns an object that allows
    an evaluation engine to operate on the expression efficiently.
    This "compiled" expression object can be passed to the Evaluate
    function instead of a string, in order to shorten the amount of time
    needed to evaluate the expression.
    """
    if not isinstance(expr, (str, unicode)):
        raise TypeError("Expected string, found %s" % type(expr))
    try:
        return XPathParser.new().parse(expr)
    except SyntaxError, error:
        # import here to avoid circularity
        from Ft.Xml.XPath import CompiletimeException
        raise CompiletimeException(CompiletimeException.SYNTAX, 0, 0, str(error))
    except:
        import traceback, cStringIO
        stream = cStringIO.StringIO()
        traceback.print_exc(None, stream)
        # import here to avoid circularity
        from Ft.Xml.XPath import CompiletimeException
        raise CompiletimeException(CompiletimeException.INTERNAL, stream.getvalue())

www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.