~landscape/zope3/ztk-1.1.3

« back to all changes in this revision

Viewing changes to src/zope/structuredtext/stdom.py

  • Committer: Sidnei da Silva
  • Date: 2010-07-05 21:07:01 UTC
  • Revision ID: sidnei.da.silva@canonical.com-20100705210701-zmqhqrbzad1mhzsl
- Reduce deps

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
##############################################################################
2
 
#
3
 
# Copyright (c) 2001 Zope Foundation and Contributors.
4
 
#
5
 
# This software is subject to the provisions of the Zope Public License,
6
 
# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
7
 
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
8
 
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
9
 
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
10
 
# FOR A PARTICULAR PURPOSE
11
 
#
12
 
##############################################################################
13
 
"""DOM implementation in StructuredText: read-only methods
14
 
"""
15
 
 
16
 
string_types = (str, unicode)
17
 
 
18
 
__metaclass__ = type
19
 
 
20
 
# Node type codes
21
 
# ---------------
22
 
 
23
 
ELEMENT_NODE                  = 1
24
 
ATTRIBUTE_NODE                = 2
25
 
TEXT_NODE                     = 3
26
 
CDATA_SECTION_NODE            = 4
27
 
ENTITY_REFERENCE_NODE         = 5
28
 
ENTITY_NODE                   = 6
29
 
PROCESSING_INSTRUCTION_NODE   = 7
30
 
COMMENT_NODE                  = 8
31
 
DOCUMENT_NODE                 = 9
32
 
DOCUMENT_TYPE_NODE            = 10
33
 
DOCUMENT_FRAGMENT_NODE        = 11
34
 
NOTATION_NODE                 = 12
35
 
 
36
 
# Exception codes
37
 
# ---------------
38
 
 
39
 
INDEX_SIZE_ERR                = 1
40
 
DOMSTRING_SIZE_ERR            = 2
41
 
HIERARCHY_REQUEST_ERR         = 3
42
 
WRONG_DOCUMENT_ERR            = 4
43
 
INVALID_CHARACTER_ERR         = 5
44
 
NO_DATA_ALLOWED_ERR           = 6
45
 
NO_MODIFICATION_ALLOWED_ERR   = 7
46
 
NOT_FOUND_ERR                 = 8
47
 
NOT_SUPPORTED_ERR             = 9
48
 
INUSE_ATTRIBUTE_ERR           = 10
49
 
 
50
 
# Exceptions
51
 
# ----------
52
 
 
53
 
class DOMException(Exception):
54
 
    pass
55
 
class IndexSizeException(DOMException):
56
 
    code = INDEX_SIZE_ERR
57
 
class DOMStringSizeException(DOMException):
58
 
    code = DOMSTRING_SIZE_ERR
59
 
class HierarchyRequestException(DOMException):
60
 
    code = HIERARCHY_REQUEST_ERR
61
 
class WrongDocumentException(DOMException):
62
 
    code = WRONG_DOCUMENT_ERR
63
 
class InvalidCharacterException(DOMException):
64
 
    code = INVALID_CHARACTER_ERR
65
 
class NoDataAllowedException(DOMException):
66
 
    code = NO_DATA_ALLOWED_ERR
67
 
class NoModificationAllowedException(DOMException):
68
 
    code = NO_MODIFICATION_ALLOWED_ERR
69
 
class NotFoundException(DOMException):
70
 
    code = NOT_FOUND_ERR
71
 
class NotSupportedException(DOMException):
72
 
    code = NOT_SUPPORTED_ERR
73
 
class InUseAttributeException(DOMException):
74
 
    code = INUSE_ATTRIBUTE_ERR
75
 
 
76
 
# Node classes
77
 
# ------------
78
 
 
79
 
class ParentNode:
80
 
    """
81
 
    A node that can have children, or, more precisely, that implements
82
 
    the child access methods of the DOM.
83
 
    """
84
 
 
85
 
    def getChildNodes(self, type=type, sts=string_types):
86
 
        """
87
 
        Returns a NodeList that contains all children of this node.
88
 
        If there are no children, this is a empty NodeList
89
 
        """
90
 
        r = []
91
 
        for n in self.getChildren():
92
 
            if type(n) in sts:
93
 
                n=TextNode(n)
94
 
            r.append(n.__of__(self))
95
 
 
96
 
        return NodeList(r)
97
 
 
98
 
    def getFirstChild(self, type=type, sts=string_types):
99
 
        """
100
 
        The first child of this node. If there is no such node
101
 
        this returns None
102
 
        """
103
 
        children = self.getChildren()
104
 
 
105
 
        if not children:
106
 
            return None
107
 
 
108
 
        n = children[0]
109
 
 
110
 
        if type(n) in sts:
111
 
            n = TextNode(n)
112
 
 
113
 
        return n.__of__(self)
114
 
 
115
 
    def getLastChild(self, type=type, sts=string_types):
116
 
        """
117
 
        The last child of this node.  If there is no such node
118
 
        this returns None.
119
 
        """
120
 
        children = self.getChildren()
121
 
        if not children:
122
 
            return None
123
 
        n = children[-1]
124
 
        if type(n) in sts:
125
 
            n=TextNode(n)
126
 
        return n.__of__(self)
127
 
 
128
 
 
129
 
class NodeWrapper(ParentNode):
130
 
    """
131
 
    This is an acquisition-like wrapper that provides parent access for
132
 
    DOM sans circular references!
133
 
    """
134
 
 
135
 
    def __init__(self, aq_self, aq_parent):
136
 
        self.aq_self=aq_self
137
 
        self.aq_parent=aq_parent
138
 
 
139
 
    def __getattr__(self, name):
140
 
        return getattr(self.aq_self, name)
141
 
 
142
 
    def getParentNode(self):
143
 
        """
144
 
        The parent of this node.  All nodes except Document
145
 
        DocumentFragment and Attr may have a parent
146
 
        """
147
 
        return self.aq_parent
148
 
 
149
 
    def _getDOMIndex(self, children, getattr=getattr):
150
 
        i=0
151
 
        self=self.aq_self
152
 
        for child in children:
153
 
            if getattr(child, 'aq_self', child) is self:
154
 
                self._DOMIndex=i
155
 
                return i
156
 
            i=i+1
157
 
        return None
158
 
 
159
 
    def getPreviousSibling(self):
160
 
        """
161
 
        The node immediately preceding this node.  If
162
 
        there is no such node, this returns None.
163
 
        """
164
 
 
165
 
        children = self.aq_parent.getChildren()
166
 
        if not children:
167
 
            return None
168
 
 
169
 
        index=getattr(self, '_DOMIndex', None)
170
 
        if index is None:
171
 
            index=self._getDOMIndex(children)
172
 
            if index is None: return None
173
 
 
174
 
        index=index-1
175
 
        if index < 0: return None
176
 
        try: n=children[index]
177
 
        except IndexError: return None
178
 
        else:
179
 
            if type(n) in string_types:
180
 
                n=TextNode(n)
181
 
            n._DOMIndex=index
182
 
            return n.__of__(self)
183
 
 
184
 
 
185
 
    def getNextSibling(self):
186
 
        """
187
 
        The node immediately preceding this node.  If
188
 
        there is no such node, this returns None.
189
 
        """
190
 
        children = self.aq_parent.getChildren()
191
 
        if not children:
192
 
            return None
193
 
 
194
 
        index=getattr(self, '_DOMIndex', None)
195
 
        if index is None:
196
 
            index=self._getDOMIndex(children)
197
 
            if index is None:
198
 
                return None
199
 
 
200
 
        index=index+1
201
 
        try: n=children[index]
202
 
        except IndexError:
203
 
            return None
204
 
        else:
205
 
            if type(n) in string_types:
206
 
                n=TextNode(n)
207
 
            n._DOMIndex=index
208
 
            return n.__of__(self)
209
 
 
210
 
    def getOwnerDocument(self):
211
 
        """
212
 
        The Document object associated with this node, if any.
213
 
        """
214
 
        return self.aq_parent.getOwnerDocument()
215
 
 
216
 
class Node(ParentNode):
217
 
    """Node Interface
218
 
    """
219
 
 
220
 
    # Get a DOM wrapper with a parent link
221
 
    def __of__(self, parent):
222
 
        return NodeWrapper(self, parent)
223
 
 
224
 
    # DOM attributes
225
 
 
226
 
    def getNodeName(self):
227
 
        """The name of this node, depending on its type
228
 
        """
229
 
 
230
 
    def getNodeValue(self):
231
 
        """The value of this node, depending on its type
232
 
        """
233
 
        return None
234
 
 
235
 
    def getParentNode(self):
236
 
        """
237
 
        The parent of this node.  All nodes except Document
238
 
        DocumentFragment and Attr may have a parent
239
 
        """
240
 
 
241
 
    def getChildren(self):
242
 
        """Get a Python sequence of children
243
 
        """
244
 
        return ()
245
 
 
246
 
    def getPreviousSibling(self):
247
 
        """
248
 
        The node immediately preceding this node.  If
249
 
        there is no such node, this returns None.
250
 
        """
251
 
 
252
 
    def getNextSibling(self):
253
 
        """
254
 
        The node immediately preceding this node.  If
255
 
        there is no such node, this returns None.
256
 
        """
257
 
 
258
 
    def getAttributes(self):
259
 
        """
260
 
        Returns a NamedNodeMap containing the attributes
261
 
        of this node (if it is an element) or None otherwise.
262
 
        """
263
 
        return None
264
 
 
265
 
    def getOwnerDocument(self):
266
 
        """The Document object associated with this node, if any.
267
 
        """
268
 
 
269
 
    # DOM Methods
270
 
    # -----------
271
 
 
272
 
    def hasChildNodes(self):
273
 
        """
274
 
        Returns true if the node has any children, false
275
 
        if it doesn't.
276
 
        """
277
 
        return len(self.getChildren())
278
 
 
279
 
class TextNode(Node):
280
 
 
281
 
    def __init__(self, str): self._value=str
282
 
 
283
 
    def getNodeType(self):
284
 
        return TEXT_NODE
285
 
 
286
 
    def getNodeName(self):
287
 
        return '#text'
288
 
 
289
 
    def getNodeValue(self):
290
 
        return self._value
291
 
 
292
 
class Element(Node):
293
 
    """Element interface
294
 
    """
295
 
 
296
 
    # Element Attributes
297
 
    # ------------------
298
 
 
299
 
    def getTagName(self):
300
 
        """The name of the element"""
301
 
        return self.__class__.__name__
302
 
 
303
 
    def getNodeName(self):
304
 
        """The name of this node, depending on its type"""
305
 
        return self.__class__.__name__
306
 
 
307
 
    def getNodeType(self):
308
 
        """A code representing the type of the node."""
309
 
        return ELEMENT_NODE
310
 
 
311
 
    def getNodeValue(self):
312
 
        r=[]
313
 
        for c in self.getChildren():
314
 
            if type(c) not in string_types:
315
 
                c=c.getNodeValue()
316
 
            r.append(c)
317
 
        return ''.join(r)
318
 
 
319
 
    def getParentNode(self):
320
 
        """
321
 
        The parent of this node.  All nodes except Document
322
 
        DocumentFragment and Attr may have a parent
323
 
        """
324
 
 
325
 
    # Element Methods
326
 
    # ---------------
327
 
 
328
 
    _attributes=()
329
 
 
330
 
    def getAttribute(self, name): return getattr(self, name, None)
331
 
    def getAttributeNode(self, name):
332
 
        if hasattr(self, name):
333
 
            return Attr(name, getattr(self, name))
334
 
 
335
 
    def getAttributes(self):
336
 
        d={}
337
 
        for a in self._attributes:
338
 
            d[a]=getattr(self, a, '')
339
 
        return NamedNodeMap(d)
340
 
 
341
 
    def getAttribute(self, name):
342
 
        """Retrieves an attribute value by name."""
343
 
        return None
344
 
 
345
 
    def getAttributeNode(self, name):
346
 
        """ Retrieves an Attr node by name or None if
347
 
        there is no such attribute. """
348
 
        return None
349
 
 
350
 
    def getElementsByTagName(self, tagname):
351
 
        """
352
 
        Returns a NodeList of all the Elements with a given tag
353
 
        name in the order in which they would be encountered in a
354
 
        preorder traversal of the Document tree.  Parameter: tagname
355
 
        The name of the tag to match (* = all tags). Return Value: A new
356
 
        NodeList object containing all the matched Elements.
357
 
        """
358
 
        nodeList = []
359
 
        for child in self.getChildren():
360
 
            if not hasattr(child, 'getNodeType'): continue
361
 
            if (child.getNodeType()==ELEMENT_NODE and \
362
 
                child.getTagName()==tagname or tagname== '*'):
363
 
 
364
 
                nodeList.append(child)
365
 
 
366
 
            if hasattr(child, 'getElementsByTagName'):
367
 
                n1       = child.getElementsByTagName(tagname)
368
 
                nodeList = nodeList + n1._data
369
 
        return NodeList(nodeList)
370
 
 
371
 
class NodeList:
372
 
    """NodeList interface - Provides the abstraction of an ordered
373
 
    collection of nodes.
374
 
 
375
 
    Python extensions: can use sequence-style 'len', 'getitem', and
376
 
    'for..in' constructs.
377
 
    """
378
 
 
379
 
    def __init__(self,list=None):
380
 
        self._data = list or []
381
 
 
382
 
    def __getitem__(self, index, type=type, sts=string_types):
383
 
        return self._data[index]
384
 
 
385
 
    def __getslice__(self, i, j):
386
 
        return self._data[i:j]
387
 
 
388
 
    def item(self, index):
389
 
        """Returns the index-th item in the collection
390
 
        """
391
 
        return self._data.get(index, None)
392
 
 
393
 
    def getLength(self):
394
 
        """The length of the NodeList
395
 
        """
396
 
        return len(self._data)
397
 
 
398
 
    __len__ = getLength
399
 
 
400
 
class NamedNodeMap:
401
 
    """
402
 
    NamedNodeMap interface - Is used to represent collections
403
 
    of nodes that can be accessed by name.  NamedNodeMaps are not
404
 
    maintained in any particular order.
405
 
 
406
 
    Python extensions: can use sequence-style 'len', 'getitem', and
407
 
    'for..in' constructs, and mapping-style 'getitem'.
408
 
    """
409
 
 
410
 
    def __init__(self, data=None):
411
 
        if data is None:
412
 
            data = {}
413
 
        self._data = data
414
 
 
415
 
    def item(self, index):
416
 
        """Returns the index-th item in the map
417
 
        """
418
 
        return self._data.values().get(index, None)
419
 
        
420
 
 
421
 
    def __getitem__(self, key):
422
 
        if isinstance(key, int):
423
 
            return self.item(key)
424
 
        else:
425
 
            return self._data[key]
426
 
 
427
 
    def getLength(self):
428
 
        """
429
 
        The length of the NodeList
430
 
        """
431
 
        return len(self._data)
432
 
 
433
 
    __len__ = getLength
434
 
 
435
 
    def getNamedItem(self, name):
436
 
        """
437
 
        Retrieves a node specified by name. Parameters:
438
 
        name Name of a node to retrieve. Return Value A Node (of any
439
 
        type) with the specified name, or None if the specified name
440
 
        did not identify any node in the map.
441
 
        """
442
 
        return self._data.get(name, None)
443
 
 
444
 
class Attr(Node):
445
 
    """
446
 
    Attr interface - The Attr interface represents an attriubte in an
447
 
    Element object. Attr objects inherit the Node Interface
448
 
    """
449
 
 
450
 
    def __init__(self, name, value, specified=1):
451
 
        self.name = name
452
 
        self.value = value
453
 
        self.specified = specified
454
 
 
455
 
    def getNodeName(self):
456
 
        """
457
 
        The name of this node, depending on its type
458
 
        """
459
 
        return self.name
460
 
 
461
 
    def getName(self):
462
 
        """
463
 
        Returns the name of this attribute.
464
 
        """
465
 
        return self.name
466
 
 
467
 
    def getNodeValue(self):
468
 
        """
469
 
        The value of this node, depending on its type
470
 
        """
471
 
        return self.value
472
 
 
473
 
    def getNodeType(self):
474
 
        """
475
 
        A code representing the type of the node.
476
 
        """
477
 
        return ATTRIBUTE_NODE
478
 
 
479
 
    def getSpecified(self):
480
 
        """
481
 
        If this attribute was explicitly given a value in the
482
 
        original document, this is true; otherwise, it is false.
483
 
        """
484
 
        return self.specified