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
|
########################################################################
#
# File Name: SortElement.py
#
#
"""
Implementation of the XSLT Spec sort stylesheet element.
WWW: http://4suite.com/4XSLT e-mail: support@4suite.com
Copyright (c) 1999-2000 Fourthought Inc, USA. All Rights Reserved.
See http://4suite.com/COPYRIGHT for license and copyright information
"""
import string
from xml.dom import EMPTY_NAMESPACE
import xml.dom.ext
import xml.dom.Element
import xml.xslt
from xml.xslt import XsltElement, XsltException, Error, AttributeValueTemplate
from xml.xpath import XPathParser
from xml.xpath import Conversions
class SortElement(XsltElement):
legalAttrs = ('select', 'lang', 'data-type', 'case-order', 'order')
def __init__(self, doc, uri=xml.xslt.XSL_NAMESPACE, localName='sort', prefix='xsl', baseUri=''):
XsltElement.__init__(self, doc, uri, localName, prefix, baseUri)
def setup(self):
self.__dict__['_select'] = self.getAttributeNS(EMPTY_NAMESPACE, 'select') or '.'
data_type = self.getAttributeNS(EMPTY_NAMESPACE, 'data-type')
self.__dict__['_data_type'] = data_type and AttributeValueTemplate.AttributeValueTemplate(data_type) or None
case_order = self.getAttributeNS(EMPTY_NAMESPACE, 'case-order')
self.__dict__['_case_order'] = case_order and AttributeValueTemplate.AttributeValueTemplate(case_order) or None
order = self.getAttributeNS(EMPTY_NAMESPACE, 'order')
self.__dict__['_order'] = order and AttributeValueTemplate.AttributeValueTemplate(order) or None
self.__dict__['_nss'] = xml.dom.ext.GetAllNs(self)
parser = XPathParser.XPathParser()
self.__dict__['_expr'] = parser.parseExpression(self._select)
return
def instantiate(self, context, processor, nodeList=None, specList=None):
if nodeList is None:
nodeList = []
if specList is None:
specList = []
origState = context.copy()
context.setNamespaces(self._nss)
if self._data_type:
data_type = self._data_type.evaluate(context)
if data_type not in ['text', 'number']:
raise XsltException(Error.ILLEGAL_SORT_DATA_TYPE_VALUE)
else:
data_type = 'text'
if self._case_order:
case_order = self._case_order.evaluate(context)
if case_order not in ['upper-first', 'lower-first']:
raise XsltException(Error.ILLEGAL_SORT_CASE_ORDER_VALUE)
else:
case_order = 'lower-first'
if self._order:
order = self._order.evaluate(context)
if order not in ['ascending', 'descending']:
raise XsltException(Error.ILLEGAL_SORT_ORDER_VALUE)
else:
order = 'ascending'
keys = []
node_dict = {}
pos = 1
size = len(nodeList)
tempState = context.copyNodePosSize()
for node in nodeList:
context.setNodePosSize((node,pos,size))
result = self._expr.evaluate(context)
key = Conversions.StringValue(result)
if not key in keys:
keys.append(key)
if node_dict.has_key(key):
node_dict[key].append(node)
else:
node_dict[key] = [node]
pos = pos + 1
context.setNodePosSize(tempState)
keys.sort(lambda x, y, o=order, d=data_type, c=case_order: Cmp(x, y, o, d, c))
sorted_list = []
for key in keys:
sub_list = node_dict[key]
if len(sub_list) > 1 and specList:
sub_list = specList[0].instantiate(context, processor, sub_list, specList[1:])[1]
sorted_list = sorted_list + sub_list
context.set(origState)
return (context, sorted_list)
def __getinitargs__(self):
return (None, self.namespaceURI, self.localName, self.prefix,
self.baseUri)
def __getstate__(self):
base_state = XsltElement.__getstate__(self)
new_state = (base_state, self._nss, self._select, self._data_type,
self._case_order, self._order, self._expr)
return new_state
def __setstate__(self, state):
XsltElement.__setstate__(self, state[0])
self._nss = state[1]
self._select = state[2]
self._data_type = state[3]
self._case_order = state[4]
self._order = state[5]
self._expr = state[6]
return
def Cmp(a, b, order, dataType, caseOrder):
if dataType == 'number':
a = float(a or 0)
b = float(b or 0)
elif caseOrder == 'lower-first':
if a: a = string.swapcase(a[0])+a[1:]
if b: b = string.swapcase(b[0])+b[1:]
if order == 'ascending':
return cmp(a,b)
else:
return cmp(b,a)
|