File: Util.py

package info (click to toggle)
python-xml 0.8.4-10.1%2Blenny1
  • links: PTS
  • area: main
  • in suites: lenny
  • size: 4,972 kB
  • ctags: 10,628
  • sloc: python: 46,730; ansic: 14,354; xml: 968; makefile: 201; sh: 20
file content (184 lines) | stat: -rw-r--r-- 6,005 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
########################################################################
#
# File Name:            Util.py
#
#
"""
General Utilities for XPath apps.
WWW: http://4suite.org/4XSLT        e-mail: support@4suite.org

Copyright (c) 2000-2001 Fourthought Inc, USA.   All Rights Reserved.
See  http://4suite.org/COPYRIGHT  for license and copyright information
"""

import os, glob, string
import xml.dom.ext
from xml.dom import XML_NAMESPACE,EMPTY_NAMESPACE
from xml.dom import Node
from xml.dom.NodeFilter import NodeFilter
from xml.xpath import g_xpathRecognizedNodes, Compile

g_documentOrderIndex = {}

g_xmlSpaceDescendant = g_xmlSpaceAncestor = None


def ElementsById(element, name):
    elements = []
    attrs = element.attributes
    idattr = attrs.get((EMPTY_NAMESPACE, 'id')) or attrs.get((EMPTY_NAMESPACE, 'ID'))
    idattr and idattr.value == name and elements.append(idattr.ownerElement)
    for element in filter(lambda node: node.nodeType == Node.ELEMENT_NODE,
                          element.childNodes):
        elements.extend(ElementsById(element, name))
    return elements


def IndexDocument(doc):
    global g_documentOrderIndex
    if g_documentOrderIndex.has_key(id(doc)):
        return
    mapping = {}
    count = __IndexNode(doc, 0, mapping)
    g_documentOrderIndex[id(doc)] = mapping


def FreeDocumentIndex(doc):
    global g_documentOrderIndex
    if g_documentOrderIndex.has_key(id(doc)):
        del g_documentOrderIndex[id(doc)]


def SortDocOrder(nList):
    if len(nList) in [0, 1]:
        return nList
    if hasattr(nList[0], 'docIndex'):
        nList.sort(lambda a, b: cmp(a.docIndex, b.docIndex))
        return nList
    doc = nList[0].ownerDocument or nList[0]
    IndexDocument(doc)
    global g_documentOrderIndex
    if g_documentOrderIndex.has_key(id(doc)):
        rt = nList[:]
        rt.sort(IndexSort)
    else:
        rt = __recurseSort([doc], nList)
    return rt


def ExpandQName(qname, refNode=None, namespaces=None):
    '''
    Expand the given QName in the context of the given node,
    or in the given namespace dictionary
    '''
    nss = {}
    if refNode:
        nss = xml.dom.ext.GetAllNs(refNode)
    elif namespaces:
        nss = namespaces
    (prefix, local) = xml.dom.ext.SplitQName(qname)
    #We're not to use the default namespace
    if prefix != '':
        split_name = (nss[prefix], local)
    else:
        split_name = (EMPTY_NAMESPACE, local)
    return split_name


def __IndexNode(node, curIndex, mapping):
    if node.nodeType in g_xpathRecognizedNodes:
        #Add this node
        mapping[id(node)] = curIndex
        curIndex = curIndex + 1
        if node.nodeType == Node.ELEMENT_NODE:
            #FIXME how do we get attributes in doc order???
            for attr in node.attributes.values():
                mapping[id(attr)] = curIndex
                curIndex = curIndex + 1

        for childNode in node.childNodes:
            curIndex = __IndexNode(childNode, curIndex, mapping)

    return curIndex


def IndexSort(left, right):
    ldocId = id(left.ownerDocument or left)
    rdocId = id(right.ownerDocument or right)
    if ldocId == rdocId:
        lid = id(left)
        rid = id(right)
        return cmp(g_documentOrderIndex[ldocId][lid], g_documentOrderIndex[rdocId][rid])
    else:
        return cmp(ldocId, rdocId)


def __recurseSort(test, toSort):
    """Check whether any of the nodes in toSort are in the list test, and if so, sort them into the result list"""
    result = []
    for node in test:
        toSort = filter(lambda x, n=node: x != n, toSort)
        if node in toSort:
            result.append(node)
        #See if node has attributes
        if node.nodeType == Node.ELEMENT_NODE:
            attrList = node.attributes.values()
            #FIXME: Optimize by unrolling this level of recursion
            result = result + __recurseSort(attrList, toSort)
            if not toSort:
                #Exit early
                break
        #See if any of t's children are in toSort
        result = result + __recurseSort(node.childNodes, toSort)
        if not toSort:
            #Exit early
            break
    return result


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
    """
    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