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
|