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