File: SortElement.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 (131 lines) | stat: -rw-r--r-- 4,866 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
########################################################################
#
# 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)