wxWidgets/wxPython/samples/stxview/StructuredText/STDOM.py
2001-05-04 18:28:27 +00:00

737 lines
20 KiB
Python

##############################################################################
#
# Zope Public License (ZPL) Version 1.0
# -------------------------------------
#
# Copyright (c) Digital Creations. All rights reserved.
#
# This license has been certified as Open Source(tm).
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# 1. Redistributions in source code must retain the above copyright
# notice, this list of conditions, and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions, and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
#
# 3. Digital Creations requests that attribution be given to Zope
# in any manner possible. Zope includes a "Powered by Zope"
# button that is installed by default. While it is not a license
# violation to remove this button, it is requested that the
# attribution remain. A significant investment has been put
# into Zope, and this effort will continue if the Zope community
# continues to grow. This is one way to assure that growth.
#
# 4. All advertising materials and documentation mentioning
# features derived from or use of this software must display
# the following acknowledgement:
#
# "This product includes software developed by Digital Creations
# for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# In the event that the product being advertised includes an
# intact Zope distribution (with copyright and license included)
# then this clause is waived.
#
# 5. Names associated with Zope or Digital Creations must not be used to
# endorse or promote products derived from this software without
# prior written permission from Digital Creations.
#
# 6. Modified redistributions of any form whatsoever must retain
# the following acknowledgment:
#
# "This product includes software developed by Digital Creations
# for use in the Z Object Publishing Environment
# (http://www.zope.org/)."
#
# Intact (re-)distributions of any official Zope release do not
# require an external acknowledgement.
#
# 7. Modifications are encouraged but must be packaged separately as
# patches to official Zope releases. Distributions that do not
# clearly separate the patches from the original work must be clearly
# labeled as unofficial distributions. Modifications which do not
# carry the name Zope may be packaged in any form, as long as they
# conform to all of the clauses above.
#
#
# Disclaimer
#
# THIS SOFTWARE IS PROVIDED BY DIGITAL CREATIONS ``AS IS'' AND ANY
# EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DIGITAL CREATIONS OR ITS
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
#
# This software consists of contributions made by Digital Creations and
# many individuals on behalf of Digital Creations. Specific
# attributions are listed in the accompanying credits file.
#
##############################################################################
"""
DOM implementation in StructuredText : Read-Only methods
All standard Zope objects support DOM to a limited extent.
"""
import string
# Node type codes
# ---------------
ELEMENT_NODE = 1
ATTRIBUTE_NODE = 2
TEXT_NODE = 3
CDATA_SECTION_NODE = 4
ENTITY_REFERENCE_NODE = 5
ENTITY_NODE = 6
PROCESSING_INSTRUCTION_NODE = 7
COMMENT_NODE = 8
DOCUMENT_NODE = 9
DOCUMENT_TYPE_NODE = 10
DOCUMENT_FRAGMENT_NODE = 11
NOTATION_NODE = 12
# Exception codes
# ---------------
INDEX_SIZE_ERR = 1
DOMSTRING_SIZE_ERR = 2
HIERARCHY_REQUEST_ERR = 3
WRONG_DOCUMENT_ERR = 4
INVALID_CHARACTER_ERR = 5
NO_DATA_ALLOWED_ERR = 6
NO_MODIFICATION_ALLOWED_ERR = 7
NOT_FOUND_ERR = 8
NOT_SUPPORTED_ERR = 9
INUSE_ATTRIBUTE_ERR = 10
# Exceptions
# ----------
class DOMException(Exception):
pass
class IndexSizeException(DOMException):
code = INDEX_SIZE_ERR
class DOMStringSizeException(DOMException):
code = DOMSTRING_SIZE_ERR
class HierarchyRequestException(DOMException):
code = HIERARCHY_REQUEST_ERR
class WrongDocumentException(DOMException):
code = WRONG_DOCUMENT_ERR
class InvalidCharacterException(DOMException):
code = INVALID_CHARACTER_ERR
class NoDataAllowedException(DOMException):
code = NO_DATA_ALLOWED_ERR
class NoModificationAllowedException(DOMException):
code = NO_MODIFICATION_ALLOWED_ERR
class NotFoundException(DOMException):
code = NOT_FOUND_ERR
class NotSupportedException(DOMException):
code = NOT_SUPPORTED_ERR
class InUseAttributeException(DOMException):
code = INUSE_ATTRIBUTE_ERR
# Node classes
# ------------
class ParentNode:
"""
A node that can have children, or, more precisely, that implements
the child access methods of the DOM.
"""
def getChildNodes(self, type=type, st=type('')):
"""
Returns a NodeList that contains all children of this node.
If there are no children, this is a empty NodeList
"""
r=[]
for n in self.getChildren():
if type(n) is st: n=TextNode(n)
r.append(n.__of__(self))
return NodeList(r)
def getFirstChild(self, type=type, st=type('')):
"""
The first child of this node. If there is no such node
this returns None
"""
children = self.getChildren()
if not children:
return None
n=children[0]
if type(n) is st:
n=TextNode(n)
return n.__of__(self)
def getLastChild(self, type=type, st=type('')):
"""
The last child of this node. If there is no such node
this returns None.
"""
children = self.getChildren()
if not children: return None
n=chidren[-1]
if type(n) is st: n=TextNode(n)
return n.__of__(self)
"""
create aliases for all above functions in the pythony way.
"""
def _get_ChildNodes(self, type=type, st=type('')):
return self.getChildNodes(type,st)
def _get_FirstChild(self, type=type, st=type('')):
return self.getFirstChild(type,st)
def _get_LastChild(self, type=type, st=type('')):
return self.getLastChild(type,st)
class NodeWrapper(ParentNode):
"""
This is an acquisition-like wrapper that provides parent access for
DOM sans circular references!
"""
def __init__(self, aq_self, aq_parent):
self.aq_self=aq_self
self.aq_parent=aq_parent
def __getattr__(self, name):
return getattr(self.aq_self, name)
def getParentNode(self):
"""
The parent of this node. All nodes except Document
DocumentFragment and Attr may have a parent
"""
return self.aq_parent
def _getDOMIndex(self, children, getattr=getattr):
i=0
self=self.aq_self
for child in children:
if getattr(child, 'aq_self', child) is self:
self._DOMIndex=i
return i
i=i+1
return None
def getPreviousSibling(self,
type=type,
st=type(''),
getattr=getattr,
None=None):
"""
The node immediately preceding this node. If
there is no such node, this returns None.
"""
children = self.aq_parent.getChildren()
if not children:
return None
index=getattr(self, '_DOMIndex', None)
if index is None:
index=self._getDOMIndex(children)
if index is None: return None
index=index-1
if index < 0: return None
try: n=children[index]
except IndexError: return None
else:
if type(n) is st:
n=TextNode(n)
n._DOMIndex=index
return n.__of__(self)
def getNextSibling(self, type=type, st=type('')):
"""
The node immediately preceding this node. If
there is no such node, this returns None.
"""
children = self.aq_parent.getChildren()
if not children:
return None
index=getattr(self, '_DOMIndex', None)
if index is None:
index=self._getDOMIndex(children)
if index is None:
return None
index=index+1
try: n=children[index]
except IndexError:
return None
else:
if type(n) is st:
n=TextNode(n)
n._DOMIndex=index
return n.__of__(self)
def getOwnerDocument(self):
"""
The Document object associated with this node, if any.
"""
return self.aq_parent.getOwnerDocument()
"""
create aliases for all above functions in the pythony way.
"""
def _get_ParentNode(self):
return self.getParentNode()
def _get_DOMIndex(self, children, getattr=getattr):
return self._getDOMIndex(children,getattr)
def _get_PreviousSibling(self,
type=type,
st=type(''),
getattr=getattr,
None=None):
return self.getPreviousSibling(type,st,getattr,None)
def _get_NextSibling(self, type=type, st=type('')):
return self.getNextSibling(type,st)
def _get_OwnerDocument(self):
return self.getOwnerDocument()
class Node(ParentNode):
"""
Node Interface
"""
# Get a DOM wrapper with a parent link
def __of__(self, parent):
return NodeWrapper(self, parent)
# DOM attributes
# --------------
def getNodeName(self):
"""
The name of this node, depending on its type
"""
def getNodeValue(self):
"""
The value of this node, depending on its type
"""
return None
def getParentNode(self):
"""
The parent of this node. All nodes except Document
DocumentFragment and Attr may have a parent
"""
def getChildren(self):
"""
Get a Python sequence of children
"""
return ()
def getPreviousSibling(self,
type=type,
st=type(''),
getattr=getattr,
None=None):
"""
The node immediately preceding this node. If
there is no such node, this returns None.
"""
def getNextSibling(self, type=type, st=type('')):
"""
The node immediately preceding this node. If
there is no such node, this returns None.
"""
def getAttributes(self):
"""
Returns a NamedNodeMap containing the attributes
of this node (if it is an element) or None otherwise.
"""
return None
def getOwnerDocument(self):
"""
The Document object associated with this node, if any.
"""
# DOM Methods
# -----------
def hasChildNodes(self):
"""
Returns true if the node has any children, false
if it doesn't.
"""
return len(self.getChildren())
"""
create aliases for all above functions in the pythony way.
"""
def _get_NodeName(self):
return self.getNodeName()
def _get_NodeValue(self):
return self.getNodeValue()
def _get_ParentNode(self):
return self.getParentNode()
def _get_Children(self):
return self.getChildren()
def _get_PreviousSibling(self,
type=type,
st=type(''),
getattr=getattr,
None=None):
return self.getPreviousSibling(type,st,getattr,None)
def _get_NextSibling(self, type=type, st=type('')):
return self.getNextSibling()
def _get_Attributes(self):
return self.getAttributes()
def _get_OwnerDocument(self):
return self.getOwnerDocument()
def _has_ChildNodes(self):
return self.hasChildNodes()
class TextNode(Node):
def __init__(self, str): self._value=str
def getNodeType(self):
return TEXT_NODE
def getNodeName(self):
return '#text'
def getNodeValue(self):
return self._value
"""
create aliases for all above functions in the pythony way.
"""
def _get_NodeType(self):
return self.getNodeType()
def _get_NodeName(self):
return self.getNodeName()
def _get_NodeValue(self):
return self.getNodeValue()
class Element(Node):
"""
Element interface
"""
# Element Attributes
# ------------------
def getTagName(self):
"""The name of the element"""
return self.__class__.__name__
def getNodeName(self):
"""The name of this node, depending on its type"""
return self.__class__.__name__
def getNodeType(self):
"""A code representing the type of the node."""
return ELEMENT_NODE
def getNodeValue(self, type=type, st=type('')):
r=[]
for c in self.getChildren():
if type(c) is not st:
c=c.getNodeValue()
r.append(c)
return string.join(r,'')
def getParentNode(self):
"""
The parent of this node. All nodes except Document
DocumentFragment and Attr may have a parent
"""
# Element Methods
# ---------------
_attributes=()
def getAttribute(self, name): return getattr(self, name, None)
def getAttributeNode(self, name):
if hasattr(self, name):
return Attr(name, getattr(self, name))
def getAttributes(self):
d={}
for a in self._attributes:
d[a]=getattr(self, a, '')
return NamedNodeMap(d)
def getAttribute(self, name):
"""Retrieves an attribute value by name."""
return None
def getAttributeNode(self, name):
""" Retrieves an Attr node by name or None if
there is no such attribute. """
return None
def getElementsByTagName(self, tagname):
"""
Returns a NodeList of all the Elements with a given tag
name in the order in which they would be encountered in a
preorder traversal of the Document tree. Parameter: tagname
The name of the tag to match (* = all tags). Return Value: A new
NodeList object containing all the matched Elements.
"""
nodeList = []
for child in self.getChildren():
if (child.getNodeType()==ELEMENT_NODE and \
child.getTagName()==tagname or tagname== '*'):
nodeList.append(child)
if hasattr(child, 'getElementsByTagName'):
n1 = child.getElementsByTagName(tagname)
nodeList = nodeList + n1._data
return NodeList(nodeList)
"""
create aliases for all above functions in the pythony way.
"""
def _get_TagName(self):
return self.getTagName()
def _get_NodeName(self):
return self.getNodeName()
def _get_NodeType(self):
return self.getNodeType()
def _get_NodeValue(self, type=type, st=type('')):
return self.getNodeValue(type,st)
def _get_ParentNode(self):
return self.getParentNode()
def _get_Attribute(self, name):
return self.getAttribute(name)
def _get_AttributeNode(self, name):
return self.getAttributeNode(name)
def _get_Attributes(self):
return self.getAttributes()
def _get_Attribute(self, name):
return self.getAttribute(name)
def _get_AttributeNode(self, name):
return self.getAttributeNode(name)
def _get_ElementsByTagName(self, tagname):
return self.getElementsByTagName(tagname)
class NodeList:
"""
NodeList interface - Provides the abstraction of an ordered
collection of nodes.
Python extensions: can use sequence-style 'len', 'getitem', and
'for..in' constructs.
"""
def __init__(self,list=None):
self._data = list or []
def __getitem__(self, index, type=type, st=type('')):
return self._data[index]
def __getslice__(self, i, j):
return self._data[i:j]
def item(self, index):
"""
Returns the index-th item in the collection
"""
try: return self._data[index]
except IndexError: return None
def getLength(self):
"""
The length of the NodeList
"""
return len(self._data)
__len__=getLength
"""
create aliases for all above functions in the pythony way.
"""
def _get_Length(self):
return self.getLength()
class NamedNodeMap:
"""
NamedNodeMap interface - Is used to represent collections
of nodes that can be accessed by name. NamedNodeMaps are not
maintained in any particular order.
Python extensions: can use sequence-style 'len', 'getitem', and
'for..in' constructs, and mapping-style 'getitem'.
"""
def __init__(self, data=None):
if data is None:
data = {}
self._data = data
def item(self, index):
"""
Returns the index-th item in the map
"""
try: return self._data.values()[index]
except IndexError: return None
def __getitem__(self, key):
if type(key)==type(1):
return self._data.values()[key]
else:
return self._data[key]
def getLength(self):
"""
The length of the NodeList
"""
return len(self._data)
__len__ = getLength
def getNamedItem(self, name):
"""
Retrieves a node specified by name. Parameters:
name Name of a node to retrieve. Return Value A Node (of any
type) with the specified name, or None if the specified name
did not identify any node in the map.
"""
if self._data.has_key(name):
return self._data[name]
return None
"""
create aliases for all above functions in the pythony way.
"""
def _get_Length(self):
return self.getLength()
def _get_NamedItem(self, name):
return self.getNamedItem(name)
class Attr(Node):
"""
Attr interface - The Attr interface represents an attriubte in an
Element object. Attr objects inherit the Node Interface
"""
def __init__(self, name, value, specified=1):
self.name = name
self.value = value
self.specified = specified
def getNodeName(self):
"""
The name of this node, depending on its type
"""
return self.name
def getName(self):
"""
Returns the name of this attribute.
"""
return self.name
def getNodeValue(self):
"""
The value of this node, depending on its type
"""
return self.value
def getNodeType(self):
"""
A code representing the type of the node.
"""
return ATTRIBUTE_NODE
def getSpecified(self):
"""
If this attribute was explicitly given a value in the
original document, this is true; otherwise, it is false.
"""
return self.specified
"""
create aliases for all above functions in the pythony way.
"""
def _get_NodeName(self):
return self.getNodeName()
def _get_Name(self):
return self.getName()
def _get_NodeValue(self):
return self.getNodeValue()
def _get_NodeType(self):
return self.getNodeType()
def _get_Specified(self):
return self.getSpecified()