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