ParsedXML/0040755000175200017500000000000007600634640012336 5ustar faasseninfraeParsedXML/DOM/0040755000175200017500000000000007600634637012763 5ustar faasseninfraeParsedXML/DOM/LoadSave.py0100644000175200017500000002305407262702414015025 0ustar faasseninfrae############################################################################## # # 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. # ############################################################################## """Implementation of the DOM Level 3 'Load' feature.""" import Core import ExpatBuilder import copy import string import xml.dom __all__ = ["DOMBuilder", "DOMEntityResolver", "DOMInputSource"] class DOMBuilder(Core.AttributeControl): entityResolver = None errorHandler = None filter = None def __init__(self): self.__dict__['_options'] = ExpatBuilder.Options() def _get_entityResolver(self): return self.entityResolver def _set_entityResolver(self, entityResolver): self.__dict__['entityResolver'] def _get_errorHandler(self): return self.errorHandler def _set_errorHandler(self, errorHandler): self.__dict__['errorHandler'] = errorHandler def _get_filter(self): return self.filter def _set_filter(self, filter): self.__dict__['filter'] = filter def setFeature(self, name, state): if self.supportsFeature(name): try: settings = self._settings[(_name_xform(name), state)] except KeyError: raise xml.dom.NotSupportedErr( "unsupported feature: " + `name`) else: for name, value in settings: setattr(self._options, name, value) else: raise xml.dom.NotFoundErr("unknown feature: " + `name`) def supportsFeature(self, name): return hasattr(self._options, _name_xform(name)) def canSetFeature(self, name, state): key = (_name_xform(name), state and 1 or 0) return self._settings.has_key(key) _settings = { ("namespaces", 0): [("namespaces", 0)], ("namespaces", 1): [("namespaces", 1)], ("namespace_declarations", 0): [("namespace_declarations", 0)], ("namespace_declarations", 1): [("namespace_declarations", 1)], ("validation", 0): [("validation", 0)], ("external_general_entities", 0): [("external_general_entities", 0)], ("external_general_entities", 1): [("external_general_entities", 1)], ("external_parameter_entities", 0): [("external_parameter_entities", 0)], ("external_parameter_entities", 1): [("external_parameter_entities", 1)], ("validate_if_cm", 0): [("validate_if_cm", 0)], ("create_entity_ref_nodes", 0): [("create_entity_ref_nodes", 0)], ("create_entity_ref_nodes", 1): [("create_entity_ref_nodes", 1)], ("entity_nodes", 0): [("create_entity_ref_nodes", 0), ("entity_nodes", 0)], ("entity_nodes", 1): [("entity_nodes", 1)], ("white_space_in_element_content", 0): [("white_space_in_element_content", 0)], ("white_space_in_element_content", 1): [("white_space_in_element_content", 1)], ("cdata_nodes", 0): [("cdata_nodes", 0)], ("cdata_nodes", 1): [("cdata_nodes", 1)], ("comments", 0): [("comments", 0)], ("comments", 1): [("comments", 1)], ("charset_overrides_xml_encoding", 0): [("charset_overrides_xml_encoding", 0)], ("charset_overrides_xml_encoding", 1): [("charset_overrides_xml_encoding", 1)], } def getFeature(self, name): try: return getattr(self._options, _name_xform(name)) except AttributeError: raise xml.dom.NotFoundErr() def parseURI(self, uri): if self.entityResolver: input = self.entityResolver.resolveEntity(None, uri) else: input = DOMEntityResolver().resolveEntity(None, uri) return self.parseDOMInputSource(input) def parseDOMInputSource(self, input): options = copy.copy(self._options) options.filter = self.filter options.errorHandler = self.errorHandler fp = input.byteStream if fp is None and options.systemId: import urllib fp = urllib.urlopen(input.systemId) builder = ExpatBuilder.makeBuilder(options) return builder.parseFile(fp) class DOMEntityResolver(Core.DOMImplementation): def resolveEntity(self, publicId, systemId): source = DOMInputSource() source.publicId = publicId source.systemId = systemId if systemId: import urllib self.byteStream = urllib.urlopen(systemId) # Should parse out the content-type: header to # get charset information so that we can set the # encoding attribute on the DOMInputSource. return source class DOMInputSource(Core.AttributeControl): byteStream = None characterStream = None encoding = None publicId = None systemId = None def _get_byteStream(self): return self.byteStream def _set_byteStream(self, byteStream): self.__dict__['byteStream'] = byteStream def _get_characterStream(self): return self.characterStream def _set_characterStream(self, characterStream): self.__dict__['characterStream'] = characterStream def _get_encoding(self): return self.encoding def _set_encoding(self, encoding): self.__dict__['encoding'] = encoding def _get_publicId(self): return self.publicId def _set_publicId(self, publicId): self.__dict__['publicId'] = publicId def _get_systemId(self): return self.systemId def _set_systemId(self, systemId): self.__dict__['systemId'] = systemId class DOMBuilderFilter: """Element filter which can be used to tailor construction of a DOM instance. """ # There's really no need for this class; concrete implementations # should just implement the endElement() method as appropriate. def endElement(self, element): # Why this method is supposed to return anything at all # is a mystery; the result doesn't appear to be used. return 1 def _name_xform(name): return string.replace(string.lower(name), '-', '_') ParsedXML/DOM/Core.py0100644000175200017500000023745607477152072014243 0ustar faasseninfrae############################################################################## # # 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. # ############################################################################## # Performance hacks: # # - Do not test node objects for truth; use an identity comparison # with None instead. This avoids all attribute lookups and # requires exactly two dictionary lookups (module globals and # builtins). # # - There is no Node.__init__(); it doesn't do much for most # classes anyway. This avoids a small performance penalty. import string _string = string del string import Acquisition _Acquisition = Acquisition def _reparent(ob, parent): ob.aq_inner.aq_parent = parent ob.aq_parent = parent if parent is None and ob._in_tree: ob.__dict__['_in_tree'] = 0 def _parent_of(ob, aq_inner=_Acquisition.aq_inner, aq_parent=_Acquisition.aq_parent): return aq_parent(aq_inner(ob)) _aq_base = _Acquisition.aq_base del Acquisition from ComputedAttribute import ComputedAttribute import xml.dom # legal qualified name pattern, from PyXML xml/dom/Document.py # see http://www.w3.org/TR/REC-xml-names/#NT-QName # we don't enforce namespace usage if using namespaces, which basically # means that we don't disallow a leading ':' # XXX there's more to the world than ascii a-z # FIXME: should allow combining characters: fix when Python gets Unicode try: import sre # Note that Python 1.5.2's re module chokes. Require sre. except ImportError: def _ok_qualified_name(s, bad_first=(_string.digits + '.-'), good=(_string.letters + _string.digits + '.-_:')): if len(s) < 1: return None if s[0] in bad_first: return None for c in s: if c not in good: return None return 1 # Indicates "passed". else: _ok_qualified_name = sre.compile('[a-zA-Z_:][\w\.\-_:]*\Z').match del sre _TupleType = type(()) try: unicode except NameError: _StringTypes = (type(''),) else: # can't use u'' syntax due to Python 1.5.2 compatibility requirement _StringTypes = (type(''), type(unicode(''))) # http://www.w3.org/TR/1999/REC-xml-names-19990114/#ns-qualnames def _check_qualified_name(name, uri='ok'): "test name for well-formedness" if _ok_qualified_name(name) is not None: if ":" in name: parts = _string.split(name, ":") if len(parts) != 2: raise xml.dom.NamespaceErr("malformed qualified name") if not (parts[0] and parts[1]): raise xml.dom.NamespaceErr("malformed qualified name") if not uri: raise xml.dom.NamespaceErr("no namespace URI for prefix") return 1 else: raise xml.dom.InvalidCharacterErr() # Common namespaces: XML_NS = "http://www.w3.org/XML/1998/namespace" XMLNS_NS = "http://www.w3.org/2000/xmlns/" def _check_reserved_prefixes(prefix, namespaceURI): """ Helper function to centralize the enforcement of reserved prefixes. Raises the appropriate NamespaceErr if the prefix is reserved but the namespaceURI doesn't match it. """ if prefix == "xml" and namespaceURI != XML_NS: raise xml.dom.NamespaceErr( "illegal use of the 'xml' prefix") if prefix == "xmlns" and namespaceURI != XMLNS_NS: raise xml.dom.NamespaceErr( "illegal use of the 'xmlns' prefix") # These are indexes into the list that is used to represent an Attr node. _ATTR_NS = 0 _ATTR_NAME = 1 _ATTR_LOCALNAME = 2 _ATTR_PREFIX = 3 _ATTR_VALUE = 4 _ATTR_SPECIFIED = 5 # These are used for schema-derived information, and are not used for # specified attributes. _ATTR_TYPE = 6 _ATTR_REQUIRED = 7 _SUPPORTED_FEATURES = ( ("core", None), ("xml", None), ("traversal", None), #("load", None), # According to DOM Erratum Core-14, the empty string should be # accepted as equivalent to null for hasFeature(). ("core", ""), ("xml", ""), ("traversal", ""), #("load", ""), ("core", "1.0"), ("xml", "1.0"), ("core", "2.0"), ("xml", "2.0"), ("traversal", "2.0"), #("load", "3.0"), ) class _Dummy(_Acquisition.Explicit): pass class DOMImplementation: def hasFeature(self, feature, version): feature = (_string.lower(feature), version) return feature in _SUPPORTED_FEATURES def createDocumentType(self, qualifiedName, publicId, systemId): _check_qualified_name(qualifiedName) import XMLExtended doctype = XMLExtended.DocumentType(qualifiedName, publicId, systemId) doctype = doctype.__of__(_Dummy()) _reparent(doctype, None) return doctype def createDocument(self, namespaceURI, qualifiedName, docType=None): return Document(docType, namespaceURI, qualifiedName) # DOM Level 3 Core (working draft, 5 Jun 2025) def getAs(self, feature): return self # DOM Level 3 Load/Save (working draft, 9 Feb 2025) def createDOMBuilder(self): import LoadSave return LoadSave.DOMBuilder() theDOMImplementation = DOMImplementation() class AttributeControl: """Base class that provides reasonable get/set behavior for DOM classes.""" _readonly = 0 def __setattr__(self, name, value): setter = getattr(self, '_set_' + name, None) if setter is None: getter = getattr(self, '_get_' + name, None) if getter: raise xml.dom.NoModificationAllowedErr( "read-only attribute: " + `name`) else: raise AttributeError, "no such attribute: " + `name` if self._readonly: raise xml.dom.NoModificationAllowedErr( "cannot set attribute on read-only node") setter(value) class Node(AttributeControl, _Acquisition.Explicit): 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 # DOM Level 3 Core (working draft, 5 Jun 2025) # enum DocumentOrder DOCUMENT_ORDER_PRECEDING = 1 DOCUMENT_ORDER_FOLLOWING = 2 DOCUMENT_ORDER_SAME = 5 DOCUMENT_ORDER_UNORDERED = 6 # enum TreePosition TREE_POSITION_PRECEDING = 1 TREE_POSITION_FOLLOWING = 2 TREE_POSITION_ANCESTOR = 3 TREE_POSITION_DESCENDANT = 4 TREE_POSITION_SAME = 5 TREE_POSITION_UNORDERED = 6 attributes = None _children = () _in_tree = 1 _v_sibling_map = None namespaceURI = None prefix = localName = None nodeValue = None def _check_if_ancestor(self, node): "Helper function that raises if node is self or an ancestor of self." n = self node = _aq_base(node) if _aq_base(n) is node: raise xml.dom.HierarchyRequestErr() if node._children: while n is not None: n = n.parentNode if _aq_base(n) is node: raise xml.dom.HierarchyRequestErr() def __cmp__(self, other): # This doesn't seem to be getting used; a problem with # acquisition? Jim thinks this may be an old bug that may # be resurfacing. ;-( return cmp(id(_aq_base(self)), id(_aq_base(other))) def __hash__(self): return hash(id(_aq_base(self))) def __repr__(self): name = self.nodeName or "#" type = self.__class__.__name__ if name[0] == "#": name = "" else: name = " " + `name` return "<%s%s at 0x%x>" % ( type, name, id(_aq_base(self))) def _changed(self): # Mark the tree as changed this way since nodes can be # modified while they're not part of the tree (say, after # being removed but before being added somewhere else; the # real marking of the tree occurs when the node is re-inserted # into the tree). try: self.aq_acquire('__changed__')(1) except AttributeError: pass def _get_attributes(self): return def _get_childNodes(self): return ChildNodeList(self) childNodes = ComputedAttribute(_get_childNodes, 1) def _get_firstChild(self): if self._children: return self._children[0].__of__(self) firstChild = ComputedAttribute(_get_firstChild, 1) def _get_lastChild(self): if self._children: return self._children[-1].__of__(self) lastChild = ComputedAttribute(_get_lastChild, 1) def _get_localName(self): return self.localName def _get_namespaceURI(self): return self.namespaceURI def _get_nodeValue(self): return self.nodeValue def _get_nextSibling(self): node = self._getSiblingInfo()[1] if node is not None: return node.__of__(self.parentNode) nextSibling = ComputedAttribute(_get_nextSibling, 1) def _get_previousSibling(self): node = self._getSiblingInfo()[0] if node is not None: return node.__of__(self.parentNode) previousSibling = ComputedAttribute(_get_previousSibling, 1) def _getSiblingInfo(self): """ Return a list containing the previous and next sibling of this node. If the sibling map doesn't exist on the parent yet, create it. """ # Acquire the parent. if not self._in_tree: return [None, None] parent = _parent_of(self) if parent is None: return [None, None] # This implementation doesn't scale, but should amortize well # if .previousSibling and .nextSibling are actually used # much. Is that enough? This could be made lazier, but at # the expense of readability. # # The parent stores the sibling map for its children. sibmap = parent._v_sibling_map if sibmap is None: # There is no sibling map, create it. sibmap = {} parent.__dict__['_v_sibling_map'] = sibmap try: return sibmap[_aq_base(self)] except KeyError: # The sibling map hasn't been filled, fill it. # The *unwrapped* node is the key, the values are the # *wrapped* previous and next siblings. prev = None siblings = parent._children for i in range(len(siblings)): node = siblings[i] try: next = siblings[i+1] except IndexError: next = None sibmap[node] = [prev, next] prev = node return sibmap[_aq_base(self)] def _get_nodeName(self): return self.nodeName def _get_nodeType(self): return self.nodeType nodeValue = None def _get_ownerDocument(self): # We leverage Acquisition to get this from the # enclosing document. try: return self.aq_acquire('_acquireDocument')() except: return ownerDocument = ComputedAttribute(_get_ownerDocument, 1) def _get_parentNode(self): # Acquire the parent. if self._in_tree: return _parent_of(self) parentNode = ComputedAttribute(_get_parentNode, 1) def _check_prefix(self, value): "check prefix for wellformedness and validity" if ":" in value: raise xml.dom.NamespaceErr("':' not allowed in prefix") _check_qualified_name(value) if value is not None and not self.namespaceURI: raise xml.dom.NamespaceErr( "can't set prefix on a node without a namespace URI") if value == "xmlns": raise xml.dom.NamespaceErr( "can't use 'xmlns' as prefix") _check_reserved_prefixes(value, self.namespaceURI) if not self.namespaceURI: raise xml.dom.NamespaceErr( "no prefix allowed on nodes with no namespace URI") def _get_prefix(self): return self.prefix def _set_prefix(self, value): return def appendChild(self, newChild): if self._readonly or ( newChild.parentNode and newChild.parentNode._readonly): raise xml.dom.NoModificationAllowedErr() if self.isSameNode(newChild): raise xml.dom.HierarchyRequestErr() # checking newChild._children here can avoid a lot of calls when # building a new tree if newChild._children: self._check_if_ancestor(newChild) children = self._children sibmap = self._v_sibling_map child = _aq_base(newChild) # Setup chidren if we don't have any, don't do this for Attr nodes. if not children and isinstance(children, _TupleType): self.__dict__['_children'] = children = [] if child.nodeType == Node.DOCUMENT_FRAGMENT_NODE: if not child._children: return newChild for node in child._children: if node.nodeType not in self._allowed_child_types: raise xml.dom.HierarchyRequestErr() for node in child._children: children.append(node) del child.__dict__['_children'] if child.__dict__.has_key('_v_sibling_map'): del child.__dict__['_v_sibling_map'] if self.__dict__.has_key('_v_sibling_map'): del self.__dict__['_v_sibling_map'] self._changed() return newChild if child.nodeType not in self._allowed_child_types: raise xml.dom.HierarchyRequestErr() thisdoc = self.ownerDocument or self if not thisdoc.isSameNode(newChild.ownerDocument): raise xml.dom.WrongDocumentErr() # Save the unwrapped child children.append(child) # Reparent the child parent = newChild.parentNode if parent is not None: parent.removeChild(newChild) _reparent(newChild, self) if child.__dict__.has_key('_in_tree'): del child.__dict__['_in_tree'] # delete the sibling map, it will be recreated next use if self.__dict__.has_key('_v_sibling_map'): del self.__dict__['_v_sibling_map'] # Notify our containing database object that we have changed self._changed() return newChild def insertBefore(self, newChild, refChild): if refChild is None: return self.appendChild(newChild) if self._readonly or ( newChild.parentNode and newChild.parentNode._readonly): raise xml.dom.NoModificationAllowedErr() if self.isSameNode(newChild): raise xml.dom.HierarchyRequestErr() if self.nodeType == Node.DOCUMENT_NODE: if (newChild.ownerDocument is not None and not self.isSameNode(newChild.ownerDocument)): raise xml.dom.WrongDocumentErr() else: thisdoc = self.ownerDocument thatdoc = newChild.ownerDocument if thatdoc is None: if thisdoc.isSameNode(newChild): raise xml.dom.HierarchyRequestErr() elif not thisdoc.isSameNode(thatdoc): raise xml.dom.WrongDocumentErr() self._check_if_ancestor(newChild) if newChild.nodeType == Node.DOCUMENT_FRAGMENT_NODE: # This is destructive of the fragment, but I think that's ok. # Note that the call to tuple() is required, or a more tedious # loop construct would have to be used. for child in tuple(newChild._children): self.insertBefore(child.__of__(newChild), refChild) return newChild if newChild.nodeType not in self._allowed_child_types: raise xml.dom.HierarchyRequestErr() children = self._children # setup children if we don't have any; don't do this for Attr nodes if not children and isinstance(children, _TupleType): self.__dict__['_children'] = children = [] if newChild.isSameNode(refChild): return newChild if newChild.parentNode: newChild.parentNode.removeChild(newChild) ref = _aq_base(refChild) try: i = children.index(ref) except ValueError: raise xml.dom.NotFoundErr() _reparent(newChild, self) new = _aq_base(newChild) if new.__dict__.has_key('_in_tree'): del new.__dict__['_in_tree'] children.insert(i, new) self._changed() sibmap = self._v_sibling_map if sibmap: del self.__dict__['_v_sibling_map'] #prev, next = sibmap[ref] #if prev: # sibmap[prev][1] = new #sibmap[new] = [prev, ref] #sibmap[ref][0] = new return newChild def removeChild(self, oldChild): if self._readonly: raise xml.dom.NoModificationAllowedErr() child = _aq_base(oldChild) if self._children: children = self._children try: i = children.index(child) except ValueError: raise xml.dom.NotFoundErr() del children[i] sibmap = self._v_sibling_map if sibmap: del self.__dict__['_v_sibling_map'] #prev, next = sibmap[child] #if prev: # sibmap[prev][1] = next #if next: # sibmap[next][0] = prev #del sibmap[child] self._changed() else: raise xml.dom.NotFoundErr() child.__dict__['_in_tree'] = 0 return oldChild def replaceChild(self, newChild, oldChild): if self._readonly or ( newChild.parentNode and newChild.parentNode._readonly): raise xml.dom.NoModificationAllowedErr() if self.isSameNode(newChild): raise xml.dom.HierarchyRequestErr() if self.nodeType == Node.DOCUMENT_NODE: if newChild.ownerDocument \ and not self.isSameNode(newChild.ownerDocument): raise xml.dom.WrongDocumentErr() elif self.ownerDocument and newChild.ownerDocument \ and not self.ownerDocument.isSameNode(newChild.ownerDocument): raise xml.dom.WrongDocumentErr() # Check for HierarchyRequestErr here so that we can fail # before mutating the currrent node: if newChild.nodeType == Node.DOCUMENT_FRAGMENT_NODE: children = newChild._children for child in children: if child.nodeType not in self._allowed_child_types: raise xml.dom.HierarchyRequestErr() elif newChild.nodeType not in self._allowed_child_types: raise xml.dom.HierarchyRequestErr() self._check_if_ancestor(newChild) next = oldChild.nextSibling self.removeChild(oldChild) if next: if newChild.nodeType == Node.DOCUMENT_FRAGMENT_NODE: nodes = newChild._children while nodes: node = nodes[0].__of__(newChild.parentNode) self.insertBefore(node, next) else: self.insertBefore(newChild, next) else: if newChild.nodeType == Node.DOCUMENT_FRAGMENT_NODE: nodes = newChild._children while nodes: node = nodes[0].__of__(newChild.parentNode) self.appendChild(node) else: self.appendChild(newChild) return oldChild def _mergeChildList(self, children): """helper function for normalize. Merge the text nodes in children in place according to normalize, normalizing element children as well, but doesn't do all of the child list housekeeping. Returns true if changes were made. Works for element child lists and attr child lists.""" changed = 0 i = 0 L = [] for child in children: if child.nodeType == Node.TEXT_NODE: if child.data == "": # drop this child child.__dict__['_in_tree'] = 0 changed = 1 elif L and L[-1].nodeType == child.nodeType: # merge this child with previous sibling data = L[-1].data + child.data d = L[-1].__dict__ d['data'] = d['nodeValue'] = data child.__dict__['_in_tree'] = 0 changed = 1 else: L.append(child) elif (child.nodeType == Node.ELEMENT_NODE and child._children): child.normalize() L.append(child) else: L.append(child) if changed: children[:] = L return changed def normalize(self): if self._readonly: raise xml.dom.NoModificationAllowedErr() aChanged = 0 d = self.__dict__ if d.has_key('_attributes'): attributes = self._attributes for attr in attributes: attrVal = attributes[0][_ATTR_VALUE] if type(attrVal) in _StringTypes: continue if len(attrVal) == 1: child = attrVal[0] if child.nodeType == Node.TEXT_NODE and not child.data: del child aChanged = 1 else: aChanged = self._mergeChildList(attrVal) or aChanged children = self._children if not children: return if len(children) == 1: child = children[0] if child.nodeType == Node.TEXT_NODE and not child.data: self.removeChild(child.__of__(self)) elif (child.nodeType == Node.ELEMENT_NODE and child._children): child.__of__(self).normalize() return cChanged = self._mergeChildList(children) if cChanged: if d.has_key('_v_sibling_map'): # this is now invalid; let it be recreated on demand del d['_v_sibling_map'] if cChanged or aChanged: self._changed() def hasAttributes(self): return 0 def hasChildNodes(self): return self._children and 1 or 0 def isSupported(self, feature, version): if self.ownerDocument: impl = self.ownerDocument.implementation else: impl = theDOMImplementation return impl.hasFeature(feature, version) def cloneNode(self, deep): node = _aq_base(self) clone = node._cloneNode(deep and 1 or 0, mutable=1, document=self.ownerDocument) clone.__dict__['_in_tree'] = 0 clone = clone.__of__(self) return clone def _cloneNode(self, deep, mutable, document): # self is *not* an acquisition wrapper! clone = self.__class__.__basicnew__() d = clone.__dict__ d.update(self.__dict__) if deep: if self._children: # make a recursive clone: d['_children'] = L = [] for child in self._children: L.append(child._cloneNode(deep, mutable, document)) elif d.has_key('_children'): del d['_children'] if d.has_key('_v_sibling_map'): del d['_v_sibling_map'] if mutable and d.has_key('_readonly'): del d['_readonly'] return clone # DOM Level 3 (Working Draft, 5 Jun 2025) def _get_baseURI(self): node = self d = node.__dict__ while not d.has_key('baseURI'): node = self.parentNode if node is None: return d = node.__dict__ return d['baseURI'] baseURI = ComputedAttribute(_get_baseURI, 1) def getAs(self, feature): return self def isSameNode(self, other): # This is useful since cmp() (hence ==, !=) don't seem to work # with acquisition. return (_aq_base(self) is _aq_base(other)) def lookupNamespacePrefix(self, namespaceURI): node = self while node is not None: ns_map = getattr(self, '_ns_uri_prefixes', None) if ns_map and ns_map.has_key(namespaceURI): return ns_map[namespaceURI][0] node = node.parentNode def lookupNamespaceURI(self, prefix): node = self while node is not None: ns_map = getattr(self, '_ns_prefix_uri', None) if ns_map and ns_map.has_key(prefix): return ns_map[prefix] node = node.parentNode class Parentless: """Node mixin that doesn't have a parent node.""" parentNode = None nextSibling = None previousSibling = None def _get_parentNode(self): return def _get_previousSibling(self): return def _get_nextSibling(self): return def _getSiblingInfo(self): return [None, None] class Childless: """Node mixin that doesn't allow child nodes. This ensures safety when used as a base class for node types that should never have children of their own, and allows slightly faster response for some methods. """ _allowed_child_types = () def _get_firstChild(self): return firstChild = None def _get_lastChild(self): return lastChild = None def appendChild(self, newChild): raise xml.dom.HierarchyRequestErr() def insertBefore(self, newChild, oldChild): raise xml.dom.HierarchyRequestErr() def removeChild(self, oldChild): raise xml.dom.NotFoundErr() def replaceChild(self, newChild, oldChild): # This could reasonably raise NotFoundErr as well. raise xml.dom.HierarchyRequestErr() def hasChildNodes(self): return 0 def normalize(self): return class TextualContent: """Mixin class defining the recursive support for textContent needed for some types of container nodes. """ # DOM Level 3 (working draft, 5 June 2025) def _get_textContent(self): L = [] for node in self.childNodes: nodeType = node.nodeType if ( nodeType == Node.COMMENT_NODE or nodeType == Node.PROCESSING_INSTRUCTION_NODE): continue if nodeType == Node.TEXT_NODE: text = node.data else: text = node._get_textContent() L.append(text) if L: return _string.join(L, '') else: return '' textContent = ComputedAttribute(_get_textContent, 1) class Document(Parentless, TextualContent, Node): nodeName = "#document" nodeType = Node.DOCUMENT_NODE _allowed_child_types = (Node.ELEMENT_NODE, Node.COMMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE) _doctype = None _in_tree = 0 implementation = theDOMImplementation def __init__(self, doctype, namespaceURI, qualifiedName): _check_qualified_name(qualifiedName, namespaceURI) if namespaceURI: e = Element(namespaceURI, qualifiedName, element_id=0) else: e = Element(None, qualifiedName, element_id=0) del e.__dict__['_in_tree'] if doctype: if doctype._in_tree: raise xml.dom.WrongDocumentErr() doctype = _aq_base(doctype) self.__dict__['_doctype'] = doctype del doctype.__dict__['_in_tree'] L = [doctype, e] else: L = [e] self.__dict__['_children'] = L self.__dict__['_attr_info'] = {} self.__dict__['_element_count'] = 1 def _set_nodeValue(self, data): return None def _get_doctype(self): if self._doctype is None: return else: return self._doctype.__of__(self) doctype = ComputedAttribute(_get_doctype) def _get_implementation(self): return self.implementation def _get_documentElement(self): for node in self._children: if node.nodeType == Node.ELEMENT_NODE: return node.__of__(self) documentElement = ComputedAttribute(_get_documentElement) ownerDocument = None def _get_ownerDocument(self): return def _acquireDocument(self): # This method gets acquired by descendents that want their # owner; the result is an unwrapped Document node. return self # child insertion methods: # check for adding 2nd element node; other checks are elsewhere # helper method for 2nd element node detection def _hasDocumentElement(self): for node in self._children: if node.nodeType == Node.ELEMENT_NODE: return 1 def appendChild(self, newChild): if newChild.nodeType == Node.DOCUMENT_TYPE_NODE: raise xml.dom.HierarchyRequestErr( "cannot change document type via tree manipulation") if (newChild.nodeType == Node.ELEMENT_NODE and self._children and self._hasDocumentElement()): raise xml.dom.HierarchyRequestErr() return Node.appendChild(self, newChild) def insertBefore(self, newChild, refChild): if newChild.nodeType == Node.DOCUMENT_TYPE_NODE: raise xml.dom.HierarchyRequestErr( "cannot change document type via tree manipulation") if (newChild.nodeType == Node.ELEMENT_NODE and self._children and self._hasDocumentElement()): raise xml.dom.HierarchyRequestErr() return Node.insertBefore(self, newChild, refChild) def removeChild(self, oldChild): if oldChild.nodeType == Node.DOCUMENT_TYPE_NODE: raise xml.dom.NoModificationAllowedErr( "cannot change document type via tree manipulation") return Node.removeChild(self, oldChild) def replaceChild(self, newChild, oldChild): if (newChild.nodeType == Node.ELEMENT_NODE and self._children and oldChild.nodeType != Node.ELEMENT_NODE and self._hasDocumentElement()): raise xml.dom.HierarchyRequestErr() if (newChild.nodeType == Node.DOCUMENT_TYPE_NODE or oldChild.nodeType == Node.DOCUMENT_TYPE_NODE): raise xml.dom.HierarchyRequestErr( "cannot change document type via tree manipulation") return Node.replaceChild(self, newChild, oldChild) # unknown acquisition environment, no computedAttribute unwrapping # so we must redefine these methods def _get_childNodes(self): return ChildNodeList(self) childNodes = ComputedAttribute(_get_childNodes) def _get_firstChild(self): if self._children: return self._children[0].__of__(self) firstChild = ComputedAttribute(_get_firstChild) def _get_lastChild(self): if self._children: return self._children[-1].__of__(self) lastChild = ComputedAttribute(_get_lastChild) def createAttribute(self, name): _check_qualified_name(name) return Attr([None, name, None, None, "", 1], self).__of__(self) def createAttributeNS(self, namespaceURI, qualifiedName): _check_qualified_name(qualifiedName, namespaceURI) names = _string.split(qualifiedName, ":", 1) localName = names[-1] if len(names) > 1: prefix = names[0] _check_reserved_prefixes(prefix, namespaceURI) else: prefix = None item = [namespaceURI, qualifiedName, localName, prefix, "", 1] return Attr(item, self).__of__(self) def createCDATASection(self, data): import XMLExtended return XMLExtended.CDATASection(data).__of__(self) def createComment(self, data): return Comment(data).__of__(self) def createDocumentFragment(self): return DocumentFragment(self).__of__(self) def createElement(self, tagName): _check_qualified_name(tagName) e = Element(None, tagName, element_id=self._element_count).__of__(self) self.__dict__['_element_count'] = self._element_count + 1 if self._attr_info.has_key(tagName): e.__dict__['_attr_info'] = self._attr_info[tagName] self._changed() return e def createElementNS(self, namespaceURI, qualifiedName, stuff=None): _check_qualified_name(qualifiedName, namespaceURI) if ":" in qualifiedName and not namespaceURI: raise xml.dom.NamespaceErr( "tag name with prefix has no namespace URI") e = Element(namespaceURI, qualifiedName, stuff, element_id=self._element_count).__of__(self) self.__dict__['_element_count'] = self._element_count + 1 if self._attr_info.has_key(qualifiedName): e.__dict__['_attr_info'] = self._attr_info[qualifiedName] self._changed() return e def createEntityReference(self, name): if not _ok_qualified_name(name): raise xml.dom.InvalidCharacterErr() import XMLExtended return XMLExtended.EntityReference(name).__of__(self) def createProcessingInstruction(self, target, data): if not _ok_qualified_name(target): raise xml.dom.InvalidCharacterErr() if _string.lower(target) == "xml": raise xml.dom.InvalidCharacterErr( "'%s' not allowed as a processing instruction target" % target) import XMLExtended return XMLExtended.ProcessingInstruction(target, data).__of__(self) def createTextNode(self, data): return Text(data).__of__(self) def getElementById(self, elementId): # This performs a depth-first search of the tree for every request # (if any ID attributes are defined); this is necessary in order # to create the proper chain of acquisition wrappers. # info = self._compute_id_map() if not info: return queue = [self.documentElement] while queue: elem = queue.pop(0) if info.has_key(elem.tagName): attrs = info[elem.tagName] for name in attrs: if elem.getAttribute(name) == elementId: return elem if elem.hasChildNodes(): childNodes = elem.childNodes L = [] for node in childNodes: if node.nodeType == Node.ELEMENT_NODE: L.append(node) queue[:0] = L def _compute_id_map(self): # Returns a mapping from tagName to a list of attribute names # that bear IDs. The computed value is cached on the instance; # if this is used during a transaction that modifies the document # the structure will be saved as an "accidental" side effect. # Since the DOM does not support changing the content model, this # is acceptable. try: return self._id_info except AttributeError: self.__dict__['_id_info'] = info = {} for tagName, L in self._attr_info.items(): for item in L: if item[_ATTR_TYPE] == "ID": if info.has_key(tagName): info[tagName].append(item[_ATTR_NAME]) else: info[tagName] = [item[_ATTR_NAME]] return info def getElementsByTagName(self, tagName): nodeList = SimpleNodeList() _getElementsByTagNameHelper(self, tagName, nodeList._data) return nodeList def getElementsByTagNameNS(self, namespaceURI, localName): nodeList = SimpleNodeList() _getElementsByTagNameNSHelper( self, namespaceURI, localName, nodeList._data) return nodeList def isSupported(self, feature, version): return self.implementation.hasFeature(feature, version) def importNode(self, importedNode, deep): if importedNode.nodeType in ( Node.DOCUMENT_NODE, Node.DOCUMENT_TYPE_NODE): raise xml.dom.NotSupportedErr( "can't import this kind of node") doc = importedNode.ownerDocument if doc.implementation == self.implementation: # same implementation, so we're in good shape node = _aq_base(importedNode) clone = node._cloneNode(deep and 1 or 0, mutable=1, document=self) clone.__dict__['_in_tree'] = 0 clone = clone.__of__(self) if hasattr(clone, '_set_owner_document'): clone._set_owner_document(self) return clone raise xml.dom.NotSupportedErr( "can't import from a different DOM implementation") # DOM Level 2 Traversal def createNodeIterator(self, root, whatToShow, filter, entityReferenceExpansion): import Traversal return Traversal.NodeIterator(root, whatToShow, filter, entityReferenceExpansion) def createTreeWalker(self, root, whatToShow, filter, entityReferenceExpansion): import Traversal return Traversal.TreeWalker(root, whatToShow, filter, entityReferenceExpansion) # DOM Level 3 (Working Draft, 5 Jun 2025) # I expect some or all of these will become read-only before the # recommendation is finished. actualEncoding = None encoding = None standalone = 0 strictErrorChecking = 0 version = None # Override the inherited handler for textContent since the # acquisition context is different. textContent = ComputedAttribute(TextualContent._get_textContent) def _get_actualEncoding(self): return self.actualEncoding def _set_actualEncoding(self, value): self.__dict__['actualEncoding'] = value self._changed() def _get_encoding(self): return self.encoding def _set_encoding(self, value): self.__dict__['encoding'] = value self._changed() def _get_standalone(self): return self.standalone def _set_standalone(self, value): self.__dict__['standalone'] = value and 1 or 0 self._changed() def _get_strictErrorChecking(self): return self.strictErrorChecking def _set_strictErrorChecking(self, value): self.__dict__['strictErrorChecking'] = value and 1 or 0 self._changed() def _get_version(self): return self.version def _set_version(self, value): self.__dict__['version'] = value self._changed() def normalizeNS(self): pass def setBaseURI(self, baseURI): # we really need something like urlparse.isabs()! if ':' not in baseURI: raise xml.dom.SyntaxErr("baseURI is not an absolute URI") self.__dict__['baseURI'] = baseURI self._changed() def _getElementsByTagNameHelper(parent, name, list): for node in parent._children: if node.nodeType == Node.ELEMENT_NODE: if (name == "*" or node.tagName == name): list.append(node.__of__(parent)) _getElementsByTagNameHelper(node.__of__(parent), name, list) def _getElementsByTagNameNSHelper(parent, nsURI, localName, list): for node in parent._children: if node.nodeType == Node.ELEMENT_NODE: if ((localName == "*" or node.localName == localName) and (nsURI == "*" or node.namespaceURI == nsURI)): list.append(node.__of__(parent)) _getElementsByTagNameNSHelper(node.__of__(parent), nsURI, localName, list) class DocumentFragment(Parentless, TextualContent, Node): nodeName = "#document-fragment" nodeType = Node.DOCUMENT_FRAGMENT_NODE parentNode = None _in_tree = 0 _allowed_child_types = (Node.ELEMENT_NODE, Node.TEXT_NODE, Node.PROCESSING_INSTRUCTION_NODE, Node.COMMENT_NODE, Node.CDATA_SECTION_NODE, Node.ENTITY_REFERENCE_NODE) def __init__(self, owner): self.__dict__['ownerDocument'] = owner def _set_nodeValue(self, data): return None def _get_ownerDocument(self): return self.ownerDocument def _get_parentNode(self): return def _set_owner_document(self, doc): self.__dict__['ownerDocument'] = doc def _split_qname(namespaceURI, qualifiedName): if ":" in qualifiedName: prefix, localName = _string.split(qualifiedName, ':', 1) if prefix == "xml" and namespaceURI != XML_NS: raise xml.dom.NamespaceErr( "illegal use of the 'xml' prefix") if prefix == "xmlns" and namespaceURI != XMLNS_NS: raise xml.dom.NamespaceErr( "illegal use of the 'xmlns' prefix") return prefix, localName else: return None, qualifiedName # Element _attribute members can be shared with Attr nodes; see comment # at the Attr class. class Element(TextualContent, Node): nodeType = Node.ELEMENT_NODE _allowed_child_types = (Node.ELEMENT_NODE, Node.TEXT_NODE, Node.COMMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE, Node.CDATA_SECTION_NODE, Node.ENTITY_REFERENCE_NODE) _attributes = () _attr_info = () def __init__(self, namespaceURI, qualifiedName, stuff=None, element_id=0): d = self.__dict__ d['_in_tree'] = 0 d['_element_id'] = element_id d['nodeName'] = qualifiedName d['tagName'] = qualifiedName if stuff: d['namespaceURI'] = namespaceURI d['prefix'] = stuff[0] d['localName'] = stuff[1] elif namespaceURI: d['namespaceURI'] = namespaceURI prefix, localName = _split_qname(namespaceURI, qualifiedName) d['prefix'] = prefix d['localName'] = localName def _cloneNode(self, deep, mutable, document): clone = Node._cloneNode(self, deep, mutable, document) d = clone.__dict__ # create element_id for cloned element d['_element_id'] = document._element_count document.__dict__['_element_count'] = document._element_count + 1 # we need to notify changes as we change element_count self._changed() info = document._attr_info.get(self.tagName) if info: d['_attr_info'] = info elif clone._attr_info: del d['_attr_info'] if d.has_key('_attributes'): d['_attributes'] = attrs = map(list, self._attributes) for i in range(len(attrs) - 1, -1, -1): item = attrs[i] if not item[_ATTR_SPECIFIED]: del attrs[i] return clone def _set_nodeValue(self, data): return None def _set_prefix(self, value): self._check_prefix(value) d = self.__dict__ d['prefix'] = value s = "%s:%s" % (value, self.localName) d['nodeName'] = s # Do this here to avoid paying for a method call d['tagName'] = s def _get_tagName(self): return self.tagName tagName = ComputedAttribute(_get_tagName, 1) # not DOM, but convenience elementId accessor. Each element node # has a document-unique element_id def _get_elementId(self): return self._element_id elementId = ComputedAttribute(_get_elementId, 1) def getElementsByTagName(self, tagName): nodeList = SimpleNodeList() _getElementsByTagNameHelper(self, tagName, nodeList._data) return nodeList def getElementsByTagNameNS(self, namespaceURI, localName): nodeList = SimpleNodeList() _getElementsByTagNameNSHelper( self, namespaceURI, localName, nodeList._data) return nodeList def _get_attributes(self): return AttributeMap(self) attributes = ComputedAttribute(_get_attributes, 1) def hasAttributes(self): return ((self._attributes or self._attr_info) and 1 or 0) def getAttribute(self, name): for item in self._attributes: if name == item[_ATTR_NAME]: if type(item[_ATTR_VALUE]) in _StringTypes: # value is a string return item[_ATTR_VALUE] # value is a subtree return _attr_get_value(item[_ATTR_VALUE]) for item in self._attr_info: if name == item[_ATTR_NAME]: # will always be a string in the current implementation return item[_ATTR_VALUE] return "" def getAttributeNode(self, name): for item in self._attributes: if name == item[_ATTR_NAME]: doc = self.ownerDocument return Attr(item, doc, self).__of__(self) for item in self._attr_info: if name == item[_ATTR_NAME]: item = item[:] if self._attributes: self._attributes.append(item) else: self.__dict__['_attributes'] = [item] return Attr(item, self.ownerDocument, self).__of__(self) def getAttributeNS(self, namespaceURI, localName): for item in self._attributes: if ( namespaceURI == item[_ATTR_NS] and localName == item[_ATTR_LOCALNAME]): if type(item[_ATTR_VALUE]) in _StringTypes: # value is a string return item[_ATTR_VALUE] # value is a subtree return _attr_get_value(item[_ATTR_VALUE]) for item in self._attr_info: if ( namespaceURI == item[_ATTR_NS] and localName == item[_ATTR_LOCALNAME]): # will always be a string in the current implementation return item[_ATTR_VALUE] return "" def getAttributeNodeNS(self, namespaceURI, localName): for item in self._attributes: if ( namespaceURI == item[_ATTR_NS] and localName == item[_ATTR_LOCALNAME]): return Attr(item, self.ownerDocument, self).__of__(self) for item in self._attr_info: if ( namespaceURI == item[_ATTR_NS] and localName == item[_ATTR_LOCALNAME]): item = item[:] if self._attributes: self._attributes.append(item) else: self.__dict__['_attributes'] = [item] return Attr(item, self.ownerDocument, self).__of__(self) def hasAttribute(self, name): for item in self._attributes: if name == item[_ATTR_NAME]: return 1 for item in self._attr_info: if name == item[_ATTR_NAME]: return 1 return 0 def hasAttributeNS(self, namespaceURI, localName): for item in self._attributes: if ( namespaceURI == item[_ATTR_NS] and localName == item[_ATTR_LOCALNAME]): return 1 for item in self._attr_info: if ( namespaceURI == item[_ATTR_NS] and localName == item[_ATTR_LOCALNAME]): return 1 return 0 def removeAttribute(self, name): if self._readonly: raise xml.dom.NoModificationAllowedErr() for i in range(len(self._attributes)): item = self._attributes[i] if item[_ATTR_NAME] == name: break else: return if not self._attributes: self.__dict__['_attributes'] = [] del self._attributes[i] if item[_ATTR_SPECIFIED]: self._changed() def removeAttributeNS(self, namespaceURI, localName): if self._readonly: raise xml.dom.NoModificationAllowedErr() for i in range(len(self._attributes)): item = self._attributes[i] if (item[_ATTR_NS] == namespaceURI and item[_ATTR_LOCALNAME] == localName): if not self._attributes: self.__dict__['_attributes'] = [] del self._attributes[i] self._changed() return def removeAttributeNode(self, oldAttr): if self._readonly: raise xml.dom.NoModificationAllowedErr() item = oldAttr._item if item in self._attributes: self._attributes.remove(item) oldAttr._set_owner_element(None) if item[_ATTR_SPECIFIED]: self._changed() return oldAttr else: raise xml.dom.NotFoundErr() # Because we don't _changed on any existing attr nodes, all attr nodes # must have the same persistent parent as their ownerElement def setAttribute(self, name, value): if self._readonly: raise xml.dom.NoModificationAllowedErr() if not _ok_qualified_name(name): raise xml.dom.InvalidCharacterErr() if type(value) not in _StringTypes: raise TypeError, "attribute value must be a string" if self._attributes: for item in self._attributes: if ( name == item[_ATTR_NAME] and not item[_ATTR_NS]): if type(item[_ATTR_VALUE]) in _StringTypes: # value is a string if item[_ATTR_VALUE] != value: item[_ATTR_VALUE] = value self._changed() else: # value is a list of children, there's an Attr node # for this attr which shares this list. if _attr_get_value(item[_ATTR_VALUE]) != value: _attr_set_value(item, value) self._changed() return # attr hasn't been found if not self._attributes: self.__dict__['_attributes'] = [] # should look up namespaceURI here... self._attributes.append([None, name, None, None, value, 1]) self._changed() # Because we don't _changed on any existing attr nodes, all attr nodes # must have the same persistent parent as their ownerElement def setAttributeNS(self, namespaceURI, qualifiedName, value): if self._readonly: raise xml.dom.NoModificationAllowedErr() _check_qualified_name(qualifiedName, namespaceURI) if ":" in qualifiedName: prefix, localName = _string.split(qualifiedName, ":", 1) _check_reserved_prefixes(prefix, namespaceURI) elif namespaceURI: prefix = None localName = qualifiedName else: prefix = None localName = qualifiedName if self._attributes: # replace existing attribute rather than add new one for item in self._attributes: if ( namespaceURI == item[_ATTR_NS] and localName == item[_ATTR_LOCALNAME]): if type(item[_ATTR_VALUE]) in _StringTypes: # value is a string if ( item[_ATTR_VALUE] != value or item[_ATTR_PREFIX] != prefix): item[_ATTR_VALUE] = value item[_ATTR_PREFIX] = prefix item[_ATTR_NAME] = "%s:%s" % ( prefix, item[_ATTR_LOCALNAME]) self._changed() else: # value is a list of children, there's an Attr node # for this attr which shares this list. if ( _attr_get_value(item[_ATTR_VALUE]) != value or item[_ATTR_PREFIX] != prefix): _attr_set_value(item, value) item[_ATTR_PREFIX] = prefix item[_ATTR_NAME] = "%s:%s" % ( prefix, item[_ATTR_LOCALNAME]) self._changed() return if not self._attributes: self.__dict__['_attributes'] = [] self._attributes.append( [namespaceURI, qualifiedName, localName, prefix, value, 1]) self._changed() def setAttributeNode(self, newAttr): return self._set_attribute_node( newAttr.name, _attr_item_match_name, newAttr) def setAttributeNodeNS(self, newAttr): name = (newAttr.namespaceURI, newAttr.localName) return self._set_attribute_node( name, _attr_item_match_ns, newAttr) def _set_attribute_node(self, name, matcher, newAttr): if self._readonly: raise xml.dom.NoModificationAllowedErr() if newAttr.ownerElement: raise xml.dom.InuseAttributeErr() if newAttr.nodeType != Node.ATTRIBUTE_NODE: raise xml.dom.HierarchyRequestErr( "attributes must have nodeType xml.dom.Node.ATTRIBUTE_NODE") if not self.ownerDocument.isSameNode(newAttr.ownerDocument): raise xml.dom.WrongDocumentErr() oldAttr = None if not self._attributes: self.__dict__['_attributes'] = [] for i in range(len(self._attributes)): item = self._attributes[i] if matcher(item, name): # replace existing node # XXX set ownerElement for other nodes oldAttr = Attr(item, self.ownerDocument).__of__(self) self._attributes[i] = newAttr._item break if oldAttr is None: self._attributes.append(newAttr._item) newAttr._set_owner_element(self) self._changed() return oldAttr class ChildNodeList: """NodeList implementation that provides the children of a single node. This is returned by Node.childNodes and Node._get_childNodes(). The list operations supported by this object can be used to mutate the document contents. """ def __init__(self, parent): self.__dict__['_parent'] = parent def __getstate__(self): raise RuntimeError, "ChildNodeList instances cannot be stored" def item(self, i): try: return self[i] except IndexError: return def __getitem__(self, i): return self._parent._children[i].__of__(self._parent) def __setitem__(self, i, newChild): p = self._parent oldChild = p._children[i].__of__(p) p.replaceChild(newChild, oldChild) def __delitem__(self, i): oldChild = self._parent._children[i].__of__(self._parent) self._parent.removeChild(oldChild) def _get_length(self): return len(self._parent._children) __len__ = _get_length def __getattr__(self, name): if name == "length": return len(self._parent._children) raise AttributeError, name def __setattr__(self, name, value): if name == "length": raise xml.dom.NoModificationAllowedErr() else: raise TypeError, "NodeList has only read-only attributes" def __nonzero__(self): return self._parent._children and 1 or 0 def count(self, value): value = _aq_base(value) for node in self._parent._children: if node is value: return 1 return 0 def index(self, value): children = self._parent._children value = _aq_base(value) for i in range(len(children)): if value is children[i]: return i raise ValueError, "NodeList.index(x): x not in sequence" class SimpleNodeList: """NodeList implementation that contains pre-wrapped nodes. This is returned by the getElementsByTagName() and getElementsByTagNameNS() methods of Document and Element. It cannot be used to mutate the document contents. """ def __init__(self, list=None): if list is None: list = [] self.__dict__['_data'] = list def __getstate__(self): raise RuntimeError, "SimpleNodeList instances cannot be stored" # # NodeList interface # def __getattr__(self, name): if name == "length": return len(self._data) raise AttributeError, name def __setattr__(self, name, value): if name == "length": raise xml.dom.NoModificationAllowedErr() self.__dict__[name] = value def _get_length(self): return len(self._data) def item(self, i): if 0 <= i < len(self._data): return self._data[i] # # Read-only sequence interface # def __contains__(self, obj): base = _aq_base(obj) for node in self._data: if _aq_base(node) is base: return 1 return 0 def __getitem__(self, i): return self._data[i] def __getslice__(self, i, j): return SimpleNodeList(self._data[i:j]) def __len__(self): return len(self._data) def __nonzero__(self): return self._data and 1 or 0 def count(self, value): value = _aq_base(value) for node in self._data: if _aq_base(node) is value: return 1 return 0 def index(self, value): value = _aq_base(value) for i in range(len(self._data)): base = _aq_base(self._data[i]) if value is base: return i raise ValueError, "NodeList.index(x): x not in sequence" class CharacterData(Childless, Node): def __init__(self, data): d = self.__dict__ d['_in_tree'] = 0 d['data'] = data d['nodeValue'] = data def _get_data(self): return self.data def _set_data(self, data): if self._readonly: raise xml.dom.NoModificationAllowedErr() d = self.__dict__ if d['data'] != data: d['data'] = data d['nodeValue'] = data self._changed() _set_nodeValue = _set_data def _get_length(self): return len(self.data) length = ComputedAttribute(_get_length, 1) def __len__(self): return len(self.data) def appendData(self, arg): if arg: data = self.data + arg d = self.__dict__ d['data'] = data d['nodeValue'] = data self._changed() def deleteData(self, offset, count): if count < 0 or offset < 0 or offset > len(self.data): raise xml.dom.IndexSizeErr() if count: data = self.data[:offset] + self.data[offset+count:] self.__dict__['data'] = data self.__dict__['nodeValue'] = data self._changed() def insertData(self, offset, arg): if offset < 0 or offset > len(self.data): raise xml.dom.IndexSizeErr() if arg: data = self.data data = _string.join((data[:offset], arg, data[offset:]), '') self.__dict__['data'] = data self.__dict__['nodeValue'] = data self._changed() def replaceData(self, offset, count, arg): if count < 0 or offset < 0 or offset > len(self.data): raise xml.dom.IndexSizeErr() if count or arg: data = self.data data = _string.join((data[:offset], arg, data[offset+count:]), '') self.__dict__['data'] = data self.__dict__['nodeValue'] = data self._changed() def substringData(self, offset, count): if count < 0 or offset < 0 or offset > len(self.data): raise xml.dom.IndexSizeErr() return self.data[offset:offset+count] # DOM Level 3 (working draft, 5 June 2025) def _get_textContent(self): return self.nodeValue textContent = ComputedAttribute(_get_textContent, 1) class Text(CharacterData): nodeName = "#text" nodeType = Node.TEXT_NODE def splitText(self, offset): if offset < 0 or offset > len(self.data): raise xml.dom.IndexSizeErr() parent = self.parentNode newText = Text(self.data[offset:]) data = self.data[:offset] self.__dict__['data'] = self.__dict__['nodeValue'] = data if parent is not None: newText = newText.__of__(parent) sibmap = parent._v_sibling_map if sibmap: del self.__dict__['_v_sibling_map'] #prev, next = sibmap[_aq_base(self)] #if next is not None: # next = next.__of__(parent) else: next = self.nextSibling if next is None: parent.appendChild(newText) else: parent.insertBefore(newText, next.__of__(parent)) self._changed() return newText # DOM Level 3 (working draft 01 Sep 2025) isWhitespaceInElementContent = 0 def _get_isWhitespaceInElementContent(self): return self.isWhitespaceInElementContent class Comment(CharacterData): nodeName = "#comment" nodeType = Node.COMMENT_NODE # Attr nodes can share their _children with the attribute structure of # their ownerElements, so this list reference must never be changed - don't # replace _children, instead add and remove list members. Same for _item # members, which are shared with the ownerElement and other Attr ndoes. # # We expect that the usual access of attrs is via the element string methods # getAttribute* and setAttribute, so usually attr values are stored as strings # in the element. When getAttributeNode is called, we turn the string into a # list with a single text node, the attr node shares this reference. Similarly # for setAttributeNode. We could stay with the string in many cases at the # cost of complexity. class Attr(Parentless, Node): nodeType = Node.ATTRIBUTE_NODE _in_tree = 0 _allowed_child_types = (Node.TEXT_NODE, Node.ENTITY_REFERENCE_NODE) def __init__(self, item, ownerDocument, ownerElement=None): d = self.__dict__ # attributes that must be shared with the ownerElement's representation if type(item[_ATTR_VALUE]) in _StringTypes: # turn string representation into list of children itemNode = Text(item[_ATTR_VALUE]) del itemNode.__dict__['_in_tree'] item[_ATTR_VALUE] = [itemNode] d['_children'] = item[_ATTR_VALUE] d['_item'] = item # attributes that aren't shared with the ownerElement d['ownerDocument'] = ownerDocument if item[_ATTR_NS]: d['namespaceURI'] = item[_ATTR_NS] d['localName'] = item[_ATTR_LOCALNAME] # ownerElement arg is for readonlyness, not the OwnerElement attribute if ownerElement is not None and ownerElement._readonly: d['_readonly'] = 1 # XXX must be shared in case of removal? d['specified'] = item[_ATTR_SPECIFIED] def __getstate__(self): raise RuntimeError("Attr nodes cannot be pickled") def __cmp__(self, other): if (other.nodeType == Node.ATTRIBUTE_NODE and self._item is other._item): return 0 else: return cmp(id(_aq_base(self)), id(_aq_base(other))) def __repr__(self): return "" % ( self.name, id(_aq_base(self)), id(self._item)) def _cloneNode(self, deep, mutable, document): # self is *not* an acquisition wrapper! clone = self.__class__.__basicnew__() d = clone.__dict__ d.update(self.__dict__) d['_item'] = item = list(self._item) item[_ATTR_SPECIFIED] = 1 d['specified'] = 1 if d.has_key('_readonly'): del d['_readonly'] # clone the children d['_children'] = L = [] for child in self._children: newChild = child._cloneNode(1, mutable, document) if newChild.__dict__.has_key('_in_tree'): del newChild.__dict__['_in_tree'] L.append(newChild) return clone #nodeName, name, prefix must be shared between attr nodes and #element storage, because we can change the prefix with either interface. _get_name = Node._get_nodeName def _get_nodeName(self): return self._item[_ATTR_NAME] nodeName = ComputedAttribute(_get_nodeName, 1) def _get_name(self): return self._item[_ATTR_NAME] name = ComputedAttribute(_get_name, 1) def _get_prefix(self): return self._item[_ATTR_PREFIX] prefix = ComputedAttribute(_get_prefix, 1) # we aren't checking to see if this attr was created with a lvl2 method; # if it wasn't, setting the prefix will make the name funny - # but that's undefined behavior anyway. def _set_prefix(self, value): self._check_prefix(value) d = self.__dict__ self._item[_ATTR_PREFIX] = value if value: name = "%s:%s" % (value, self._item[_ATTR_LOCALNAME]) else: name = self._item[_ATTR_LOCALNAME] self._item[_ATTR_NAME] = name if not self.specified: self.__dict__['specified'] = 1 self._item[_ATTR_SPECIFIED] = 1 self._changed() def _set_owner_element(self, owner): # set ownerElement with acquisition XXX same aq bug as parent usage _reparent(self, owner) if owner is not None: self.__dict__['ownerDocument'] = owner.ownerDocument def _set_owner_document(self, doc): self.__dict__['ownerDocument'] = doc def _get_ownerDocument(self): return self.ownerDocument def _get_ownerElement(self): # Acquire the owner. parent = _parent_of(self) if parent and parent.isSameNode(self.ownerDocument): return None # we use this for unowned attrs return parent ownerElement = ComputedAttribute(_get_ownerElement, 1) def _get_value(self): return _attr_get_value(self._children) value = ComputedAttribute(_get_value) _get_nodeValue = _get_value nodeValue = value def _set_value(self, data): if self._readonly: raise xml.dom.NoModificationAllowedErr() _attr_set_value(self._item, data) _set_nodeValue = _set_value childNodes = ComputedAttribute(Node._get_childNodes) # DOM Level 3 (Working Draft, 01 Sep 2025) def _get_specified(self): return self.specified def _get_textContent(self): return self._item[ATTR_VALUE] textContent = ComputedAttribute(_get_textContent) def isSameNode(self, other): return (other is not None and other.nodeType == Node.ATTRIBUTE_NODE and self._item is other._item) class MapFromParent(AttributeControl): """ Baseclass for a NamedNodeMap that works by extracting information from a parent. Must be subclassed to determine what we're looking for and returning. """ def __init__(self, parent): self.__dict__['_parent'] = parent # subclass must set _parentListName def _getParentList(self): "return the parent's list used to make this map" return getattr(self._parent, self._parentListName) def __getstate__(self): raise RuntimeError, "NamedNodeMap type instances cannot be stored" def _get_length(self): return len(self._getParentList()) __len__ = _get_length def __getattr__(self, name): if name == "length": return self._get_length() raise AttributeError, name def __setattr__(self, name, value): if name == "length": raise xml.dom.NoModificationAllowedErr() AttributeControl.__setattr__(self, name, value) def get(self, name, default=None): node = self.getNamedItem(name) if node is None: return default else: return node def item(self, i): try: itemSource = self._getParentList()[i] except IndexError: return else: return self._item_helper(itemSource) # subclass must define _item_helper def getNamedItem(self, name): for item in self._getParentList(): if self._nameMatcher(item, name): return self._item_helper(item) def getNamedItemNS(self, namespaceURI, localName): for item in self._getParentList(): if self._nsMatcher(item, (namespaceURI, localName)): return self._item_helper(item) def __getitem__(self, name): node = self.getNamedItem(name) if node is None: raise KeyError, name return node # subclass must define _set_named_item, _nameMatcher, nsMatcher def setNamedItem(self, node): return self._set_named_item(node.nodeName, self._nameMatcher, node) def setNamedItemNS(self, node): nameinfo = (node.namespaceURI, node.localName) return self._set_named_item(nameinfo, self._nsMatcher, node) def __setitem__(self, name, node): if self._parent._readonly or self._readonly: raise xml.dom.NoModificationAllowedErr() assert name == node.nodeName self.setNamedItem(node) # subclass must define _key_helper, _delFromParentList def removeNamedItem(self, name): return self._remove_named_item(name, self._nameMatcher) def removeNamedItemNS(self, namespaceURI, localName): return self._remove_named_item((namespaceURI, localName), self._nsMatcher) def _remove_named_item(self, name, matcher): # # The workhorse of item removal; this removes whatever # item the 'matcher' test determines matches. 'name' is # passed to the matcher but is not used otherwise. # if self._parent._readonly or self._readonly: raise xml.dom.NoModificationAllowedErr() pList = self._getParentList() for i in range(len(pList)): item = pList[i] if matcher(item, name): break else: raise xml.dom.NotFoundErr() self._delFromParentList(pList, i) node = self._item_helper(item) node._set_owner_element(None) return node def __delitem__(self, name): if self._parent._readonly or self._readonly: raise xml.dom.NoModificationAllowedErr() pList = self._getParentList() for i in range(len(pList)): item = pList[i] s = self._key_helper(item) if s == name: self._delFromParentList(pList, i) return raise KeyError, name def has_key(self, name): for item in self._getParentList(): if self._key_helper(item) == name: return 1 return 0 def items(self): L = [] for item in self._getParentList(): L.append((self._key_helper(item), self._item_helper(item))) return L def keys(self): L = [] for item in self._getParentList(): L.append(self._key_helper(item)) return L def values(self): L = [] for item in self._getParentList(): L.append(self._item_helper(item)) return L class AttributeMap(MapFromParent): """NamedNodeMap that works on the attribute structure. This doesn't do anything about the namespace declarations. """ _parentListName = '_attributes' def __init__(self, parent): d = self.__dict__ d['_attr_info'] = parent._attr_info d['_parent'] = parent d['_nameMatcher'] = _attr_item_match_name d['_nsMatcher'] = _attr_item_match_ns def _get_length(self): d = {} for item in self._parent._attributes: if item[_ATTR_NS]: key = item[_ATTR_NS], item[_ATTR_LOCALNAME] else: key = item[_ATTR_NAME] d[key] = 1 for item in self._attr_info: if item[_ATTR_NS]: key = item[_ATTR_NS], item[_ATTR_LOCALNAME] else: key = item[_ATTR_NAME] d[key] = 1 return len(d) __len__ = _get_length def item(self, i): node = MapFromParent.item(self, i) if node is None and self._attr_info: d = {} for item in self._parent._attributes: if item[_ATTR_NS]: key = item[_ATTR_NS], item[_ATTR_LOCALNAME] else: key = item[_ATTR_NAME] d[key] = 1 j = len(d) for item in self._attr_info: name = item[_ATTR_NAME] if d.has_key(name): pass else: if j == i: item = list(item) if self._parent._attributes: self._parent._attributes.append(item) else: self._parent.__dict__['_attributes'] = [item] node = Attr( item, self._parent.ownerDocument, self._parent) node = node.__of__(self._parent) break j = j + 1 return node def _item_helper(self, itemSource): "used by item; create an Attribute from the item and return it" node = Attr(itemSource, self._parent.ownerDocument, self._parent) return node.__of__(self._parent) def _set_named_item(self, nameinfo, matcher, node): "utility function for setNamedItem" if self._parent._readonly or self._readonly: raise xml.dom.NoModificationAllowedErr() if node.nodeType != Node.ATTRIBUTE_NODE: raise xml.dom.HierarchyRequestErr() if not self._parent.ownerDocument.isSameNode(node.ownerDocument): raise xml.dom.WrongDocumentErr() if node.ownerElement: if node.ownerElement.isSameNode(self._parent): # This is already our node; no extra work needed, and no # change to the storage object. return node raise xml.dom.InuseAttributeErr() attributes = self._getParentList() if not attributes: self._parent.__dict__['_attributes'] = [node._item] node._set_owner_element(self._parent) return node oldNode = None for i in range(len(attributes)): item = attributes[i] if matcher(item, nameinfo): oldNode = item attributes[i] = node._item break if oldNode is None: self._addToParentList(attributes, node) node._set_owner_element(self._parent) return oldNode def _delFromParentList(self, attrs, i): "workhorse for __delitem__; remove ith item from attrs" del attrs[i] #XXX ownerElement needs to be updated in other refs self._parent._changed() def _addToParentList(self, attrs, node): if self._parent._attributes: self._parent._attributes.append(node._item) else: self._parent.__dict__['_attributes'] = [node._item] self._parent._changed() def _key_helper(self, itemSource): "given an item source, return an appropriate key for our mapping" return itemSource[_ATTR_NAME] # Utility functions for Attrs, used by more than the Attr class. def _attr_item_match_name(item, name, _ATTR_NAME=_ATTR_NAME): "utility function for AttributeMap; return true if name matches item" return item[_ATTR_NAME] == name def _attr_item_match_ns(item, (namespaceURI, localName), _ATTR_NS=_ATTR_NS, _ATTR_LOCALNAME=_ATTR_LOCALNAME): "utility function for AttributeMap; return true if name matches item" return (item[_ATTR_LOCALNAME] == localName and item[_ATTR_NS] == namespaceURI) def _attr_get_value(nodes): "utility function to get attr value; concatenate values of list of nodes" L = [] for node in nodes: L.append(node.nodeValue) return _string.join(filter(None, L), '') def _attr_set_value(item, value): "utility function to safely set shared value of attr item" newChild = Text(value) del newChild.__dict__['_in_tree'] while item[_ATTR_VALUE]: item[_ATTR_VALUE].pop() item[_ATTR_VALUE].append(newChild) # no longer needed del ComputedAttribute ParsedXML/DOM/Exceptions.py0100644000175200017500000002625007276046313015455 0ustar faasseninfrae############################################################################## # # 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. # ############################################################################## """Replacement DOM exceptions to be used if the xml.dom package is not available. """ """ Why does this module exist? The Python DOM API defines exceptions that DOM implementations should use to allow DOM client code to detect errors that can occur during processing. Since not all client code knows about the DOM implementation used, all implementations must use shared exceptions. These are defined in the xml.dom package (in the package's __init__.py). The xml.dom package is provided as part of PyXML and Python 2.0. Since ParsedXML may be used from Python 1.5.2 without having PyXML or a more recent version of Python available, we need to provide an alternate implementation. However, DOM client code that works on DOM instances created elsewhere will still expect to get the exception classes from xml.dom. Since the code may be part of third-party packages that know nothing of ParsedXML or Zope, we need to provide an implementation of xml.dom if it doesn't already exist. So how does this module solve the problem? This module defines the required exception objects and constants and 'installs' the values in the xml.dom module if they are not already present. Since the xml.dom module may not exist, or may pre-date the addition of these exceptions to the standard implementation (Python 2.0 or PyXML 0.6.2), the modules xml and xml.dom are created by surgically adding them to sys.modules if needed, and inserting the required values into an existing xml.dom module if needed. This works because of the way the module import machinery works in Python. sys.modules is a mapping from module name to module object; sys.modules['sys'] evaluates to the sys module object. When an import statement is executed, the Python runtime first looks in sys.modules to retrieve an already-loaded module. The set of built-in modules and the filesystem are only consulted if the module has not already been loaded. For modules in packages (xml.dom), each level of enclosing package is checked before attempting to load the module; i.e., xml is checked before xml.dom. This machinery is invoked each time an import is attempted. When ParsedXML.DOM is imported, it imports this module. This first attempts to load the standard xml.dom package. If that fails (which it is likely to do for Python 1.5.2 without PyXML installed), this module is an acceptable implementation of xml.dom, but we still need the xml package. This is created artificially using the new.module() function and inserted in sys.modules. Once this is done, this module may be inserted for the key 'xml.dom', after which attempts to import xml.dom will provide this module. If xml.dom is already available, but older than the introduction of DOMException and its specializations, the implementations defined here are inserted into it, so that it is extended to match the more recent version of the interface definition. What are the limitations of this approach? Some versions of PyXML may have defined DOMException without defining the subclasses. The specialized versions of DOMException were added in PyXML version 0.6.3 (XXX ??). Versions which contain DOMException but not the specializations will not be compatible with this module. This should not be a substantial limitation in the context of Zope. There is no way to protect against code that imports xml.dom before ParsedXML.DOM has been imported. Such code will receive an ImportError. Reloading that code after ParsedXML.DOM is imported will cause it to work properly. """ # These have to be in order: _CODE_NAMES = [ "INDEX_SIZE_ERR", "DOMSTRING_SIZE_ERR", "HIERARCHY_REQUEST_ERR", "WRONG_DOCUMENT_ERR", "INVALID_CHARACTER_ERR", "NO_DATA_ALLOWED_ERR", "NO_MODIFICATION_ALLOWED_ERR", "NOT_FOUND_ERR", "NOT_SUPPORTED_ERR", "INUSE_ATTRIBUTE_ERR", "INVALID_STATE_ERR", "SYNTAX_ERR", "INVALID_MODIFICATION_ERR", "NAMESPACE_ERR", "INVALID_ACCESS_ERR", ] for i in range(len(_CODE_NAMES)): globals()[_CODE_NAMES[i]] = i + 1 del i class DOMException(Exception): """Base class for exceptions raised by the DOM.""" def __init__(self, code, *args): self.code = code self.args = (code,) + args Exception.__init__(self, g_errorMessages[code]) if self.__class__ is DOMException: self.__class__ = g_realExceptions[code] def _derived_init(self, *args): """Initializer method that does not expect a code argument, for use in derived classes.""" if not args: args = (self, g_errorMessages[self.code]) else: args = (self,) + args apply(Exception.__init__, args) try: from xml.dom import DOMException except ImportError: pass import string _EXCEPTION_NAMES = ["DOMException"] template = """\ class %s(DOMException): code = %s __init__ = _derived_init """ g_realExceptions = {} for s in _CODE_NAMES: words = string.split(string.lower(s), "_") ename = string.join(map(string.capitalize, words), "") exec template % (ename, s) g_realExceptions[globals()[s]] = globals()[ename] _EXCEPTION_NAMES.append(ename) del s, words, ename, string, template try: import xml.dom except ImportError: # We have to define everything, which we've done above. # This installs it: import sys try: mod = __import__("xml") except ImportError: import new mod = new.module("xml") del new sys.modules["xml"] = mod import Exceptions mod.dom = Exceptions sys.modules["xml.dom"] = Exceptions del mod, sys del Exceptions from Core import Node else: # The exception classes may not have been defined, so add any # that are needed. import Exceptions for s in _CODE_NAMES + _EXCEPTION_NAMES: if not hasattr(xml.dom, s): setattr(xml.dom, s, getattr(Exceptions, s)) if not hasattr(xml.dom, "Node") or type(xml.dom.Node) is type(Exceptions): # We need to provide the Node class so the .nodeType constants # are in the right place. import Core xml.dom.Node = Core.Node del Core del s, Exceptions del _CODE_NAMES, _EXCEPTION_NAMES g_errorMessages = { INDEX_SIZE_ERR: "Index error accessing NodeList or NamedNodeMap", DOMSTRING_SIZE_ERR: "DOMString exceeds maximum size.", HIERARCHY_REQUEST_ERR: "Node manipulation results in invalid parent/child relationship.", WRONG_DOCUMENT_ERR: "", INVALID_CHARACTER_ERR: "", NO_DATA_ALLOWED_ERR: "", NO_MODIFICATION_ALLOWED_ERR: "Attempt to modify a read-only attribute.", NOT_FOUND_ERR: "", NOT_SUPPORTED_ERR: "DOM feature not supported.", INUSE_ATTRIBUTE_ERR: "Illegal operation on an attribute while in use by an element.", INVALID_STATE_ERR: "", SYNTAX_ERR: "", INVALID_MODIFICATION_ERR: "", NAMESPACE_ERR: "Namespace operation results in malformed or invalid name or name declaration.", INVALID_ACCESS_ERR: "", } # To be sure that unused alternate implementations of the DOM # exceptions are not used by accessing this module directly, import # the "right" versions over those defined here. They may be the same, # and they may be from an up-to-date PyXML or Python 2.1 or newer. # This causes alternate implementations to be discarded if not needed. from xml.dom import * ParsedXML/DOM/ExpatBuilder.py0100644000175200017500000010350307600633530015713 0ustar faasseninfrae############################################################################## # # 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. # ############################################################################## """Facility to use the Expat parser to load a ParsedXML.DOM instance from a string or file.""" # Warning! # # This module is tightly bound to the implementation details of the # Parsed XML DOM and can't be used with other DOM implementations. This # is due, in part, to a lack of appropriate methods in the DOM (there is # no way to create Entity and Notation nodes via the DOM Level 2 # interface), and for performance. The later is the cause of some fairly # cryptic code. # # Performance hacks: # # - .character_data_handler() has an extra case in which continuing # data is appended to an existing Text node; this can be a # substantial speedup since Expat seems to break data at every # newline. # # - Determining that a node exists is done using an identity comparison # with None rather than a truth test; this avoids searching for and # calling any methods on the node object if it exists. (A rather # nice speedup is achieved this way as well!) import string import Core import XMLExtended from xml.parsers import expat class Options: """Features object that has variables set for each DOMBuilder feature. The DOMBuilder class uses an instance of this class to pass settings to the ExpatBuilder class. """ # Note that the DOMBuilder class in LoadSave constrains which of these # values can be set using the DOM Level 3 LoadSave feature. namespaces = 1 namespace_declarations = 1 validation = 0 external_general_entities = 1 external_parameter_entities = 1 validate_if_cm = 0 create_entity_ref_nodes = 1 entity_nodes = 1 white_space_in_element_content = 1 cdata_nodes = 1 comments = 1 charset_overrides_xml_encoding = 1 errorHandler = None filter = None class ExpatBuilder: """Document builder that uses Expat to build a ParsedXML.DOM document instance.""" def __init__(self, options=None): if options is None: options = Options() self._options = options self._parser = None self.reset() try: {}.setdefault except AttributeError: def _intern(self, s): try: return self._interns[s] except KeyError: self._interns[s] = s return s else: def _intern(self, s): return self._interns.setdefault(s, s) def createParser(self): """Create a new parser object.""" return expat.ParserCreate() def getParser(self): """Return the parser object, creating a new one if needed.""" if not self._parser: self._parser = self.createParser() self.install(self._parser) return self._parser def reset(self): """Free all data structures used during DOM construction.""" self.document = None self._cdata = 0 self._standalone = -1 self._version = None self._encoding = None self._doctype_args = None self._entities = [] self._notations = [] self._pre_doc_events = [] self._attr_info = {} self._elem_info = {} self._interns = {} def install(self, parser): """Install the callbacks needed to build the DOM into the parser.""" # This creates circular references! parser.StartDoctypeDeclHandler = self.start_doctype_decl_handler parser.StartElementHandler = self.start_element_handler parser.EndElementHandler = self.end_element_handler parser.ProcessingInstructionHandler = self.pi_handler parser.CharacterDataHandler = self.character_data_handler parser.EntityDeclHandler = self.entity_decl_handler parser.NotationDeclHandler = self.notation_decl_handler parser.CommentHandler = self.comment_handler parser.StartCdataSectionHandler = self.start_cdata_section_handler parser.EndCdataSectionHandler = self.end_cdata_section_handler parser.ExternalEntityRefHandler = self.external_entity_ref_handler parser.ordered_attributes = 1 parser.specified_attributes = 1 parser.XmlDeclHandler = self.xml_decl_handler parser.ElementDeclHandler = self.element_decl_handler parser.AttlistDeclHandler = self.attlist_decl_handler def parseFile(self, file): """Parse a document from a file object, returning the document node.""" parser = self.getParser() first_buffer = 1 strip_newline = 0 while 1: buffer = file.read(16*1024) if not buffer: break if strip_newline: if buffer[0] == "\n": buffer = buffer[1:] strip_newline = 0 if buffer and buffer[-1] == "\r": strip_newline = 1 buffer = _normalize_lines(buffer) parser.Parse(buffer, 0) if first_buffer and self.document: if self.document.doctype: self._setup_subset(buffer) first_buffer = 0 parser.Parse("", 1) doc = self.document self.reset() self._parser = None return doc def parseString(self, string): """Parse a document from a string, returning the document node.""" string = _normalize_lines(string) parser = self.getParser() parser.Parse(string, 1) self._setup_subset(string) doc = self.document self.reset() self._parser = None return doc def _setup_subset(self, buffer): """Load the internal subset if there might be one.""" if self.document.doctype: extractor = InternalSubsetExtractor() extractor.parseString(buffer) subset = extractor.getSubset() if subset is not None: d = self.document.doctype.__dict__ d['internalSubset'] = subset def start_doctype_decl_handler(self, doctypeName, systemId, publicId, has_internal_subset): self._pre_doc_events.append(("doctype",)) self._doctype_args = (self._intern(doctypeName), publicId, systemId) def pi_handler(self, target, data): target = self._intern(target) if self.document is None: self._pre_doc_events.append(("pi", target, data)) else: node = self.document.createProcessingInstruction(target, data) self.curNode.appendChild(node) def character_data_handler(self, data): if self._cdata: if (self._cdata_continue and (self.curNode._children[-1].nodeType == Core.Node.CDATA_SECTION_NODE)): d = self.curNode._children[-1].__dict__ data = d['data'] + data d['data'] = d['nodeValue'] = data return node = self.document.createCDATASection(data) self._cdata_continue = 1 elif (self.curNode._children and self.curNode._children[-1].nodeType == Core.Node.TEXT_NODE): node = self.curNode._children[-1] data = node.data + data d = node.__dict__ d['data'] = d['nodeValue'] = data return else: node = self.document.createTextNode(data) self.curNode.appendChild(node) def entity_decl_handler(self, entityName, is_parameter_entity, value, base, systemId, publicId, notationName): if is_parameter_entity: # we don't care about parameter entities for the DOM return if not self._options.entity_nodes: return entityName = self._intern(entityName) notationName = self._intern(notationName) node = XMLExtended.Entity(entityName, publicId, systemId, notationName) if value is not None: # internal entity child = Core.Text(value) # must still get to parent, even if entity isn't _in_tree child.__dict__['_in_tree'] = 1 child.__dict__['_readonly'] = 1 node.__dict__['_children'] = [child] self._entities.append(node) def notation_decl_handler(self, notationName, base, systemId, publicId): notationName = self._intern(notationName) node = XMLExtended.Notation(notationName, publicId, systemId) self._notations.append(node) def comment_handler(self, data): if self._options.comments: if self.document is None: self._pre_doc_events.append(("comment", data)) else: node = self.document.createComment(data) self.curNode.appendChild(node) def start_cdata_section_handler(self): if self._options.cdata_nodes: self._cdata = 1 self._cdata_continue = 0 def end_cdata_section_handler(self): self._cdata = 0 self._cdata_continue = 0 def external_entity_ref_handler(self, context, base, systemId, publicId): return 1 def start_element_handler(self, name, attributes): name = self._intern(name) if self.document is None: doctype = self._create_doctype() doc = Core.theDOMImplementation.createDocument( None, name, doctype) if self._standalone >= 0: doc.standalone = self._standalone doc.encoding = self._encoding doc.version = self._version doc.__dict__['_elem_info'] = self._elem_info doc.__dict__['_attr_info'] = self._attr_info self.document = doc self._include_early_events() node = doc.documentElement # chicken & egg: if this isn't inserted here, the document # element doesn't get the information about the defined # attributes for its element type if self._attr_info.has_key(name): node.__dict__['_attr_info'] = self._attr_info[name] else: node = self.document.createElement(name) self.curNode.appendChild(node) self.curNode = node if attributes: L = [] for i in range(0, len(attributes), 2): L.append([None, self._intern(attributes[i]), None, None, attributes[i+1], 1]) node.__dict__['_attributes'] = L def end_element_handler(self, name): curNode = self.curNode assert curNode.tagName == name, "element stack messed up!" self.curNode = self.curNode.parentNode self._handle_white_text_nodes(curNode) if self._options.filter: self._options.filter.endElement(curNode) def _handle_white_text_nodes(self, node): info = self._elem_info.get(node.tagName) if not info: return type = info[0] if type in (expat.model.XML_CTYPE_ANY, expat.model.XML_CTYPE_MIXED): return # # We have element type information; look for text nodes which # contain only whitespace. # L = [] for child in node.childNodes: if ( child.nodeType == Core.Node.TEXT_NODE and not string.strip(child.data)): L.append(child) # # Depending on the options, either mark the nodes as ignorable # whitespace or remove them from the tree. # for child in L: if self._options.white_space_in_element_content: child.__dict__['isWhitespaceInElementContent'] = 1 else: node.removeChild(child) def element_decl_handler(self, name, model): self._elem_info[self._intern(name)] = model def attlist_decl_handler(self, elem, name, type, default, required): elem = self._intern(elem) name = self._intern(name) type = self._intern(type) if self._attr_info.has_key(elem): L = self._attr_info[elem] else: L = [] self._attr_info[elem] = L L.append([None, name, None, None, default, 0, type, required]) def xml_decl_handler(self, version, encoding, standalone): self._version = version self._encoding = encoding self._standalone = standalone def _create_doctype(self): if not self._doctype_args: return doctype = apply(Core.theDOMImplementation.createDocumentType, self._doctype_args) doctype._entities[:] = self._entities self._entities = doctype._entities doctype._notations[:] = self._notations self._notations = doctype._notations return doctype def _include_early_events(self): doc = self.document if self._doctype_args: docelem = doc.doctype else: docelem = doc.documentElement for event in self._pre_doc_events: t = event[0] if t == "comment": node = doc.createComment(event[1]) elif t == "doctype": # marker; switch to before docelem docelem = doc.documentElement continue elif t == "pi": node = doc.createProcessingInstruction(event[1], event[2]) else: raise RuntimeError, "unexpected early event type: " + `t` doc.insertBefore(node, docelem) def _normalize_lines(s): """Return a copy of 's' with line-endings normalized according to XML 1.0 section 2.11.""" s = string.replace(s, "\r\n", "\n") return string.replace(s, "\r", "\n") # framework document used by the fragment builder. # Takes a string for the doctype, subset string, and namespace attrs string. _FRAGMENT_BUILDER_INTERNAL_SYSTEM_ID = \ "http://xml.zope.org/entities/fragment-builder/internal" _FRAGMENT_BUILDER_TEMPLATE = ( '''\ %%s ]> &fragment-builder-internal;''' % _FRAGMENT_BUILDER_INTERNAL_SYSTEM_ID) class FragmentBuilder(ExpatBuilder): """Builder which constructs document fragments given XML source text and a context node. The context node is expected to provide information about the namespace declarations which are in scope at the start of the fragment. """ def __init__(self, context, options=None): if context.nodeType == Core.Node.DOCUMENT_NODE: self.originalDocument = context self.context = context else: self.originalDocument = context.ownerDocument self.context = context ExpatBuilder.__init__(self, options) def reset(self): ExpatBuilder.reset(self) self.fragment = None def parseFile(self, file): """Parse a document fragment from a file object, returning the fragment node.""" return self.parseString(file.read()) def parseString(self, string): """Parse a document fragment from a string, returning the fragment node.""" self._source = string parser = self.getParser() doctype = self.originalDocument.doctype ident = "" if doctype: subset = doctype.internalSubset or self._getDeclarations() if doctype.publicId: ident = ('PUBLIC "%s" "%s"' % (doctype.publicId, doctype.systemId)) elif doctype.systemId: ident = 'SYSTEM "%s"' % doctype.systemId else: subset = "" nsattrs = self._getNSattrs() # get ns decls from node's ancestors document = _FRAGMENT_BUILDER_TEMPLATE % (ident, subset, nsattrs) try: parser.Parse(document, 1) except: self.reset() raise fragment = self.fragment self.reset() ## self._parser = None return fragment def _getDeclarations(self): """Re-create the internal subset from the DocumentType node. This is only needed if we don't already have the internalSubset as a string. """ doctype = self.originalDocument.doctype s = "" if doctype: for i in range(doctype.notations.length): notation = doctype.notations.item(i) if s: s = s + "\n " s = "%s' \ % (s, notation.publicId, notation.systemId) else: s = '%s SYSTEM "%s">' % (s, notation.systemId) for i in range(doctype.entities.length): entity = doctype.entities.item(i) if s: s = s + "\n " s = "%s" return s def _getNSattrs(self): return "" def external_entity_ref_handler(self, context, base, systemId, publicId): if systemId == _FRAGMENT_BUILDER_INTERNAL_SYSTEM_ID: # this entref is the one that we made to put the subtree # in; all of our given input is parsed in here. old_document = self.document old_cur_node = self.curNode self._save_namespace_decls() parser = self._parser.ExternalEntityParserCreate(context) self._restore_namespace_decls() # put the real document back, parse into the fragment to return self.document = self.originalDocument self.fragment = self.document.createDocumentFragment() self.curNode = self.fragment try: parser.Parse(self._source, 1) finally: self.curNode = old_cur_node self.document = old_document self._source = None return -1 else: return ExpatBuilder.external_entity_ref_handler( self, context, base, systemId, publicId) def _save_namespace_decls(self): pass def _restore_namespace_decls(self): pass class Namespaces: """Mix-in class for builders; adds support for namespaces.""" def _initNamespaces(self): # # These first two dictionaries are used to track internal # namespace state, and contain all "current" declarations. # # URI -> [prefix, prefix, prefix...] # # The last prefix in list is most recently declared; there's # no way to be sure we're using the right one if more than one # has been defined for a particular URI. self._nsmap = { Core.XML_NS: ["xml"], Core.XMLNS_NS: ["xmlns"], } # prefix -> URI self._prefixmap = { "xml": [Core.XML_NS], "xmlns": [Core.XMLNS_NS], } # # These dictionaries are used to store the namespace # declaractions made on a single element; they are used to add # the attributes of the same name to the DOM structure. When # added to the DOM, they are replaced with new, empty # dictionaries on the Builder object. # self._ns_prefix_uri = {} self._ns_uri_prefixes = {} # list of (prefix, uri) ns declarations. Namespace attrs are # constructed from this and added to the element's attrs. self._ns_ordered_prefixes = [] def createParser(self): """Create a new namespace-handling parser.""" return expat.ParserCreate(namespace_separator=" ") def install(self, parser): """Insert the namespace-handlers onto the parser.""" ExpatBuilder.install(self, parser) parser.StartNamespaceDeclHandler = self.start_namespace_decl_handler parser.EndNamespaceDeclHandler = self.end_namespace_decl_handler def start_namespace_decl_handler(self, prefix, uri): "push this namespace declaration on our storage" # # These are what we use internally: # prefix = self._intern(prefix) uri = self._intern(uri) L = self._nsmap.get(uri) if L is None: self._nsmap[uri] = L = [] L.append(prefix) L = self._prefixmap.get(prefix) if L is None: self._prefixmap[prefix] = L = [] L.append(uri) # # These are used to provide namespace declaration info to the DOM: # self._ns_prefix_uri[prefix] = uri L = self._ns_uri_prefixes.get(uri) if not L: self._ns_uri_prefixes[uri] = L = [] L.append(prefix) self._ns_ordered_prefixes.append((prefix, uri)) def end_namespace_decl_handler(self, prefix): "pop the latest namespace declaration." uri = self._prefixmap[prefix].pop() self._nsmap[uri].pop() def _save_namespace_decls(self): """Save the stored namespace decls and reset the new ones. This lets us launch another parser and have its namespace declarations not affect future elements. Must be called outside of any start/end namespace_decl_handler calls.""" self._oldnsmap = self._nsmap self._oldprefixmap = self._prefixmap self._oldns_prefix_uri = self._ns_prefix_uri self._oldns_uri_prefixes = self._ns_uri_prefixes self._oldns_ordered_prefixes = self._ns_ordered_prefixes self._initNamespaces() def _restore_namespace_decls(self): "Restore the namespace decls from _save_namespace_decls." self._nsmap = self._oldnsmap self._prefixmap = self._oldprefixmap self._ns_prefix_uri = self._oldns_prefix_uri self._ns_uri_prefixes = self._oldns_uri_prefixes self._ns_ordered_prefixes = self._oldns_ordered_prefixes def start_element_handler(self, name, attributes): if ' ' in name: uri, localname = string.split(name, ' ') localname = self._intern(localname) uri = self._intern(uri) prefix = self._intern(self._nsmap[uri][-1]) if prefix: qname = "%s:%s" % (prefix, localname) else: qname = localname else: uri = None qname = name localname = prefix = None qname = self._intern(qname) if self.document is None: doctype = self._create_doctype() doc = Core.theDOMImplementation.createDocument( uri, qname, doctype) if self._standalone >= 0: doc.standalone = self._standalone doc.encoding = self._encoding doc.version = self._version doc.__dict__['_elem_info'] = self._elem_info doc.__dict__['_attr_info'] = self._attr_info self.document = doc self._include_early_events() node = doc.documentElement # chicken & egg: if this isn't inserted here, the document # element doesn't get the information about the defined # attributes for its element type if self._attr_info.has_key(qname): node.__dict__['_attr_info'] = self._attr_info[qname] else: node = self.document.createElementNS( uri, qname, (prefix, localname)) self.curNode.appendChild(node) self.curNode = node L = [] # [[namespaceURI, qualifiedName, localName, prefix, # value, specified]] if self._ns_ordered_prefixes and self._options.namespace_declarations: for prefix, uri in self._ns_ordered_prefixes: if prefix: attrPrefix = "xmlns" tagName = self._intern('%s:%s' % (attrPrefix, prefix)) else: attrPrefix = tagName = "xmlns" L.append([Core.XMLNS_NS, tagName, self._intern(prefix), attrPrefix, uri, 1]) if attributes: # This uses the most-recently declared prefix, not necessarily # the right one. for i in range(0, len(attributes), 2): aname = attributes[i] value = attributes[i+1] if ' ' in aname: uri, localname = string.split(aname, ' ') localname = self._intern(localname) prefix = self._intern(self._nsmap[uri][-1]) uri = self._intern(uri) if prefix: qualifiedname = self._intern( '%s:%s' % (prefix, localname)) else: qualifiedname = localname L.append([uri, qualifiedname, localname, prefix, value, 1]) else: name = self._intern(aname) L.append([None, name, name, None, value, 1]) if L: node.__dict__['_attributes'] = L if self._ns_prefix_uri: # insert this stuff on the element: d = node.__dict__ d['_ns_prefix_uri'] = self._ns_prefix_uri d['_ns_uri_prefixes'] = self._ns_uri_prefixes # reset for the next: self._ns_prefix_uri = {} self._ns_uri_prefixes = {} self._ns_ordered_prefixes = [] def end_element_handler(self, name): if ' ' in name: uri, localname = string.split(name, ' ') assert (self.curNode.namespaceURI == uri and self.curNode.localName == localname), \ "element stack messed up! (namespace)" else: assert self.curNode.nodeName == name, \ "element stack messed up - bad nodeName" assert self.curNode.namespaceURI is None, \ "element stack messed up - bad namespaceURI" self._handle_white_text_nodes(self.curNode) self.curNode = self.curNode.parentNode class ExpatBuilderNS(Namespaces, ExpatBuilder): """Document builder that supports namespaces.""" def reset(self): ExpatBuilder.reset(self) self._initNamespaces() class FragmentBuilderNS(Namespaces, FragmentBuilder): """Fragment builder that supports namespaces.""" def reset(self): FragmentBuilder.reset(self) self._initNamespaces() def _getNSattrs(self): """Return string of namespace attributes from this element and ancestors.""" attrs = "" context = self.context L = [] while context: if hasattr(context, '_ns_prefix_uri'): for prefix, uri in context._ns_prefix_uri.items(): # add every new NS decl from context to L and attrs string if prefix in L: continue L.append(prefix) if prefix: declname = "xmlns:" + prefix else: declname = "xmlns" if attrs: attrs = "%s\n %s='%s'" % (attrs, declname, uri) else: attrs = " %s='%s'" % (declname, uri) context = context.parentNode return attrs class ParseEscape(Exception): """Exception raised to short-circuit parsing in InternalSubsetExtractor.""" pass class InternalSubsetExtractor(ExpatBuilder): """XML processor which can rip out the internal document type subset.""" def getSubset(self): """Return the internal subset as a string.""" subset = self.subset while subset and subset[0] != "[": del subset[0] if subset: x = subset.index("]") return string.join(subset[1:x], "") else: return None def parseFile(self, file): try: ExpatBuilder.parseFile(self, file) except ParseEscape: pass def parseString(self, string): try: ExpatBuilder.parseString(self, string) except ParseEscape: pass def install(self, parser): parser.StartDoctypeDeclHandler = self.start_doctype_decl_handler parser.EndDoctypeDeclHandler = self.end_doctype_decl_handler parser.StartElementHandler = self.start_element_handler def start_doctype_decl_handler(self, *args): self.subset = [] self.getParser().DefaultHandler = self.default_handler def end_doctype_decl_handler(self): self.getParser().DefaultHandler = None raise ParseEscape() def start_element_handler(self, name, attrs): raise ParseEscape() def default_handler(self, s): self.subset.append(s) def parse(file, namespaces=1): """Parse a document, returning the resulting Document node. 'file' may be either a file name or an open file object. """ if namespaces: builder = ExpatBuilderNS() else: builder = ExpatBuilder() if isinstance(file, type('')): fp = open(file, 'rb') result = builder.parseFile(fp) fp.close() else: result = builder.parseFile(file) return result def parseFragment(file, context, namespaces=1): """Parse a fragment of a document, given the context from which it was originally extracted. context should be the parent of the node(s) which are in the fragment. 'file' may be either a file name or an open file object. """ if namespaces: builder = FragmentBuilderNS(context) else: builder = FragmentBuilder(context) if isinstance(file, type('')): fp = open(file, 'rb') result = builder.parseFile(fp) fp.close() else: result = builder.parseFile(file) return result def makeBuilder(options): """Create a builder based on an Options object.""" if options.namespaces: return ExpatBuilderNS(options) else: return ExpatBuilder(options) ParsedXML/DOM/SAXBuilder.py0100644000175200017500000002037407300403436015266 0ustar faasseninfrae############################################################################## # # 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. # ############################################################################## """Constructor for ParsedXML.DOM, based on a SAX parser.""" import os import urllib import xml.sax class SAXBuilder(xml.sax.ContentHandler): _locator = None document = None documentElement = None def __init__(self, documentFactory=None): self.documentFactory = documentFactory self._ns_contexts = [{}] # contains uri -> prefix dicts self._current_context = self._ns_contexts[-1] def install(self, parser): parser.setContentHandler(self) def setDocumentLocator(self, locator): self._locator = locator def startPrefixMapping(self, prefix, uri): self._ns_contexts.append(self._current_context.copy()) self._current_context[uri] = prefix or None def endPrefixMapping(self, prefix): self._current_context = self._ns_contexts.pop() def _make_qname(self, uri, localname, tagname): # When using namespaces, the reader may or may not # provide us with the original name. If not, create # *a* valid tagName from the current context. if uri: if tagname is None: prefix = self._current_context.get(uri) if prefix: tagname = "%s:%s" % (prefix, localname) else: tagname = localname else: tagname = localname return tagname def startElementNS(self, name, tagName, attrs): uri, localname = name tagName = self._make_qname(uri, localname, tagName) if not self.document: factory = self.documentFactory self.document = factory.createDocument(uri or None, tagName, None) node = self.document.documentElement else: if uri: node = self.document.createElementNS(uri, tagName) else: node = self.document.createElement(localname) self.curNode.appendChild(node) self.curNode = node for aname, value in attrs.items(): a_uri, a_localname = aname if a_uri: qname = "%s:%s" % (self._current_context[a_uri], a_localname) node.setAttributeNS(a_uri, qname, value) else: attr = self.document.createAttribute(a_localname) node.setAttribute(a_localname, value) def endElementNS(self, name, tagName): self.curNode = self.curNode.parentNode def startElement(self, name, attrs): if self.documentElement is None: factory = self.documentFactory self.document = factory.createDocument(None, name, None) node = self.document.documentElement self.documentElement = 1 else: node = self.document.createElement(name) self.curNode.appendChild(node) self.curNode = node for aname, value in attrs.items(): node.setAttribute(aname, value) def endElement(self, name): self.curNode = self.curNode.parentNode def comment(self, s): node = self.document.createComment(s) self.curNode.appendChild(node) def processingInstruction(self, target, data): node = self.document.createProcessingInstruction(target, data) self.curNode.appendChild(node) def ignorableWhitespace(self, chars): node = self.document.createTextNode(chars) self.curNode.appendChild(node) def characters(self, chars): node = self.document.createTextNode(chars) self.curNode.appendChild(node) def parse(file, namespaces=1, dom=None, parser=None): if not parser: parser = xml.sax.make_parser() parser.setFeature(xml.sax.handler.feature_namespaces, namespaces) if not dom: import Core dom = Core.theDOMImplementation if isinstance(file, type('')): try: fp = open(file) except IOError, e: if e.errno != errno.ENOENT: raise fp = urllib.urlopen(file) systemId = file else: # Ugh! Why doesn't urllib.pathname2url() do something useful? systemId = "file://" + os.path.abspath(file) else: source = xml.sax.InputSource() fp = file try: systemId = file.name except AttributeError: systemId = None source = xml.sax.InputSource(file) source.setByteStream(fp) source.setSystemId(systemId) builder = SAXBuilder(documentFactory=dom) builder.install(parser) parser.parse(source) if fp is not file: fp.close() return builder.document ParsedXML/DOM/Traversal.py0100644000175200017500000003323507256312425015276 0ustar faasseninfrae"""Implementation of DOM Level 2 Traversal. Based on the W3C recommendation at: http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ """ # This code could be sped up. # - uses DOM methods, could use implementation internals, esp. childNodes # - if we had mutation events, NodeIterator could build an array as it # iterated, and move over that, only updating on mutation import xml.dom __all__ = [ "NodeFilter", "NodeIterator", "TreeWalker", ] class NodeFilter: # Constants returned by acceptNode(): FILTER_ACCEPT = 1 FILTER_REJECT = 2 FILTER_SKIP = 3 # Constants for whatToShow: SHOW_ALL = 0xFFFFFFFF SHOW_ELEMENT = 0x00000001 SHOW_ATTRIBUTE = 0x00000002 SHOW_TEXT = 0x00000004 SHOW_CDATA_SECTION = 0x00000008 SHOW_ENTITY_REFERENCE = 0x00000010 SHOW_ENTITY = 0x00000020 SHOW_PROCESSING_INSTRUCTION = 0x00000040 SHOW_COMMENT = 0x00000080 SHOW_DOCUMENT = 0x00000100 SHOW_DOCUMENT_TYPE = 0x00000200 SHOW_DOCUMENT_FRAGMENT = 0x00000400 SHOW_NOTATION = 0x00000800 def acceptNode(self, node): # Just accept everything by default: return NodeFilter.FILTER_ACCEPT _whatToShow_bits = ( (xml.dom.Node.ELEMENT_NODE, NodeFilter.SHOW_ELEMENT), (xml.dom.Node.ATTRIBUTE_NODE, NodeFilter.SHOW_ATTRIBUTE), (xml.dom.Node.TEXT_NODE, NodeFilter.SHOW_TEXT), (xml.dom.Node.CDATA_SECTION_NODE, NodeFilter.SHOW_CDATA_SECTION), (xml.dom.Node.ENTITY_REFERENCE_NODE, NodeFilter.SHOW_ENTITY_REFERENCE), (xml.dom.Node.ENTITY_NODE, NodeFilter.SHOW_ENTITY), (xml.dom.Node.PROCESSING_INSTRUCTION_NODE, NodeFilter.SHOW_PROCESSING_INSTRUCTION), (xml.dom.Node.COMMENT_NODE, NodeFilter.SHOW_COMMENT), (xml.dom.Node.DOCUMENT_NODE, NodeFilter.SHOW_DOCUMENT), (xml.dom.Node.DOCUMENT_TYPE_NODE, NodeFilter.SHOW_DOCUMENT_TYPE), (xml.dom.Node.DOCUMENT_FRAGMENT_NODE, NodeFilter.SHOW_DOCUMENT_FRAGMENT), (xml.dom.Node.NOTATION_NODE, NodeFilter.SHOW_NOTATION), ) class AccessorBase: def __init__(self, root, whatToShow, filter, entityReferenceExpansion): if root is None: raise xml.dom.NotSupportedErr( "root of traversal object can't be None") d = self.__dict__ d['root'] = root d['whatToShow'] = whatToShow d['filter'] = filter d['expandEntityReferences'] = entityReferenceExpansion # # Decode the whatToShow flags for faster tests; the W3C # reserves the first 200 NodeType values, but the whatToShow # flags have to fit in 32 bits (leave slot 0 empty since it's # not a valid NodeType). # d['_whatToShow'] = what = [0] * 33 for nodeType, bit in _whatToShow_bits: what[nodeType] = whatToShow & bit def __setattr__(self, name, value): setter = getattr(self, '_set_' + name, None) if setter is None: getter = getattr(self, '_get_' + name, None) if getter: raise xml.dom.NoModificationAllowedErr( "read-only attribute: " + `name`) else: raise AttributeError, "no such attribute: " + `name` setter(value) def _get_root(self): return self.root def _get_whatToShow(self): return self.whatToShow def _get_filter(self): return filter def _get_expandEntityReferences(self): return self.expandEntityReferences def _should_show(self, node): if not self._whatToShow[node.nodeType]: return NodeFilter.FILTER_SKIP else: if ( node.nodeType == xml.dom.Node.ENTITY_REFERENCE_NODE and not self.expandEntityReferences): return NodeFilter.FILTER_REJECT elif self.filter is not None: return self._filterNode(node) return NodeFilter.FILTER_ACCEPT def _nextInTree(self, node): """Return first visible node in node's subtree, or None.""" # check given node first if self._should_show(node) == NodeFilter.FILTER_ACCEPT: return node elif self._should_show(node) == NodeFilter.FILTER_REJECT: return None for c in node.childNodes: child = self._nextInTree(c) if child: return child if c.isSameNode(self.root): # don't leave root subtree return None return None def _lastInTree(self, node): """Return last visible node in node's subtree, or None.""" if self._should_show(node) == NodeFilter.FILTER_REJECT: return None childNodes = node.childNodes childNums = range(childNodes.length) childNums.reverse() for c in childNums: childNode = childNodes[c] child = self._lastInTree(childNode) if child: return child if childNode.isSameNode(self.root): # don't leave root subtree return None # subtree exhausted, check given node if self._should_show(node) == NodeFilter.FILTER_ACCEPT: return node return None # we don't do any visibilty tests here, _nextInTree does. def _nextNode(self, startNode): """Return next visible node after startNode, or None.""" # check children for child in startNode.childNodes: node = self._nextInTree(child) if node: return node if child.isSameNode(self.root): # don't leave root subtree return None # check next siblings sib = startNode.nextSibling while sib: node = self._nextInTree(sib) if node: return node if sib.isSameNode(self.root): # don't leave root subtree return None sib = sib.nextSibling # check ancestors' next siblings; don't visit ancestors ancestor = startNode.parentNode while ancestor: sib = ancestor.nextSibling while sib: node = self._nextInTree(sib) if node: return node if sib.isSameNode(self.root): # don't leave root subtree return None sib = sib.nextSibling # no visible nodes in siblings or subtrees of this ancestor if ancestor.isSameNode(self.root): # don't leave root subtree return None ancestor = ancestor.parentNode return None # we *do* a visibilty test here, _lastInTree does too. def _previousNode(self, startNode): """Return the previous visible node after startNode, or None.""" # check previous siblings sib = startNode.previousSibling while sib: node = self._lastInTree(sib) if node: return node if sib.isSameNode(self.root): # don't leave root subtree return None sib = sib.previousSibling # check ancestors, then ancestors' previous siblings ancestor = startNode.parentNode while ancestor: if self._should_show(ancestor) == NodeFilter.FILTER_ACCEPT: return ancestor sib = ancestor.previousSibling while sib: node = self._lastInTree(sib) if node: return node if sib.isSameNode(self.root): # don't leave root subtree return None sib = sib.previousSibling if ancestor.isSameNode(self.root): # don't leave root subtree return None ancestor = ancestor.parentNode return None # Since we don't need to know about structure, we could probably be a lot # faster if we kept a list of nodes in document order and updated # it when we got a mutation event - once we have mutation events. class NodeIterator(AccessorBase): BEFORE_NODE = 1 # iterator crossed reference node moving forward AFTER_NODE = 0 # iterator crossed reference node moving backward def __init__(self, root, whatToShow=NodeFilter.SHOW_ALL, filter=None, entityReferenceExpansion=1): AccessorBase.__init__(self, root, whatToShow, filter, entityReferenceExpansion) self.__dict__['_refNode'] = None self.__dict__['_refPos'] = NodeIterator.BEFORE_NODE def detach(self): self.__dict__['root'] = None def nextNode(self): if self.root is None: raise xml.dom.InvalidStateErr( "can't iterate using a detached NodeIterator") if self._refNode == None: self.__dict__['_refNode'] = self.root self.__dict__['_refPos'] = NodeIterator.AFTER_NODE if self._should_show(self._refNode) == NodeFilter.FILTER_ACCEPT: return self._refNode elif self._refPos == NodeIterator.BEFORE_NODE: if self._should_show(self._refNode) == NodeFilter.FILTER_ACCEPT: self.__dict__['_refPos'] = NodeIterator.AFTER_NODE return self._refNode node = AccessorBase._nextNode(self, self._refNode) if node: self.__dict__['_refNode'] = node self.__dict__['_refPos'] = NodeIterator.AFTER_NODE return node def previousNode(self): if self.root is None: raise xml.dom.InvalidStateErr( "can't iterate using a detached NodeIterator") if self._refNode == None: self.__dict__['_refNode'] = self.root self.__dict__['_refPos'] = NodeIterator.BEFORE_NODE elif self._refPos == NodeIterator.AFTER_NODE: if self._should_show(self._refNode) == NodeFilter.FILTER_ACCEPT: self.__dict__['_refPos'] = NodeIterator.BEFORE_NODE return self._refNode node = AccessorBase._previousNode(self, self._refNode) if node: self.__dict__['_refNode'] = node self.__dict__['_refPos'] = NodeIterator.BEFORE_NODE return node def __getitem__(self, index): node = self.nextNode() if node is None: raise IndexError, "NodeIterator index out of range" return node def _filterNode(self, node): """Return what the filter says to do with node, translating reject into skip""" filterAction = self.filter.acceptNode(node) if filterAction == NodeFilter.FILTER_REJECT: return NodeFilter.FILTER_SKIP return filterAction class TreeWalker(AccessorBase): def __init__(self, root, whatToShow=NodeFilter.SHOW_ALL, filter=None, entityReferenceExpansion=1): AccessorBase.__init__(self, root, whatToShow, filter, entityReferenceExpansion) self.__dict__['currentNode'] = root def _get_currentNode(self): return self.currentNode def _set_currentNode(self, node): if node is None: raise xml.dom.NotSupportedErr("can't set current node to None") self.__dict__['currentNode'] = node def parentNode(self): if self.root.isSameNode(self.currentNode): return None node = self.currentNode.parentNode while node is not None and ( self._should_show(node) != NodeFilter.FILTER_ACCEPT): if node.isSameNode(self.root): # can't step any further up return else: node = node.parentNode if node is not None: self.__dict__['currentNode'] = node return node def firstChild(self): node = self.currentNode.firstChild while node is not None and ( self._should_show(node) != NodeFilter.FILTER_ACCEPT): node = node.nextSibling if node is not None: self.__dict__['currentNode'] = node return node def lastChild(self): node = self.currentNode.lastChild while node is not None and ( self._should_show(node) != NodeFilter.FILTER_ACCEPT): node = node.previousSibling if node is not None: self.__dict__['currentNode'] = node return node # the rec doesn't say that *Sibling should pay attention to root! def previousSibling(self): node = self.currentNode.previousSibling while node is not None and ( self._should_show(node) != NodeFilter.FILTER_ACCEPT): node = node.previousSibling if node is not None: self.__dict__['currentNode'] = node return node def nextSibling(self): node = self.currentNode.nextSibling while node is not None and ( self._should_show(node) != NodeFilter.FILTER_ACCEPT): node = node.nextSibling if node is not None: self.__dict__['currentNode'] = node return node # TreeWalkers don't move if there is no visible next or previous, # so we do nothing for a None return. def nextNode(self): node = AccessorBase._nextNode(self, self.currentNode) if node: self.__dict__['currentNode'] = node return node def previousNode(self): node = AccessorBase._previousNode(self, self.currentNode) if node: self.__dict__['currentNode'] = node return node def _filterNode(self, node): """Return what the filter says to do with node.""" return self.filter.acceptNode(node) ParsedXML/DOM/XMLExtended.py0100644000175200017500000002511307403740624015450 0ustar faasseninfrae############################################################################## # # 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. # ############################################################################## """Acquisition-based implementation of the DOM 'XML' feature classes.""" import Core import xml.dom from ComputedAttribute import ComputedAttribute class CDATASection(Core.Text): nodeName = "#cdata-section" nodeType = Core.Node.CDATA_SECTION_NODE class Identified: """Mix-in class that supports the publicId and systemId attributes.""" def _identified_mixin_init(self, publicId, systemId): d = self.__dict__ d['publicId'] = publicId d['systemId'] = systemId def _get_publicId(self): return self.publicId def _get_systemId(self): return self.systemId class Entity(Identified, Core.Parentless, Core.Node): nodeType = Core.Node.ENTITY_NODE _readonly = 1 _in_tree = 0 _allowed_child_types = (Core.Node.ELEMENT_NODE, Core.Node.PROCESSING_INSTRUCTION_NODE, Core.Node.COMMENT_NODE, Core.Node.TEXT_NODE, Core.Node.CDATA_SECTION_NODE, Core.Node.ENTITY_REFERENCE_NODE) def __init__(self, name, publicId, systemId, notationName): self._identified_mixin_init(publicId, systemId) d = self.__dict__ d['nodeName'] = name d['notationName'] = notationName def _cloneNode(self, deep, mutable, document): # force children to not to acquire mutability: return Core.Node._cloneNode(self, deep, 0, document) def _get_notationName(self): return self.notationName # DOM Level 3 (Working Draft, 01 Sep 2025) # I expect some or all of these will become read-only before the # recommendation is finished. actualEncoding = None encoding = None version = None def _get_actualEncoding(self): return self.actualEncoding def _set_actualEncoding(self, value): self.__dict__['actualEncoding'] = value def _get_encoding(self): return self.encoding def _set_encoding(self, value): self.__dict__['value'] = value def _get_version(self): return self.version def _set_version(self, value): self.__dict__['version'] = value class EntityReference(Core.Node): nodeType = Core.Node.ENTITY_REFERENCE_NODE _readonly = 1 _allowed_child_types = (Core.Node.ELEMENT_NODE, Core.Node.PROCESSING_INSTRUCTION_NODE, Core.Node.COMMENT_NODE, Core.Node.TEXT_NODE, Core.Node.CDATA_SECTION_NODE, Core.Node.ENTITY_REFERENCE_NODE) def __init__(self, name): self.__dict__['_in_tree'] = 0 self.__dict__['nodeName'] = name class Notation(Identified, Core.Childless, Core.Parentless, Core.Node): nodeType = Core.Node.NOTATION_NODE _readonly = 1 def __init__(self, name, publicId, systemId): self._identified_mixin_init(publicId, systemId) d = self.__dict__ d['_in_tree'] = 0 d['nodeName'] = name def _cloneNode(self, deep, mutable, document): # force children to not to acquire mutability: return Core.Node._cloneNode(self, deep, 0, document) # DOM Level 3 (working draft, 5 June 2025) def _get_textContent(self): return '' textContent = '' class ProcessingInstruction(Core.Childless, Core.Node): nodeType = Core.Node.PROCESSING_INSTRUCTION_NODE def __init__(self, target, data): d = self.__dict__ d['_in_tree'] = 0 d['nodeName'] = target d['target'] = target d['nodeValue'] = data d['data'] = data def _get_data(self): return self.data def _set_data(self, data): if self._readonly: raise xml.dom.NoModificationAllowedErr() d = self.__dict__ if d['data'] != data: d['data'] = data d['nodeValue'] = data self._changed() _set_nodeValue = _set_data def _get_target(self): return self.target target = ComputedAttribute(_get_target, 1) # DOM Level 3 (working draft, 5 June 2025) def _get_textContent(self): return self.nodeValue textContent = ComputedAttribute(_get_textContent, 1) class DocumentType(Identified, Core.Childless, Core.Node): nodeType = Core.Node.DOCUMENT_TYPE_NODE nodeValue = None internalSubset = None def __init__(self, qualifiedName, publicId, systemId): self._identified_mixin_init(publicId, systemId) d = self.__dict__ d['name'] = qualifiedName d['nodeName'] = qualifiedName d['_entities'] = [] d['_notations'] = [] d['_in_tree'] = 0 def _get_internalSubset(self): return self.internalSubset def _get_name(self): return self.name _get_nodeName = _get_name def _set_nodeValue(self, data): return def _get_entities(self): return OwnedEntityMap(self, '_entities') entities = ComputedAttribute(_get_entities, 1) def _get_notations(self): return OwnedEntityMap(self, '_notations') notations = ComputedAttribute(_get_notations, 1) def isSupported(self, feature, version): doc = self.ownerDocument if doc: impl = doc.implementation else: impl = Core.theDOMImplementation return impl.hasFeature(feature, version) # DOM Level 3 (working draft, 5 June 2025) def _get_textContent(self): return '' textContent = '' class OwnedEntityMap(Core.MapFromParent): """ NamedNodeMap that works on the entity or notation structure of a DocumentType. """ def __init__(self, parent, listName): Core.MapFromParent.__init__(self, parent) self.__dict__['_parentListName'] = listName def _item_helper(self, itemSource): "used by item; create an Attribute from the item and return it" # XXX is ownerDocument ok with this? #itemSource.__dict__['ownerDocument'] = self._parent return itemSource.__of__(self._parent) def _nameMatcher(self, itemSource, name): return itemSource.nodeName == name def _nsMatcher(self, itemSource, namespaceURI, localName): return (itemSource.namespaceURI == namespaceURI and itemSource.localName == localName) def _set_named_item(self, name, matcher, node): raise xml.dom.NoModificationAllowedErr() def _delFromParentList(self, entities, i): raise xml.dom.NoModificationAllowedErr() def _addToParentList(self, entities, node): raise xml.dom.NoModificationAllowedErr() def _key_helper(self, itemSource): "Given an item source, return an appropriate key for our mapping" if itemSource.prefix: return "%s:%s" % (itemSource.prefix, itemSource.localName) else: return itemSource.localName # no longer needed del ComputedAttribute ParsedXML/DOM/__init__.py0100644000175200017500000001007307222727455015073 0ustar faasseninfrae############################################################################## # # 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. # ############################################################################## """Digital Creation's light-weight, acquisition-based DOM implementation.""" __version__ = '$Revision: 1.4 $' # Work around the possible lack of a decent XML package; the # Exceptions module will masquerade as xml.dom if it needs to. # See the comments in Exceptions for a full explanation. # import Exceptions from Core import theDOMImplementation ParsedXML/dtml/0040755000175200017500000000000007600634637013304 5ustar faasseninfraeParsedXML/dtml/DOMTree.dtml0100644000175200017500000000570507236340463015425 0ustar faasseninfrae

You can view the DOM tree which represents your XML document by using the controls below. Clicking on a node will allow you to edit the contents of the node.

Expand entire tree | Collapse tree | no for... in attributes until issue (15) resolved Show/Hide Attributes | Show/Hide Attributes | Show/Hide text node values Show/Hide text node values


=""
O
 = ""
ParsedXML/dtml/documentAdd.dtml0100644000175200017500000000424307255460567016422 0ustar faasseninfrae

A Parsed XML document can contain any well-formed XML text. You can use a Parsed XML document to hold and manipulate structured data in XML format.

You may create a new Parsed XML document using the form below. You may also choose to upload an existing html file from your local computer by clicking the Browse button.

Id
Title
File
Content-type
Parsing with namespaces
yes no
ParsedXML/dtml/persEdit.dtml0100644000175200017500000000747707471744760015766 0ustar faasseninfrae This form is for a persistent proxy node. It would be cleaner to just include a section specific to the persistent/transient node, but DTML can be tricky.

You may edit the source for this document using the form below. You may also upload the source for this document from a local file. Click the browse button to select a local file to upload.

this is the document not at the document, some things not editable
Title
Content-type
Parsing with namespaces
yes checked> no checked>
Title
Content-type
Parsing with namespaces:
no yes
     
File  
ParsedXML/dtml/transEdit.dtml0100644000175200017500000000666607471744760016143 0ustar faasseninfrae This form is for a transient proxy node, so some actions aren't present. It would be cleaner to just include a section specific to the persistent/transient node, but DTML can be tricky.

You may edit the source for this document using the form below. You may also upload the source for this document from a local file. Click the browse button to select a local file to upload.

this is the document

This is a transient proxy of the DOM Document node; unlike subnodes, the transient Document can't be edited. The persistent Document proxy can be edited. The persistent Document can be traversed to at /manage_editForm .

Title
Content-type
Parsing with namespaces:
no yes
     
File  
ParsedXML/CHANGES.txt0100644000175200017500000001020507600633530014137 0ustar faasseninfraeParsedXML changes ParsedXML 1.3.1 Bugs Fixed - Bugfix/performance improvement. Do not rely on getPersistentDocument() but instead use acquisition parent. This fixes a memory leak triggered when doing 'document.documentElement', and also likely improves performance when accessing the DOM through the ManageableDOM wrappers. - The Zope Find tab should now not give an error anymore when searching with ids. - Use the One True Way to import expat now ('from xml.parsers import expat'). ParsedXML 1.3.0 Features - All element nodes now have a _element_id id. This id is guaranteed to be unique in the document, though which id an element has may change in a reparse. - NodePath system for creating various paths to nodes. This can be based on 'child' (child node index), 'element_id', or 'robust', which is not very robust as yet in some ways, but should be resistent to quite a few changes to the document. - added pretty printing feature. A pretty print button renders the document in pretty printed form, but does not save this changed version (you can do so yourself). Bugs Fixed - Removed ParsedXML's Expat, introduced dependency on PyXML's pyexpat instead (or just compile your own). This gets rid of lots of install hassles, especially on Windows. Just install PyXML. - An ongoing attempt to bring sanity to the unit test story. - Avoid XML-garbling bug in Printer by using PrettyPrinter. - various bugfixes in the DOM. ParsedXML 1.2.1 Features - pyexpat.c is now in sync with Python's and PyXML's version. ParsedXML 1.2.0 Bugs Fixed - Tests are now more conformant with Zope unit testing guidelines. - Should work with Python 2.1/Zope 2.4, but not all the way there yet (parser segfault..) - new version of PyExpat Features - Access to DOM from Zope environment sped up by new DOMProxy implementation ParsedXML 1.1b1 Bugs Fixed - Fixed an ExpatBuilder bug that caused a DOM reference to be leaked when parsing occured at the document. There is still a leak for fragment parsing that we're looking into. Features - ZCatalog support added - ZCache support added ParsedXML 1.1a1 Bugs Fixed - Version numbers make more sense :) Features - The value returned by get_size() is cached, which will often speed up the management view of an instance's container. ParsedXML 1.0 Bugs Fixed - Problems with Attr Node manipulation not being reflected by the getAttribute methods of their Elements and vice versa fixed. - Erroneous position information for parse error output on subnodes fixed. - Default attributes are noticed by the parser and printer, and the relevent DOM methods work. Features - ManageableDOM Nodes can find the persistent Document wrapper when it has been installed in a Zope ObjectManager. This object, rather than a newly created ManageableDocument wrapper, is returned when available by OwnerDocument calls. This allows Zopish navigation and discovery out of the Document, helps shorten acquisition paths, and fixes some bugs with manipulation at the Document. - ManageableDOM's usage of namespaces for parsing is now optional and settable. - The DOM 2 Traversal interface has been fleshed out, although support for visiblity and roots is not complete. ParsedXML 0.1b3 Bugs Fixed - Yet a few more DOM bugs fixed. - Fixed a distribution error that was causing build problems under Solaris. ParsedXML 0.1b2 Bugs Fixed - Many bugs found and fixed as we hammered out new DOM tests, especially in namespace usage, attribute printing, and attribute children. Features - Several speedups throughout the code. - ManageableDOM refactored into several base classes to make extension easier. ParsedXML/CREDITS.txt0100644000175200017500000000120407510343110014153 0ustar faasseninfraeCurrent Maintainer: Martijn Faassen The Zope Corporation Parsed XML team: Karl Anderson Fred Drake Todd Corum Martijn Pieters External Contributor: Martijn Faassen Much test and implementation help was provided by Chris McDonough Shane Hathaway Guido van Rossum Parsed XML also contains code from versions of the original XMLDocument, written by Amos Latteier and Fourthought Inc. ParsedXML contains software derived from works by Fourthought Inc; see LICENSE.Fourthought for their license. ParsedXML/DOMProxy.py0100644000175200017500000004574507443150451014403 0ustar faasseninfraeimport DOM import xml.dom from ComputedAttribute import ComputedAttribute import string _DOM_PROXY_FEATURES = () class DOMImplementationProxy: def __init__(self): self._domimplementation = DOM.theDOMImplementation def hasFeature(self, feature, version): feature = string.lower(feature) if (feature, version) in _DOM_PROXY_FEATURES: return 1 return self._domimplementation.hasFeature(feature, version) def _createDOMDocumentType(self, qualifiedName, publicId, systemId): return self._domimplementation.createDocumentType( qualifiedName, publicId, systemId) def _createDOMDocument(self, namespaceURI, qualifiedName, docType=None): return self._domimplementation.createDocument( namespaceURI, qualifiedName, docType) class DOMProxy: def __init__(self, node, persistentDoc=None): self._node = node self._persistentDoc = persistentDoc def getDOMObj(self): """Return the node without wrappers. """ return self._node def getPersistentDoc(self): """Return a reference to a security friendly persistent document if we can, or None. This can be None when OwnerDocument, if it exsists, is not None. If you don't need to reach the document through the security checks, you don't need to use this method. """ # We do this because the userfolder container needs to be in the aq # context of the unwrapped returned object. if self._persistentDoc and getattr( self._persistentDoc, "_container", None): try: # If we can get to self, we can get to the persistent doc - # but restrictedTraverse is necessary for some reason for # what we return to be used in an acquisition chain return self._persistentDoc._container.restrictedTraverse( self._persistentDoc.getPhysicalPath()) except: pass return None def __setattr__(self, name, value): """Proxy DOM attribute writes, else write to our attribute. """ if name in self._DOMAttrs: setattr(self._node, name, value) else: self.__dict__[name] = value # flag that we're dirty if we're persistent # FIXME: perhaps there's a better way to make those # test cases work? if hasattr(self, '_p_changed'): self._p_changed = 1 def __nonzero__(self): "is this node true?" # FIXME: not sure this makes sense try: return self._node.__nonzero__() except: if self._node: return 1 else: return 0 # no need to avoid aq bugs fixed in Zope 2.3.1 so no __len__ class NodeProxy(DOMProxy): _DOMAttrs = ("nodeName", "attributes", "childNodes", "firstChild", "lastChild", "localName", "namespaceURI", "nextSibling", "previousSibling", "nodeType", "nodeValue", "ownerDocument", "parentNode", "prefix") 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 def _get_nodeName(self): return self._node._get_nodeName() nodeName = ComputedAttribute(_get_nodeName) def _get_attributes(self): return self.wrapNamedNodeMap(self._node._get_attributes()) attributes = ComputedAttribute(_get_attributes) def _get_childNodes(self): return self.wrapNodeList(self._node._get_childNodes()) childNodes = ComputedAttribute(_get_childNodes) def _get_firstChild(self): return self.wrapDOMObj(self._node._get_firstChild()) firstChild = ComputedAttribute(_get_firstChild) def _get_lastChild(self): return self.wrapDOMObj(self._node._get_lastChild()) lastChild = ComputedAttribute(_get_lastChild) def _get_localName(self): return self._node._get_localName() localName = ComputedAttribute(_get_localName) def _get_namespaceURI(self): return self._node._get_namespaceURI() namespaceURI = ComputedAttribute(_get_namespaceURI) def _get_nextSibling(self): return self.wrapDOMObj(self._node._get_nextSibling()) nextSibling = ComputedAttribute(_get_nextSibling) def _get_previousSibling(self): return self.wrapDOMObj(self._node._get_previousSibling()) previousSibling = ComputedAttribute(_get_previousSibling) def _get_nodeType(self): return self._node._get_nodeType() nodeType = ComputedAttribute(_get_nodeType) def _get_nodeValue(self): return self._node._get_nodeValue() nodeValue = ComputedAttribute(_get_nodeValue) def _get_parentNode(self): return self.wrapDOMObj(self._node._get_parentNode()) parentNode = ComputedAttribute(_get_parentNode) def _get_prefix(self): return self._node._get_prefix() prefix = ComputedAttribute(_get_prefix) def hasAttributes(self): return self._node.hasAttributes() def hasChildNodes(self): return self._node.hasChildNodes() def appendChild(self, newChild): self._node.appendChild(newChild._node) return newChild def insertBefore(self, newChild, refChild): self._node.insertBefore(newChild._node, getattr(refChild, "_node", None)) return newChild def removeChild(self, oldChild): self._node.removeChild(oldChild._node) return oldChild def replaceChild(self, newChild, oldChild): self._node.replaceChild(newChild._node, oldChild._node) return oldChild def normalize(self): self._node.normalize() def isSupported(self, feature, version): return self._node.isSupported(feature, version) def isSameNode(self, other): return self._node.isSameNode(other._node) def cloneNode(self, deep): return self.wrapDOMObj(self._node.cloneNode(deep)) def __cmp__(self, other): try: return cmp(self._node, other._node) except AttributeError: return 1 def _get_ownerDocument(self): """ Return the DOM document - the persistent document that was instantiated if we can, otherwise another generated proxy node. """ return (self.getPersistentDoc() or self.wrapDOMObj(self._node._get_ownerDocument())) ownerDocument = ComputedAttribute(_get_ownerDocument) def __hash__(self): return self._node.__hash__() class NodeListProxy(DOMProxy): _DOMAttrs = ("length",) def __len__(self): return self._node.__len__() def _get_length(self): return self._node._get_length() length = ComputedAttribute(_get_length) def __nonzero__(self): return self._node.__nonzero__() def __setitem__(self, i, newChild): self._node.__setitem__(i, newChild._node) def __delitem__(self, i): self._node.__delitem__(i) def __getitem__(self, i): return self.wrapDOMObj(self._node.__getitem__(i)) def __getslice__(self, i, j): return self.wrapNodeList(self._node.__getslice__(i, j)) def item(self, i): return self.wrapDOMObj(self._node.item(i)) def count(self, value): return self._node.count(value._node) def index(self, value): return self._node.index(value._node) class NamedNodeMapProxy(DOMProxy): _DOMAttrs = ("length", "keys") def getDOMObj(self): """Return the Node without any of our wrappers """ return self._node def __len__(self): return self._node.__len__() def _get_length(self): return self._node._get_length() length = ComputedAttribute(_get_length) def setNamedItem(self, arg): return self.wrapDOMObj(self._node.setNamedItem(arg._node)) def setNamedItemNS(self, arg): return self.wrapDOMObj(self._node.setNamedItemNS(arg._node)) def removeNamedItem(self, name): return self.wrapDOMObj(self._node.removeNamedItem(name)) def removeNamedItemNS(self, namespaceURI, localName): return self.wrapDOMObj(self._node.removeNamedItemNS(namespaceURI, localName)) def get(self, name, default=None): node = self._node.getNamedItem(name) if node is None: return default else: return self.wrapDOMObj(node) def has_key(self, name): return self._node.has_key(name) def item(self, i): return self.wrapDOMObj(self._node.item(i)) def getNamedItem(self, name): return self.wrapDOMObj(self._node.getNamedItem(name)) def getNamedItemNS(self, namespaceURI, localName): return self.wrapDOMObj(self._node.getNamedItemNS(namespaceURI, localName)) def __setitem__(self, name, node): self._node.__setitem__(name, node._node) def __getitem__(self, name): return self.wrapDOMObj(self._node.__getitem__(name)) def __delitem__(self, name): self._node.__delitem__(name) def keys(self): return self._node.keys() def values(self): return map(self.wrapDOMObj, self._node.values()) def items(self): result = [] for key, value in self.getDOMObj().items(): result.append((key, self.wrapDOMObj(value))) return result class DocumentFragmentProxy(NodeProxy): pass class ElementProxy(NodeProxy): _DOMAttrs = NodeProxy._DOMAttrs + ("tagName", 'element_id') def _get_tagName(self): return self._node._get_tagName() tagName = ComputedAttribute(_get_tagName) def _get_elementId(self): return self._node._get_elementId() elementId = ComputedAttribute(_get_elementId) def getAttribute(self, name): return self._node.getAttribute(name) def getAttributeNS(self, namespaceURI, localName): return self._node.getAttributeNS(namespaceURI, localName) def getAttributeNode(self, name): return self.wrapDOMObj(self._node.getAttributeNode(name)) def getAttributeNodeNS(self, namespaceURI, localName): return self.wrapDOMObj(self._node.getAttributeNodeNS(namespaceURI, localName)) def getElementsByTagName(self, name): return self.wrapNodeList(self._node.getElementsByTagName(name)) def getElementsByTagNameNS(self, namespaceURI, localName): return self.wrapNodeList(self._node.getElementsByTagNameNS(namespaceURI, localName)) def hasAttribute(self, name): return self._node.hasAttribute(name) def hasAttributeNS(self, namespaceURI, localName): return self._node.hasAttributeNS(namespaceURI, localName) def removeAttribute(self, name): self._node.removeAttribute(name) def removeAttributeNS(self, namespaceURI, localName): self._node.removeAttributeNS(namespaceURI, localName) def removeAttributeNode(self, oldAttr): return self.wrapDOMObj(self._node.removeAttributeNode(oldAttr._node)) def setAttribute(self, name, value): self._node.setAttribute(name, value) def setAttributeNS(self, namespaceURI, qualifiedName, value): self._node.setAttributeNS(namespaceURI, qualifiedName, value) def setAttributeNode(self, newAttr): return self.wrapDOMObj(self._node.setAttributeNode(newAttr._node)) def setAttributeNodeNS(self, newAttr): return self.wrapDOMObj(self._node.setAttributeNodeNS(newAttr._node)) class CharacterDataProxy(NodeProxy): _DOMAttrs = NodeProxy._DOMAttrs + ("data", "length") def __len__(self): return self._node.__len__() def _get_data(self): return self._node._get_data() data = ComputedAttribute(_get_data) def _set_data(self, value): self._node._set_data(value) def _get_length(self): return self._node._get_length() length = ComputedAttribute(_get_length) def appendData(self, arg): self._node.appendData(arg) def deleteData(self, offset, count): self._node.deleteData(offset, count) def insertData(self, offset, arg): self._node.insertData(offset, arg) def replaceData(self, offset, count, arg): self._node.replaceData(offset, count, arg) def substringData(self, offset, count): return self._node.substringData(offset, count) class TextProxy(CharacterDataProxy): def splitText(self, offset): return self.wrapDOMObj(self._node.splitText(offset)) class CDATASectionProxy(TextProxy): pass class CommentProxy(CharacterDataProxy): pass class ProcessingInstructionProxy(NodeProxy): _DOMAttrs = NodeProxy._DOMAttrs + ("target", "data") def _get_target(self): return self._node._get_target() target = ComputedAttribute(_get_target) def _get_data(self): return self._node._get_data() data = ComputedAttribute(_get_data) def _set_data(self, value): self._node._set_data(value) class AttrProxy(NodeProxy): _DOMAttrs = NodeProxy._DOMAttrs + ("name", "value", "specified", "ownerElement") def _get_name(self): return self._node._get_name() name = ComputedAttribute(_get_name) def _get_value(self): return self._node._get_value() # setting should also be okay value = ComputedAttribute(_get_value) def _set_value(self, value): self._node._set_value(value) def _get_specified(self): return self._node._get_specified() specified = ComputedAttribute(_get_specified) def _get_ownerElement(self): return self.wrapDOMObj(self._node._get_ownerElement()) ownerElement = ComputedAttribute(_get_ownerElement) class DocumentProxy(NodeProxy): _DOMAttrs = NodeProxy._DOMAttrs + ("doctype", "documentElement") def _get_doctype(self): return self.wrapDOMObj(self._node._get_doctype()) doctype = ComputedAttribute(_get_doctype) def _get_documentElement(self): return self.wrapDOMObj(self._node._get_documentElement()) documentElement = ComputedAttribute(_get_documentElement) # _get_implementation defined in subclass def createAttribute(self, name): return self.wrapDOMObj(self._node.createAttribute(name)) def createAttributeNS(self, namespaceURI, qualifiedName): return self.wrapDOMObj(self._node.createAttributeNS(namespaceURI, qualifiedName)) def createCDATASection(self, data): return self.wrapDOMObj(self._node.createCDATASection(data)) def createComment(self, data): return self.wrapDOMObj(self._node.createComment(data)) def createDocumentFragment(self): return self.wrapDOMObj(self._node.createDocumentFragment()) def createElement(self, tagName): return self.wrapDOMObj(self._node.createElement(tagName)) def createElementNS(self, namespaceURI, qualifiedName): return self.wrapDOMObj(self._node.createElementNS(namespaceURI, qualifiedName)) def createEntityReference(self, name): return self.wrapDOMObj(self._node.createEntityReference(name)) def createProcessingInstruction(self, target, data): return self.wrapDOMObj(self._node.createProcessingInstruction(target, data)) def createTextNode(self, data): return self.wrapDOMObj(self._node.createTextNode(data)) def getElementById(self, elementId): return self.wrapDOMObj(self._node.getElementById(elementId)) def getElementsByTagName(self, tagName): return self.wrapNodeList(self._node.getElementsByTagName(tagName)) def getElementsByTagNameNS(self, namespaceURI, localName): return self.wrapNodeList(self._node.getElementsByTagNameNS(namespaceURI, localName)) def importNode(self, importedNode, deep): return self.wrapDOMObj(self._node.importNode(importedNode._node, deep)) def createNodeIterator(self, root, whatToShow, filter, entityReferenceExpansion): # FIXME: needs wrapper! return self._node.createNodeIterator(root, whatToShow, filter, entityReferenceExpansion) def createTreeWalker(self, root, whatToShow, filter, entityReferenceExpansion): # FIXME: needs wrapper! return self._node.createTreeWalker(root, whatToShow, filter, entityReferenceExpansion) class EntityProxy(NodeProxy): _DOMAttrs = NodeProxy._DOMAttrs + ("publicId", "systemId", "notationName") def _get_publicId(self): return self._node._get_publicId() publicId = ComputedAttribute(_get_publicId) def _get_systemId(self): return self._node._get_systemId() systemId = ComputedAttribute(_get_systemId) def _get_notationName(self): return self._node._get_notationName() notationName = ComputedAttribute(_get_notationName) class EntityReferenceProxy(NodeProxy): pass class NotationProxy(NodeProxy): _DOMAttrs = NodeProxy._DOMAttrs + ("publicId", "systemId") def _get_publicId(self): return self._node._get_publicId() publicId = ComputedAttribute(_get_publicId) def _get_systemId(self): return self._node._get_systemId() systemId = ComputedAttribute(_get_systemId) class DocumentTypeProxy(NodeProxy): _DOMAttrs = NodeProxy._DOMAttrs + ("publicId", "systemId", "name", "entities", "notations", "internalSubset") def _get_entities(self): return self.wrapNamedNodeMap(self._node._get_entities()) entities = ComputedAttribute(_get_entities) def _get_internalSubset(self): return self._node._get_internalSubset() internalSubset = ComputedAttribute(_get_internalSubset) def _get_name(self): return self._node._get_name() name = ComputedAttribute(_get_name) def _get_notations(self): return self.wrapNamedNodeMap(self._node._get_notations()) notations = ComputedAttribute(_get_notations) def _get_publicId(self): return self._node._get_publicId() publicId = ComputedAttribute(_get_publicId) def _get_systemId(self): return self._node._get_systemId() systemId = ComputedAttribute(_get_systemId) ParsedXML/Example.zexp0100644000175200017500000002714607255732671014661 0ustar faasseninfraeZEXP ((U OFS.FolderqUFolderqtqNt.}q(UidqUExampleqUtreeq(Uq(hUFolderq ttQU_objectsq (}q (U meta_typeq UFolderq UidqUslidequ}q(h h hUtreequtU__ac_local_roles__q}qUkarlq]qUOwnerqasUtitleqUh(U q(hUFolderqttQU_ownerq(]qU acl_usersqahtu.Q((U OFS.FolderqUFolderqtqNt.}q(UtitleqUUidqUtreeqUtreeq(Uq (UOFS.DTMLDocumentq U DTMLDocumentq ttQU_objectsq (}q (U meta_typeqU DTML DocumentqUidqUtreequ}q(hU Parsed XMLqhUTreequtqUTreeq(Uq(UProducts.ParsedXML.ParsedXMLqU ParsedXMLqttQU__ac_local_roles__q}qUkarlq]qUOwnerqasu. 6((U OFS.FolderqUFolderqtqNt.}q(U nextSlideq(Uq(U#Products.PythonScripts.PythonScriptqU PythonScriptqttQUidq Uslideq U__ac_local_roles__q }q Ukarlq ]qUOwnerqasU_objectsq(}q(U meta_typeqU DTML Documentqh Uslidequ}q(U meta_typeqU Parsed XMLqUidqUSlidesqu}q(U meta_typeqU DTML MethodqUidqU viewSlidequ}q(U meta_typeq UScript (Python)q!Uidq"hu}q#(h h!h"U previousSlideq$u}q%(h h!h"UdomURLq&u}q'(h h!h"UgetColorq(utq)h(Uq*(UOFS.DTMLDocumentq+U DTMLDocumentq,ttQU_ownerq-(]q.U acl_usersq/aUkarlq0tq1USlidesq2(Uq3(UProducts.ParsedXML.ParsedXMLq4U ParsedXMLq5ttQU viewSlideq6(Uq7(UOFS.DTMLMethodq8U DTMLMethodq9ttQh((Uq:(hU PythonScriptq;ttQUtitleqttQUdomURLq?(Uq@(hU PythonScriptqAttQu.((UOFS.DTMLDocumentqU DTMLDocumentqtqNt.}q(UtitleqU tree tag demoqUrawqT)

The dtml-tree tag will show the ParsedXML DOM tree. We use it in the DOM tree view, too.

qU__ac_local_roles__q }q Ukarlq ]q UOwnerq asUglobalsq}qU__name__qUtreeqU_varsq}qu.:((UProducts.ParsedXML.ParsedXMLqU ParsedXMLqtqNt.}q(UidqUTreeqU_persistentDocq(Uq(hU ParsedXMLq ttQU _containerq NU__ac_local_roles__q }q Ukarlq ]qUOwnerqasUtitleqUU contentTypeqUtext/xmlqU noNamespacesqKU_nodeqcProducts.ParsedXML.DOM.Core Document qNRq}q(U _childrenq]qcProducts.ParsedXML.DOM.Core Element qNRq}q(h]q(cProducts.ParsedXML.DOM.Core Text qNRq}q (U nodeValueq!U q"Udataq#h"ubhNRq$}q%(U localNameq&Nh]q'(hNRq(}q)(h!U q*h#h*ubhNRq+}q,(h&Nh]q-(hNRq.}q/(h!U q0h#h0ubhNRq1}q2(UtagNameq3Uhairq4UnodeNameq5h4h&NUprefixq6NU namespaceURIq7NubhNRq8}q9(h!U q:h#h:ubeh3Uheadq;h5h;h6Nh7NubhNRq<}q=(h!U q>h#h>ubhNRq?}q@(h3UbodyqAh5hAh&Nh6Nh7NubhNRqB}qC(h!U qDh#hDubhNRqE}qF(h&Nh]qG(hNRqH}qI(h!U qJh#hJubhNRqK}qL(h3UtoesqMh5hMh&Nh6Nh7NubhNRqN}qO(h!U qPh#hPubeh3UfeetqQh5hQh6Nh7NubhNRqR}qS(h!U h#U ubeh3UthingqTh5hTh6Nh7NubhNRqU}qV(h!U qWh#hWubhNRqX}qY(h&Nh]qZ(hNRq[}q\(h!U q]h#h]ubhNRq^}q_(h3Ufirstq`h5h`h&Nh6Nh7NubhNRqa}qb(h!U qch#hcubhNRqd}qe(h&Nh]qf(hNRqg}qh(h!U qih#hiubhNRqj}qk(h3Uthirdqlh5hlh&Nh6Nh7NubhNRqm}qn(h!U qoh#houbeh3Usecondqph5hph6Nh7NubhNRqq}qr(h!U h#U ubeh3hTh5hTh6Nh7NubhNRqs}qt(h!U quh#huubeh3Uthingsqvh5hvubaUvalueqwNU _elem_infoqx}qyUversionqzU1.0q{U _attr_infoq|}q}ubu.5((U#Products.PythonScripts.PythonScriptqU PythonScriptqtqNt.}q(U func_codeq(cShared.DC.Scripts.Signature FuncCode qoq}q(U co_varnamesq (Unodeq U $loop_watcherq U $read_guardq U $write_guardq U$guardqtU co_argcountqKubUidqU nextSlideqU__ac_local_roles__q}qUkarlq]qUOwnerqasU_tq(hN(KKKKUt}|t}t}t} |ti} xL |oA ||idjo  |Sn ||i}|q:WtSdSq(NUslideqtq(UcontextqU nextSiblingqUnodeqUnodeNameqUNoneqU $loop_watcherq U $read_guardq!U $write_guardq"U$guardq#tq$(hh h!h"h#tq%UScript (Python)q&hKU   q')tN}q(tq)U_bodyq*T# return the next sibling with a nodeName of 'slide', or None. # We need to do this because the parser doesn't treat whitespace text # nodes specially; they're parsed into DOM text nodes just like # everything else. # Acquire this from the slide node that wants to find the next slide. node = context.nextSibling while node: if node.nodeName == 'slide': return node node = node.nextSibling return Noneq+U _bind_namesq,(cShared.DC.Scripts.Bindings NameAssignments q-oq.}q/U_asgnsq0}q1(Uname_containerq2U containerq3U name_subpathq4Utraverse_subpathq5U name_contextq6Ucontextq7U name_m_selfq8Uscriptq9usbU Python_magicq:UN q;U func_defaultsq

  1. /viewSlide">
qU__ac_local_roles__q }q Ukarlq ]q UOwnerq asUglobalsq}qU__name__qUslideqU_varsq}qu.((UProducts.ParsedXML.ParsedXMLqU ParsedXMLqtqNt.}q(UidqUSlidesqU_persistentDocq(Uq(hU ParsedXMLq ttQU _containerq NU__ac_local_roles__q }q Ukarlq ]qUOwnerqasUtitleqUU contentTypeqUtext/xmlqU noNamespacesqKU_nodeqcProducts.ParsedXML.DOM.Core Document qNRq}q(U _childrenq]qcProducts.ParsedXML.DOM.Core Element qNRq}q(U _attributesq]q]q(NUcolorq NNUgrayq!KeaUtagNameq"Uslidesq#UnodeNameq$h#h]q%(cProducts.ParsedXML.DOM.Core Text q&NRq'}q((U nodeValueq)U q*Udataq+h*ubhNRq,}q-(h]q.]q/(NUtitleq0NNU first slideq1KeaU localNameq2Nh]q3(h&NRq4}q5(h)U q6h+h6ubhNRq7}q8(h2Nh]q9h&NRq:}q;(h)U This is the first slide Here are some points, that I want to make: * one thing * another thing qNU namespaceURIq?Nubh&NRq@}qA(h)U qBh+hBubeh"UslideqCh$hCh>Nh?Nubh&NRqD}qE(h)U qFh+hFubhNRqG}qH(h]qI]qJ(Nh0NNU second slideqKKeah2Nh]qL(h&NRqM}qN(h)U qOh+hOubhNRqP}qQ(h2Nh]qRh&NRqS}qT(h)U This is the second slide Here are some points, that I want to make: 1. one thing 2. another thing 3. final point qUh+hUubah"h=h$h=h>Nh?Nubh&NRqV}qW(h)U qXh+hXubeh"hCh$hCh>Nh?Nubh&NRqY}qZ(h)U q[h+h[ubhNRq\}q](h]q^(]q_(Nh0NNU the red slideq`Ke]qa(Nh NNUredqbKeeh2Nh]qc(h&NRqd}qe(h)U qfh+hfubhNRqg}qh(h2Nh]qih&NRqj}qk(h)U This slide is red because it has a color attribute. All the others are gray because they didn't have a color attribute, but their parent did. qlh+hlubah"h=h$h=h>Nh?Nubh&NRqm}qn(h)U qoh+houbeh"hCh$hCh>Nh?Nubh&NRqp}qq(h)U qrh+hrubeubaUvalueqsNU _elem_infoqt}quUversionqvU1.0qwU _attr_infoqx}qyubu.((UOFS.DTMLMethodqU DTMLMethodqtqNt.}q(UtitleqUUrawqT

next: /viewSlide"> previous: /viewSlide">
qU__ac_local_roles__q}q Ukarlq ]q UOwnerq asUglobalsq }qU__name__qU viewSlideqU_varsq}qu.{((U#Products.PythonScripts.PythonScriptqU PythonScriptqtqNt.}q(U func_codeq(cShared.DC.Scripts.Signature FuncCode qoq}q(U co_varnamesq (Unodeq U $loop_watcherq U $read_guardq U $write_guardq U$guardqtU co_argcountqKubUidqUgetColorqU__ac_local_roles__q}qUkarlq]qUOwnerqasU_tq(hN(KKKKUt}|t}t}t }t}x[|oP||ido||idSn||i}|q1W tSdSq(NUcolorqtq(UcontextqUnodeqU hasAttributeqU getAttributeqU parentNodeqUNoneq U $loop_watcherq!U $read_guardq"U $write_guardq#U$guardq$tq%(hh!h"h#h$tq&UScript (Python)q'hKU  q()tN}q)tq*U_bodyq+U# return a color attribute value from context or ancestors, or None. node = context while node: if node.hasAttribute('color'): return node.getAttribute('color') node = node.parentNode return Noneq,U _bind_namesq-(cShared.DC.Scripts.Bindings NameAssignments q.oq/}q0U_asgnsq1}q2(Uname_containerq3U containerq4U name_subpathq5Utraverse_subpathq6U name_contextq7Ucontextq8U name_m_selfq9Uscriptq:usbU Python_magicq;UN qNu.ParsedXML/ExtraDOM.py0100644000175200017500000001274207471755671014354 0ustar faasseninfrae############################################################################## # # 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. # ############################################################################## """ Non-DOM helper functions useful when working with either of our DOM implementations, but not specific to any instantiation. """ from xml.dom import Node import DOM.ExpatBuilder import PrettyPrinter from StrIO import StringIO def parseFile(node, file, namespaces = 1): """ Parse XML file, replace node with the resulting tree, return replacement. Node must be in an existing DOM tree if not a Document. """ if node.nodeType == Node.DOCUMENT_NODE: return DOM.ExpatBuilder.parse(file, namespaces) elif node.nodeType == Node.DOCUMENT_FRAGMENT_NODE: raise Exception, "replacing a document fragment doesn't make sense" else: fragment = DOM.ExpatBuilder.parseFragment( file, node.parentNode, namespaces) #if fragment.childNodes.length != 1: # # we could do this, actually, if we wanted # raise Exception, "replacing a Node with less or more " + \ # "than one tree of Nodes is not implemented" sib = node.nextSibling parent = node.parentNode parent.removeChild(node) #print fragment.childNodes.length #for child in fragment.childNodes: # print child.nodeType, node.nodeName # if child.nodeType == Node.TEXT_NODE: # print repr(child.data) return parent.insertBefore(fragment.firstChild, sib) # frag.firstChild def writeStream(node, stream = None, encoding = None, html = 0, contentType = None, prettyPrint = 0): "Write the XML representation of node to stream." if stream is None: stream = StringIO() PrettyPrinter.PrintVisitor(node, stream, encoding, html, contentType, prettyPrint=prettyPrint)() return stream ParsedXML/INSTALL.txt0100644000175200017500000000101107471031224014166 0ustar faasseninfraeRequirements This release requires Zope 2.4.x and later. You also need PyXML 0.7.x or later installed, or at least a recent version of pyexpat. Installation Unpack the ParsedXML tarball in the Products directory of your Zope installation (usually this is lib/python/Products). Rename the unpacked directory to "ParsedXML" so that Python can import it. Restart Zope. There should be a ParsedXML product in your Products folder, and a ParsedXML option for available objects to add in the root folder. ParsedXML/LICENSE.Fourthought0100644000175200017500000000174307227224142015657 0ustar faasseninfraeCopyright (c) 2000 Fourthought Inc, USA All Rights Reserved Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of FourThought LLC not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. FOURTHOUGHT LLC DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL FOURTHOUGHT BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ParsedXML/LICENSE.txt0100644000175200017500000000733207243034551014161 0ustar faasseninfrae############################################################################## # # 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. # ############################################################################## ParsedXML/ManageableDOM.py0100755000175200017500000007330707600633530015273 0ustar faasseninfrae ############################################################################# # # 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. # ############################################################################## """ Zope management support for DOM classes. """ import Globals import Acquisition from Acquisition import aq_parent import App.Management from OFS.Traversable import Traversable from DateTime import DateTime # for manage_edit cookie expire import marshal # for ftp import DOMProxy import DOM import ExtraDOM import string from xml.parsers import expat import xml.dom import types from StrIO import StringIO from NodePath import registry parserr=('Sorry, an XML parsing error occurred. Check ' 'your XML document for well-formedness and try ' 'to upload it again after modification.

') # # Management mixin classes # class DOMTraversable(Traversable): "Mixin class for DOM classes to provide Zope traversability." getPhysicalPath__roles__ = None # Public def getPhysicalPath(self): """Returns a path that can be used to access this object again later.""" # first get path to persistent document doc = self._persistentDoc._earlyAqChain() path = doc.getPhysicalPath() # then get path to node and attach it to that path steps nodepath = registry.create_path(doc, self, 'child') if nodepath: return path + (nodepath,) else: return path def getNodePath(self, scheme_name): """Create a node path for this node. FIXME: this has the same name but other signature as the one in ParsedXML for document. """ return registry.create_path(self._persistentDoc._earlyAqChain(), self, scheme_name) # sequence interface, for backwards compatibility. # normally the document's __getitem__ takes care of this def __getitem__(self, key): return self.childNodes[int(key)].__of__(self) # other helpers def _earlyAqChain(self): """Return the earliest ref to self in self's aq_chain. Helper function for getPhysicalPath.""" chain = self.aq_chain chain.reverse() for parent in chain: if parent == self: return parent return self class DOMPublishable(DOMTraversable): "Mixin class for DOM classes to provide Zope publishability." # tree tag methods def tpURL(self): """ Return a string used for an URL relative to parent. Used by the dtml-tree tag. """ i = 0 node = self.getDOMObj().previousSibling while node: i = i + 1 node = node.previousSibling return str(i) def tpValues(self): "Return a list of immediate subobjects. Used by the dtml-tree tag." retList = [] # dtml-tree wants to own this for i in self.childNodes: retList.append(i) return retList def tpId(self): "Return a value to be used as an id in tree state." return self.tpURL() # partial ObjectManagerItem interface def getId(self): "Return the id of the object as a string." if hasattr(self.aq_base): base = self.aq_base else: base = self name=getattr(base, 'id', None) if name is not None: return name return self.tpURL() # I don't want to add PrincipiaSearchSource, because it'd be expensive # to trigger printing every node in a document. Look into this when # we have a better caching plan. # Partial ObjectManager interface. Nodes are *not* ObjectManagers, # these are for other Zope tools to be useful. def objectValues(self, spec=None): """ Returns a list of actual subobjects of the current object. If 'spec' is specified, returns only objects whose meta_type match 'spec'. """ if spec is not None: if isinstance(spec, type('s')): spec=[spec] set=[] for ob in self.childNodes: if ob['meta_type'] in spec: set.append(ob) return set return list(self.childNodes) def objectIds(self, spec=None): """ Returns a list of subobject ids of the current object. If 'spec' is specified, returns objects whose meta_type matches 'spec'. """ return map(lambda i: i.getId(), self.objectValues(spec)) def objectItems(self, spec=None): """ Returns a list of (id, subobject) tuples of the current object. If 'spec' is specified, returns only objects whose meta_type match 'spec' """ r=[] a=r.append for ob in self.objectValues(spec): a((ob.getId(), ob)) return r # FTP interface def manage_FTPget(self): """Returns the source content of an object. For example, the source text of a Document, or the data of a file.""" return self.__str__() #def manage_FTPstat(self,REQUEST): # """Returns a stat-like tuple. (marshalled to a string) Used by # FTP for directory listings, and MDTM and SIZE""" # # mode = 0100000 | 0004 | 0002 XXX open # from AccessControl.User import nobody # mode=0100000 # # # read permissions # if (hasattr(self.aq_base,'manage_FTPget') and # hasattr(self.manage_FTPget, '__roles__')): # try: # if getSecurityManager().validateValue(self.manage_FTPget): # mode=mode | 0440 # except: pass # if nobody.allowed(self.manage_FTPget, # self.manage_FTPget.__roles__): # mode=mode | 0004 # # # write permissions # if hasattr(self.aq_base,'PUT') and hasattr(self.PUT, '__roles__'): # try: # if getSecurityManager().validateValue(self.PUT): # mode=mode | 0220 # except: pass # # if nobody.allowed(self.PUT, self.PUT.__roles__): # mode=mode | 0002 # # size = len(self.manage_FTPget()) # # modification time # mtime = self.bobobase_modification_time().timeTime() # # owner and group # owner = group = 'Zope' # for user, roles in self.get_local_roles(): # if 'Owner' in roles: # owner=user # break # return marshal.dumps((mode,0,0,1,owner,group,size,mtime,mtime,mtime)) # #def manage_FTPlist(self,REQUEST): # """Directory listing for FTP. In the case of non-Foldoid objects, # the listing should contain one object, the object itself.""" # # check to see if we are being acquiring or not # ob=self # while 1: # if App.Common.is_acquired(ob): # raise ValueError('FTP List not supported on acquired objects') # if not hasattr(ob,'aq_parent'): # break # ob=ob.aq_parent # # stat=marshal.loads(self.manage_FTPstat(REQUEST)) # id = self.getId() # return marshal.dumps((id,stat)) class DOMIO: "Mixin class for DOM classes to provide parsing, writing." def writeStream(self, stream = None, encoding = None, html = 0, contentType = None, prettyPrint=0): "Write the XML representation of this object to stream." # work thru DOM object to avoid making proxy nodes return ExtraDOM.writeStream(self.getDOMObj(), stream, encoding, html, contentType, prettyPrint=prettyPrint) def __str__(self): "Return the XML representation of this object." return self.writeStream().getvalue() # This is a workaround for newer browser behavior, and will probably # break older browsers. Recent browsers put '<' in the textarea when the # source is '<", and when the form is sent they send '<', and so on. # This quotes the relevent refs; when the textarea is sent back the # browser unquotes them, so the end result is WYSIWYG. Yuck! # If a browser doesn't do this __str__ should be used. def textareaStr(self, prettyPrint=0): """Return the XML representation of this object in a format safe for a textarea, with certain entity references quoted.""" # FIXME # perhaps we should output text in the encoding the document # was saved in, but this is too complicated for now, so we just # output UTF-8. Unfortunately this is not very pretty in the browser # unless you set it to display in UTF-8. outStr = self.writeStream( encoding=None, prettyPrint=prettyPrint).getvalue().encode('UTF-8') outStr = string.replace(outStr, '&', '&') outStr = string.replace(outStr, '<', '<') outStr = string.replace(outStr, '>', '>') outStr = string.replace(outStr, '<', '<') outStr = string.replace(outStr, '>', '>') return outStr # kinda silly that index_html can be xml, eh? # I need to figure out what the convention is for multimode docs. def index_html(self, REQUEST = None, RESPONSE = None): "Returns publishable source according to content type" if self._persistentDoc: contentType = self._persistentDoc.contentType else: contentType = 'text/xml' if RESPONSE: RESPONSE.setHeader('Content-type', contentType) type = string.split(contentType, '/')[1] # the printer can do html mode xml, but we set according to type isHtml = (type == "html") return self.writeStream(None, None, isHtml, type).getvalue() # Parsing a node removes self & subtree from document; users of other # refs to subnodes have to take care to notice this. def parseXML(self, file): """Parse file as XML, replace myself with the resulting tree, return node replacing self.""" errorStr = ("Parsing at the document node must be done on the " "persistent proxy node, which can't be found for some " "reason.\n" "Traverse to the persistent node and try there.") doc = self._persistentDoc namespaces = not (doc and doc.noNamespaces) # default true node = ExtraDOM.parseFile(self.getDOMObj(), file, namespaces) if self.nodeType == xml.dom.Node.DOCUMENT_NODE: raise RuntimeError, errorStr # This probably isn't worth it. If we had an easy way to get to # a securityfriendly persistent object... (see getPersistentDoc) # This is overridden by ParsedXML.ParsedXML if we're persistent #doc_self = getattr(doc, "aq_self", doc) #self_self = getattr(self, "aq_self", self) #if doc and self_self is doc_self: # # we're a nonpersistent proxy node; the node needs parents # # to attach to if we're not persistent. # # we should probably KISS & bail here... # pdoc = self.getPersistentDoc() # if pdoc: # need to publish from this object, need security # return pdoc.parseXML(file) # raise RuntimeError, errorStr ## ExtraDOM can't insert node wihtout parents; we have to do it. #ManageableDocument.__init__(self, node, self._persistentDoc) ## we may still be a nonpersistent proxy node #self._p_changed = 1 #return self # proxy still part of tree, DOM node isn't else: return doc.wrapDOMObj(node) # proxy and node not part of tree class DOMManageable(DOMIO, DOMPublishable, App.Management.Tabs): "Mixin class for DOM classes to provide Zope management interfaces." manage_editForm = Globals.HTMLFile('dtml/transEdit',globals()) #pretty_html = Globals.HTMLFile('dtml/pretty',globals()) manage_DOMTree = Globals.HTMLFile('dtml/DOMTree',globals()) try: manage_DOMTree._setName('manage_DOMTree') except AttributeError: pass # _setName only exists in Zope 2.4+ manage_main = manage_DOMTree manage_options = ({'label':'DOM', 'action':'manage_DOMTree', 'help': ('ParsedXML', 'ParsedXML_DOM.stx')}, {'label':'Edit', 'action':'manage_editForm', 'help': ('ParsedXML', 'ParsedXML_Edit.stx')}, {'label':'Raw', 'action':'index_html'}) def makeErrorOutput(self, data, offset, lineno): """return a HTML-renderable output of data with a text pointer to the position at offset, lineno""" # make pointer pointerLine = ('' + '-' * (offset - 1) + '^' + '\n\n' + '') # add rest of data # the parser saw a normalized version; normalize data data = string.replace(data, "\r\n", "\n") data = string.replace(data, "\r", "\n") # make reconstruced data rep with break at error dataA = '' dataB = '' # add earlier data for line in range(lineno - 1): dataA = dataA + data[0:string.index(data, '\n') + 1] data = data[string.index(data, '\n') + 1:] dataA = dataA + data[0:offset] + '\n\n' # add later data dataB = dataB + ' ' * (offset) dataB = dataB + data[offset:] + '\n' # strip brackets, format dataA = string.replace(dataA, "<", "<") dataA = string.replace(dataA, ">", ">") dataB = string.replace(dataB, "<", "<") dataB = string.replace(dataB, ">", ">") dataOut = ('


' +
                   dataA + pointerLine + dataB +
                   '


') return dataOut # dict to help notice, handle size change request in manage_editForm _size_changes={ 'Bigger': (5,5), 'Smaller': (-5,-5), 'Narrower': (0,-5), 'Wider': (0,5), 'Taller': (5,0), 'Shorter': (-5,0), } # helper function to set size cookies and return edit form def _er(self, data, title, contentType, SUBMIT, dtpref_cols, dtpref_rows, REQUEST): dr,dc = self._size_changes[SUBMIT] rows=max(1,string.atoi(dtpref_rows)+dr) cols=max(40,string.atoi(dtpref_cols)+dc) e=(DateTime('GMT') + 365).rfc822() resp=REQUEST['RESPONSE'] resp.setCookie('dtpref_rows',str(rows),path='/',expires=e) resp.setCookie('dtpref_cols',str(cols),path='/',expires=e) return self.manage_editForm(self, REQUEST, dtpref_cols = cols, dtpref_rows = rows) def manage_edit(self, data, title = '', contentType = None, useNamespaces = 1, SUBMIT = 'Change', dtpref_cols = '50', dtpref_rows = '20', REQUEST = None): """ If SUBMIT is a size pref variable, handle a textarea size change. Otherwise parse the given text and handle the result. """ # just get back to the dtml if we're changing size if self._size_changes.has_key(SUBMIT): return self._er(data, title, contentType, SUBMIT, dtpref_cols, dtpref_rows, REQUEST) # if we are pretty printing, just redraw the form if SUBMIT == 'PrettyPrint': return self.manage_editForm( self, REQUEST, textareaStr=self.textareaStr(prettyPrint=1)) if ( hasattr(self, 'nodeType') and self.nodeType == xml.dom.Node.DOCUMENT_NODE): #if we're the main doc self.title = str(title) if contentType: self.contentType = str(contentType) self.noNamespaces = not useNamespaces text=StringIO(data) try: newNode = self.parseXML(text) # self not in doc if this succeeds except expat.error, e: get_transaction().abort() if REQUEST: dataOut = self.makeErrorOutput(data, e.offset, e.lineno) err = "%s%s%s" % (parserr, '%s' % getattr(e, 'args', ''), dataOut) return Globals.MessageDialog( title = 'XML Parsing Error', message = err, action = 'manage_editForm') raise if REQUEST: message = "Saved changes." # wish I knew why we have to set textareaStr for the form return newNode.manage_editForm(self, REQUEST, textareaStr=newNode.textareaStr(), management_view="Edit", manage_tabs_message=message) def manage_upload(self, file, REQUEST=None): "Parse the given file and handle the result." try: newNode = self.parseXML(file) except expat.error, e: get_transaction().abort() if REQUEST: file.seek(0) dataOut = self.makeErrorOutput(file.read(), e.offset, e.lineno) err = "%s%s%s" % (parserr, '%s' % getattr(e, 'args', ''), dataOut) return Globals.MessageDialog( title = 'XML Parsing Error', message = err, action = 'manage_main') raise if REQUEST: return newNode.manage_main(self, REQUEST, manage_tabs_message='Saved changes.') Globals.default__class_init__(DOMManageable) # activate perms # # And finally, classes to mix management and DOM proxies. # class ManageableWrapper: """ Mixin class to go alongside ManageableNode classes. Provides the wrapDOMObj function to create ManageableNode classes. """ # anything that returns subobjs must grant access to them __allow_access_to_unprotected_subobjects__ = 1 def wrapNamedNodeMap(self, obj): if obj is None: return None parent = aq_parent(self) or self return ManageableNamedNodeMap(obj, self._persistentDoc).__of__(parent) def wrapNodeList(self, obj): parent = aq_parent(self) or self return ManageableNodeList(obj, self._persistentDoc).__of__(parent) def wrapDOMObj(self, node): """Return the appropriate manageable class wrapped around the node.""" if node is None: return wrapper_type = WRAPPER_TYPES[node._get_nodeType()] parent = aq_parent(self) or self return wrapper_type(node, self._persistentDoc).__of__(parent) # According to DOM Erratum Core-14, the empty string should be # accepted as equivalent to null for hasFeature(). _MANAGEABLE_DOM_FEATURES = ( ("org.zope.dom.persistence", None), ("org.zope.dom.persistence", ""), ("org.zope.dom.persistence", "1.0"), ("org.zope.dom.acquisition", None), ("org.zope.dom.acquisition", ""), ("org.zope.dom.acquisition", "1.0"), ) _MANAGEABLE_DOM_NON_FEATURES = ( ("load", None), ("load", ""), ("load", "3.0"), ) class ManageableDOMImplementation(DOMProxy.DOMImplementationProxy): """A proxy of a DOMImplementation node that defines createDocument to return a ManageableDocument. """ def hasFeature(self, feature, version): feature = string.lower(feature) if (feature, version) in _MANAGEABLE_DOM_FEATURES: return 1 if (feature, version) in _MANAGEABLE_DOM_NON_FEATURES: return 0 return DOMProxy.DOMImplementationProxy.hasFeature(self, feature, version) def createDocumentType(self, qualifiedName, publicId, systemId): DOMDocumentType = self._createDOMDocumentType(qualifiedName, publicId, systemId) return ManageableDocumentType(DOMDocumentType) def createDocument(self, namespaceURI, qualifiedName, docType=None): if docType is not None: if docType.ownerDocument is not None: raise xml.dom.WrongDocumentErr mdocType = docType.getDOMObj() else: mdocType = None DOMDocument = self._createDOMDocument(namespaceURI, qualifiedName, mdocType) return ManageableDocument(DOMDocument, DOMDocument) theDOMImplementation = ManageableDOMImplementation() # XXX We're implicitly acquiring so we can get ZopeTime (and probably a # jillion other things) in our DTML methods. We should be explicit. class ManageableNode(ManageableWrapper, DOMProxy.NodeProxy, DOMManageable, Acquisition.Implicit): "A wrapper around a DOM Node." # this is mainly here to make later inheritance safer def __init__(self, node, persistentDocument): # inherit from DOMProxy.NodeProxy ManageableNode.inheritedAttribute('__init__')(self, node, persistentDocument) class ManageableNodeList(ManageableWrapper, DOMProxy.NodeListProxy, Acquisition.Implicit): "A wrapper around a DOM NodeList." meta_type = "Manageable NodeList" # redefine to get back the [] syntax with acquisition, eh? def __getslice__(self, i, j): return self.wrapNodeList(self._node.__getslice__(i,j)) # redefine to get back the [] syntax with acquisition, eh? def __getitem__(self, i): return self.wrapDOMObj(self._node.__getitem__(i)) class ManageableNamedNodeMap(ManageableWrapper, DOMProxy.NamedNodeMapProxy, Acquisition.Implicit): "A wrapper around a DOM NamedNodeMap." meta_type = "Manageable NamedNodeMap" # redefine to get back the [] syntax with acquisition, eh? def __getitem__(self, i): return self.wrapDOMObj(self._node.__getitem__(i)) class ManageableDocumentFragment(ManageableWrapper, DOMProxy.DocumentFragmentProxy, ManageableNode): "A wrapper around a DOM DocumentFragment." meta_type = "Manageable Document Fragment" class ManageableElement(ManageableWrapper, DOMProxy.ElementProxy, ManageableNode): "A wrapper around a DOM Element." meta_type = "Manageable Element" class ManageableCharacterData(ManageableWrapper, DOMProxy.CharacterDataProxy, ManageableNode): "A wrapper around a DOM CharacterData." meta_type = "Manageable Character Data" class ManageableCDATASection(ManageableWrapper, DOMProxy.CDATASectionProxy, ManageableNode): "A wrapper around a DOM CDATASection." meta_type = "Manageable CDATASection" class ManageableText(ManageableWrapper, DOMProxy.TextProxy, ManageableCharacterData): "A wrapper around a DOM Text." meta_type = "Manageable Text" class ManageableComment(ManageableWrapper, DOMProxy.CommentProxy, ManageableCharacterData): "A wrapper around a DOM Comment." meta_type = "Manageable Comment" class ManageableProcessingInstruction(ManageableWrapper, DOMProxy.ProcessingInstructionProxy, ManageableNode): "A wrapper around a DOM ProcessingInstruction." meta_type = "Manageable Processing Instruction" class ManageableAttr(ManageableWrapper, DOMProxy.AttrProxy, ManageableNode): "A wrapper around a DOM Attr." meta_type = "Manageable Attr" #ManageableDocument is not necessarily a persistent object, even when a #persistent subclass such as ParsedXML has been instantiated. Traversing #up to the document can create a new transient proxy. Persistent attributes #must be set on the persistent version. class ManageableDocument(ManageableWrapper, DOMProxy.DocumentProxy, ManageableNode): "A wrapper around a DOM Document." meta_type = "Manageable Document" implementation = theDOMImplementation def __init__(self, node, persistentDocument): ManageableNode.__init__(self, node, persistentDocument) def _get_implementation(self): return self.implementation #block set of implementation, since we don't proxy it the same def __setattr__(self, name, value): if name == "implementation": raise xml.dom.NoModificationAllowedErr() ManageableDocument.inheritedAttribute('__setattr__')(self, name, value) # DOM extended interfaces class ManageableEntityReference(ManageableWrapper, DOMProxy.EntityReferenceProxy, ManageableNode): "A wrapper around a DOM EntityReference." meta_type = "Manageable Entity Reference" class ManageableEntity(ManageableWrapper, DOMProxy.EntityProxy, ManageableNode): "A wrapper around a DOM Entity." meta_type = "Manageable Entity" class ManageableNotation(ManageableWrapper, DOMProxy.NotationProxy, ManageableNode): "A wrapper around a DOM Notation." meta_type = "Manageable Notation" class ManageableDocumentType(ManageableWrapper, DOMProxy.DocumentTypeProxy, ManageableNode): "A wrapper around a DOM DocumentType." meta_type = "Manageable Document Type" Node = xml.dom.Node WRAPPER_TYPES = { Node.ELEMENT_NODE: ManageableElement, Node.ATTRIBUTE_NODE: ManageableAttr, Node.TEXT_NODE: ManageableText, Node.CDATA_SECTION_NODE: ManageableCDATASection, Node.ENTITY_REFERENCE_NODE: ManageableEntityReference, Node.ENTITY_NODE: ManageableEntity, Node.PROCESSING_INSTRUCTION_NODE: ManageableProcessingInstruction, Node.COMMENT_NODE: ManageableComment, Node.DOCUMENT_NODE: ManageableDocument, Node.DOCUMENT_TYPE_NODE: ManageableDocumentType, Node.DOCUMENT_FRAGMENT_NODE: ManageableDocumentFragment, Node.NOTATION_NODE: ManageableNotation, } del Node ParsedXML/ParsedXML.py0100755000175200017500000003145707600633530014516 0ustar faasseninfrae############################################################################## # # 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. # ############################################################################## """ Zope Product creation for Parsed XML. """ from OFS.SimpleItem import SimpleItem from AccessControl.Role import RoleManager from Persistence import Persistent from Acquisition import Implicit from OFS.Cache import Cacheable import Globals from ManageableDOM import ManageableDocument, DOMManageable, \ theDOMImplementation from StrIO import StringIO from xml.parsers import expat import DOM, ExtraDOM from types import FileType, StringType from urllib import quote from NodePath import registry _marker = [] # dummy default object for cache return parserr=('Sorry, an XML parsing error occurred. Check ' 'your XML document for well-formedness and try ' 'to upload it again after modification.

') def manage_addParsedXML(self,id,title='',file='', useNamespaces = 1, contentType = "text/xml", REQUEST=None,submit=None): "Add a Parsed XML instance with optional file content." if not file or not isinstance(file, StringType): file ='' try: ob = ParsedXML(id, file, useNamespaces, contentType) except expat.error, e: if REQUEST is not None: err = "%s%s" % (parserr, '%s' % getattr(e, 'args', '')) return Globals.MessageDialog( title= 'XML Parsing Error', message = err, action='manage_main') raise ob.title = str(title) id = self._setObject(id, ob) if REQUEST is not None: try: u=self.DestinationURL() except: u=REQUEST['URL1'] if submit==" Add and Edit ": u="%s/%s" % (u,quote(id)) REQUEST.RESPONSE.redirect(u+'/manage_main') manage_addParsedXMLForm = Globals.DTMLFile('dtml/documentAdd', globals()) def createDOMDocument(XMLstring = None, namespaces = 1): "Helper function to create a DOM document, without any proxy wrappers." if XMLstring: XMLstring=StringIO(XMLstring) # more efficient to not use ExtraDOM here return DOM.ExpatBuilder.parse(XMLstring, namespaces) # we use DOM.theDOMImplementation, not ManageableDOMs, for efficiency return DOM.theDOMImplementation.createDocument( None, "mydocument", None) contentTypes = ['text/html', 'application/html', 'text/xml'] class ParsedXML(SimpleItem, ManageableDocument, Cacheable): "The Parsed XML top object, and the persistent head of the tree." meta_type = 'Parsed XML' manage_editForm = Globals.HTMLFile('dtml/persEdit',globals()) manage_options = (DOMManageable.manage_options + RoleManager.manage_options + Cacheable.manage_options) __ac_permissions__ = (('View management screens', ('manage_main',), ('Manager',)), ('View DOM hierarchy', ('manage_DOMTree',), ('Manager',)), ('Edit ParsedXML', ('manage_editForm',), ('Manager',)), ('View source', ('index_html',), ('Manager',)), ('Access contents information', ('objectIds', 'objectValues', 'objectItems', ''), ('Manager',)),) icon = 'misc_/ParsedXML/pxml.gif' def __init__(self, id, XMLstring = None, namespaces = 1, contentType = "text/xml"): "Initialize a Parsed XML object" self.id = id self._persistentDoc = self # used by transient proxies self.noNamespaces = not namespaces if contentType not in contentTypes: import string raise RuntimeError, ( "Bad content type %s; valid types are %s" % (str(contentType), string.join(contentTypes))) self.contentType = contentType self.initFromDOMDocument(createDOMDocument(XMLstring, namespaces)) if XMLstring: self._lenCache = len(XMLstring) else: self._lenCache = len(str(self)) self._lenCorrect = 1 initFromDOMDocument__roles__ = () # Private def initFromDOMDocument(self, DOMdoc): "Initialize a Parsed XML from a DOM Document" # inherit from ManageableDocument ParsedXML.inheritedAttribute('__init__')(self, DOMdoc, self) def manage_afterAdd(self, object, container): """Store the container that we're being added to. This is used to traverse back to the persistent document.""" self._container = container # # methods that deal with persistence # # DOM nodes use __changed__ because its acquirable # Setting _p_changed is equivalent. def __changed__(self, *args): """Override the acquired __changed__ method used by the non-DB DOM nodes, update length cache, and mark this object as dirty.""" if getattr(self, '_v_lenCorrect', None): self._lenCorrect = 1 else: self._lenCorrect = 0 self.ZCacheable_invalidate() self._p_changed = 1 # wrap DOMIO to provide cacheing def index_html(self, REQUEST = None, RESPONSE = None): "Returns publishable source according to content type" if RESPONSE: RESPONSE.setHeader('Content-type', self.contentType) data = self.ZCacheable_get(default = _marker) if data is not _marker: return data # inherit from DOMIO data = ParsedXML.inheritedAttribute('index_html')(self, REQUEST, RESPONSE) self.ZCacheable_set(data) return data def get_size(self): "Length of the XML string representing this node in characters." if not getattr(self, '_lenCorrect', 0): self._lenCache = len(str(self)) self._lenCorrect = 1 return self._lenCache # methods that override ZDOM methods that are incorrect # def getElementsByTagName(self, tagName): return self.__getattr__("getElementsByTagName")(tagName) def hasChildNodes(self): return self.__getattr__("hasChildNodes")() # # methods that override SimpleItem; sigh, multiple inheritance. # def objectValues(self, spec=None): """ Returns a list of actual subobjects of the current object. If 'spec' is specified, returns only objects whose meta_type match 'spec'. """ return ManageableDocument.objectValues(self, spec) def objectIds(self, spec=None): """ Returns a list of subobject ids of the current object. If 'spec' is specified, returns objects whose meta_type matches 'spec'. """ return ManageableDocument.objectIds(self, spec) def objectItems(self, spec=None): """ Returns a list of (id, subobject) tuples of the current object. If 'spec' is specified, returns only objects whose meta_type match 'spec' """ return ManageableDocument.objectItems(self, spec) def tpValues(self): "Return a list of immediate subobjects. Used by the dtml-tree tag." return ManageableDocument.tpValues(self) # override ManageableDocument's method; we can't persist new DOM node by # hanging off of parents def parseXML(self, file): "parse file as XML, replace DOM node with resulting tree, return self" namespaces = not self.noNamespaces node = ExtraDOM.parseFile(self.getDOMObj(), file, namespaces) self.initFromDOMDocument(node) self.__changed__(1) return self def getDOM(self): """Get the Document node of the DOM tree. """ return self def getNodePath(self, scheme_name, node): """Create the node path for a particular node in the tree. """ # if we're asking for node of this document itself if node is self: return 'scheme_name' # otherwise ask for nodepath of node return node.getNodePath(scheme_name) def resolveNodePath(self, path): """Resolve node path from top of the tree to node. """ # start resolving from the document node doc = self._persistentDoc._earlyAqChain() # FIXME: could use raw DOM instead of management wrappers return registry.resolve_path(doc, path) def __getitem__(self, s): """Handle node paths. """ # backwards compatibility -- handle classic 0/1/2 paths try: return self.childNodes[int(s)].__of__(self) except ValueError: pass # start resolving from the document node doc = self._persistentDoc._earlyAqChain() # FIXME: could use raw DOM instead of management wrappers result = registry.resolve_path(doc, s) # FIXME: does this convince ZPublisher to show NotFound? if result is None: raise KeyError, "Could not resolve node path." return result Globals.default__class_init__(ParsedXML) # activate perms ParsedXML/PrettyPrinter.py0100644000175200017500000002633107471217055015550 0ustar faasseninfraeimport re import string from DOM.Core import Node, XMLNS_NS, XML_NS import sys from StrIO import StringIO # an XML printer which: # * can do pretty printing, optionally # * as opposed to the one defined in Printer.py, actually should # be less buggy class PrintVisitor: def __init__(self, root, stream=sys.stdout, encoding=None, html=0, contentType=None, entityReferenceExpansion=1, prettyPrint=0, indentLevel=2): self.namePrint = lambda s: s # identity if contentType and html: if contentType == 'html': self.namePrint = string.upper elif contentType == 'xml': self.namePrint = string.lower self.root = root self.stream = stream self.encoding = encoding self.html = html self.contentType = contentType self.entityReferenceExpansion = entityReferenceExpansion self.prettyPrint = prettyPrint self.indent = 0 self.indentLevel = indentLevel self.nodeType2method = { Node.ELEMENT_NODE: self.renderElement, Node.ATTRIBUTE_NODE: self.renderAttr, Node.TEXT_NODE: self.renderText, Node.CDATA_SECTION_NODE: self.renderCDATASection, Node.ENTITY_REFERENCE_NODE: self.renderEntityReference, Node.ENTITY_NODE: self.renderEntity, Node.PROCESSING_INSTRUCTION_NODE:\ self.renderProcessingInstruction, Node.COMMENT_NODE: self.renderComment, Node.DOCUMENT_NODE: self.renderDocument, Node.DOCUMENT_TYPE_NODE: self.renderDocumentType, Node.DOCUMENT_FRAGMENT_NODE: self.renderDocumentFragment, Node.NOTATION_NODE: self.renderNotation, } def renderAll(self): return self.render(self.stream, self.root) __call__ = renderAll def render(self, f, node): self.nodeType2method[node.nodeType](f, node) def renderElement(self, f, node): if self.prettyPrint: f.write(" " * self.indent * self.indentLevel) f.write("<") f.write(self.namePrint(node.tagName)) for attribute in node.attributes.values(): self.renderAttr(f, attribute) if not node.hasChildNodes(): if self.html: if node.tagName.upper() not in HTML_FORBIDDEN_END: f.write('>') else: f.write(' />') else: f.write('/>') if self.prettyPrint: f.write("\n") else: f.write('>') prettyPrint = self.prettyPrint stream = f if prettyPrint: f.write("\n") no_indentation = 0 for child in node.childNodes: if (child.nodeType == Node.TEXT_NODE and child.data.strip() != ''): no_indentation = 1 break if no_indentation: stream = StringIO() self.prettyPrint = 0 self.indent += 1 for child in node.childNodes: self.render(stream, child) self.prettyPrint = prettyPrint if prettyPrint: if no_indentation: f.write(indentBlock( stream.getvalue().strip(), self.indent * self.indentLevel, 70)) f.write('\n') self.indent -= 1 f.write(" " * self.indent * self.indentLevel) f.write("" % self.namePrint(node.tagName)) if self.prettyPrint: f.write("\n") def renderAttr(self, f, node): if not node.specified: return text, delimiter = _translateCdataAttr(node.value, encoding=self.encoding) f.write(" %s=%s%s%s" % (self.namePrint(node.name), delimiter, text, delimiter)) def renderText(self, f, node): data = node.data if self.prettyPrint: data = node.data.strip() if data == "": return data = indentBlock(data, self.indent * self.indentLevel, 70) f.write(_translateCdata(data, self.encoding)) if self.prettyPrint: f.write('\n') def renderCDATASection(self, f, node): f.write("", "]]]>")) f.write("]]>") def renderEntityReference(self, f, node): f.write('&') f.write(node.nodeName) f.write(';') def renderEntity(self, f, node): st = "\n') def renderProcessingInstruction(self, f, node): f.write('') def renderComment(self, f, node): f.write('') def renderDocument(self, f, node): if not self.html: f.write('\n') for child in node.childNodes: self.render(f, child) f.write('\n') def renderDocumentType(self, f, node): if (not node.entities.length and not node.notations.length and not node.systemId): return f.write("\n') def renderNotation(self, f, node): st = "\n') def renderDocumentFragment(self, f, node): for child in node.childNodes: self.render(f, child) # regexps used by _translateCdata(), # made global to compile once. # see http://www.xml.com/axml/target.html#dt-character ILLEGAL_LOW_CHARS = '[\x01-\x08\x0B-\x0C\x0E-\x1F]' SURROGATE_BLOCK = '[\xF0-\xF7][\x80-\xBF][\x80-\xBF][\x80-\xBF]' ILLEGAL_HIGH_CHARS = '\xEF\xBF[\xBE\xBF]' # Note: Prolly fuzzy on this, but it looks as if characters from the # surrogate block are allowed if in scalar form, which is encoded in UTF8 the # same was as in surrogate block form XML_ILLEGAL_CHAR_PATTERN = re.compile( '%s|%s' % (ILLEGAL_LOW_CHARS, ILLEGAL_HIGH_CHARS)) # the characters that we will want to turn into entrefs # We must do so for &, <, and > following ]]. # The xml parser has more leeway, but we're not the parser. # http://www.xml.com/axml/target.html#dt-chardata # characters that we must *always* turn to entrefs: g_cdataCharPatternReq = re.compile('[&<]|]]>') g_charToEntityReq = { '&': '&', '<': '<', ']]>': ']]>', } # characters that we must turn to entrefs in attr values: g_cdataCharPattern = re.compile('[&<>"\']|]]>') g_charToEntity = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''', ']]>': ']]>', } # HTML nodes to always be minimzied, else never minimize # from PyXML's xml.dom.html # http://www.w3.org/TR/xhtml1/#guidelines HTML_FORBIDDEN_END = ['AREA', 'BASE', 'BASEFONT', 'BR', 'COL', 'FRAME', 'HR', 'IMG', 'INPUT', 'ISINDEX', 'LINK', 'META', 'PARAM'] def _translateCdata(characters, allEntRefs = None, encoding='UTF-8'): """Translate characters into a legal format.""" if not characters: return '' if allEntRefs: # translate all chars to entrefs; for attr value if g_cdataCharPattern.search(characters): new_string = g_cdataCharPattern.subn( lambda m, d=g_charToEntity: d[m.group()], characters)[0] else: new_string = characters else: # translate only required chars to entrefs if g_cdataCharPatternReq.search(characters): new_string = g_cdataCharPatternReq.subn( lambda m, d=g_charToEntityReq: d[m.group()], characters)[0] else: new_string = characters if XML_ILLEGAL_CHAR_PATTERN.search(new_string): new_string = XML_ILLEGAL_CHAR_PATTERN.subn( lambda m: '&#%i;' % ord(m.group()), new_string)[0] #new_string = utf8_to_code(new_string, encoding) # XXX ugh return new_string def _translateCdataAttr(characters, encoding='UTF-8'): """ Translate attribute value characters into a legal format; return the value and the delimiter used. """ if not characters: return '', '"' if '"' not in characters or "'" in characters: delimiter = '"' new_chars = _translateCdata(characters, allEntRefs = 1, encoding=encoding) new_chars = re.sub("'", "'", new_chars) else: delimiter = "'" new_chars = _translateCdata(characters, allEntRefs = 1, encoding=encoding) new_chars = re.sub(""", '"', new_chars) return new_chars, delimiter def indentBlock(text, indent, line_length): words = text.split() lines = [] i = 0 while i < len(words): line = [] while i < len(words) and indent + len(" ".join(line)) < line_length: line.append(words[i]) i += 1 if len(line) > 1 and indent + len(" ".join(line)) >= line_length: i -= 1 line.pop() lines.append(" " * indent + " ".join(line)) return '\n'.join(lines) ParsedXML/Printer.py0100644000175200017500000004200307247525676014346 0ustar faasseninfrae############################################################################## # # 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. # ############################################################################## # # Specifically, most of this code is from PyXML's xml.dom.ext.Printer. # See LICENSE.Fourthought. # """ Printing and XML generating support for DOM classes. """ import re import string # regexps used by _translateCdata(), # made global to compile once. # see http://www.xml.com/axml/target.html#dt-character ILLEGAL_LOW_CHARS = '[\x01-\x08\x0B-\x0C\x0E-\x1F]' SURROGATE_BLOCK = '[\xF0-\xF7][\x80-\xBF][\x80-\xBF][\x80-\xBF]' ILLEGAL_HIGH_CHARS = '\xEF\xBF[\xBE\xBF]' #Note: Prolly fuzzy on this, but it looks as if characters from the surrogate block are allowed if in scalar form, which is encoded in UTF8 the same was as in surrogate block form XML_ILLEGAL_CHAR_PATTERN = re.compile('%s|%s'%(ILLEGAL_LOW_CHARS, ILLEGAL_HIGH_CHARS)) # the characters that we will want to turn into entrefs # We must do so for &, <, and > following ]]. # The xml parser has more leeway, but we're not the parser. # http://www.xml.com/axml/target.html#dt-chardata # characters that we must *always* turn to entrefs: g_cdataCharPatternReq = re.compile('[&<]|]]>') g_charToEntityReq = { '&': '&', '<': '<', ']]>': ']]>', } # characters that we must turn to entrefs in attr values: g_cdataCharPattern = re.compile('[&<>"\']|]]>') g_charToEntity = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''', ']]>': ']]>', } # HTML nodes to always be minimzied, else never minimize # from PyXML's xml.dom.html # http://www.w3.org/TR/xhtml1/#guidelines HTML_FORBIDDEN_END = ['AREA', 'BASE', 'BASEFONT', 'BR', 'COL', 'FRAME', 'HR', 'IMG', 'INPUT', 'ISINDEX', 'LINK', 'META', 'PARAM'] from DOM.Core import Node, XMLNS_NS, XML_NS from DOM import Traversal import sys class Visitor: """A class to visit an entire tree according to a TreeWalker.""" # These are both used for html mode. These aren't the types that # the server returns; 'html' covers '*/html', etc. contentTypes = ['html', 'xml'] def __init__(self, root, stream = sys.stdout, encoding = None, html = 0, contentType = None, whatToShow = Traversal.NodeFilter.SHOW_ALL, filter = None, entityReferenceExpansion = 1): if root.ownerDocument: doc = root.ownerDocument else: doc = root self.tw = doc.createTreeWalker(root, whatToShow, filter, entityReferenceExpansion) self.stream = stream self.encoding = encoding self.html = html if contentType and contentType not in self.contentTypes: raise RuntimeError, ( "Bad content type %s; valid types are 'html', 'xml'" % contentType) self.contentType = contentType # elt/attr names: html */html upcase, html */xml lowercase. # http://www.w3.org/TR/xhtml1/#guidelines self.namePrint = lambda string: string # identity if self.contentType and self.html: if self.contentType == 'html': self.namePrint = string.upper elif self.contentType == 'xml': self.namePrint = string.lower # maps node type to visitor method self.NODE_TYPES = { Node.ELEMENT_NODE: self.visitElement, Node.ATTRIBUTE_NODE: self.visitAttr, Node.TEXT_NODE: self.visitText, Node.CDATA_SECTION_NODE: self.visitCDATASection, Node.ENTITY_REFERENCE_NODE: self.visitEntityReference, Node.ENTITY_NODE: self.visitEntity, Node.PROCESSING_INSTRUCTION_NODE: \ self.visitProcessingInstruction, Node.COMMENT_NODE: self.visitComment, Node.DOCUMENT_NODE: self.visitDocument, Node.DOCUMENT_TYPE_NODE: self.visitDocumentType, Node.DOCUMENT_FRAGMENT_NODE: self.visitDocumentFragment, Node.NOTATION_NODE: self.visitNotation, } # methods to drive the walker def visitWhole(self): curNode = self.tw.currentNode self.visit(curNode, start = 1) self.visitChildren() self.visit(curNode, start = 0) __call__ = visitWhole def visitChildren(self): if self.tw.firstChild(): self.visitWhole() while (self.tw.nextSibling()): self.visitWhole() self.tw.parentNode() # methods that do stuff once we're there, without moving the walker def visitElement(self, node, start): self.visitGeneric(node) def visitAttr(self, node, start): self.visitGeneric(node) def visitText(self, node, start): self.visitGeneric(node) def visitCDATASection(self, node, start): self.visitGeneric(node) def visitEntityReference(self, node, start): self.visitGeneric(node) def visitEntity(self, node, start): self.visitGeneric(node) def visitProcessingInstruction(self, node, start): self.visitGeneric(node) def visitComment(self, node, start): self.visitGeneric(node) def visitDocument(self, node, start): self.visitGeneric(node) def visitDocumentType(self, node, start): self.visitGeneric(node) def visitDocumentFragment(self, node, start): self.visitGeneric(node) def visitNotation(self, node, start): self.visitGeneric(node) def visitGeneric(self, node): self.stream.write("visit %s node %s\n"%(node.nodeType, node.nodeName)) def visit(self, node, start): "Find the element type and call the appropriate visit method" visitMethod = self.NODE_TYPES.get(node.nodeType, None) if visitMethod is None: raise TypeError, ( "Cannot print unknown nodeType: %s" % node.nodeType) else: return visitMethod(node, start) # we'll want hooks to generalize this for prettyprinting etc: # add formatting, named constants for < etc so we can < etc. class PrintVisitor(Visitor): """A class to generate XML for a tree according to a TreeWalker""" def visitElement(self, node, start): if start: self.stream.write('<' + self.namePrint(node.tagName)) st = '' for item in node.attributes.values(): self.visitAttr(item, start=1) if not node.hasChildNodes(): if self.html: if string.upper(node.tagName) not in HTML_FORBIDDEN_END: self.stream.write('>') else: self.stream.write(' />') else: self.stream.write('/>') else: self.stream.write('>') else: if node.hasChildNodes(): self.stream.write('') def visitAttr(self, node, start): if start and node.specified: text, delimiter = _translateCdataAttr(node.value) self.stream.write(" %s=%s%s%s" % (self.namePrint(node.name), delimiter, text, delimiter)) def visitText(self, node, start): if start: self.stream.write(_translateCdata(node.data, self.encoding)) def visitCDATASection(self, node, start): if start: self.stream.write('", "]]]>")) self.stream.write(']]>') def visitEntityReference(self, node, start): if start: self.stream.write('&') self.stream.write(node.nodeName) self.stream.write(';') def visitEntity(self, node, start): if start: st = "\n') def visitNotation(self, node, start): if start: st = "\n') def visitProcessingInstruction(self, node, start): if start: self.stream.write('') def visitComment(self, node, start): if start: self.stream.write('') def visitDocument(self, node, start): if start: if not self.html: self.stream.write('\n') else: self.stream.write('\n') # Add a final newline def visitDocumentType(self, node, start): if start: if not node.entities.length and not node.notations.length and \ not node.systemId: return self.stream.write("\n') def visitDocumentFragment(self, node, start): pass # we're just here for the children def _translateCdata(characters, allEntRefs = None, encoding='UTF-8'): """Translate characters into a legal format.""" if not characters: return '' if allEntRefs: # translate all chars to entrefs; for attr value if g_cdataCharPattern.search(characters): new_string = g_cdataCharPattern.subn( lambda m, d=g_charToEntity: d[m.group()], characters)[0] else: new_string = characters else: # translate only required chars to entrefs if g_cdataCharPatternReq.search(characters): new_string = g_cdataCharPatternReq.subn( lambda m, d=g_charToEntityReq: d[m.group()], characters)[0] else: new_string = characters # This was never used, & I never got it anyway - prettyprinting? #if prev_chars[-2:] == ']]' and characters[0] == '>': # new_string = '>' + new_string[1:] # Note: use decimal char entity rep because some browsers are broken # FIXME: This will bomb for high characters. # Should, for instance, detect the UTF-8 for 0xFFFE # and put out ￾ if XML_ILLEGAL_CHAR_PATTERN.search(new_string): new_string = XML_ILLEGAL_CHAR_PATTERN.subn( lambda m: '&#%i;' % ord(m.group()), new_string)[0] #new_string = utf8_to_code(new_string, encoding) # XXX ugh return new_string def _translateCdataAttr(characters): """ Translate attribute value characters into a legal format; return the value and the delimiter used. """ if not characters: return '', '"' if '"' not in characters or "'" in characters: delimiter = '"' new_chars = _translateCdata(characters, allEntRefs = 1) new_chars = re.sub("'", "'", new_chars) else: delimiter = "'" new_chars = _translateCdata(characters, allEntRefs = 1) new_chars = re.sub(""", '"', new_chars) #FIXME: There's more to normalization #Convert attribute new-lines to character entity # characters is possibly shorter than new_chars (no entities) # I think this was a prettyprinting issue, newlines aren't illegal # http://www.xml.com/axml/target.html#NT-AttValue #if "\n" in characters: # new_chars = re.sub('\n', ' ', new_chars) return new_chars, delimiter ParsedXML/README.DOMProxy0100644000175200017500000001343207375564712014711 0ustar faasseninfraeHow and why we are proxying DOM nodes. Parsed XML consists of two DOM interfaces. Our DOM is a tight and fast implementation. Our ManageableDOM (of which the ParsedXML object that is instantiated acts as the top object) contains an instance of a DOM tree, proxies its DOM interface, and also provides Zope support such as management interfaces. A Parsed XML object can be created from scratch, in which case its DOM document will be created with it, or it can be wrapped around an existing DOM document. Parsed XML objects should be able to provide some management support for any compliant DOM document, since it proxies DOM calls. However, since it uses our builder, which is optimized for our DOM storage, parsing will not work on storages other than our DOM. Why are we proxying? Our DOM implementation is fast and scalable, and we didn't want to compromise this with our extras. Some users won't want or need the Zopish features to be married to the DOM implementation. When should the proxy be used, and when should the simple DOM be used? There's no reason to use the proxies when you don't need their features. If all that you need is a DOM storage, then the proxies aren't necessary, and you can create and use a DOM document without the proxy wrappers. However, you will have to know what you are doing; some Zope machinery won't be taken care of for you: - The DOM storage doesn't keep track of any non-DOM attributes. For example, namespace usage and content type are stored by the proxy Document, and if you're not using this, you'll have to keep track of these attributes yourself, since the DOM doesn't keep track of them. - The DOM storage doesn't know about Zope permissions, so your containing object must handle this. - The DOM storage doesn't provide any persistence machinery, although it will acquire and call the persistence triggering methods when available, so storing it in a persistent container will suffice to persist the DOM. To create a DOM Document without any proxy wrappers, see createDOMDocument() in ParsedXML.py. When should the proxy not be used? When you reference the proxied DOM object through a different persistent object, *and* change the DOM through that reference, *and* rely on get_size() or use a ZCache, *and* the ParsedXML Document isn't notified when the change occurs. The DOM objects persist by acquiring persistence methods from their containers. The proxy objects update certain cached values when these methods are called. That means that if a DOM Document is referenced by a different persistent object, and changes are made through that reference, the ParsedXML proxy won't know to update its cached values. ParsedXML caches the result of get_size(), and provides support for a ZCache to cache index_html. If you use a ZCache with a ParsedXML instance, or rely on the result of get_size(), you will need to make sure that these values are updated if the DOM is modified through a reference other than the ParsedXML Document. This can be done by calling __changed__() on the ParsedXML Document. How are we proxying? Our DOM implementation is in the DOM subdirectory. The baseclasses for the DOMImplementation is in DOMProxy.py. These define the machinery for proxying our DOM tree. The basic proxying is defined here, except for methods to create the proxy nodes, which we'll describe soon. The base proxy class is DOMProxy. It contains a reference to the actual DOM node it is proxying for. NodeProxy, ElementProxy, etc. all specialize DOMProxy for the appropriate DOM classes. These proxy classes all lack the ability to actually create instances of the proxy nodes. This is because they are designed to be subclassed, and they don't yet know what class to wrap a DOM node into when they want a proxy object. Subclasses should define the methods wrapDOMObj(), wrapNodeList() and wrapNamedNodeMap(). wrapDOMObj() and it should take a DOM Node and return the appropriate proxy node; wrapNodeList() and wrapNamedNodeMap() should take a NodeList and NamedNodeMap object respectively and returned proxied versions. Because these methods are undefined, these baseclasses cannot be instantiated, they must be subclassed. A simple example of a working implementation is in TransPubDOMProxy.py. The actual proxy classes that Parsed XML uses are in ManageableDOM.py, and the basic DOM baseclass is ManageableNode, which corresponds to a DOM node. It mixes DOMProxy.NodeProxy with ManageableWrapper, which provides the needed methods that return ManageableNode, ManageableNodeList and ManageableNamedNodeMap subclasses. ManageableNode also mixes in DOMManageable, which provides our management and publishing support, and an Acquisition class. When a Parsed XML product is added to a Zope installation, a ParsedXML object is instantiated, which is a subclass of ManageableDocument. It is important to note that none of the other proxy nodes are persistent! wrapDOMObj() wraps a new proxy node around an existing DOM node whenever it is called. It never reuses existing proxy nodes, or even knows of their existence. So although you can do things like assign non-DOM attributes to a ManageableNode, re-navigating to the ManageableNode corresponding to the same place in the DOM tree won't get you a node with those attributes, since it's a whole new instance. This also means that navigating with DOM calls is slower, because of all that instantiating and wrapping. It's more efficient to work through the proxied DOM objects when you can and wrap the result when you must. There are ways to make persistent proxy objects if you're developing your own proxy classes based on ours, by inheriting a wrapDOMObj() method that makes persistent proxy objects and returns existing ones when appropriate. ParsedXML/README.parseprint0100644000175200017500000000402507256751027015410 0ustar faasseninfraeDOM objects, XML, printing, and parsing ParsedXML doesn't store any XML. It stores a DOM tree, which is an object representation of the data in an XML document; or perhaps it is more accurate to say that an XML document is a serial representation of some data, and the corresponding DOM tree is a hierarchical representation of the same data. The primary way of accessing and manipulating that data is with DOM API calls. When a ParsedXML object is viewed as XML, the DOM tree is serialized into the XML which is viewed. This is what is seen in the Edit management view. When XML is inputted into a ParsedXML object, it is parsed to create DOM objects which are inserted into the DOM tree. This is what happens when XML is edited or uploaded in the Edit management view. It is important to note that the DOM is not the XML because the information that each stores is not the same. The XML specification states what information can be expressed by a well-formed XML document, and some of this information is not preserved by the parser, printer, and DOM storage. For example, whitespace in attribute strings isn't significant. The Infoset specification at "http://www.w3.org/TR/xml-infoset/" states what can be lost; parsers are also allowed certain liberties with their input. Our parser, printer, and DOM keep more information than the Infoset requires, such as attribute order. Entities and entity references are an example of how the parser and printer manipulate XML. Currently, entity references are expanded to their entities by the parser; it never adds entity reference nodes to the document. This is legal, if annoying, behavior. Because of this, when an XML file containing "&" in a text node is parsed, the node will contain a literal "&" where the "&" was in the XML. It is legal for a DOM text node to contain a literal "&" character. However, it is not legal for an XML text node to contain a literal "&", so when that node is printed, the "&" will be converted back into a "&" entity reference.ParsedXML/README.txt0100644000175200017500000001256107471031224014031 0ustar faasseninfraeREADME for Parsed XML. What is it? Parsed XML allows you to use XML objects in the Zope environment. You can create XML documents in Zope and leverage Zope to format, query, and manipulate XML. Parsed XML consists of a DOM storage, a builder that uses PyExpat to parse XML into the DOM, and a management proxy product that provides Zope management features for a DOM tree. It also includes a system to create paths to nodes in Zope URLs (NodePath). Requirements, Installation See INSTALL.txt. Feedback, discussion, more information The latest released version can be found at the "product":http://www.zope.org/Members/faassen/ParsedXML site. For more information, see the Parsed XML "wiki":http://www.zope.org/Wikis/DevSite/Projects/ParsedXML. Bug reports and status is kept by the the Parsed XML "tracker":http://www.zope.org/Members/karl/ParsedXML/ParsedXMLTracker. There is a "mailing list":http://mail.zope.org/mailman/listinfo/parsed-xml-dev with archives. The latest version is available through "CVS":http://www.zope.org/Wikis/DevSite/Projects/ParsedXML/Releases. Features The Parsed XML product parses XML into a Zopish DOM tree. The elements of this tree support persistence, acquisition, etc.. The document and subnodes are editable and manageable through management proxy objects, and the underlying DOM tree can be directly manipulated via DTML, Python, etc.. DOM and ManageableDOM We're implementing a lean, mean DOM tree for pure DOM access, and a tree of proxy shells to handle management and take care of the conveniences like publishing and security. The ManageableNodes are the proxy objects. These are what you see in the management interface, and the top object that gets put in the ZODB. Note that only the top proxy object is persistent, the others are transient. The Nodes are pure DOM objects. From a ManageableNode, the DOM Node is retrieved with the getDOMObj() call. See README.DOMProxy for information about the proxy objects. DOM API support The DOM tree created by Zope aims to comply with the DOM level 2 standard. This allows you to access your XML in DTML or External Methods using a standard and powerful API. We are currently supporting the DOM level 2 Core and Traversal specifications. The DOM tree is not built with the XML-SIG's DOM package, because it requires significantly different node classes. DOM attributes are made available according to the Python language mapping for the IDL interfaces described by the DOM recommendation; see the "mapping":http://cgi.omg.org/cgi-bin/doc?ptc/00-04-08. URL traversal Parsed XML implements a 'NodePath' system to create references to XML nodes (most commonly elements). FIXME include examples here Currently, traversal uses an element's index within its parent as an URL key. For example, 'http://server/myDoc/0/2/mymethod' This URL traverses from an XML Document object with id 'myDoc' to it's first sub-element, to that element's second sub-element to an acquired method with id 'myMethod' DOM methods can also be used in URLs, for example, 'http://server/myDoc/firstChild/nextSibling/mymethod' Editing XML with the management interface XML Documents and subnodes are editable via the management interface. Documents and subtrees can be replaced by uploading XML files. Security Security is handled at the document level. DOM attributes and methods are protected by the "Access contents information" permission. Subnodes will acquire security settings from the document. Developing with Parsed XML We like to think that Parsed XML provides a flexible platform for using a DOM storage and extending that storage to do interesting things. See README.DOMProxy for an explanation of how we're using this for Parsed XML. We've included a comprehensive unit test suite to make testing for DOM compliance easier. See tests/README for details. If you want to submit changes to Parsed XML, please use the test suite to make sure that your changes don't break anything. Bugs There are bugs in how multiple node references reflect the hierarchy above the node: - A reference to a subnode of a DOM document won't reflect some hierarchy changes made on other references to the same node. If two references to a node are created, and one is then reparented, the other reference won't reflect the new parent. The parentNode attribute will be incorrect, for example, as well as the ownerDocument and ownerElement attributes. - A reference to a subnode of a DOM document can't be properly stored as a persistent attribute of a ZODB object; it will lose hierarchy information about its parent as well. Entity reference handling is not complete: - Entity references do not have child nodes that mirror the child nodes of the referenced entity; they do not have child nodes at all. - TreeWalker.expandEntityReferences has no effect, because of the above bug. Unicode support is still incomplete. It appears to work with Python 2.1 and Zope 2.4, but there are still some issues with the parser. Traversal support for visibility and roots is not complete. Credits see CREDITS.txt and LICENSE.Fourthought. ParsedXML/StrIO.py0100644000175200017500000000026207471163777013723 0ustar faasseninfrae"""Module which selects the right version of StringIO.""" # Python 2.1 and up is now a requirement, so we don't need to # do anything special here from StringIO import StringIO ParsedXML/TransPubDOMProxy.py0100644000175200017500000002362007300404325016040 0ustar faasseninfrae############################################################################## # # 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. # ############################################################################## """ A simple example implementation of DOMProxy. Provide a class to implement wrapDOMObj(), mix that and the DOMProxy proxy classes, and add whatever you want to make it interesting. """ import DOMProxy import Acquisition class TransPubWrapper: """ Mixin class to go alongside DOMProxy classes. Provides the wrapDOMObj function to create TransPubNode classes. This is what makes TransPubNodes transient - we never re-use proxies, but create new ones when we need them. """ # In the future we may want to return different proxy types based # on non-DOM node types, such as DB/nonDB. Probably map # the same way that the DOM classes will map. def wrapDOMObj(self, node): """ Return the appropriate manageable class wrapped around the Node. We never create Nodes ourselves, only wrap existing ones. Wrapped node can be single DOM object, a non-DOM object, or a container that contains only non-DOM objects - DOM objects in containters aren't wrapped. """ from xml.dom import Node import types if node == None: return None elif isinstance(node, types.InstanceType) \ and node.__class__.__name__ == "ChildNodeList": # XXX impl detail return TransPubNodeList(node) elif isinstance(node, types.InstanceType) \ and node.__class__.__name__ == "AttributeMap": # XXX impl detail return TransPubNamedNodeMap(node) elif not hasattr(node, "nodeType"): return node # not DOM, don't wrap. elif node.nodeType == Node.ELEMENT_NODE: return TransPubElement(node) elif node.nodeType == Node.ATTRIBUTE_NODE: return TransPubAttr(node) elif node.nodeType == Node.TEXT_NODE: return TransPubText(node) elif node.nodeType == Node.CDATA_SECTION_NODE: return TransPubCDATASection(node) elif node.nodeType == Node.ENTITY_REFERENCE_NODE: return TransPubEntityReference(node) elif node.nodeType == Node.ENTITY_NODE: return TransPubEntity(node) elif node.nodeType == Node.PROCESSING_INSTRUCTION_NODE: return TransPubProcessingInstruction(node) elif node.nodeType == Node.COMMENT_NODE: return TransPubComment(node) elif node.nodeType == Node.DOCUMENT_NODE: return TransPubDocument(node) elif node.nodeType == Node.DOCUMENT_TYPE_NODE: return TransPubDocumentType(node) elif node.nodeType == Node.DOCUMENT_FRAGMENT_NODE: return TransPubDocumentFragment(node) elif node.nodeType == Node.NOTATION_NODE: return TransPubNotation(node) else: raise TypeError _TRANS_PUB_DOM_PROXY_FEATURES = ( ("org.zope.dom.acquisition", None), ("org.zope.dom.acquisition", "1.0"), ) class TransPubDOMImplementation(DOMProxy.DOMImplementationProxy): """ A DOMImplementation proxy that implements createDocument to produce TransPubDocument instances. """ def hasFeature(self, feature, version): feature = string.lower(feature) if (feature, version) in _TRANS_PUB_DOM_PROXY_FEATURES: return 1 return self._domimplementation.hasFeature(feature, version) def createDocument(self, namespaceURI, qualifiedName, docType=None): DOMDocument = self._createDOMDocument(namespaceURI, qualifiedName, docType) return TransPubDocument(DOMDocument.aq_base) # XXX check aq theDOMImplementation = TransPubDOMImplementation() #DOMIO, DOMManageable, DOMPublishable, class TransPubNode(TransPubWrapper, DOMProxy.NodeProxy, Acquisition.Implicit): "The core of the TransPub DOM proxies." pass class TransPubNodeList(TransPubWrapper, DOMProxy.NodeListProxy): "A TransPubWrapper mixer with NodeListProxy." pass class TransPubNamedNodeMap(TransPubWrapper, DOMProxy.NamedNodeMapProxy): "A TransPubWrapper mixer with NamedNodeMapProxy." pass class TransPubDocumentFragment(DOMProxy.DocumentFragmentProxy, TransPubNode): "A TransPubWrapper mixer with DocumentFragmentProxy." pass class TransPubElement(DOMProxy.ElementProxy, TransPubNode): "A TransPubWrapper mixer with ElementProxy." pass class TransPubCharacterData(DOMProxy.CharacterDataProxy, TransPubNode): "A TransPubWrapper mixer with CharacterDataProxy." pass class TransPubCDATASection(DOMProxy.CDATASectionProxy, TransPubNode): "A TransPubWrapper mixer with CDATASectionProxy." pass class TransPubText(TextProxy, DOMProxy.TransPubCharacterData): "A TransPubWrapper mixer with TextProxy." pass class TransPubComment(CommentProxy, DOMProxy.TransPubCharacterData): "A TransPubWrapper mixer with CommentProxy." pass class TransPubProcessingInstruction(DOMProxy.ProcessingInstructionProxy, TransPubNode): "A TransPubWrapper mixer with ProcessingInstructionProxy." pass class TransPubAttr(DOMProxy.AttrProxy, TransPubNode): "A TransPubWrapper mixer with AttrProxy." pass class TransPubDocument(DOMProxy.DocumentProxy, TransPubNode): """ A TransPubWrapper mixer with DocumentProxy. Provides and protects the implementation attribute. """ implementation = theDOMImplementation #block set of implementation, since we don't proxy it the same def __setattr__(self, name, value): if name == "implementation": raise xml.dom.NoModificationAllowedErr() # wacky ExtensionClass inheritance TransPubDocument.inheritedAttribute('__setattr__')(self, name, value) # DOM extended interfaces class TransPubEntityReference(DOMProxy.EntityReferenceProxy, TransPubNode): "A TransPubWrapper mixer with EntityReferenceProxy." pass class TransPubEntity(DOMProxy.EntityProxy, TransPubNode): "A TransPubWrapper mixer with EntityProxy." pass class TransPubNotation(DOMProxy.NotationProxy, TransPubNode): "A TransPubWrapper mixer with NotationProxy." pass class TransPubDocumentType(DOMProxy.DocumentTypeProxy, TransPubNode): "A TransPubWrapper mixer with DocumentTypeProxy." pass ParsedXML/__init__.py0100755000175200017500000001027607303013714014446 0ustar faasseninfrae############################################################################## # # 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. # ############################################################################## """ Parsed XML product """ def initialize(context): import ParsedXML context.registerClass( ParsedXML.ParsedXML, permission = 'Add Documents, Images, and Files', icon='www/pxml.gif', constructors = (ParsedXML.manage_addParsedXMLForm, ParsedXML.manage_addParsedXML) ) context.registerHelp() context.registerHelpTitle('Parsed XML Help') #context.registerHelpTopic('ParsedXML_Edit', ParsedXML_Edit()) ParsedXML/main.dtml0100755000175200017500000000006207213244131014132 0ustar faasseninfrae hello worldParsedXML/version.txt0100644000175200017500000000002007600633530014546 0ustar faasseninfraeParsedXML 1.3.1 ParsedXML/NodePath/0040755000175200017500000000000007600634637014046 5ustar faasseninfraeParsedXML/NodePath/tests/0040755000175200017500000000000007600634637015210 5ustar faasseninfraeParsedXML/NodePath/tests/test_nodepath.py0100644000175200017500000000574707461533230020425 0ustar faasseninfraeimport unittest # needed to import NodePath module import sys sys.path.insert(0, '../..') from NodePath import registry def DOMParseString(xml): # FIXME: change this if using another DOM from Products.ParsedXML.StrIO import StringIO from Products.ParsedXML.DOM import ExpatBuilder file = StringIO(xml) return ExpatBuilder.parse(file) class NodePathTestCase(unittest.TestCase): def setUp(self): doc = DOMParseString('''

This is a very trival XML document.

We will test whether our node path facility works with it.

Here is a second chapter, which contains a list.

Foo Bar Baz
''') self._doc = doc def _shotgun_check(self, top_node, node, scheme_name): path = registry.create_path(top_node, node, scheme_name) found = registry.resolve_path(top_node, path) assert found == node, ("Found %s with '%s', wanted %s" % (found, path, node)) cycled_path = registry.create_path(top_node, node, scheme_name) assert path == cycled_path, ("Cycled path %s found, wanted %s" % (cycled_path, path)) for child in node.childNodes: self._shotgun_check(top_node, child, scheme_name) def _shotgun_check_robust(self, top_node, node): path = registry.create_path(top_node, node, 'robust') found = registry.resolve_path(top_node, path) assert found == node, ("Found %s with '%s', wanted %s" % (found, path, node)) # can't cycle path as words are selected randomly for child in node.childNodes: self._shotgun_check_robust(top_node, child) def checkChildPath(self): self._shotgun_check(self._doc, self._doc.documentElement, 'child') def checkElementIdPath(self): self._shotgun_check(self._doc, self._doc.documentElement, 'element_id') def checkRobustPath(self): self._shotgun_check_robust(self._doc, self._doc.documentElement) def checkEmptyPath(self): self.assertEquals('', registry.create_path(self._doc, self._doc, 'child')) self.assertEquals('', registry.create_path(self._doc, self._doc, 'element_id')) #self.assertEquals('', # registry.create_path(self._doc, self._doc, 'robust')) found = registry.resolve_path(self._doc, '') self.assertEquals(self._doc, found) def test_suite(): suite = unittest.TestSuite() suite.addTest(unittest.makeSuite(NodePathTestCase, "check")) return suite def main(): unittest.TextTestRunner().run(test_suite()) if __name__ == "__main__": main() ParsedXML/NodePath/ElementIdPath.py0100644000175200017500000000264407404477171017106 0ustar faasseninfraefrom NodePath import BaseNodePathScheme, registry class ElementIdPathScheme(BaseNodePathScheme): def __init__(self, scheme_name=None): scheme_name = scheme_name or 'element_id' BaseNodePathScheme.__init__(self, scheme_name) def resolve_steps(self, top_node, steps): node = top_node for step in steps: if step[0] == 'e': element_id = int(step[1:]) for child in node.childNodes: if self.get_element_id(child) == element_id: node = child break else: # couldn't find node with such element_id return None else: node = node.childNodes.item(int(step)) if node is None: return None return node # return node def create_steps(self, top_node, node): steps = [] while node is not top_node: parent = node.parentNode if parent is None: break element_id = self.get_element_id(node) if element_id != -1: steps.append("e%s" % element_id) else: steps.append(str(parent.childNodes.index(node))) node = parent steps.reverse() return steps def get_element_id(self, node): return getattr(node, 'elementId', -1) ParsedXML/NodePath/NodePath.py0100644000175200017500000000555707461533230016123 0ustar faasseninfraeimport string class NodePathError(Exception): pass class NodePathSchemeRegistry: def __init__(self): self._schemes = {} def register_scheme(self, scheme): self._schemes[scheme._scheme_name] = scheme def resolve_steps(self, top_node, steps, scheme_name): """Resolve steps from top_node. """ # if we don't know scheme, return None as node could not be found if not self._schemes.has_key(scheme_name): raise NodePathError, "Unknown scheme: %s" % scheme_name # we do know the scheme, so look it up scheme = self._schemes[scheme_name] # now resolve steps using this scheme return scheme.resolve_steps(top_node, steps) def resolve_path(self, top_node, path): """Resolve path. """ if not path: return top_node steps = string.split(path, ',') # get scheme as first element of path scheme_name, steps = steps[0], steps[1:] # resolve steps using scheme return self.resolve_steps(top_node, steps, scheme_name) def create_steps(self, top_node, node, scheme_name): """Construct steps tuple to node. """ return self._schemes[scheme_name].create_steps(top_node, node) def create_path(self, top_node, node, scheme_name): """Construct path to node according to scheme_name. """ steps = self.create_steps(top_node, node, scheme_name) if not steps: return '' return '%s,%s' % (scheme_name, string.join(steps, ',')) class BaseNodePathScheme: def __init__(self, scheme_name): self._scheme_name = scheme_name def resolve_steps(self, top_node, steps): """Resolve path from top_node, return node found or None. Steps are in order top_node to node. """ pass def create_steps(self, top_node, node): """Return list of steps from top_node to node. Steps returned are in reverse order. """ pass class ChildNodePathScheme(BaseNodePathScheme): def __init__(self): BaseNodePathScheme.__init__(self, 'child') def resolve_steps(self, top_node, steps): node = top_node for step in steps: node = node.childNodes.item(int(step)) if node is None: return None return node # return node def create_steps(self, top_node, node): steps = [] # FIXME: is it safe to compare nodes like this? while node is not top_node: parent = node.parentNode if parent is None: break # FIXME: can index() be used in all python DOMs? steps.append(str(parent.childNodes.index(node))) node = parent steps.reverse() return steps # create the registry registry = NodePathSchemeRegistry() ParsedXML/NodePath/README.txt0100644000175200017500000000033607403751323015534 0ustar faasseninfraeEverything in this directory, including the tests subdirectory, should work independently of ParsedXML and with another Python DOM as well. The only change necessary should be to the DOM loading in the unit tests subdir. ParsedXML/NodePath/RobustPath.py0100644000175200017500000003044107404477171016512 0ustar faasseninfraefrom NodePath import BaseNodePathScheme, NodePathError import random, string, urllib import xml.dom words_amount = 5 class RobustPathScheme(BaseNodePathScheme): def __init__(self): BaseNodePathScheme.__init__(self, 'robust') def resolve_steps(self, top_node, steps): steps, type_step, context_step = steps[:-2], steps[-2], steps[-1] rsteps = [] # create element steps for step in steps: nodeName, nodeIndex = string.split(step, "*") rsteps.append(GenericStep(xml.dom.Node.ELEMENT_NODE, nodeName, int(nodeIndex))) # now create type and context end steps context_parts = string.split(context_step, "*") node_type, nodeIndex = string.split(type_step, "*") nodeIndex = int(nodeIndex) if node_type == 'element': type_rstep = GenericStep(xml.dom.Node.ELEMENT_NODE, context_parts[0], nodeIndex) context_rstep = ElementEndStep(int(context_parts[1]), int(context_parts[2])) elif node_type == 'text': type_rstep = GenericStep(xml.dom.Node.TEXT_NODE, "#text", nodeIndex) words = [] for i in range(0, len(context_parts), 2): words.append((urllib.unquote(context_parts[i]), int(context_parts[i + 1]))) context_rstep = TextEndStep(words) elif node_type == 'empty': type_rstep = GenericStep(xml.dom.Node.TEXT_NODE, "#text", nodeIndex) context_rstep = EmptyTextEndStep() elif node_type == 'other': raise NodePathError, "Cannot handle other path elements yet." else: raise NodePathError, "Unknown step type in path: %s" % node_type rsteps.append(type_rstep) rsteps.append(context_rstep) # resolve the steps, starting with step 0 context = Context(0, rsteps) node, level = rsteps[0].resolve(context, top_node, 0) return node def create_steps(self, top_node, node): # first create last two steps parent = node.parentNode steps = self.create_end_steps(parent, node) node = parent # now create element steps while node is not top_node: parent = node.parentNode if parent is None: break steps.append(self.create_element_step(parent, node)) node = parent steps.reverse() return steps def create_end_steps(self, parent, node): nodeType = node.nodeType if nodeType == node.ELEMENT_NODE: return ['%s*%s*%s' % (node.nodeName, len(node.attributes), len(node.childNodes)), 'element*%s' % parent.childNodes.index(node) ] elif nodeType == node.TEXT_NODE: if string.strip(node.data) == '': return ['empty', 'empty*%s' % parent.childNodes.index(node)] else: return [string.join(get_words_sample(node.data), "*"), 'text*%s' % parent.childNodes.index(node)] else: # FIXME: simplistic way to deal with other nodes return ['%s' % node.nodeType, 'other*%s' % parent.childNodes.index(node)] def create_element_step(self, parent, node): return "%s*%s" % (node.nodeName, parent.childNodes.index(node)) class Context: threshold = 30 success_threshold = 10 offset_unreliability = 3 tree_skip_unreliability = 3 step_skip_unreliability = 3 word_max_distance = 7 word_offset_unreliability = 2 def __init__(self, i, steps): self._i = i self._steps = steps def resolve_next(self, node, level): steps = self._steps i = self._i + 1 if i < len(steps): # prepare new context for next step context = Context(i, steps) # resolve the next step return steps[i].resolve(context, node, level) else: return node, level class GenericStep: def __init__(self, nodeType, nodeName, index): self._nodeType = nodeType self._nodeName = nodeName self._index = index def resolve(self, context, node, level): nodeType = self._nodeType nodeName = self._nodeName i = self._index childNodes = node.childNodes l = len(childNodes) results = [] # try if the indicate node is the one, if so, return it if i < l: current = childNodes[i] if (current.nodeType == nodeType and current.nodeName == nodeName): current_node, current_unreliability = context.resolve_next( current, level) if current_unreliability < context.success_threshold: return current_node, current_unreliability results.append((current_node, current_unreliability)) # we need to go forward and backward from position i forward_i = i + 1 backward_i = i - 1 can_go_forward = can_go_backward = 1 else: # i is beyond length, so we need to go backward from end backward_i = l - 1 forward_i = l can_go_forward = 0 can_go_backward = 1 # try nodes forward and backward of this one unreliability = level + context.offset_unreliability while ((can_go_forward or can_go_backward) and unreliability < context.threshold): if forward_i < l: current = childNodes[forward_i] if (current.nodeType == nodeType and current.nodeName == nodeName): current_node, current_unreliability = context.resolve_next( current, unreliability) if current_unreliability < context.success_threshold: return current_node, current_unreliability results.append((current_node, current_unreliability)) forward_i = forward_i + 1 else: can_go_forward = 0 if backward_i >= 0: current = childNodes[backward_i] if (current.nodeType == nodeType and current.nodeName == nodeName): current_node, current_unreliability = context.resolve_next( current, unreliability) if current_unreliability < context.success_threshold: return current_node, current_unreliability results.append((current_node, current_unreliability)) backward_i = backward_i - 1 else: can_go_backward = 0 unreliability = unreliability + context.offset_unreliability # try skipping level in the tree unreliability = level + context.tree_skip_unreliability if unreliability < context.threshold: for current in childNodes: # use same step but with next nodes current_node, current_unreliability = self.resolve( context, current, unreliability) if current_unreliability < context.success_threshold: return current_node, current_unreliability results.append((current_node, current_unreliability)) # try skipping this step # use same node but with next step unreliability = level + context.step_skip_unreliability if unreliability < context.threshold: current_node, current_unreliability = context.resolve_next( node, unreliability) if current_unreliability < context.success_threshold: return current_node, current_unreliability results.append((current_node, current_unreliability)) # no immediate success, so try the best branch best_unreliability = context.threshold best_node = None for found_node, found_unreliability in results: if found_unreliability < best_unreliability: best_unreliability = found_unreliability best_node = found_node return best_node, best_unreliability class ElementEndStep: """Not very robust, but representable in a url pretty easily. """ def __init__(self, attributeAmount, childAmount): self._attributeAmount = attributeAmount self._childAmount = childAmount def resolve(self, context, node, level): if node.nodeType != node.ELEMENT_NODE: return None, context.threshold if (len(node.attributes) != self._attributeAmount or len(node.childNodes) != self._childAmount): return None, context.threshold return node, level class EmptyTextEndStep: def resolve(self, context, node, level): if node.nodeType != node.TEXT_NODE: return None, context.threshold if string.strip(node.data) == "": return node, level return None, context.threshold class TextEndStep: def __init__(self, words): self._words = words def resolve(self, context, node, level): if node.nodeType != node.TEXT_NODE: return None, context.threshold words = string.split(node.data) if len(words) == 0: return None, context.threshold unreliability = level for word, nr in self._words: unreliability = unreliability + ( find_word_distance(words, word, nr, context.word_max_distance) * context.word_offset_unreliability ) if unreliability >= context.threshold: return None, context.threshold return node, unreliability def find_word_distance(words, word, i, max_distance): """Find distance of word in words from expected location i. If word could not be found or is further than max_distance, return -1. """ try: if words[i] == word: return 0 except IndexError: l = len(words) distance = i - l + 1 forward_i = l backward_i = l - 1 can_go_forward = 0 can_go_backward = 1 else: l = len(words) distance = 1 forward_i = i + 1 backward_i = i - 1 can_go_forward = can_go_backward = 1 while (can_go_forward or can_go_backward) and (distance < max_distance): if forward_i < l: if words[forward_i] == word: return distance forward_i = forward_i + 1 else: can_go_forward = 0 if backward_i >= 0: if words[backward_i] == word: return distance backward_i = backward_i - 1 else: can_go_backward = 0 distance = distance + 1 return max_distance def get_words_sample(text, words_amount=words_amount, quote=urllib.quote): words = string.split(text) result = [] if len(words) <= words_amount: # get all words if there are only a few for i in range(len(words)): # don't add any words with separator in it, so as not to confuse if "*" not in words[i] and "," not in words[i]: qword = quote(words[i]) result.append(qword + "*" + str(i)) else: # otherwise, take a random sample of words from the text nrs = [] l = len(words) - 1 for i in range(words_amount): while 1: r = random.randint(0, l) # if we selected new word from sample, done # NOTE: would introduce subtle bug if we checked for # * or , here if r not in nrs: break nrs.append(r) nrs.sort() for nr in nrs: # don't want any word with separator in it if "*" not in words[nr] and "," not in words[nr]: qword = quote(words[nr]) result.append(qword + "*" + str(nr)) return result ParsedXML/NodePath/__init__.py0100644000175200017500000000041507404477171016154 0ustar faasseninfraeimport NodePath, RobustPath, ElementIdPath from NodePath import registry, BaseNodePathScheme registry.register_scheme(NodePath.ChildNodePathScheme()) registry.register_scheme(RobustPath.RobustPathScheme()) registry.register_scheme(ElementIdPath.ElementIdPathScheme()) ParsedXML/help/0040755000175200017500000000000007600634637013274 5ustar faasseninfraeParsedXML/help/ExtraDOM.py0100644000175200017500000001024607243333032015255 0ustar faasseninfrae############################################################################## # # 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. # ############################################################################## """ Non-DOM helper functions. Useful when working with either of our DOM implementations, but not specific to any instantiation. """ def parseFile(node, file, namespaces = 1): """ Parse XML file, replace node with the resulting tree, return replacement. Node must be in an existing DOM tree if not a Document. """ def writeStream(node, stream = None, encoding = None): "Write the XML representation of node to stream." ParsedXML/help/Core.py0100644000175200017500000001002207243333032014512 0ustar faasseninfrae############################################################################## # # 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 Level 2 Core classes. Classes and interfaces are made available according to the Python language mapping for the IDL interfaces described by the DOM recommendation; see for the mapping specification and for the IDL interfaces. """ ParsedXML/help/ExpatBuilder.py0100644000175200017500000001033207243333032016216 0ustar faasseninfrae############################################################################## # # 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. # ############################################################################## """ XML to DOM building methods using Expat. """ def parse(file, namespaces=1): """Parse a document, returning the resulting Document node. 'file' may be either a file name or an open file object. """ def parseFragment(file, context, namespaces=1): """Parse a fragment of a document, given the context from which it was originally extracted. context should be the parent of the node(s) which are in the fragment. 'file' may be either a file name or an open file object. """ ParsedXML/help/ManageableDOM.py0100644000175200017500000001566407243333032016217 0ustar faasseninfrae############################################################################## # # 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 proxying classes which provide Zope support. """ class DOMPublishable: "Mixin class for DOM classes to provide Zope publishability." def tpURL(self): """ Return a string used for an URL relative to parent. Used by the dtml-tree tag. """ def tpValues(self): "Return a list of immediate subobjects. Used by the dtml-tree tag." def tpId(self): "Return a value to be used as an id in tree state." def __getitem__(self, key): "" def manage_FTPget(self): """Returns the source content of an object. For example, the source text of a Document, or the data of a file.""" class DOMIO: "Mixin class for DOM classes to provide parsing, writing." def writeStream(self, stream = None, encoding = None): "Write the XML representation of this object to stream." def __str__(self): "Return the XML representation of this object." def get_size(self): "Size of this tree or subtree in bytes." def index_html(self, REQUEST, RESPONSE): "Returns publishable raw XML source" def parseXML(self, file): "Parse file as XML, replace myself with the resulting tree." class DOMManageable: "Mixin class for DOM classes to provide Zope management interfaces." def manage_edit(self, data, title = '', SUBMIT = 'Change', dtpref_cols = '50', dtpref_rows = '20', REQUEST = None): """ If SUBMIT is a size pref variable, handle a textarea size change. Otherwise parse the given text and handle the result. """ def manage_upload(self, file, REQUEST=None): "Parse the given file and handle the result." class ManageableWrapper: """ Mixin class to go alongside ManageableNode classes. Provides the wrapDOMObj function to create ManageableNode classes. """ def wrapDOMObj(self, node): "Return the appropriate manageable class wrapped around the Node." class ManageableDOMImplementation: """ A proxy of a DOMImplementation node that defines createDocument to return a ManageableDocument. """ class ManageableNode: "A wrapper around a DOM Node." class ManageableNodeList: "A wrapper around a DOM NodeList." class ManageableNamedNodeMap: "A wrapper around a DOM NamedNodeMap." class ManageableDocumentFragment: "A wrapper around a DOM DocumentFragment." class ManageableElement: "A wrapper around a DOM Element." class ManageableCharacterData: "A wrapper around a DOM CharacterData." class ManageableCDATASection: "A wrapper around a DOM CDATASection." class ManageableText: "A wrapper around a DOM Text." class ManageableComment: "A wrapper around a DOM Comment." class ManageableProcessingInstruction: "A wrapper around a DOM ProcessingInstruction." class ManageableAttr: "A wrapper around a DOM Attr." class ManageableDocument: "A wrapper around a DOM Document." class ManageableEntityReference: "A wrapper around a DOM EntityReference." class ManageableEntity: "A wrapper around a DOM Entity." class ManageableNotation: "A wrapper around a DOM Notation." class ManageableDocumentType: "A wrapper around a DOM DocumentType." ParsedXML/help/ParsedXML0100644000175200017500000000032607235672456015021 0ustar faasseninfraeParsedXML: Store XML as DOM objects Description ParsedXML products are DOM storage objects that support input and output in XML format, as well as DOM editing and discovery methods. ParsedXML/help/ParsedXML.stx0100644000175200017500000000101207236370145015616 0ustar faasseninfraeParsedXML: Store XML as DOM objects Description Parsed XML products are DOM storage objects that support input and output in XML format, as well as DOM editing and discovery methods. Parsed XML nodes are URL addressable, as are the argumentless DOM methods, and editable as XML. For more information, see the README file included with the distribution, or visit the Parsed XML "wiki":http://www.zope.org/Wikis/DevSite/Projects/ParsedXML. ParsedXML/help/ParsedXML_DOM.stx0100644000175200017500000000050007243065543016317 0ustar faasseninfraeParsdXML - DOM: View DOM tree Description This view shows the tree of DOM nodes that is rooted at this node. Clicking on a node will bring you to its management screen. At the top of the screen is a clickable "breadcrumbs" style path with links to ancestors of this node. ParsedXML/help/ParsedXML_Edit.stx0100644000175200017500000000357307251013566016577 0ustar faasseninfraeParsedXML - Edit: Edit and Upload XML Description This view allows you to alter the tree at a particular node by either editing the XML source or replacing the XML source with an uploaded file. An XML representation of the DOM tree is presented in a textarea. When the "Change" button is pressed, the XML in the textarea is parsed. Alternately, you can select a file from your local computer. When it is uploaded, it will be parsed. If the parse succeeds, the node that is being edited will be replaced with the parsed tree. If the parse fails, you will be presented with an error message. Note that because the storage uses DOM objects, rather than XML strings, the XML output after parsing may not be exactly the XML input, although it will be functionally the same and will follow the XML Infoset specification. The title, content type, and namespace usage are displayed. These values can be changed if the view is being displayed by the persistent version of the document, and not a transient version - currently, navigating to the top node using ownerDocument DOM calls reaches the persistent document. The title is the Zope title and does not affect the source. The content type will be returned by the HTTP server with the default publishing view index_html; receiving agents can act on this. A content type ending in "/html" will also cause index_html to use the HTML format. This doesn't affect the document content, just the rendering. Differences in HTML and XML formats are described at the "HTML Compatibility Guidelines":"http://www.w3.org/TR/xhtml1/#guidelines" Namespace usage affects which DOM calls are useful and which names are legal.ParsedXML/help/ParsedXML_Raw.stx0100644000175200017500000000053207236370145016435 0ustar faasseninfraeParsedXML - Raw: Download unformatted XML Description Clicking on the Raw tab will send the XML source for that node to your browser, unformatted, with a content-type of 'text/xml'. This is also the index_html method, so navigating to a node without a different view will also download the source.ParsedXML/help/ParsedXML_Security.stx0100644000175200017500000000057007236370145017515 0ustar faasseninfraeParsedXML - Security: About security settings for Parsed XML Description All Parsed XML security is handled by the document. Security settings for subnodes will be acquired from the document. The "Access contents information" setting will determine who can access DOM methods, including the ability to traverse to subnodes. ParsedXML/help/ParsedXML_URLTraversal.stx0100644000175200017500000000111107236370145020224 0ustar faasseninfraeParsedXML - URLTraversal: About URL accessibility of Parsed XML objects Description Currently, traversal uses an element's index within its parent as an URL key. For example, 'http://server/myDoc/0/2/mymethod' This URL traverses from an XML Document object with id 'myDoc' to it's first sub-element, to that element's second sub-element, and then to an acquired method with id 'myMethod' DOM methods can also be used in URLs, for example, 'http://server/myDoc/firstChild/nextSibling/mymethod' ParsedXML/help/ParsedXML_Upload.stx0100644000175200017500000000065207266643410017134 0ustar faasseninfraeParsedXML - Upload: Upload XML Description This view allows you to upload XML source at a particular node. A file can be chosen from your local computer. When it is uploaded, it will be parsed. If the parse succeeds, the node that the upload is calle on will be replaced with the parsed tree. If the parse fails, you will be presented with an error message. ParsedXML/help/Printer.py0100644000175200017500000001046307243333032015256 0ustar faasseninfrae############################################################################## # # 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. # ############################################################################## # # Specifically, most of this code is from PyXML's xml.dom.ext.Printer. # See LICENSE.Fourthought. # """ Printing and XML generating support for DOM classes. """ class Visitor: """A class to visit an entire tree according to a TreeWalker.""" def __init__(self, root, stream, encoding, whatToShow, filter, entityReferenceExpansion): "Init the walker." def visitWhole(self): "Visit the entire tree rooted at our current node." class PrintVisitor(Visitor): """A class to generate XML for a tree according to a TreeWalker""" ParsedXML/help/Traversal.py0100644000175200017500000001002707243333032015572 0ustar faasseninfrae############################################################################## # # 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 Level 2 Traversal classes. Classes and interfaces are made available according to the Python language mapping for the IDL interfaces described by the DOM recommendation; see for the mapping specification and for the IDL interfaces. """ ParsedXML/help/XMLExtended.py0100644000175200017500000001003307243333032015745 0ustar faasseninfrae############################################################################## # # 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 Level 2 Core extended classes. Classes and interfaces are made available according to the Python language mapping for the IDL interfaces described by the DOM recommendation; see for the mapping specification and for the IDL interfaces. """ ParsedXML/tests/0040755000175200017500000000000007600634640013500 5ustar faasseninfraeParsedXML/tests/domapi/0040755000175200017500000000000007600634637014757 5ustar faasseninfraeParsedXML/tests/domapi/CoreLvl1.py0100644000175200017500000026032007274131366016756 0ustar faasseninfrae############################################################################## # # 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. # ############################################################################## from Base import * import string import xml.dom from xml.dom import Node # --- DOMImplementation class DOMImplementationReadTestCase(TestCaseBase): def setUp(self): # self.implementation is already set. pass # Combinations to feed to the hasFeature method; some of these will always # return false, of course. # ('Core', '1.0') was never defined for DOM level 1, it was implicit. Most # DOM level 2 implementations return true, but this is a courtesy. featureMatrix = ( ('Core', None), #('Core', '1.0'), ('Core', '2.0'), ('Core', '3.0'), ('XML', None), ('XML', '1.0'), ('XML', '2.0'), ('XML', '3.0'), ('Traversal', None), ('Traversal', '1.0'), ('Traversal', '2.0'), ('Traversal', '3.0'), ('BogusFeature', None), ('BogusFeature', '1.0'), ('BogusFeature', '2.0'), ('BogusFeature', '3.0'), ) def checkHasFeature(self): impl = self.implementation for feature, level in self.featureMatrix: result1 = impl.hasFeature(feature, level) result2 = impl.hasFeature(string.upper(feature), level) result3 = impl.hasFeature(string.lower(feature), level) expect = ((feature, level) in self.supportedFeatures) assert result1 == result2 and result1 == result3, ( "Different results from different case feature string.") assert (result1 and 1 or 0) == expect, ( "Test for %s, version %s should have returned %s, " "returned %s" % (repr(feature), repr(level), repr(expect), repr(result1))) # --- Node class NodeReadTestCaseBase(TestCaseBase): nodeTypes = ( 'ATTRIBUTE_NODE', 'CDATA_SECTION_NODE', 'COMMENT_NODE', 'DOCUMENT_FRAGMENT_NODE', 'DOCUMENT_NODE', 'DOCUMENT_TYPE_NODE', 'ELEMENT_NODE', 'ENTITY_NODE', 'ENTITY_REFERENCE_NODE', 'NOTATION_NODE', 'PROCESSING_INSTRUCTION_NODE', 'TEXT_NODE', ) def checkNodeTypeConstants(self): for type in self.nodeTypes: checkAttribute(self.node, type, getattr(Node, type)) def checkAttributes(self): if self.node.nodeType == Node.ELEMENT_NODE: checkLength(self.node.attributes, 0) else: checkAttribute(self.node, 'attributes', None) checkReadOnly(self.node, 'attributes') def checkChildNodes(self): if self.node.nodeType in (Node.ATTRIBUTE_NODE, Node.DOCUMENT_NODE, Node.ENTITY_NODE): expectedLength = 1 else: expectedLength = 0 checkLength(self.node.childNodes, expectedLength) checkReadOnly(self.node, 'childNodes') def checkFirstChild(self): # The following node types are expected to have one childNode. if self.node.nodeType not in (Node.ATTRIBUTE_NODE, Node.DOCUMENT_NODE, Node.ENTITY_NODE): expected = None else: expected = self.node.childNodes[0] checkAttributeSameNode(self.node, 'firstChild', expected) checkReadOnly(self.node, 'firstChild') if expected: checkAttributeSameNode(self.node.firstChild, 'parentNode', self.node) def checkLastChild(self): # The following node types are expected to have one childNode. if self.node.nodeType not in (Node.ATTRIBUTE_NODE, Node.DOCUMENT_NODE, Node.ENTITY_NODE): expected = None else: expected = self.node.childNodes[0] checkAttributeSameNode(self.node, 'lastChild', expected) checkReadOnly(self.node, 'lastChild') if expected: checkAttributeSameNode(self.node.lastChild, 'parentNode', self.node) def checkNextSibling(self): checkAttribute(self.node, 'nextSibling', None) checkReadOnly(self.node, 'nextSibling') nodeNameMap = { Node.CDATA_SECTION_NODE: '#cdata-section', Node.COMMENT_NODE: '#comment', Node.DOCUMENT_NODE: '#document', Node.DOCUMENT_FRAGMENT_NODE: '#document-fragment', Node.TEXT_NODE: '#text', } def checkNodeName(self): if self.node.nodeType in (Node.ATTRIBUTE_NODE, Node.DOCUMENT_TYPE_NODE): expected = self.node.name elif self.node.nodeType == Node.ELEMENT_NODE: expected = self.node.tagName elif self.node.nodeType in (Node.ENTITY_NODE, Node.ENTITY_REFERENCE_NODE, Node.NOTATION_NODE): expected = self.expectedNodeName elif self.node.nodeType == Node.PROCESSING_INSTRUCTION_NODE: expected = self.node.target else: expected = self.nodeNameMap[self.node.nodeType] checkAttribute(self.node, 'nodeName', expected) checkReadOnly(self.node, "nodeName") def checkNodeType(self): checkAttribute(self.node, 'nodeType', self.expectedType) checkReadOnly(self.node, "nodeType") emptyNodeValueList = ( Node.DOCUMENT_FRAGMENT_NODE, Node.DOCUMENT_NODE, Node.DOCUMENT_TYPE_NODE, Node.ELEMENT_NODE, Node.ENTITY_NODE, Node.ENTITY_REFERENCE_NODE, Node.NOTATION_NODE, ) def checkNodeValue(self): if self.node.nodeType in self.emptyNodeValueList: expected = None elif self.node.nodeType in (Node.CDATA_SECTION_NODE, Node.COMMENT_NODE, Node.TEXT_NODE, Node.PROCESSING_INSTRUCTION_NODE): expected = self.node.data elif self.node.nodeType == Node.ATTRIBUTE_NODE: expected = self.node.value checkAttribute(self.node, 'nodeValue', expected) def checkParentNode(self): checkAttribute(self.node, 'parentNode', None) checkReadOnly(self.node, 'parentNode') def checkPreviousSibling(self): checkAttribute(self.node, 'previousSibling', None) checkReadOnly(self.node, 'previousSibling') def hasChildNodes(self): if self.node.nodeType in (Node.ATTRIBUTE_NODE, Node.DOCUMENT_NODE, Node.ENTITY_NODE): expectTrue = 1 else: expectTrue = 0 if expectTrue: assert self.node.hasChildNodes(), \ "hasChildNodes returned 'false' when 'true' was expected." else: assert not self.node.hasChildNodes(), \ "hasChildNodes returned 'true' when 'false' was expected." class NodeWriteTestCaseBase(TestCaseBase): TEST_NAME = 'somename' emptyNodeValueList = NodeReadTestCaseBase.emptyNodeValueList readOnlyNodeList = ( Node.ENTITY_NODE, Node.ENTITY_REFERENCE_NODE, Node.NOTATION_NODE, ) def checkNodeValue(self): # Nodetypes that are read-only. if self.node.nodeType in self.readOnlyNodeList: checkReadOnly(self.node, 'nodeValue') return # Nodetypes that should ignore changes. if self.node.nodeType in self.emptyNodeValueList: self.node.nodeValue = "Ignore this." checkAttribute(self.node, "nodeValue", None) return # Nodetypes where nodeValue is an alias. if self.node.nodeType in (Node.CDATA_SECTION_NODE, Node.COMMENT_NODE, Node.TEXT_NODE, Node.PROCESSING_INSTRUCTION_NODE): alias = 'data' elif self.node.nodeType == Node.ATTRIBUTE_NODE: alias = 'value' self.node.nodeValue = 'foo' checkAttribute(self.node, 'nodeValue', 'foo') checkAttribute(self.node, alias, 'foo') allowedChildrenMap = { Node.DOCUMENT_NODE: ( Node.ELEMENT_NODE, # Maximum of one, special case Node.PROCESSING_INSTRUCTION_NODE, Node.COMMENT_NODE, Node.DOCUMENT_TYPE_NODE, # Maximum of one, special case ), Node.DOCUMENT_FRAGMENT_NODE: ( Node.ELEMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE, Node.COMMENT_NODE, Node.TEXT_NODE, Node.CDATA_SECTION_NODE, Node.ENTITY_REFERENCE_NODE, ), Node.DOCUMENT_TYPE_NODE: (), Node.ENTITY_REFERENCE_NODE: ( Node.ELEMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE, Node.COMMENT_NODE, Node.TEXT_NODE, Node.CDATA_SECTION_NODE, Node.ENTITY_REFERENCE_NODE, ), Node.ELEMENT_NODE: ( Node.ELEMENT_NODE, Node.TEXT_NODE, Node.COMMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE, Node.CDATA_SECTION_NODE, Node.ENTITY_REFERENCE_NODE, ), Node.ATTRIBUTE_NODE: ( Node.TEXT_NODE, Node.ENTITY_REFERENCE_NODE, ), Node.PROCESSING_INSTRUCTION_NODE: (), Node.COMMENT_NODE: (), Node.TEXT_NODE: (), Node.CDATA_SECTION_NODE: (), Node.ENTITY_NODE: ( Node.ELEMENT_NODE, Node.PROCESSING_INSTRUCTION_NODE, Node.COMMENT_NODE, Node.TEXT_NODE, Node.CDATA_SECTION_NODE, Node.ENTITY_REFERENCE_NODE, ), Node.NOTATION_NODE: (), } nodeCreateMap = { # from Document 'createAttribute': ('anAttr',), 'createCDATASection': ('a CDATA Section',), 'createComment': ('a Comment',), 'createDocumentFragment': (), 'createElement': ('anElement',), 'createEntityReference': ('anEntityReference',), 'createProcessingInstruction': ('aPI', 'data for PI'), 'createTextNode': ('A Text Node',), # From DOMImplementation (marked as tuples) ('createDocument',): (None, 'aDocument', None), ('createDocumentType',): ('aDocType', 'uri:public', 'uri:system'), } def checkAppendChild(self): allowedChildren = self.allowedChildrenMap[self.node.nodeType] if self.node.nodeType == Node.DOCUMENT_NODE: # To create a better test for Document Nodes, we remove the # documentElement Node. self.node.removeChild(self.node.documentElement) # Since appending a Document Type Node to a Document Node isn't # allowed, we remove it from the allowed children list for now. allowedChildren = allowedChildren[:-1] # We add Document Fragment to the list if any child is allowed. Document # Fragments can also hold such children. This test only adds empty # Document Fragments. if allowedChildren: allowedChildren = allowedChildren + (Node.DOCUMENT_FRAGMENT_NODE,) for factoryMethod, factoryArgs in self.nodeCreateMap.items(): if type(factoryMethod) is type(()): # DOMImplementation methods factory = self.implementation factoryMethod = factoryMethod[0] else: factory = self.document newNode = apply(getattr(factory, factoryMethod), factoryArgs) numberOfChildren = self.node.childNodes.length try: # We append two different copies to see how we fare. Esp. handy # with testing the restrictions of a Document Node returnedNode = self.node.appendChild(newNode) newNode = apply(getattr(factory, factoryMethod), factoryArgs) returnedNode = self.node.appendChild(newNode) except xml.dom.HierarchyRequestErr: if self.node.nodeType == Node.DOCUMENT_NODE: if newNode.nodeType == Node.ELEMENT_NODE: assert self.node.documentElement, ( "Couldn't add a Element node to an empty Document." ) else: # tried to append nonElement to a Document node assert newNode.nodeType not in allowedChildren, ( "Couldn't append a %s Node." % TYPE_NAME[ newNode.nodeType]) else: # tried to append a node to a nonDocument node assert newNode.nodeType not in allowedChildren, ( "Couldn't append a %s Node." % TYPE_NAME[ newNode.nodeType]) except xml.dom.NoModificationAllowedErr: assert self.node.nodeType in self.readOnlyNodeList, ( "Claim of read-only-ness on a modifiable node. " "Tried to append a %s Node" % TYPE_NAME[newNode.nodeType] ) else: if newNode.nodeType != Node.DOCUMENT_FRAGMENT_NODE: assert isSameNode(newNode, returnedNode), ( "Returned Node is not the same as has been added.") checkAttributeSameNode(self.node, 'lastChild', newNode) checkLength(self.node.childNodes, numberOfChildren + 2) else: checkLength(self.node.childNodes, numberOfChildren) assert newNode.nodeType in allowedChildren, ( "Was allowed to append a %s Node." % TYPE_NAME[ newNode.nodeType]) assert self.node.nodeType not in self.readOnlyNodeList, ( "Was allowed to append a %s Node to a read-only Node" % ( TYPE_NAME[newNode.nodeType])) def checkAppendChildForeignNode(self): allowedChildren = self.allowedChildrenMap[self.node.nodeType] # No use when no children are allowed or read-only if not allowedChildren or self.node.nodeType in self.readOnlyNodeList: return foreignDoc = self.implementation.createDocument(None, 'anotherDoc', None) if Node.TEXT_NODE in allowedChildren: foreignNode = foreignDoc.createTextNode('a Text Node') else: foreignNode = foreignDoc.createComment('a Comment Node') try: self.node.appendChild(foreignNode) except xml.dom.WrongDocumentErr: pass else: assert 0, ( "Allowed to add %s Node from a foreign Document." % TYPE_NAME[foreignNode.nodeType]) def checkAppendChildAncestorNode(self): if self.node.nodeType in self.readOnlyNodeList: return if Node.ELEMENT_NODE not in self.allowedChildrenMap[self.node.nodeType]: return if self.node.nodeType not in self.allowedChildrenMap[Node.ELEMENT_NODE]: return ancestorNode = self.document.createElement('foo') ancestorNode.appendChild(self.node) try: self.node.appendChild(ancestorNode) except xml.dom.HierarchyRequestErr: pass else: assert 0, ( "Allowed to append ancestor Node to a %s Node." % TYPE_NAME[newNode.nodeType]) def checkAppendChildSelf(self): # See DOM erratum core-6 if self.node.nodeType in self.readOnlyNodeList: return if self.node.nodeType not in self.allowedChildrenMap[ self.node.nodeType]: return try: self.node.appendChild(self.node) except xml.dom.HierarchyRequestErr: pass else: assert 0, ( "Allowed to append the Node to itself." % TYPE_NAME[newNode.nodeType]) def checkAppendChildWithAttachedNode(self): # Test appending a Node that itself is part of a tree allowedChildren = self.allowedChildrenMap[self.node.nodeType] # No use when no children are allowed or read-only if not allowedChildren or self.node.nodeType in self.readOnlyNodeList: return if Node.TEXT_NODE in allowedChildren: newNode = self.document.createTextNode('a Text Node') else: newNode = self.document.createComment('a Comment Node') oldParent = self.document.createElement('aParentElement') oldParent.appendChild(newNode) self.node.appendChild(newNode) assert not oldParent.hasChildNodes(), ( "Appended Node not removed from previous parent.") def checkAppendChildNodeParentReadOnly(self): # See DOM erratum core-2 http://www.w3.org/2000/11/DOM-Level-2-errata if self.node.nodeType in self.readOnlyNodeList: return if Node.TEXT_NODE not in self.allowedChildrenMap[self.node.nodeType]: return if self.node.nodeType in [Node.DOCUMENT_NODE, Node.DOCUMENT_TYPE_NODE]: return # can't import doc = self.parse(""" ]> """) # This Text Node has a read-only parent. textNode = doc.doctype.entities.getNamedItem('entity').firstChild # we need self.node to have the same doc as textNode self.node = doc.importNode(self.node, 1) try: self.node.appendChild(textNode) except xml.dom.NoModificationAllowedErr: pass else: assert 0, ( "Was allowed to append a Node from a read-only tree.") def checkRemoveChild(self): if self.node.nodeType in self.readOnlyNodeList: if self.node.hasChildNodes(): # Test for read-only try: self.node.removeChild(self.node.firstChild) except xml.dom.NoModificationAllowedErr: pass else: assert 0, "Removed child from read-only Node." return # If this is a Document Node, let's try and remove the doctype. # We actually test this when we have a doctype, as the Document Node # created for the Document Node tests doesn't *have* a doctype. if self.node.nodeType == Node.DOCUMENT_TYPE_NODE: doc = self.implementation.createDocument('', 'foo', self.node) try: doc.removeChild(doc.doctype) except xml.dom.NotFoundErr: assert 0, ( "The doctype of a Document Node should also be a " "childNode of that Node.") except xml.dom.NoModificationAllowedErr: pass else: assert 0, ( "Was allowed to remove the doctype of a Document Node.") allowedChildren = self.allowedChildrenMap[self.node.nodeType] # No use when no children are allowed if not allowedChildren: return if Node.TEXT_NODE in allowedChildren: newNode = self.document.createTextNode('a Text Node') else: newNode = self.document.createComment('a Comment Node') self.node.appendChild(newNode) returnedNode = self.node.removeChild(newNode) assert isSameNode(newNode, returnedNode), ( "Returned Node is not the appended Node.") checkAttribute(newNode, "parentNode", None) checkAttribute(returnedNode, "parentNode", None) def checkRemoveChildNotFound(self): if self.node.nodeType in self.readOnlyNodeList: return loseNode = self.document.createTextNode('booh') try: self.node.removeChild(loseNode) except xml.dom.NotFoundErr: pass else: assert 0, "Removed a Node that was no longer a child node." def checkInsertBefore(self): if self.node.nodeType in self.readOnlyNodeList: if self.node.hasChildNodes(): # Test for read-only newNode = self.document.createTextNode('a Text Node') try: self.node.insertBefore(newNode, self.node.firstChild) except xml.dom.NoModificationAllowedErr: pass else: assert 0, "Allowed to insert Node into read-only Node." return allowedChildren = self.allowedChildrenMap[self.node.nodeType] if self.node.nodeType == Node.DOCUMENT_NODE: # To create a better test for Document Nodes, we remove the # documentElement Node. self.node.removeChild(self.node.documentElement) # Since inserting a Document Type Node into a Document Node isn't # allowed, we remove it from the allowed children list for now. allowedChildren = allowedChildren[:-1] # No use when no children are allowed. if not allowedChildren: return else: # Append DOCUMENT_FRAGMENT to alowed, because we'll add an empty # fragment. allowedChildren = allowedChildren + (Node.DOCUMENT_FRAGMENT_NODE,) if Node.TEXT_NODE in allowedChildren: refNode = self.document.createTextNode('a Text Node') else: refNode = self.document.createComment('a Comment Node') # Now create the reference to insert before. self.node.appendChild(refNode) for factoryMethod, factoryArgs in self.nodeCreateMap.items(): if type(factoryMethod) is type(()): # DOMImplementation methods factory = self.implementation factoryMethod = factoryMethod[0] else: factory = self.document newNode = apply(getattr(factory, factoryMethod), factoryArgs) numberOfChildren = self.node.childNodes.length try: returnedNode = self.node.insertBefore(newNode, refNode) except xml.dom.HierarchyRequestErr: if self.node.nodeType == Node.DOCUMENT_NODE: if newNode.nodeType == Node.ELEMENT_NODE: assert self.node.documentElement, ( "Couldn't add a Element node to an empty Document." ) assert newNode.nodeType not in allowedChildren, ( "Couldn't append a %s Node." % TYPE_NAME[ newNode.nodeType]) except xml.dom.NoModificationAllowedErr: assert self.node.nodeType in self.readOnlyNodeList, ( "Claim of read-only-ness on a modifiable node. " "Tried to append a %s Node" % TYPE_NAME[self.node.nodeType] ) else: if newNode.nodeType != Node.DOCUMENT_FRAGMENT_NODE: assert isSameNode(newNode, returnedNode), ( "Returned Node is not the same as has been added.") checkAttributeSameNode(newNode, 'nextSibling', refNode) checkAttributeSameNode(refNode, 'previousSibling', newNode) checkLength(self.node.childNodes, numberOfChildren + 1) else: checkLength(self.node.childNodes, numberOfChildren) assert newNode.nodeType in allowedChildren, ( "Was allowed to insert a %s Node." % TYPE_NAME[ newNode.nodeType]) def checkInsertBeforeNotFound(self): allowedChildren = self.allowedChildrenMap[self.node.nodeType] # No use when no children are allowed or read-only if not allowedChildren or self.node.nodeType in self.readOnlyNodeList: return if Node.TEXT_NODE in allowedChildren: refNode = self.document.createTextNode('a Text Node') else: refNode = self.document.createComment('a Comment Node') try: self.node.insertBefore(refNode, refNode.cloneNode(0)) except xml.dom.NotFoundErr: pass else: assert 0, "Inserted Node using a document-less Node as reference." def checkInsertBeforeExtraElementToDocument(self): if self.node.nodeType == Node.DOCUMENT_NODE: newNode = self.document.createElement('foo') try: self.node.insertBefore(newNode, self.node.documentElement) except xml.dom.HierarchyRequestErr: pass else: assert 0, ( "Was allowed to insert a second Element into a Document " "Node.") def checkInsertBeforeForeignNode(self): allowedChildren = self.allowedChildrenMap[self.node.nodeType] # No use when no children are allowed or read-only if not allowedChildren or self.node.nodeType in self.readOnlyNodeList: return foreignDoc = self.implementation.createDocument(None, 'anotherDoc', None) if Node.TEXT_NODE in allowedChildren: refNode = self.document.createTextNode('a Text Node') foreignNode = foreignDoc.createTextNode('a Text Node') else: refNode = self.document.createComment('a Comment Node') foreignNode = foreignDoc.createComment('a Comment Node') self.node.appendChild(refNode) try: self.node.insertBefore(foreignNode, refNode) except xml.dom.WrongDocumentErr: pass else: assert 0, ( "Allowed to insert %s Node from a foreign Document." % TYPE_NAME[foreignNode.nodeType]) def checkInsertBeforeAncestorNode(self): if self.node.nodeType in self.readOnlyNodeList: return if Node.ELEMENT_NODE not in self.allowedChildrenMap[self.node.nodeType]: return if self.node.nodeType not in self.allowedChildrenMap[Node.ELEMENT_NODE]: return ancestorNode = self.document.createElement('foo') ancestorNode.appendChild(self.node) if Node.TEXT_NODE in self.allowedChildrenMap[self.node.nodeType]: refNode = self.document.createTextNode('a Text Node') else: refNode = self.document.createComment('a Comment Node') self.node.appendChild(refNode) try: self.node.insertBefore(ancestorNode, refNode) except xml.dom.HierarchyRequestErr: pass else: assert 0, ( "Allowed to insert ancestor Node into a %s Node." % TYPE_NAME[newNode.nodeType]) def checkInsertBeforeSelf(self): # See DOM erratum core-7 if self.node.nodeType in self.readOnlyNodeList: return if self.node.nodeType not in self.allowedChildrenMap[ self.node.nodeType]: return if Node.TEXT_NODE in self.allowedChildrenMap[self.node.nodeType]: refNode = self.document.createTextNode('a Text Node') else: refNode = self.document.createComment('a Comment Node') self.node.appendChild(refNode) try: self.node.insertBefore(self.node, refNode) except xml.dom.HierarchyRequestErr: pass else: assert 0, ( "Allowed to insert the Node into itself." % TYPE_NAME[newNode.nodeType]) def checkInsertBeforeWithAttachedNode(self): # Test appending a Node that itself is part of a tree allowedChildren = self.allowedChildrenMap[self.node.nodeType] # No use when no children are allowed or read-only if not allowedChildren or self.node.nodeType in self.readOnlyNodeList: return if Node.TEXT_NODE in allowedChildren: refNode = self.document.createTextNode('a Text Node') newNode = self.document.createTextNode('a Text Node') else: refNode = self.document.createComment('a Comment Node') newNode = self.document.createComment('a Comment Node') oldParent = self.document.createElement('aParentElement') oldParent.appendChild(newNode) self.node.appendChild(refNode) self.node.insertBefore(newNode, refNode) assert not oldParent.hasChildNodes(), ( "Appended Node not removed from previous parent.") def checkInsertBeforeNodeParentReadOnly(self): # See DOM erratum core-2 http://www.w3.org/2000/11/DOM-Level-2-errata if self.node.nodeType in self.readOnlyNodeList: return if Node.TEXT_NODE not in self.allowedChildrenMap[self.node.nodeType]: return if self.node.nodeType in [Node.DOCUMENT_NODE, Node.DOCUMENT_TYPE_NODE]: return # can't import doc = self.parse(""" ]> """) # This Text Node has a read-only parent. textNode = doc.doctype.entities.getNamedItem('entity').firstChild refNode = doc.createTextNode('a Text Node') # we need self.node to have the same doc as textNode self.node = doc.importNode(self.node, 1) self.node.appendChild(refNode) try: self.node.insertBefore(textNode, refNode) except xml.dom.NoModificationAllowedErr: pass else: assert 0, ( "Was allowed to insert a Node from a read-only tree.") def checkReplaceChild(self): if self.node.nodeType in self.readOnlyNodeList: if self.node.hasChildNodes(): # Test for read-only newNode = self.document.createTextNode('a Text Node') try: self.node.replaceChild(newNode, self.node.firstChild) except xml.dom.NoModificationAllowedErr: pass else: assert 0, "Allowed to replace childNode of read-only Node." return allowedChildren = self.allowedChildrenMap[self.node.nodeType] if self.node.nodeType == Node.DOCUMENT_NODE: # To create a better test for Document Nodes, we remove the # documentElement Node. self.node.removeChild(self.node.documentElement) # Since replacing with a Document Type Node on a Document Node isn't # allowed, we remove it from the allowed children list for now. allowedChildren = allowedChildren[:-1] # No use when no children are allowed. if not allowedChildren: return else: # Append DOCUMENT_FRAGMENT to alowed, because we'll use an empty # fragment. allowedChildren = allowedChildren + (Node.DOCUMENT_FRAGMENT_NODE,) if Node.TEXT_NODE in allowedChildren: refNode = self.document.createTextNode('a Text Node') else: refNode = self.document.createComment('a Comment Node') for factoryMethod, factoryArgs in self.nodeCreateMap.items(): if type(factoryMethod) is type(()): # DOMImplementation methods factory = self.implementation factoryMethod = factoryMethod[0] else: factory = self.document # Now create the reference to replace. We do this for every Node # type we try and replace with. self.node.appendChild(refNode) newNode = apply(getattr(factory, factoryMethod), factoryArgs) numberOfChildren = self.node.childNodes.length try: returnedNode = self.node.replaceChild(newNode, refNode) except xml.dom.HierarchyRequestErr: if self.node.nodeType == Node.DOCUMENT_NODE \ and newNode.nodeType == Node.ELEMENT_NODE: assert self.node.documentElement, \ "Couldn't add an Element node to an empty Document." assert newNode.nodeType not in allowedChildren, ( "Couldn't replace an old Node with a %s Node." % TYPE_NAME[ newNode.nodeType]) except xml.dom.NoModificationAllowedErr: assert self.node.nodeType in self.readOnlyNodeList, ( "Claim of read-only-ness on a modifiable node. " "Tried to replace an old Node with a %s Node" % TYPE_NAME[ self.node.nodeType] ) else: if newNode.nodeType != Node.DOCUMENT_FRAGMENT_NODE: assert isSameNode(refNode, returnedNode), ( "Returned Node is not the same as has been replaced.") checkAttributeSameNode(self.node, 'lastChild', newNode) checkLength(self.node.childNodes, numberOfChildren) assert isSameNode(refNode, returnedNode), ( "Returned Node is not the same as has been replaced.") else: checkLength(self.node.childNodes, numberOfChildren - 1) assert newNode.nodeType in allowedChildren, ( "Was allowed to replace an old Node with a " "%s Node." % TYPE_NAME[newNode.nodeType]) def checkReplaceChildNotFound(self): allowedChildren = self.allowedChildrenMap[self.node.nodeType] # No use when no children are allowed or read-only if not allowedChildren or self.node.nodeType in self.readOnlyNodeList: return if Node.TEXT_NODE in allowedChildren: refNode = self.document.createTextNode('a Text Node') else: refNode = self.document.createComment('a Comment Node') try: self.node.replaceChild(refNode, refNode.cloneNode(0)) except xml.dom.NotFoundErr: pass else: assert 0, "Replaced perentless Node (reference had no parent)." def checkReplaceChildExtraElementToDocument(self): if self.node.nodeType == Node.DOCUMENT_NODE: refNode = self.document.createComment('a Comment Node') self.node.appendChild(refNode) newNode = self.document.createElement('foo') try: self.node.replaceChild(newNode, refNode) except xml.dom.HierarchyRequestErr: pass else: assert 0, ( "Was allowed to replace an old Node with a second Element " "into a Document Node.") def checkReplaceChildForeignNode(self): allowedChildren = self.allowedChildrenMap[self.node.nodeType] # No use when no children are allowed or read-only if not allowedChildren or self.node.nodeType in self.readOnlyNodeList: return foreignDoc = self.implementation.createDocument(None, 'anotherDoc', None) if Node.TEXT_NODE in allowedChildren: refNode = self.document.createTextNode('a Text Node') foreignNode = foreignDoc.createTextNode('a Text Node') else: refNode = self.document.createComment('a Comment Node') foreignNode = foreignDoc.createComment('a Comment Node') self.node.appendChild(refNode) try: self.node.replaceChild(foreignNode, refNode) except xml.dom.WrongDocumentErr: pass else: assert 0, ( "Allowed to replace an old Node with a %s Node from a " "foreign Document." % TYPE_NAME[foreignNode.nodeType]) def checkReplaceChildAncestorNode(self): if self.node.nodeType in self.readOnlyNodeList: return if Node.ELEMENT_NODE not in self.allowedChildrenMap[self.node.nodeType]: return if self.node.nodeType not in self.allowedChildrenMap[Node.ELEMENT_NODE]: return ancestorNode = self.document.createElement('foo') ancestorNode.appendChild(self.node) if Node.TEXT_NODE in self.allowedChildrenMap[self.node.nodeType]: refNode = self.document.createTextNode('a Text Node') else: refNode = self.document.createComment('a Comment Node') self.node.appendChild(refNode) try: self.node.replaceChild(ancestorNode, refNode) except xml.dom.HierarchyRequestErr: pass else: assert 0, ( "Allowed to replace an old Node with a ancestor Node.") def checkReplaceChildSelf(self): # See DOM erratum core-8 if self.node.nodeType in self.readOnlyNodeList: return if self.node.nodeType not in self.allowedChildrenMap[ self.node.nodeType]: return if Node.TEXT_NODE in self.allowedChildrenMap[self.node.nodeType]: refNode = self.document.createTextNode('a Text Node') else: refNode = self.document.createComment('a Comment Node') self.node.appendChild(refNode) try: self.node.replaceChild(self.node, refNode) except xml.dom.HierarchyRequestErr: pass else: assert 0, ( "Allowed to replace an old child Node with the parent Node " "itself.") def checkReplaceChildWithAttachedNode(self): # Test replacing with a Node that itself is part of a tree allowedChildren = self.allowedChildrenMap[self.node.nodeType] # No use when no children are allowed or read-only if not allowedChildren or self.node.nodeType in self.readOnlyNodeList: return if Node.TEXT_NODE in allowedChildren: refNode = self.document.createTextNode('a Text Node') newNode = self.document.createTextNode('a Text Node') else: refNode = self.document.createComment('a Comment Node') newNode = self.document.createComment('a Comment Node') oldParent = self.document.createElement('aParentElement') oldParent.appendChild(newNode) self.node.appendChild(refNode) self.node.replaceChild(newNode, refNode) assert not oldParent.hasChildNodes(), ( "Replacing Node not removed from previous parent.") def checkReplaceChildNodeParentReadOnly(self): # See DOM erratum core-2 http://www.w3.org/2000/11/DOM-Level-2-errata if self.node.nodeType in self.readOnlyNodeList: return if Node.TEXT_NODE not in self.allowedChildrenMap[self.node.nodeType]: return if self.node.nodeType in [Node.DOCUMENT_NODE, Node.DOCUMENT_TYPE_NODE]: return # can't import doc = self.parse(""" ]> """) # This Text Node has a read-only parent. textNode = doc.doctype.entities.getNamedItem('entity').firstChild # we need self.node to have the same doc as textNode self.node = doc.importNode(self.node, 1) refNode = doc.createTextNode('a Text Node') self.node.appendChild(refNode) try: self.node.replaceChild(textNode, refNode) except xml.dom.NoModificationAllowedErr: pass else: assert 0, ( "Was allowed to replace a Node with a Node from a read-only " "tree.") # --- Document class DocumentReadTestCase(NodeReadTestCaseBase): def setUp(self): self.createDocument() self.node = self.document self.expectedType = Node.DOCUMENT_NODE def checkGetDoctype(self): checkAttribute(self.document, "doctype", None) checkReadOnly(self.document, "doctype") def checkGetImplementation(self): checkAttribute(self.document, "implementation", self.implementation) checkReadOnly(self.document, "implementation") def checkGetDocumentElement(self): checkAttributeNot(self.document, "documentElement", None) checkReadOnly(self.document, "documentElement") def checkCloneNode(self): # TODO: Implementation dependent, what should we test? pass class DocumentWriteTestCase(NodeWriteTestCaseBase): def setUp(self): self.node = self.createDocument() def checkGetElementsByTagName(self): doc = self.document elements = {} names = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'] for c in names: elements[c] = doc.createElement(c) # set up simple tree elements['a'].appendChild(elements['b']) elements['a'].appendChild(elements['d']) elements['b'].appendChild(elements['c']) elements['d'].appendChild(elements['e']) elements['d'].appendChild(elements['h']) elements['e'].appendChild(elements['f']) elements['e'].appendChild(elements['g']) elements['h'].appendChild(elements['i']) doc.documentElement.appendChild(elements['a']) # now test # find all elements in the right order result = doc.getElementsByTagName('*') assert len(result) == len(names) + 1 for name, element in map(None, names, result[1:]): assert name == element.tagName # find single element, top result = doc.getElementsByTagName('a') assert len(result) == 1 assert result[0].tagName == 'a' # find single element somewhere in tree result = doc.getElementsByTagName('h') assert len(result) == 1 assert result[0].tagName == 'h' def checkCreateAttribute(self): attr = self.document.createAttribute(self.TEST_NAME) checkAttribute(attr, 'nodeType', Node.ATTRIBUTE_NODE) checkAttribute(attr, 'name', self.TEST_NAME) checkAttribute(attr, 'localName', None) checkAttribute(attr, 'prefix', None) checkAttribute(attr, 'namespaceURI', None) checkAttribute(attr, 'value', '') checkAttributeSameNode(attr, 'ownerDocument', self.document) # Note the ':' in the name, createAttribute does not know about # namespaces, so the colon has no special meaning. attr = self.document.createAttribute('not_a_prefix:not_a_localname') checkAttribute(attr, 'name', 'not_a_prefix:not_a_localname') checkAttribute(attr, 'localName', None) checkAttribute(attr, 'prefix', None) try: self.document.createAttribute('5_illegal') except xml.dom.InvalidCharacterErr: pass else: assert 0, "Created Attribute Node with illegal name." def checkCreateCDATASection(self): cdata = self.document.createCDATASection('A CDATA Section') checkAttribute(cdata, 'nodeType', Node.CDATA_SECTION_NODE) checkAttribute(cdata, 'data', 'A CDATA Section') checkAttributeSameNode(cdata, 'ownerDocument', self.document) def checkCreateComment(self): comment = self.document.createComment('A Comment') checkAttribute(comment, 'nodeType', Node.COMMENT_NODE) checkAttribute(comment, 'data', 'A Comment') checkAttributeSameNode(comment, 'ownerDocument', self.document) def checkCreateDocumentFragment(self): fragment = self.document.createDocumentFragment() checkAttribute(fragment, 'nodeType', Node.DOCUMENT_FRAGMENT_NODE) checkLength(fragment.childNodes, 0) checkAttributeSameNode(fragment, 'ownerDocument', self.document) def checkCreateElement(self): el = self.document.createElement(self.TEST_NAME) checkAttribute(el, 'nodeType', Node.ELEMENT_NODE) checkAttribute(el, 'tagName', self.TEST_NAME) checkAttribute(el, 'localName', None) checkAttribute(el, 'prefix', None) checkAttribute(el, 'namespaceURI', None) checkAttributeSameNode(el, 'ownerDocument', self.document) # Note the ':' in the name, createElement does not know about # namespaces, so the colon has no special meaning. el = self.document.createElement('not_a_prefix:not_a_localname') checkAttribute(el, 'tagName', 'not_a_prefix:not_a_localname') checkAttribute(el, 'localName', None) checkAttribute(el, 'prefix', None) def checkCreateElementInvalidCharacter(self): try: self.document.createElement('5_illegal') except xml.dom.InvalidCharacterErr: pass else: assert 0, "Created Element Node with illegal name." def checkCreateEntityReference(self): entRef = self.document.createEntityReference('entityReference') checkAttribute(entRef, 'nodeType', Node.ENTITY_REFERENCE_NODE) checkAttribute(entRef, 'nodeName', 'entityReference') checkAttributeSameNode(entRef, 'ownerDocument', self.document) def checkCreateEntityReferenceInvalidCharacter(self): try: self.document.createEntityReference('5_illegal') except xml.dom.InvalidCharacterErr: pass else: assert 0, "Created Entity Reference Node with illegal name." def checkCreateProcessingInstruction(self): pi = self.document.createProcessingInstruction('PITarget', 'PI Data') checkAttribute(pi, 'nodeType', Node.PROCESSING_INSTRUCTION_NODE) checkAttribute(pi, 'target', 'PITarget') checkAttribute(pi, 'data', 'PI Data') checkAttributeSameNode(pi, 'ownerDocument', self.document) def checkCreateProcessingInstructionInvalidCharacter(self): try: self.document.createProcessingInstruction('5_illegal', 'data') except xml.dom.InvalidCharacterErr: pass else: assert 0, "Created Processing Instruction Node with illegal name." def checkCreateTextNode(self): text = self.document.createTextNode('A Text Node') checkAttribute(text, 'nodeType', Node.TEXT_NODE) checkAttribute(text, 'data', 'A Text Node') checkAttributeSameNode(text, 'ownerDocument', self.document) # --- Element class ElementReadTestCase(NodeReadTestCaseBase): def setUp(self): doc = self.createDocument() self.element = self.node = doc.createElement("per") self.expectedType = Node.ELEMENT_NODE self.floating_element = self.element self.attached_element = doc.createElement("attached") doc.documentElement.appendChild(self.attached_element) def checkDocumentElementChildNodes(self): checkLength(self.document.documentElement.childNodes, 1) def checkAttachedElementParentNode(self): checkAttributeSameNode(self.attached_element, "parentNode", self.document.documentElement) def checkDocumentElementFirstChild(self): checkAttributeSameNode(self.document.documentElement, "firstChild", self.attached_element) checkAttributeSameNode( self.document.documentElement.firstChild, "parentNode", self.document.documentElement) def checkTagName(self): checkAttribute(self.floating_element, "tagName", "per") checkAttribute(self.attached_element, "tagName", "attached") checkReadOnly(self.floating_element, "tagName") def checkGetAttribute(self): assert self.element.getAttribute("ugga") == "", \ "non-existant attribute should return ''" def checkGetAttributeNode(self): assert self.element.getAttributeNode("ugga") is None, \ "non-existant attribute should return None" def checkCloneNode(self): el = self.element doc = self.document el.appendChild(doc.createTextNode('A Text Node')) el.appendChild(doc.createComment('A Comment')) el.setAttribute('attr1', 'An attribute') el.setAttribute('attr2', 'Another attribute') el.appendChild(el.cloneNode(0)) clone = el.cloneNode(1) assert not isSameNode(el, clone), "Clone is same Node as original." assert not isSameNode(el, clone.lastChild), ( "Clone is same Node as original.") checkAttribute(clone, 'parentNode', None) checkLength(clone.childNodes, el.childNodes.length) checkLength(clone.attributes, el.attributes.length) checkLength(clone.lastChild.childNodes, 0) checkLength(clone.lastChild.attributes, el.attributes.length) checkAttribute(clone, 'nodeName', el.nodeName) checkAttribute(clone.lastChild, 'nodeName', el.nodeName) checkAttribute(clone, 'nodeType', el.nodeType) checkAttribute(clone.lastChild, 'nodeType', el.nodeType) checkAttribute(clone, 'nodeValue', el.nodeValue) checkAttribute(clone.lastChild, 'nodeValue', el.nodeValue) for i in range(clone.childNodes.length): checkAttribute(clone.childNodes.item(i), 'nodeType', el.childNodes.item(i).nodeType) if clone.childNodes.item(i).nodeType != Node.ELEMENT_NODE: checkAttribute(clone.childNodes.item(i), 'data', el.childNodes.item(i).data) for i in range(clone.attributes.length): checkAttribute(clone.attributes.item(i), 'name', el.attributes.item(i).name) checkAttribute(clone.lastChild.attributes.item(i), 'name', el.attributes.item(i).name) checkAttribute(clone.attributes.item(i), 'value', el.attributes.item(i).value) checkAttribute(clone.lastChild.attributes.item(i), 'value', el.attributes.item(i).value) # deep and shallow clones should clone attributes value = clone.attributes.item(i).value el.attributes.item(i).value = 'spam' checkAttribute(clone.attributes.item(i), 'value', value) checkAttribute(clone.lastChild.attributes.item(i), 'value', value) checkAttributeSameNode(clone.attributes.item(i), 'ownerElement', clone) checkAttributeSameNode(clone.lastChild.attributes.item(i), 'ownerElement', clone.lastChild) assert not isSameNode(el.attributes.item(i), clone.attributes.item(i)) class ElementWriteTestCase(NodeWriteTestCaseBase): def setUp(self): doc = self.createDocument() self.element = self.node = doc.createElement("per") self.floating_element = self.element self.attached_element = doc.createElement("attached") self.attached_element2 = doc.createElement("attached2") doc.documentElement.appendChild(self.attached_element) doc.documentElement.appendChild(self.attached_element2) def checkAttachedElementsNextSibling(self): checkAttributeSameNode(self.attached_element, "nextSibling", self.attached_element2) checkAttributeSameNode(self.attached_element2, "nextSibling", None) def checkAttachedElementsPreviousSibling(self): checkAttributeSameNode(self.attached_element, "previousSibling", None) checkAttributeSameNode(self.attached_element2, "previousSibling", self.attached_element) def checkGetElementsByTagName(self): doc = self.document el = self.element elements = {} names = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'] for c in names: elements[c] = doc.createElement(c) # set up simple tree elements['a'].appendChild(elements['b']) elements['a'].appendChild(elements['d']) elements['b'].appendChild(elements['c']) elements['d'].appendChild(elements['e']) elements['d'].appendChild(elements['h']) elements['e'].appendChild(elements['f']) elements['e'].appendChild(elements['g']) elements['h'].appendChild(elements['i']) el.appendChild(elements['a']) # now test # find all elements in the right order result = el.getElementsByTagName('*') assert len(result) == len(names) for name, element in map(None, names, result): assert name == element.tagName # find single element, top result = el.getElementsByTagName('a') assert len(result) == 1 assert result[0].tagName == 'a' # find single element somewhere in tree result = el.getElementsByTagName('h') assert len(result) == 1 assert result[0].tagName == 'h' def checkSetAttribute(self): self.element.setAttribute("ugga", "foo") assert self.element.hasAttribute("ugga"), \ "Test for presence of created attribute returned false." value = self.element.getAttribute("ugga") assert value == 'foo', \ ("Incorrect attr value returned. Expected 'foo', got %s" % repr(value)) def checkSetAttributeIllegalCharacter(self): try: self.element.setAttribute('5_illegal', "Don't eat this") except xml.dom.InvalidCharacterErr: pass else: assert 0, "Was allowed to use an illegal attribute name." def checkSetAttributeNode(self): node = self.document.createAttribute("ugga") node.value = 'foo' returnValue = self.element.setAttributeNode(node) assert self.element.hasAttribute("ugga"), \ "Test for presence of created attribute returned false." assert returnValue is None, "Returned value is %s" % repr(returnValue) value = self.element.getAttribute("ugga") assert value == 'foo', \ ("Incorrect attr value returned. Expected 'foo', got %s" % repr(value)) returnedNode = self.element.getAttributeNode("ugga") assert isSameNode(node, returnedNode), \ "Incorrect node returned from getAttributeNode." def checkSetAttributeNodeReplaceExisting(self): node = self.document.createAttribute("ugga") self.element.setAttributeNode(node) newNode = self.document.createAttribute("ugga") returnValue = self.element.setAttributeNode(newNode) if returnValue is None: assert 0, "setAttributeNode did not replace original attribute" assert isSameNode(node, returnValue), ( "setAttributeNode returned %s" % repr(returnValue)) def checkSetAttributeNodeWrongDocument(self): foreignDoc = self.implementation.createDocument(None, 'foo', None) foreignAttr = foreignDoc.createAttribute('spam') try: self.element.setAttributeNodeNS(foreignAttr) except xml.dom.WrongDocumentErr: pass else: assert 0, "Was allowed to setAttributeNode with a foreign Attr." def checkSetAttributeNodeAlreadyInUse(self): otherElement = self.document.createElement('foo') otherAttr = self.document.createAttribute('spam') otherElement.setAttributeNodeNS(otherAttr) try: self.element.setAttributeNodeNS(otherAttr) except xml.dom.InuseAttributeErr: pass else: assert 0, ( "Was allowed to setAttributeNode with an Attr already in use.") def checkRemoveAttribute(self): node1 = self.document.createAttribute("foo") node2 = self.document.createAttribute("bar") self.element.setAttributeNode(node1) self.element.setAttributeNode(node2) self.element.removeAttribute("foo") assert not self.element.hasAttribute("foo"), \ "Test for presence of created attribute still returns true." assert self.element.hasAttribute("bar"), \ "Test for presence of created attribute returned false." checkAttribute(node1, 'ownerElement', None) def checkRemoveAttributeNode(self): node1 = self.document.createAttribute("foo") node2 = self.document.createAttribute("bar") self.element.setAttributeNode(node1) self.element.setAttributeNode(node2) returnedNode = self.element.removeAttributeNode(node1) assert isSameNode(node1, returnedNode), ( "Returned node not the same as the one removed.") checkAttribute(node1, 'ownerElement', None) assert not self.element.hasAttribute("foo"), ( "Test for presence of created attribute still returns true.") assert self.element.hasAttribute("bar"), ( "Test for presence of created attribute returned false.") def checkRemoveAttributeNodeNotFound(self): node = self.document.createAttribute("foo") try: self.element.removeAttributeNode(node) except xml.dom.NotFoundErr: pass else: assert 0, ( "No NotFoundErr raised when trying to remove " "non-attached Node.") # --- CharacterData class CharacterDataReadTestCaseBase(NodeReadTestCaseBase): def checkGetData(self): checkAttribute(self.chardata, "data", "com") def checkGetLength(self): checkLength(self.chardata, 3) assert len(self.chardata.data) == 3 assert len(self.chardata._get_data()) == 3 def checkSubstringData(self): assert self.chardata.substringData(0, 2) == "co" def checkSubstringDataNegativeOffset(self): try: self.chardata.substringData(-2, 0) except xml.dom.IndexSizeErr: pass else: assert 0, "Expected exception for negative offset." def checkSubstringDataOffsetGreaterThanLength(self): try: self.chardata.substringData(10, 0) except xml.dom.IndexSizeErr: pass else: assert 0, "Expected exception for too high offset." def checkSubstringDataNegativeCount(self): try: self.chardata.substringData(0, -2) except xml.dom.IndexSizeErr: pass else: assert 0, "Expected exception for negative count." def checkSubstringDataOffsetAndCountGreaterThanLength(self): assert self.chardata.substringData(1, 10) == "om" def checkCloneNode(self): clone = self.chardata.cloneNode(0) deepClone = self.chardata.cloneNode(1) assert not isSameNode(self.chardata, clone), ( "Clone is same as original.") assert not isSameNode(self.chardata, deepClone), ( "Clone is same as original.") checkAttribute(clone, 'parentNode', None) checkAttribute(deepClone, 'parentNode', None) checkAttribute(clone, 'nodeType', self.chardata.nodeType) checkAttribute(deepClone, 'nodeType', self.chardata.nodeType) checkAttribute(clone, 'data', self.chardata.data) checkAttribute(deepClone, 'data', self.chardata.data) checkLength(clone.childNodes, 0) checkLength(deepClone.childNodes, 0) class CharacterDataWriteTestCaseBase(NodeWriteTestCaseBase): def checkSetData(self): self.chardata._set_data("data") checkAttribute(self.chardata, "data", "data") def checkAppendData(self): self.chardata.appendData("com") checkAttribute(self.chardata, "data", "comcom") def checkInsertData(self): self.chardata.insertData(2, "com") checkAttribute(self.chardata, "data", "cocomm") def checkInsertDataNegativeOffset(self): try: self.chardata.insertData(-2, 'foo') except xml.dom.IndexSizeErr: pass else: assert 0, "Expected exception for negative offset." def checkInsertDataOffsetGreaterThanLength(self): try: self.chardata.insertData(10, 'foo') except xml.dom.IndexSizeErr: pass else: assert 0, "Expected exception for too high offset." def checkDeleteData(self): self.chardata.deleteData(1, 1) checkAttribute(self.chardata, "data", "cm") def checkDeleteDataNegativeOffset(self): try: self.chardata.deleteData(-2, 0) except xml.dom.IndexSizeErr: pass else: assert 0, "Expected exception for negative offset." def checkDeleteDataOffsetGreaterThanLength(self): try: self.chardata.deleteData(10, 0) except xml.dom.IndexSizeErr: pass else: assert 0, "Expected exception for too high offset." def checkDeleteDataNegativeCount(self): try: self.chardata.deleteData(0, -2) except xml.dom.IndexSizeErr: pass else: assert 0, "Expected exception for negative count." def checkDeleteDataOffsetAndCountGreaterThanLength(self): self.chardata.deleteData(0, 10) checkAttribute(self.chardata, "data", "") def checkReplaceData(self): self.chardata.replaceData(1, 3, "uuuu") checkAttribute(self.chardata, "data", "cuuuu") def checkReplaceDataNegativeOffset(self): try: self.chardata.replaceData(-2, 0, 'foo') except xml.dom.IndexSizeErr: pass else: assert 0, "Expected exception for negative offset." def checkReplaceDataOffsetGreaterThanLength(self): try: self.chardata.replaceData(10, 0, 'foo') except xml.dom.IndexSizeErr: pass else: assert 0, "Expected exception for too high offset." def checkReplaceDataNegativeCount(self): try: self.chardata.replaceData(0, -2, 'foo') except xml.dom.IndexSizeErr: pass else: assert 0, "Expected exception for negative count." def checkReplaceDataOffsetAndCountGreaterThanLength(self): self.chardata.replaceData(0, 10, "foo") checkAttribute(self.chardata, "data", "foo") # --- Comment class CommentReadTestCase(CharacterDataReadTestCaseBase): def setUp(self): self.chardata = self.node = self.createDocument().createComment("com") self.expectedType = Node.COMMENT_NODE class CommentWriteTestCase(CharacterDataWriteTestCaseBase): def setUp(self): self.chardata = self.node = self.createDocument().createComment("com") # --- Text class TextReadTestCase(CharacterDataReadTestCaseBase): def setUp(self): self.chardata = self.node = self.createDocument().createTextNode("com") self.expectedType = Node.TEXT_NODE class TextWriteTestCase(CharacterDataWriteTestCaseBase): def setUp(self): self.chardata = self.node = self.createDocument().createTextNode("com") def checkAcquisition(self): if 1: # This test is disabled. Simple implicit acquisition # causes removeAttribute() to be acquired when it # probably should not, but this issue is not of # sufficient importance for now. return cdata = self.document.createTextNode("com") self.document.documentElement.appendChild(cdata) cdata2 = self.document.createTextNode("com2") self.document.documentElement.appendChild(cdata2) attr = self.document.createAttribute("attrName") self.document.documentElement.setAttributeNode(attr) # Technically these should raise. Because of acquisition they # might not. We want to make sure that they don't affect # the tree. try: self.document.documentElement.firstChild.normalize() except: pass try: self.document.documentElement.firstChild.removeAttribute( "attrName") except: pass else: assert 0, 'removeAttribute() was acquired from documentElement.' checkAttribute(self.document.documentElement.childNodes, "length", 2) checkAttribute(self.document.documentElement.attributes, "length", 1) def checkSplitText(self): newNode = self.chardata.splitText(2) checkAttribute(self.chardata, 'data', 'co') checkAttribute(newNode, 'data', 'm') def checkSplitTextOffsetEqualToLength(self): try: newNode = self.chardata.splitText(self.chardata.length) except xml.dom.IndexSizeErr: assert 0, ( "INDEX_SIZE_ERR raised on splitText with offset == length.") checkAttribute(self.chardata, 'data', 'com') checkAttribute(newNode, 'data', '') def checkSplitTextNegativeOffset(self): try: self.chardata.splitText(-2) except xml.dom.IndexSizeErr: pass else: assert 0, "Expected exception for negative offset." def checkSplitTextOffsetGreateThanLength(self): try: self.chardata.splitText(10) except xml.dom.IndexSizeErr: pass else: assert 0, "Expected exception for too high offset." def checkSplitTextWithParent(self): el = self.document.createElement('foo') el.appendChild(self.chardata) newNode = self.chardata.splitText(2) checkAttributeSameNode(self.chardata, 'nextSibling', newNode) # --- Attr class AttrReadTestCase(NodeReadTestCaseBase): def setUp(self): self.attr = self.node = self.createDocument().createAttribute("name") self.expectedType = Node.ATTRIBUTE_NODE def checkGetName(self): checkAttribute(self.attr, "name", "name") def checkGetSpecified(self): assert self.attr._get_specified() assert self.attr.specified def checkGetValue(self): checkAttribute(self.attr, "value", "") checkLength(self.attr.childNodes, 1) checkAttribute(self.attr.firstChild, 'nodeType', Node.TEXT_NODE) checkAttribute(self.attr.firstChild, 'data', '') def checkCloneNode(self): clone = self.attr.cloneNode(0) deepClone = self.attr.cloneNode(1) assert not isSameNode(self.attr, clone), "Clone is same as original." assert not isSameNode(self.attr, deepClone), ( "Clone is same as original.") checkAttribute(clone, 'parentNode', None) checkAttribute(deepClone, 'parentNode', None) checkAttribute(clone, 'nodeType', self.attr.nodeType) checkAttribute(deepClone, 'nodeType', self.attr.nodeType) checkAttribute(clone, 'name', self.attr.name) checkAttribute(deepClone, 'name', self.attr.name) checkAttribute(clone, 'value', self.attr.value) checkAttribute(deepClone, 'value', self.attr.value) checkAttribute(clone, 'specified', 1) checkAttribute(deepClone, 'specified', 1) checkAttribute(clone, 'nodeName', self.attr.nodeName) checkAttribute(deepClone, 'nodeName', self.attr.nodeName) checkAttribute(clone, 'nodeValue', self.attr.nodeValue) checkAttribute(deepClone, 'nodeValue', self.attr.nodeValue) checkLength(clone.childNodes, 1) # Subtree models value checkAttribute(clone.firstChild, 'nodeType', Node.TEXT_NODE) checkAttribute(clone.firstChild, 'data', self.attr.value) checkLength(deepClone.childNodes, 1) checkAttribute(deepClone.firstChild, 'nodeType', Node.TEXT_NODE) checkAttribute(deepClone.firstChild, 'data', self.attr.value) class AttrWriteTestCase(NodeWriteTestCaseBase): def setUp(self): self.attr = self.node = self.createDocument().createAttribute( "attrName") self.element = self.document.createElement("eltName") def checkSetValue(self): self.attr._set_value("14") checkAttribute(self.attr, "value", "14") checkLength(self.attr.childNodes, 1) checkAttribute(self.attr.firstChild, 'nodeType', Node.TEXT_NODE) checkAttribute(self.attr.firstChild, 'data', '14') def checkManipulateSubTree(self): attr = self.attr assert attr.hasChildNodes(), "Attr doesn't have subtree to manipulate!" newNode = self.document.createTextNode('New Value') attr.replaceChild(newNode, attr.firstChild) checkAttribute(attr.firstChild, 'data', 'New Value') checkAttribute(attr, 'value', 'New Value') attr.appendChild(self.document.createTextNode(' (appended)')) checkAttribute(attr, 'value', 'New Value (appended)') attr.firstChild.appendData(' ') attr.replaceChild(self.document.createEntityReference('foo'), attr.lastChild) checkAttribute(attr, 'value', 'New Value ') # Setting the value with a string containing an XML reference does *not* # cause it to create an EntiyReference. Everything is a string literal. attr.value = 'Some Value &test;' checkLength(attr.childNodes, 1) checkAttribute(attr.firstChild, 'data', 'Some Value &test;') def checkOwnerElement(self): checkAttribute(self.attr, "ownerElement", None) checkReadOnly(self.attr, "ownerElement") self.element.setAttributeNode(self.attr) checkAttributeSameNode(self.attr, "ownerElement", self.element) checkReadOnly(self.attr, "ownerElement") def checkAttrTwoReferencesIntegrity(self): #XXX this test should be generalized to any reference attr = self.document.createAttribute('spam') self.document.documentElement.setAttributeNode(attr) a1 = self.document.documentElement.attributes.item(0) a2 = self.document.documentElement.attributes.item(0) a1.appendChild(self.document.createTextNode('eggs')) assert a1.childNodes.length == a2.childNodes.length, \ "Write to one attr reference isn't reflected in another ref." def checkAttrReferenceElementAttributeIntegrity(self): "changing an attribute node should be reflected by getAttribute" attr = self.document.createAttribute('spam') self.document.documentElement.setAttributeNode(attr) a1 = self.document.documentElement.attributes.item(0) a1.value = 'eggs' assert (self.document.documentElement.getAttribute('spam') == 'eggs'), ( "setting value of attr reference isn't reflected by getAttribute") a1.appendChild(self.document.createTextNode('ham')) assert (self.document.documentElement.getAttribute('spam') == 'eggsham'), ( "appendChild on attr reference isn't reflected by getAttribute.") def checkSetAttrWithSubtree(self): "setAttributeNode shouldn't lose attr subtree information" eggs = self.document.createTextNode('eggs') ham = self.document.createTextNode('ham') self.attr.appendChild(eggs) self.attr.appendChild(ham) self.element.setAttributeNode(self.attr) # check that getting the attr from the element preserves subtree checkAttribute(self.element.attributes.item(0).childNodes, "length", 3) assert self.attr.firstChild.nextSibling.isSameNode(eggs), ( "setting an attribute node destroys children") assert self.attr.firstChild.nextSibling.nextSibling.isSameNode(ham), ( "setting an attribute node destroys children") # check that another ref preserves subtree, too attr2 = self.element.getAttributeNode('attrName') checkAttribute(attr2.childNodes, "length", 3) assert attr2.firstChild.nextSibling.isSameNode(eggs), ( "setting an attribute node destroys children") assert attr2.firstChild.nextSibling.nextSibling.isSameNode(ham), ( "setting an attribute node destroys children") def checkCloneNode(self): attr = self.attr clone = attr.cloneNode(0) assert not isSameNode(attr, clone), "Clone is same Node as original." checkAttribute(clone, 'value', attr.value) # make sure the cloned attr isn't sharing data with the original oldValue = self.attr.value self.attr.value = 'spam' checkAttribute(clone, 'value', oldValue) # --- Default attributes class DefaultAttrTestCase(TestCaseBase): def setUp(self): self.document = self.parse(""" ]> """) def checkHasAttribute(self): el = self.document.documentElement assert el.hasAttribute('foo'), 'Default attribute not found.' def checkGetAttribute(self): el = self.document.documentElement assert el.getAttribute('foo') == 'bar', ( "Wrong value of default attribute found, expected 'bar', found %s" % repr(el.getAttribute('foo'))) def checkCreateElement(self): el = self.document.createElement('doc') assert el.hasAttribute('foo'), ( 'Newly created Element Node should have default attribute.') assert el.getAttribute('foo') == 'bar', ( "Wrong value of default attribute found, expected 'bar', found %s" % el.getAttribute('foo')) checkAttribute(el.getAttributeNode('foo'), 'specified', 0) def checkCloneNode(self): attr = self.document.documentElement.getAttributeNode('foo') clone = attr.cloneNode(0) checkAttribute(clone, 'specified', 1) def checkCloneNodeElement(self): clone = self.document.documentElement.cloneNode(0) checkAttribute(clone.getAttributeNode('foo'), 'specified', 0) # XXX also check that cloned attrs aren't the same nodes, changes # aren't reflected across refs def checkRemoveAttribute(self): el = self.document.documentElement # Replace default with specified attr el.setAttribute('foo', 'baz') el.removeAttribute('foo') assert el.hasAttribute('foo'), ( 'Removing specified attribute should bring back default attribute.') assert el.getAttribute('foo') == 'bar', ( "Wrong value of default attribute found, expected 'bar', found %s" % el.getAttribute('foo')) checkAttribute(el.getAttributeNode('foo'), 'specified', 0) def checkRemoveAttributeNode(self): el = self.document.documentElement newAttr = self.document.createAttribute('foo') newAttr.value = 'baz' # Replace default with specified attr el.setAttributeNode(newAttr) el.removeAttributeNode(newAttr) assert el.hasAttribute('foo'), ( 'Removing specified attribute should bring back default attribute.') assert el.getAttribute('foo') == 'bar', ( "Wrong value of default attribute found, expected 'bar', found %s" % el.getAttribute('foo')) checkAttribute(el.getAttributeNode('foo'), 'specified', 0) def checkRemoveNamedItem(self): el = self.document.documentElement # Replace default with specified attr el.setAttribute('foo', 'baz') el.attributes.removeNamedItem('foo') assert el.hasAttribute('foo'), ( 'Removing specified attribute should bring back default attribute.') assert el.getAttribute('foo') == 'bar', ( "Wrong value of default attribute found, expected 'bar', found %s" % el.getAttribute('foo')) checkAttribute(el.getAttributeNode('foo'), 'specified', 0) def checkSpecified(self): checkAttribute(self.document.documentElement.getAttributeNode('foo'), 'specified', 0) def checkSetAttribute(self): el = self.document.documentElement el.setAttribute('foo', 'baz') checkAttribute(el.getAttributeNode('foo'), 'specified', 1) def checkSetAttributeNode(self): el = self.document.documentElement newAttr = self.document.createAttribute('foo') newAttr.value = 'baz' el.setAttributeNode(newAttr) checkAttribute(el.getAttributeNode('foo'), 'specified', 1) # --- DocumentFragment class DocumentFragmentReadTestCase(NodeReadTestCaseBase): def setUp(self): self.docfrag = self.createDocument().createDocumentFragment() self.node = self.docfrag self.expectedType = Node.DOCUMENT_FRAGMENT_NODE def checkCloneNode(self): frag = self.docfrag frag.appendChild(self.document.createComment('foo')) frag.appendChild(self.document.createTextNode('bar')) clone = frag.cloneNode(0) deepClone = frag.cloneNode(1) assert not isSameNode(frag, clone), "Clone is same Node as original." assert not isSameNode(frag, deepClone), ( "Clone is same Node as original.") checkAttribute(clone, 'parentNode', None) checkAttribute(deepClone, 'parentNode', None) checkLength(clone.childNodes, 0) checkLength(deepClone.childNodes, frag.childNodes.length) for i in range(deepClone.childNodes.length): checkAttribute(deepClone.childNodes.item(i), 'nodeType', frag.childNodes.item(i).nodeType) checkAttribute(deepClone.childNodes.item(i), 'data', frag.childNodes.item(i).data) class DocumentFragmentWriteTestCase(NodeWriteTestCaseBase): def setUp(self): self.createDocument() self.docfrag = self.node = self.document.createDocumentFragment() def checkInsertBeforeEnd(self): doc = self.document fragment = self.docfrag fragment.appendChild(doc.createElement('foo')) fragment.appendChild(doc.createTextNode('textual magic')) docelem = doc.documentElement docelem.insertBefore(fragment, None) checkAttribute(docelem.childNodes[0], "nodeName", "foo") checkAttribute(docelem.childNodes[1], "nodeValue", "textual magic") checkLength(docelem.childNodes, 2) checkAttribute(docelem.firstChild, "nodeName", "foo") # --- NodeList class NodeListReadTestCase(TestCaseBase): def setUp(self): self.createDocument() self.list = self.document.createElement("foo")._get_childNodes() def checkGetLength(self): checkLength(self.list, 0) checkLength(self.document.childNodes, 1) def checkItem(self): assert self.list.item(0) is None def checkGetItem(self): try: self.list[0] assert 0, "expected IndexError to be raised" except IndexError: pass # there's no cmp for NodeList right now #def checkCmp(self): # list1 = self.document.documentElement._get_childNodes() # list2 = self.document.firstChild._get_childNodes() # assert list1 == list2, "two NodeLists of the same thing don't compare" ## def checkGetSlice(self): ## assert self.list[2 : 5] == [] class NodeListWriteTestCase(TestCaseBase): def setUp(self): self.createDocument() self.list = self.document.childNodes def checkGetLength(self): checkLength(self.list, 1) self.document.appendChild(self.document.createComment('foo')) # A NodeList is 'live', changes to source Node should be reflected checkLength(self.list, 2) def checkItem(self): newNode = self.document.createComment('foo') self.document.appendChild(newNode) # A NodeList is 'live', changes to source Node should be reflected isSameNode(newNode, self.list.item(1)) # This extends to the Nodes contained in the NodeList newNode.data = 'bar' checkAttribute(self.list.item(1), 'data', 'bar') # --- NamedNodeMap class NamedNodeMapReadTestCase(TestCaseBase): def setUp(self): self.map = self.createDocument().createElement("foo")._get_attributes() def checkGetLength(self): checkLength(self.map, 0) def checkGetNamedItem(self): assert self.map.getNamedItem("uuu") is None def checkRemoveNamedItem(self): try: self.map.removeNamedItem("uuu") assert 0, "expected NotFoundErr to be raised" except xml.dom.NotFoundErr: pass def checkItem(self): assert self.map.item(0) is None def checkGetItem(self): try: self.map["uuu"] assert 0, "expected KeyError to be raised" except KeyError: pass def checkGet(self): assert self.map.get("uuu", 5) == 5 def checkHasKey(self): assert not self.map.has_key("uuu") def checkItems(self): assert self.map.items() == [] def checkKeys(self): assert self.map.keys() == [] def checkValues(self): assert self.map.values() == [] class NonemptyNamedNodeMapWriteTestCase(TestCaseBase): def setUp(self): self.map = self.createDocument().createElement("foo")._get_attributes() self.attribute = self.document.createAttribute("attrName") self.attribute.value = "attrValue" self.map.setNamedItem(self.attribute) def checkRemoveNonexistentNamedItem(self): try: self.map.removeNamedItem("uuu") assert 0, "did not catch expected DOMException" except xml.dom.DOMException: pass def checkRemoveNamedItem(self): attribute2 = self.document.createAttribute("attrName2") self.map.setNamedItem(attribute2) attrOut = self.map.removeNamedItem("attrName2") assert isSameNode(attrOut, attribute2) def checkRemoveNamedItemNotFound(self): try: self.map.removeNamedItem("bogus") except xml.dom.NotFoundErr: pass else: assert 0, ( "Expected an exception when trying to remove non-existing " "entry.") def checkGetLength(self): checkLength(self.map, 1) def checkGetNamedItem(self): assert isSameNode(self.attribute, self.map.getNamedItem("attrName")) def checkGetNonexistentNamedItem(self): assert self.map.getNamedItem("uuu") is None def checkItem(self): assert isSameNode(self.map.item(0), self.attribute) assert isSameNode(self.attribute, self.map.item(0)) def checkGetNonexistentItem(self): try: self.map["uuu"] assert 0, "expected KeyError to be raised" except KeyError: pass def checkGetItem(self): assert isSameNode(self.attribute, self.map["attrName"]) def checkGet(self): assert isSameNode(self.attribute, self.map.get("attrName")) def checkHasKey(self): assert self.map.has_key("attrName") assert not self.map.has_key("uuu") def checkItems(self): key, node = self.map.items()[0] assert key == "attrName" and isSameNode(self.attribute, node) def checkKeys(self): assert self.map.keys() == ["attrName"] def checkValues(self): L = [] for attr in self.map.values(): L.append(attr.value) assert L == ["attrValue"], "bad values list: %s" % `L` def checkSetNamedItem(self): newAttr = self.document.createAttribute('someAttr') newAttr.value = 'spam' retVal = self.map.setNamedItem(newAttr) assert retVal is None, "setNamedItem returned %s" % repr(retVal) checkLength(self.map, 2) assert isSameNode(self.map.getNamedItem('someAttr'), newAttr), ( "setNamedItem store seems to have failed, can't retrieve.") def checkSetNamedItemReplacingExistingNode(self): newAttr = self.document.createAttribute('someAttr') self.map.setNamedItem(newAttr) anotherAttr = self.document.createAttribute('someAttr') anotherAttr.value = 'eggs' retVal = self.map.setNamedItem(newAttr) assert retVal is not None, "setNamedItem returned None" assert isSameNode(retVal, newAttr), ( "setNamedItem didn't return replaced Node.") checkLength(self.map, 2) def checkSetNamedItemWrongDocument(self): newDoc = self.implementation.createDocument(None, 'foo', None) foreignAttr = newDoc.createAttribute('someAttr') try: self.map.setNamedItem(foreignAttr) except xml.dom.WrongDocumentErr: pass else: assert 0, "Was allowed to add foreign Node to NamedNodeMap." def checkSetNamedItemAlreadyInUse(self): el = self.document.createElement('someElement') attr = self.document.createAttribute('someAttribute') el.setAttributeNode(attr) try: self.map.setNamedItem(attr) except xml.dom.InuseAttributeErr: pass else: assert 0, ( "Was allowed to add attribute already in use to NamedNodeMap.") def checkSetNamedItemHierarchyRequestErr(self): # See DOM erratum core-4. textNode = self.document.createTextNode('text node') try: self.map.setNamedItem(textNode) except xml.dom.HierarchyRequestErr: pass else: assert 0, ( "Was allowed to add a Node Type not belonging in this " "NamedNodeMap (a Text Node to a map of attributes).") cases = buildCases(__name__, 'Core', None) ParsedXML/tests/domapi/Base.py0100644000175200017500000002167607274131366016212 0ustar faasseninfrae############################################################################## # # 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. # ############################################################################## import xml.dom from xml.dom import Node import sys import unittest # Namespace URI for namespace tests TEST_NAMESPACE = 'uri:namespacetests' # Convenience map for assert messages TYPE_NAME = { Node.ATTRIBUTE_NODE: 'Attribute', Node.CDATA_SECTION_NODE: 'CDATA Section', Node.COMMENT_NODE: 'Comment', Node.DOCUMENT_FRAGMENT_NODE: 'Document Fragment', Node.DOCUMENT_NODE: 'Document', Node.DOCUMENT_TYPE_NODE: 'DocumentType', Node.ELEMENT_NODE: 'Element', Node.ENTITY_NODE: 'Entity', Node.ENTITY_REFERENCE_NODE: 'Entity Reference', Node.NOTATION_NODE: 'Notation', Node.PROCESSING_INSTRUCTION_NODE: 'Processing Instruction', Node.TEXT_NODE: 'Text', } def checkAttribute(node, attribute, value): """Check that an attribute holds the expected value, and that the corresponding accessor method, if provided, returns an equivalent value.""" # v1 = getattr(node, attribute) if v1 != value: raise AssertionError( "attribute value does not match\n expected: %s\n found: %s" % (`value`, `v1`)) if hasattr(node, "_get_" + attribute): v2 = getattr(node, "_get_" + attribute)() if v2 != value: raise AssertionError( "accessor result does not match\n expected: %s\n found: %s" % (`value`, `v2`)) if v1 != v2: raise AssertionError( "attribute & accessor result don't compare equal\n" " attribute: %s\n accessor: %s" % (`v1`, `v2`)) def checkAttributeNot(node, attribute, value): """Check that an attribute doesn't hold a specific failing value, and that the corresponding accessor method, if provided, returns an equivalent value.""" # v1 = getattr(node, attribute) if v1 == value: raise AssertionError( "attribute value should not match\n found: %s" % `v1`) if hasattr(node, "_get_" + attribute): v2 = getattr(node, "_get_" + attribute)() if v2 == value: raise AssertionError( "accessor result should not match\n found: %s" % `v2`) if v1 != v2: raise AssertionError( "attribute & accessor result don't compare equal\n" " attribute: %s\n accessor: %s" % (`v1`, `v2`)) def checkAttributeSameNode(node, attribute, value): v1 = getattr(node, attribute) if value is None: if v1 is not None: raise AssertionError( "attribute value does not match\n expected: %s\n found: %s" % (`value`, `v1`)) else: if not isSameNode(value, v1): raise AssertionError( "attribute value does not match\n expected: %s\n found: %s" % (`value`, `v1`)) if hasattr(node, "_get_" + attribute): v2 = getattr(node, "_get_" + attribute)() if value is None: if v2 is not None: raise AssertionError( "accessor result does not match\n" " expected: %s\n found: %s" % (`value`, `v2`)) elif not isSameNode(value, v2): raise AssertionError( "accessor result does not match\n" " expected: %s\n found: %s" % (`value`, `v2`)) def checkReadOnly(node, attribute): try: setattr(node, attribute, "don't set this!") except xml.dom.NoModificationAllowedErr: pass else: raise AssertionError("write-access to the '%s' attribute not blocked" % attribute) if hasattr(node, "_set_" + attribute): # setter implemented; make sure it won't allow update try: getattr(node, "_set_" + attribute)("don't set this!") except xml.dom.NoModificationAllowedErr: pass else: raise AssertionError("_set_%s() allowed attribute update" % attribute) def checkLength(node, value): checkAttribute(node, "length", value) if len(node) != value: raise AssertionError("broken support for __len__()") checkReadOnly(node, "length") def isSameNode(node1, node2): """Compare two nodes, returning true if they are the same. Use the DOM lvl 3 Node.isSameNode method if available, otherwise use a simple 'is' test. """ if hasattr(node1, 'isSameNode'): return node1.isSameNode(node2) else: return node1 is node2 class TestCaseBase(unittest.TestCase): def createDocumentNS(self): self.document = self.implementation.createDocument( TEST_NAMESPACE, 'foo:bar', None) return self.document def createDocument(self): self.document = self.implementation.createDocument(None, 'root', None) return self.document def buildCases(modName, feature, level): cases = [] add = cases.append objects = sys.modules[modName].__dict__ for obj in objects.keys(): if obj[-8:] != 'TestCase': continue add((objects[obj], feature, level)) return list(cases) ParsedXML/tests/domapi/CoreLvl2.py0100644000175200017500000020317007471017164016755 0ustar faasseninfrae############################################################################## # # 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. # ############################################################################## from Base import * import CoreLvl1 _DOMImplCase = CoreLvl1.DOMImplementationReadTestCase _NodeTestCaseBase = CoreLvl1.NodeWriteTestCaseBase del CoreLvl1 import sys import string import xml.dom from xml.dom import Node # --- DOMIMplementation class DOMImplementationReadTestCase(TestCaseBase): TEST_NAMESPACE = TEST_NAMESPACE TEST_PREFIX = 'aprefix' TEST_LOCAL_NAME = 'somelocalname' TEST_QUALIFIED_NAME = '%s:%s' % (TEST_PREFIX, TEST_LOCAL_NAME) def setUp(self): # self.implementation is already set. pass def checkCreateDocument(self): # Non namespace Document newDoc = self.implementation.createDocument(None, self.TEST_LOCAL_NAME, None) checkAttribute(newDoc, 'nodeType', Node.DOCUMENT_NODE) checkAttribute(newDoc, 'doctype', None) checkAttributeNot(newDoc, 'documentElement', None) assert newDoc.implementation is self.implementation, ( 'Created Document has different implementation.') checkAttribute(newDoc.documentElement, 'namespaceURI', None) checkAttribute(newDoc.documentElement, 'tagName', self.TEST_LOCAL_NAME) def checkCreateDocumentWithNamespace(self): newDoc = self.implementation.createDocument(self.TEST_NAMESPACE, self.TEST_QUALIFIED_NAME, None) checkAttribute(newDoc.documentElement, 'namespaceURI', self.TEST_NAMESPACE) checkAttribute(newDoc.documentElement, 'tagName', self.TEST_QUALIFIED_NAME) def checkCreateDocumentWithDocumentType(self): docType = self.implementation.createDocumentType( self.TEST_QUALIFIED_NAME, 'uri:public', 'uri:system') newDoc = self.implementation.createDocument(None, self.TEST_LOCAL_NAME, docType) checkAttributeSameNode(newDoc, 'doctype', docType) def checkCreateDocumentIllegalCharacterErr(self): try: self.implementation.createDocument(self.TEST_NAMESPACE, '4_prefix:5_illegal', None) except xml.dom.InvalidCharacterErr: pass else: assert 0, "Created Document with illegal qualified name." def checkCreateDocumentMalformedQA(self): try: self.implementation.createDocument(self.TEST_NAMESPACE, 'malformed:qualfied:name', None) except xml.dom.NamespaceErr: pass else: assert 0, "Created document with a malformed qualified name." try: self.implementation.createDocument(self.TEST_NAMESPACE, ':malformed_qn', None) except xml.dom.NamespaceErr: pass else: assert 0, "Created document with a malformed qualified name." def checkCreateDocumentWithPrefixNoNamespace(self): try: self.implementation.createDocument(None, self.TEST_QUALIFIED_NAME, None) except xml.dom.NamespaceErr: pass else: assert 0, "Created document with a prefix but no namespace." def checkCreateDocumentWithXMLPrefixWrongNamespace(self): try: self.implementation.createDocument(self.TEST_NAMESPACE, 'xml:nope', None) except xml.dom.NamespaceErr: pass else: assert 0, ( "Created document with a 'xml' prefix but not the XML " "namespace.") def checkCreateDocumentWithUsedDocType(self): docType = self.implementation.createDocumentType( self.TEST_QUALIFIED_NAME, 'uri:public', 'uri:system') self.implementation.createDocument(None, self.TEST_LOCAL_NAME, docType) try: self.implementation.createDocument(None, self.TEST_LOCAL_NAME, docType) except xml.dom.WrongDocumentErr: pass else: assert 0, ( "Used a doctype that was already in use to create a new " "Document.") def checkCreateDocumentType(self): docType = self.implementation.createDocumentType( self.TEST_QUALIFIED_NAME, 'uri:public', 'uri:system') checkAttribute(docType, 'ownerDocument', None) checkAttribute(docType, 'name', self.TEST_QUALIFIED_NAME) checkAttribute(docType, 'publicId', 'uri:public') checkAttribute(docType, 'systemId', 'uri:system') checkLength(docType.entities, 0) checkLength(docType.notations, 0) def checkCreateDocumentTypeIllegalCharacterErr(self): try: self.implementation.createDocumentType('4_prefix:5_illegal', 'uri:public', 'uri:system') except xml.dom.InvalidCharacterErr: pass else: assert 0, "Created Document Type with illegal qualified name." def checkCreateDocumentTypeMalformedQA(self): try: self.implementation.createDocumentType('malformed:qualfied:name', 'uri:public', 'uri:system') except xml.dom.NamespaceErr: pass else: assert 0, "Created Document Type with a malformed qualified name." try: self.implementation.createDocumentType(':malformed_qn', 'uri:public', 'uri:system') except xml.dom.NamespaceErr: pass else: assert 0, "Created Document Type with a malformed qualified name." # --- Node class NodeReadTestCaseBase(TestCaseBase): TEST_NAMESPACE = TEST_NAMESPACE TEST_PREFIX = 'aprefix' TEST_LOCAL_NAME = 'somelocalname' TEST_QUALIFIED_NAME = '%s:%s' % (TEST_PREFIX, TEST_LOCAL_NAME) def checkLocalName(self): if self.node.nodeType in (Node.ATTRIBUTE_NODE, Node.ELEMENT_NODE): expect = self.TEST_LOCAL_NAME noNS = self.nodeNoNS else: expect = None noNS = None checkAttribute(self.node, 'localName', expect) checkReadOnly(self.node, 'localName') if noNS: checkAttribute(noNS, 'localName', None) def checkNameSpaceURI(self): if self.node.nodeType in (Node.ATTRIBUTE_NODE, Node.ELEMENT_NODE): expect = self.TEST_NAMESPACE noNS = self.nodeNoNS else: expect = None noNS = None checkAttribute(self.node, 'namespaceURI', expect) checkReadOnly(self.node, 'namespaceURI') if noNS: checkAttribute(noNS, 'namespaceURI', None) def checkOwnerDocument(self): if self.node.nodeType in (Node.DOCUMENT_NODE, Node.DOCUMENT_TYPE_NODE): expect = None else: expect = self.document checkAttributeSameNode(self.node, 'ownerDocument', expect) checkReadOnly(self.node, 'ownerDocument') def checkPrefix(self): if self.node.nodeType in (Node.ATTRIBUTE_NODE, Node.ELEMENT_NODE): expect = self.TEST_PREFIX noNS = self.nodeNoNS else: expect = None noNS = None checkAttribute(self.node, 'prefix', expect) if noNS: checkAttribute(noNS, 'prefix', None) def hasAttributes(self): assert not self.node.hasAttributes(), \ "hasAttributes returned 'true' when 'false' was expected." featureMatrix = _DOMImplCase.featureMatrix def checkIsSupported(self): for feature, level in self.featureMatrix: result1 = self.node.isSupported(feature, level) result2 = self.node.isSupported(string.upper(feature), level) result3 = self.node.isSupported(string.lower(feature), level) expect = ((feature, level) in self.supportedFeatures) assert result1 == result2 and result1 == result3, ( "Different results from different case feature string.") assert (result1 and 1 or 0) == expect, ( "Test for %s, version %s should have returned %s, " "returned %s" % (repr(feature), repr(level), repr(expect), repr(result1))) class NodeWriteTestCaseBase(TestCaseBase): TEST_NAMESPACE = NodeReadTestCaseBase.TEST_NAMESPACE TEST_PREFIX = NodeReadTestCaseBase.TEST_PREFIX TEST_LOCAL_NAME = NodeReadTestCaseBase.TEST_LOCAL_NAME TEST_QUALIFIED_NAME = NodeReadTestCaseBase.TEST_QUALIFIED_NAME readOnlyNodeList = _NodeTestCaseBase.readOnlyNodeList def checkPrefix(self): # Nodetypes that are read-only. if self.node.nodeType in self.readOnlyNodeList: checkReadOnly(self.node, 'nodeValue') return # Nodetypes that should ignore changes. if self.node.nodeType not in (Node.ATTRIBUTE_NODE, Node.ELEMENT_NODE): self.node.prefix = "Ignore_this" checkAttribute(self.node, "prefix", None) return # All other node types self.node.prefix = 'foo' checkAttribute(self.node, 'prefix', 'foo') checkAttribute(self.node, 'nodeName', 'foo:%s' % self.TEST_LOCAL_NAME) # Changing the prefix also changes other attributes newQualifiedName = '%s:%s' % ('foo', self.TEST_LOCAL_NAME) checkAttribute(self.node, 'nodeName', newQualifiedName) if self.node.nodeType == Node.ATTRIBUTE_NODE: checkAttribute(self.node, 'name', newQualifiedName) else: checkAttribute(self.node, 'tagName', newQualifiedName) def checkPrefixInvalidCharacter(self): if self.node.nodeType in self.readOnlyNodeList: return if self.node.nodeType not in (Node.ATTRIBUTE_NODE, Node.ELEMENT_NODE): return try: self.node.prefix = '5_illegal_prefix' except xml.dom.InvalidCharacterErr: pass else: assert 0, "Setting of illegal prefix succeeded." def checkPrefixMalformedPrefix(self): if self.node.nodeType in self.readOnlyNodeList: return if self.node.nodeType not in (Node.ATTRIBUTE_NODE, Node.ELEMENT_NODE): return try: self.node.prefix = ':prefix_with_colon' except xml.dom.NamespaceErr: pass else: assert 0, "Setting of malformed prefix with ':' succeeded." def checkPrefixNamespaceErr(self): if self.node.nodeType in self.readOnlyNodeList: return if self.node.nodeType not in (Node.ATTRIBUTE_NODE, Node.ELEMENT_NODE): return try: self.nodeNoNS.prefix = 'foo' except xml.dom.NamespaceErr: pass else: assert 0, 'Changing prefix on Node without namespace succeeded.' def checkPrefixXMLNamespace(self): if self.node.nodeType in self.readOnlyNodeList: return if self.node.nodeType not in (Node.ATTRIBUTE_NODE, Node.ELEMENT_NODE): return try: self.node.prefix = 'xml' except xml.dom.NamespaceErr: pass else: assert 0, ("Changing prefix to 'xml' on Node without " "W3C XML namespace succeeded.") def checkPrefixXMLNSNamespace(self): if self.node.nodeType in self.readOnlyNodeList: return if self.node.nodeType not in (Node.ATTRIBUTE_NODE, Node.ELEMENT_NODE): return if self.node.nodeType == Node.ATTRIBUTE_NODE: try: self.node.prefix = 'xmlns' except xml.dom.NamespaceErr: pass else: assert 0, ("Changing prefix to 'xmlns' on Attribute without " "W3C XML Namespaces namespace succeeded.") # --- Document class DocumentReadTestCase(NodeReadTestCaseBase): def setUp(self): self.node = self.createDocumentNS() def checkImportNode(self): foreignDoc = self.implementation.createDocument(None, 'foo', None) try: foreignDoc.importNode(self.document, 0) except xml.dom.NotSupportedErr: pass else: assert 0, "Was allowed to import a Document Node." class DocumentWriteTestCase(NodeWriteTestCaseBase): def setUp(self): self.node = self.createDocumentNS() def checkGetElementsByTagNameNS(self): doc = self.document elements = {} names = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'] for c in names: elements[c + '1'] = doc.createElementNS('uri:1', 'one:' + c) elements[c + '2'] = doc.createElementNS('uri:2', 'two:' + c) # set up simple tree elements['a1'].appendChild(elements['a2']) elements['a1'].appendChild(elements['b1']) elements['a1'].appendChild(elements['d1']) elements['b1'].appendChild(elements['b2']) elements['b1'].appendChild(elements['c1']) elements['c1'].appendChild(elements['c2']) elements['d1'].appendChild(elements['d2']) elements['d1'].appendChild(elements['e1']) elements['d1'].appendChild(elements['h1']) elements['e1'].appendChild(elements['e2']) elements['e1'].appendChild(elements['f1']) elements['e1'].appendChild(elements['g1']) elements['f1'].appendChild(elements['f2']) elements['g1'].appendChild(elements['g2']) elements['h1'].appendChild(elements['h2']) elements['h1'].appendChild(elements['i1']) elements['i1'].appendChild(elements['i2']) doc.documentElement.appendChild(elements['a1']) # now test # find all elements in the right order result = doc.getElementsByTagNameNS('*', '*') allnames = [] add = allnames.append for name in names: add(name) add(name) assert len(result) == len(allnames) + 1 for name, element in map(None, allnames, result[1:]): assert name == element.localName # find all elements in one namespace in the right order result = doc.getElementsByTagNameNS('uri:1', '*') assert len(result) == len(names) for name, element in map(None, names, result): assert name == element.localName # find single element, top result = doc.getElementsByTagNameNS('uri:1', 'a') assert len(result) == 1 assert result[0].tagName == 'one:a' # find single element somewhere in tree result = doc.getElementsByTagNameNS('uri:2', 'h') assert len(result) == 1 assert result[0].tagName == 'two:h' # find elements in the tree from all namespaces result = doc.getElementsByTagNameNS('*', 'f') assert len(result) == 2 assert result[0].tagName == 'one:f' assert result[1].tagName == 'two:f' def checkNormalize(self): doc = self.document docEl = doc.documentElement # First build a tree with adjacent and empty Text nodes, intermingled # with other Nodes. docEl.appendChild(doc.createTextNode('This')) docEl.appendChild(doc.createTextNode('')) docEl.appendChild(doc.createTextNode(' is')) docEl.appendChild(doc.createTextNode(' ')) docEl.appendChild(doc.createTextNode('a test.')) docEl.appendChild(doc.createCDATASection("Don't merge")) docEl.appendChild(doc.createTextNode('1')) docEl.appendChild(doc.createComment('foo')) docEl.appendChild(doc.createTextNode('2')) subEl = doc.createElement('baz') attr = doc.createAttribute('eggs') subEl.setAttributeNode(attr) docEl.appendChild(subEl) subEl.appendChild(doc.createTextNode('To ')) subEl.appendChild(doc.createTextNode('')) subEl.appendChild(doc.createTextNode('be or')) subEl.appendChild(doc.createEntityReference('amp')) subEl.appendChild(doc.createTextNode('not ')) subEl.appendChild(doc.createTextNode('to')) subEl.appendChild(doc.createTextNode(' be')) attr.appendChild(doc.createTextNode('Spanish ')) attr.appendChild(doc.createTextNode('Inquisition')) docEl.appendChild(doc.createTextNode('3')) docEl.appendChild(doc.createProcessingInstruction('bar', 'spam')) docEl.appendChild(doc.createTextNode('4')) # Now test doc.normalize() checkAttribute(docEl.childNodes, 'length', 9) checkAttribute(subEl.childNodes, 'length', 3) checkAttribute(attr.childNodes, 'length', 1) checkAttribute(docEl.childNodes[0], 'nodeType', Node.TEXT_NODE) checkAttribute(docEl.childNodes[0], 'data', 'This is a test.') checkAttribute(docEl.childNodes[1], 'nodeType', Node.CDATA_SECTION_NODE) checkAttribute(docEl.childNodes[2], 'nodeType', Node.TEXT_NODE) checkAttribute(docEl.childNodes[3], 'nodeType', Node.COMMENT_NODE) checkAttribute(docEl.childNodes[4], 'nodeType', Node.TEXT_NODE) checkAttribute(docEl.childNodes[5], 'nodeType', Node.ELEMENT_NODE) checkAttribute(docEl.childNodes[6], 'nodeType', Node.TEXT_NODE) checkAttribute(docEl.childNodes[7], 'nodeType', Node.PROCESSING_INSTRUCTION_NODE) checkAttribute(docEl.childNodes[8], 'nodeType', Node.TEXT_NODE) checkAttribute(subEl.childNodes[0], 'nodeType', Node.TEXT_NODE) checkAttribute(subEl.childNodes[1], 'nodeType', Node.ENTITY_REFERENCE_NODE) checkAttribute(subEl.childNodes[2], 'nodeType', Node.TEXT_NODE) checkAttribute(subEl.childNodes[0], 'data', 'To be or') checkAttribute(subEl.childNodes[2], 'data', 'not to be') checkAttribute(attr.childNodes[0], 'data', 'Spanish Inquisition') def checkCreateAttributeNS(self): attr = self.document.createAttributeNS(self.TEST_NAMESPACE, self.TEST_QUALIFIED_NAME) checkAttribute(attr, 'nodeType', Node.ATTRIBUTE_NODE) checkAttribute(attr, 'name', self.TEST_QUALIFIED_NAME) checkAttribute(attr, 'localName', self.TEST_LOCAL_NAME) checkAttribute(attr, 'prefix', self.TEST_PREFIX) checkAttribute(attr, 'namespaceURI', self.TEST_NAMESPACE) checkAttribute(attr, 'value', '') checkAttributeSameNode(attr, 'ownerDocument', self.document) def checkCreateAttributeNSNoPrefix(self): attr = self.document.createAttributeNS(self.TEST_NAMESPACE, self.TEST_LOCAL_NAME) checkAttribute(attr, 'name', self.TEST_LOCAL_NAME) checkAttribute(attr, 'localName', self.TEST_LOCAL_NAME) checkAttribute(attr, 'prefix', None) checkAttribute(attr, 'namespaceURI', self.TEST_NAMESPACE) def checkCreateAttributeNSIllegalCharacter(self): try: self.document.createAttributeNS(self.TEST_NAMESPACE, '4_prefix:5_illegal') except xml.dom.InvalidCharacterErr: pass else: assert 0, "Created Attribute with illegal qualified name." def checkCreateAttributeNSMalformedQA(self): try: self.document.createAttributeNS(self.TEST_NAMESPACE, 'malformed:qualfied:name') except xml.dom.NamespaceErr: pass else: assert 0, "Created Attribute with a malformed qualified name." try: self.document.createAttributeNS(self.TEST_NAMESPACE, ':malformed_qn') except xml.dom.NamespaceErr: pass else: assert 0, "Created Attribute with a malformed qualified name." def checkCreateAttributeNSPrefixNoNamespace(self): try: self.document.createAttributeNS(None, self.TEST_QUALIFIED_NAME) except xml.dom.NamespaceErr: pass else: assert 0, "Created Attribute with a prefix but no namespace." def checkCreateAttributeNSXMLNamespace(self): try: self.document.createAttributeNS(self.TEST_NAMESPACE, 'xml:nope') except xml.dom.NamespaceErr: pass else: assert 0, ( "Created Attribute with a 'xml' prefix but not the XML " "namespace.") def checkCreateAttributeNSXMLNamespace(self): try: self.document.createAttributeNS(self.TEST_NAMESPACE, 'xmlns:nope') except xml.dom.NamespaceErr: pass else: assert 0, ( "Created Attribute with a 'xmlns' prefix but not the XML " "Namespaces namespace.") def checkCreateElementNS(self): el = self.document.createElementNS(self.TEST_NAMESPACE, self.TEST_QUALIFIED_NAME) checkAttribute(el, 'nodeType', Node.ELEMENT_NODE) checkAttribute(el, 'tagName', self.TEST_QUALIFIED_NAME) checkAttribute(el, 'localName', self.TEST_LOCAL_NAME) checkAttribute(el, 'prefix', self.TEST_PREFIX) checkAttribute(el, 'namespaceURI', self.TEST_NAMESPACE) checkAttributeSameNode(el, 'ownerDocument', self.document) def checkCreateElementNSNoPrefix(self): el = self.document.createElementNS(self.TEST_NAMESPACE, self.TEST_LOCAL_NAME) checkAttribute(el, 'tagName', self.TEST_LOCAL_NAME) checkAttribute(el, 'localName', self.TEST_LOCAL_NAME) checkAttribute(el, 'prefix', None) checkAttribute(el, 'namespaceURI', self.TEST_NAMESPACE) def checkCreateElementNSIllegalCharacter(self): try: self.document.createElementNS(self.TEST_NAMESPACE, '4_prefix:5_illegal') except xml.dom.InvalidCharacterErr: pass else: assert 0, "Created Element with illegal qualified name." def checkCreateElementNSMalformedQA(self): try: self.document.createElementNS(self.TEST_NAMESPACE, 'malformed:qualfied:name') except xml.dom.NamespaceErr: pass else: assert 0, "Created Element with a malformed qualified name." try: self.document.createElementNS(self.TEST_NAMESPACE, ':malformed_qn') except xml.dom.NamespaceErr: pass else: assert 0, "Created Element with a malformed qualified name." def checkCreateElementNSPrefixNoNamespace(self): try: self.document.createElementNS(None, self.TEST_QUALIFIED_NAME) except xml.dom.NamespaceErr: pass else: assert 0, "Created Element with a prefix but no namespace." def checkCreateElementNSXMLNamespace(self): try: self.document.createElementNS(self.TEST_NAMESPACE, 'xml:nope') except xml.dom.NamespaceErr: pass else: assert 0, ( "Created Element with a 'xml' prefix but not the XML " "namespace.") class GetElementByIdTestCase(TestCaseBase): PROLOGUE = """\ ]> """ def setup(self): pass def checkWithoutId(self): doc = self.parse(self.PROLOGUE + "") self.assert_(doc.getElementById("foo") is None) def checkWithDifferentId(self): doc = self.parse(self.PROLOGUE + "") self.assert_(doc.getElementById("foo") is None) def checkWithIdOnRootElement(self): doc = self.parse(self.PROLOGUE + "") self.assert_(isSameNode(doc.getElementById("foo"), doc.documentElement)) def checkWithIdOnChildElement(self): doc = self.parse(self.PROLOGUE + "") self.assert_(isSameNode(doc.getElementById("foo"), doc.documentElement.firstChild)) # --- Element class ElementReadTestCase(NodeReadTestCaseBase): def setUp(self): doc = self.createDocument() self.element = self.nodeNoNS = self.elementNoNS = doc.createElement( self.TEST_LOCAL_NAME) self.elementNS = self.node = doc.createElementNS( self.TEST_NAMESPACE, self.TEST_QUALIFIED_NAME) def checkGetAttributeNS(self): assert self.element.getAttributeNS("uri:bugga", "ugga") == "", \ "non-existant attribute should return ''" def checkGetAttributeNodeNS(self): assert self.element.getAttributeNodeNS("uri:bugga", "ugga") is None, \ "non-existant attribute should return None" def checkCloneNode(self): el = self.element clone = el.cloneNode(0) assert not isSameNode(el, clone), "Clone is same Node as original." checkAttribute(clone, 'localName', el.localName) checkAttribute(clone, 'namespaceURI', el.namespaceURI) checkAttribute(clone, 'prefix', el.prefix) def checkImportNode(self): el = self.element doc = self.document el.appendChild(doc.createTextNode('A Text Node')) el.appendChild(doc.createComment('A Comment')) el.setAttribute('attr1', 'An attribute') el.setAttribute('attr2', 'Another attribute') foreignDoc = self.implementation.createDocument(None, 'foo', None) clone = foreignDoc.importNode(self.element, 0) deepClone = foreignDoc.importNode(self.element, 1) assert not isSameNode(el, clone), "Clone is same Node as original." assert not isSameNode(el, deepClone), "Clone is same Node as original." checkAttributeSameNode(clone, 'ownerDocument', foreignDoc) checkAttributeSameNode(deepClone, 'ownerDocument', foreignDoc) checkAttribute(clone, 'parentNode', None) checkAttribute(deepClone, 'parentNode', None) checkLength(clone.childNodes, 0) checkLength(deepClone.childNodes, el.childNodes.length) checkLength(clone.attributes, el.attributes.length) checkLength(deepClone.attributes, el.attributes.length) checkAttribute(clone, 'nodeName', el.nodeName) checkAttribute(deepClone, 'nodeName', el.nodeName) checkAttribute(clone, 'nodeType', el.nodeType) checkAttribute(deepClone, 'nodeType', el.nodeType) checkAttribute(clone, 'nodeValue', el.nodeValue) checkAttribute(deepClone, 'nodeValue', el.nodeValue) for i in range(deepClone.childNodes.length): checkAttribute(deepClone.childNodes.item(i), 'nodeType', el.childNodes.item(i).nodeType) checkAttributeSameNode(deepClone.childNodes.item(i), 'ownerDocument', foreignDoc) if deepClone.childNodes.item(i).nodeType != Node.ELEMENT_NODE: checkAttribute(deepClone.childNodes.item(i), 'data', el.childNodes.item(i).data) for i in range(deepClone.attributes.length): checkAttribute(clone.attributes.item(i), 'name', el.attributes.item(i).name) checkAttribute(deepClone.attributes.item(i), 'name', el.attributes.item(i).name) checkAttribute(clone.attributes.item(i), 'value', el.attributes.item(i).value) checkAttribute(deepClone.attributes.item(i), 'value', el.attributes.item(i).value) checkAttributeSameNode(clone.attributes.item(i), 'ownerElement', clone) checkAttributeSameNode(deepClone.attributes.item(i), 'ownerElement', deepClone) class ElementWriteTestCase(NodeWriteTestCaseBase): def setUp(self): doc = self.createDocument() self.element = self.nodeNoNS = self.elementNoNS = doc.createElement( self.TEST_LOCAL_NAME) self.elementNS = self.node = doc.createElementNS(self.TEST_NAMESPACE, self.TEST_QUALIFIED_NAME) def checkHasAttribute(self): assert not self.element.hasAttribute('ugga'), \ "Test for non-exisiting attribute returned true." self.element.setAttribute("ugga", "foo") assert self.element.hasAttribute('ugga'), \ "Test for exisiting attribute returned false." def checkSetAttributeNS(self): self.element.setAttributeNS("uri:bugga", "b:ugga", "foo") self.element.setAttributeNS("uri:bar", "bar:ugga", "baz") assert self.element.hasAttributeNS("uri:bar", "ugga"), \ "Test for presence of created attribute returned false." value = self.element.getAttributeNS("uri:bugga", "ugga") assert value == 'foo', ( "Incorrect attr value returned. Expected 'foo', got %s" % repr(value)) node = self.element.getAttributeNodeNS("uri:bugga", "ugga") assert node.prefix == 'b', ( "New Attr node has incorrect prefix, expected 'b', got " "%s" % repr(node.prefix)) #"Note that because the DOM does no lexical checking, the empty string #will be treated as a real namespace URI in DOM Level 2 methods. #Applications must use the value null as the namespaceURI parameter for #methods if they wish to have no namespace." - the rec # The NamespaceURI must be a namespace name, which Namespaces in XML # states is a URI reference. I'm assuming that "" is not a valid URI # reference, so we're not testing using that. def checkSetAttributeEmptyNS(self): self.element.setAttributeNS(None, "ugga", "foo") assert self.element.hasAttributeNS(None, "ugga"), \ "Test for presence of created attribute returned false." value = self.element.getAttributeNS(None, "ugga") assert value == 'foo', ( "Incorrect attr value returned. Expected 'foo', got %s" % repr(value)) node = self.element.getAttributeNodeNS(None, "ugga") assert node.prefix == None, ( "New Attr node has incorrect prefix, expected None, got " "%s" % repr(node.prefix)) def checkSetAttributeNSDifferentPrefix(self): self.element.setAttributeNS("uri:bugga", "b:ugga", "foo") self.element.setAttributeNS("uri:bar", "bar:ugga", "baz") self.element.setAttributeNS("uri:bugga", "c:ugga", "new value") assert self.element.hasAttributeNS("uri:bar", "ugga"), ( "Test for presence of created attribute returned false.") value = self.element.getAttributeNS("uri:bugga", "ugga") assert value == 'new value', ( "Incorrect attr value returned. Expected 'new value', got " "%s" % repr(value)) node = self.element.getAttributeNodeNS("uri:bugga", "ugga") assert node.prefix == 'c', ( "New Attr node has incorrect prefix, expected 'c', got " "%s" % repr(node.prefix)) def checkSetAttributeNSNoPrefix(self): self.element.setAttributeNS(TEST_NAMESPACE, 'foo', 'bar') assert self.element.hasAttributeNS(TEST_NAMESPACE, "foo"), ( "Test for presence of created attribute returned false.") value = self.element.getAttributeNS(TEST_NAMESPACE, "foo") assert value == 'bar', ( "Incorrect attr value returned. Expected 'bar', got " "%s" % repr(value)) node = self.element.getAttributeNodeNS(TEST_NAMESPACE, "foo") checkAttribute(node, 'prefix', None) def checkSetAttributeNSXMLNSDeclaration(self): XMLNSNamespace = 'http://www.w3.org/2000/xmlns/' self.element.setAttributeNS(XMLNSNamespace, 'xmlns', TEST_NAMESPACE) assert self.element.hasAttributeNS(XMLNSNamespace, "xmlns"), ( "Test for presence of created xmlns attribute returned false.") value = self.element.getAttributeNS(XMLNSNamespace, "xmlns") assert value == TEST_NAMESPACE, ( "Incorrect attr value returned. Expected %s, got " "%s" % (`TEST_NAMESPACE`, `value`)) node = self.element.getAttributeNodeNS(XMLNSNamespace, "xmlns") checkAttribute(node, 'prefix', None) def checkSetAttributeNSIllegalCharacter(self): try: self.element.setAttributeNS("uri:bugga", "5_b:ugga", "illegal") except xml.dom.InvalidCharacterErr: pass else: assert 0, "Was allowed to use an illegal attribute name." def checkSetAttributeNSMalformedQA(self): try: self.element.setAttributeNS("uri:bugga", 'malformed:qualfied:name', "malformed") except xml.dom.NamespaceErr: pass else: assert 0, "Was allowed to use a malformed qualified name." try: self.element.setAttributeNS("uri:bugga", ':malformed_qn', "malformed") except xml.dom.NamespaceErr: pass else: assert 0, "Was allowed to use a malformed qualified name." def checkSetAttributeNSPrefixNoNamespace(self): try: self.element.setAttributeNS(None, 'prefix:localName', 'Nono') except xml.dom.NamespaceErr: pass else: assert 0, ( 'Using a null namespace and a prefix for an ' 'attribute succeeded.') def checkSetAttributeNSXMLNamespace(self): try: self.element.setAttributeNS('uri:unknown', 'xml:localName', 'Nono') except xml.dom.NamespaceErr: pass else: assert 0, ("Using the prefix 'xml' for an attribute without " "W3C XML namespace succeeded.") def checkSetAttributeNSXMLNSNamespace(self): try: self.element.setAttributeNS('uri:unknown', 'xmlns:localName', 'No') except xml.dom.NamespaceErr: pass else: assert 0, ("Using the prefix 'xmlns' for an attribute without " "W3C XML Namespaces namespace succeeded.") def checkSetAttributeNodeNS(self): node1 = self.document.createAttributeNS("uri:bugga", "b:ugga") node1.value = 'foo' node2 = self.document.createAttributeNS("uri:bar", "bar:ugga") returnValue = self.element.setAttributeNode(node1) self.element.setAttributeNode(node2) assert returnValue is None, ( "setAttributeNodeNS returned %s" % repr(returnValue)) assert self.element.hasAttributeNS("uri:bar", "ugga"), \ "Test for presence of created attribute returned false." value = self.element.getAttributeNS("uri:bugga", "ugga") assert value == 'foo', \ ("Incorrect attr value returned. Expected 'foo', got %s" % repr(value)) node = self.element.getAttributeNodeNS("uri:bugga", "ugga") assert isSameNode(node1, node), \ "Incorrect node returned from getAttributeNodeNS." def checkSetAttributeNodeNSReplaceExisting(self): # Try a new node with same namespaceURI and localname, but differing # prefix. This should replace the existing node, returning it. node1 = self.document.createAttributeNS("uri:bugga", "b:ugga") self.element.setAttributeNode(node1) node2 = self.document.createAttributeNS("uri:bugga", "c:ugga") returnValue = self.element.setAttributeNodeNS(node2) if returnValue is None: assert 0, "setAttributeNodeNS did not replace original attribute" assert isSameNode(node1, returnValue), ( "setAttributeNodeNS returned %s" % repr(returnValue)) def checkSetAttributeNodeNSWrongDocument(self): foreignDoc = self.implementation.createDocument(None, 'foo', None) foreignAttr = foreignDoc.createAttributeNS('uri:spam', 'spam:eggs') try: self.element.setAttributeNodeNS(foreignAttr) except xml.dom.WrongDocumentErr: pass else: assert 0, "Was allowed to setAttributeNodeNS with a foreign Attr." def checkSetAttributeNodeNSAlreadyInUse(self): otherElement = self.document.createElement('foo') otherAttr = self.document.createAttributeNS('uri:spam', 'spam:eggs') otherElement.setAttributeNodeNS(otherAttr) try: self.element.setAttributeNodeNS(otherAttr) except xml.dom.InuseAttributeErr: pass else: assert 0, ( "Was allowed to setAttributeNodeNS with an Attr already in " "use.") def checkRemoveAttributeNS(self): node1 = self.document.createAttributeNS("uri:bugga", "b:ugga") node2 = self.document.createAttributeNS("uri:bar", "bar:ugga") self.element.setAttributeNode(node1) self.element.setAttributeNode(node2) self.element.removeAttributeNS("uri:bugga", "ugga") assert not self.element.hasAttributeNS("uri:bugga", "ugga"), \ "Test for presence of created attribute still returns true." assert self.element.hasAttributeNS("uri:bar", "ugga"), \ "Test for presence of created attribute returned false." def checkGetElementsByTagNameNS(self): doc = self.document el = self.element elements = {} names = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'] for c in names: elements[c + '1'] = doc.createElementNS('uri:1', 'one:' + c) elements[c + '2'] = doc.createElementNS('uri:2', 'two:' + c) # set up simple tree elements['a1'].appendChild(elements['a2']) elements['a1'].appendChild(elements['b1']) elements['a1'].appendChild(elements['d1']) elements['b1'].appendChild(elements['b2']) elements['b1'].appendChild(elements['c1']) elements['c1'].appendChild(elements['c2']) elements['d1'].appendChild(elements['d2']) elements['d1'].appendChild(elements['e1']) elements['d1'].appendChild(elements['h1']) elements['e1'].appendChild(elements['e2']) elements['e1'].appendChild(elements['f1']) elements['e1'].appendChild(elements['g1']) elements['f1'].appendChild(elements['f2']) elements['g1'].appendChild(elements['g2']) elements['h1'].appendChild(elements['h2']) elements['h1'].appendChild(elements['i1']) elements['i1'].appendChild(elements['i2']) el.appendChild(elements['a1']) # now test # find all elements in the right order result = el.getElementsByTagNameNS('*', '*') allnames = [] add = allnames.append for name in names: add(name) add(name) assert len(result) == len(allnames) for name, element in map(None, allnames, result): assert name == element.localName # find all elements in one namespace in the right order result = el.getElementsByTagNameNS('uri:1', '*') assert len(result) == len(names) for name, element in map(None, names, result): assert name == element.localName # find single element, top result = el.getElementsByTagNameNS('uri:1', 'a') assert len(result) == 1 assert result[0].tagName == 'one:a' # find single element somewhere in tree result = el.getElementsByTagNameNS('uri:2', 'h') assert len(result) == 1 assert result[0].tagName == 'two:h' # find elements in the tree from all namespaces result = el.getElementsByTagNameNS('*', 'f') assert len(result) == 2 assert result[0].tagName == 'one:f' assert result[1].tagName == 'two:f' def checkNormalize(self): doc = self.document el = self.element # Build test nodes el1 = el.appendChild(doc.createElement('e1')) el2 = el.appendChild(doc.createElement('e2')) el1.appendChild(doc.createTextNode('foo')) el1.appendChild(doc.createTextNode('bar')) el2.appendChild(doc.createTextNode('spam')) el2.appendChild(doc.createTextNode('eggs')) # Now test # Only normalize on element, sibling should be unaffected el1.normalize() checkAttribute(el1.childNodes, 'length', 1) checkAttribute(el2.childNodes, 'length', 2) checkAttribute(el1.childNodes[0], 'data', 'foobar') # Now normalize the whole test tree el.normalize() checkAttribute(el1.childNodes, 'length', 1) checkAttribute(el2.childNodes, 'length', 1) checkAttribute(el1.childNodes[0], 'data', 'foobar') checkAttribute(el2.childNodes[0], 'data', 'spameggs') # --- CharacterData class CharacterDataReadTestCaseBase(NodeReadTestCaseBase): def checkImportNode(self): foreignDoc = self.implementation.createDocument(None, 'foo', None) clone = foreignDoc.importNode(self.chardata, 0) deepClone = foreignDoc.importNode(self.chardata, 1) assert not isSameNode(self.chardata, clone), ( "Clone is same as original.") assert not isSameNode(self.chardata, deepClone), ( "Clone is same as original.") checkAttributeSameNode(clone, 'ownerDocument', foreignDoc) checkAttributeSameNode(deepClone, 'ownerDocument', foreignDoc) checkAttribute(clone, 'parentNode', None) checkAttribute(deepClone, 'parentNode', None) checkAttribute(clone, 'nodeType', self.chardata.nodeType) checkAttribute(deepClone, 'nodeType', self.chardata.nodeType) checkAttribute(clone, 'data', self.chardata.data) checkAttribute(deepClone, 'data', self.chardata.data) checkLength(clone.childNodes, 0) checkLength(deepClone.childNodes, 0) class CharacterDataWriteTestCaseBase(NodeWriteTestCaseBase): pass # --- Comment class CommentReadTestCase(CharacterDataReadTestCaseBase): def setUp(self): self.chardata = self.node = self.createDocument().createComment("com") class CommentWriteTestCase(CharacterDataWriteTestCaseBase): def setUp(self): self.chardata = self.node = self.createDocument().createComment("com") # --- Text class TextReadTestCase(CharacterDataReadTestCaseBase): def setUp(self): self.chardata = self.node = self.createDocument().createTextNode("com") self.expectedType = Node.TEXT_NODE class TextWriteTestCase(CharacterDataWriteTestCaseBase): def setUp(self): self.chardata = self.node = self.createDocument().createTextNode("com") self.expectedType = Node.TEXT_NODE # --- Attr class AttrReadTestCase(NodeReadTestCaseBase): def setUp(self): self.attr = self.node = self.createDocument().createAttributeNS( self.TEST_NAMESPACE, self.TEST_QUALIFIED_NAME) self.attrNoNS = self.nodeNoNS = self.document.createAttribute( self.TEST_LOCAL_NAME) def checkCloneNode(self): attr = self.attr clone = attr.cloneNode(0) assert not isSameNode(attr, clone), "Clone is same Node as original." checkAttribute(clone, 'localName', attr.localName) checkAttribute(clone, 'namespaceURI', attr.namespaceURI) checkAttribute(clone, 'prefix', attr.prefix) # make sure the cloned attr isn't sharing data with the original newPrefix = 'foo' newQname = '%s:%s' % (newPrefix, self.TEST_LOCAL_NAME) oldPrefix = self.attr.prefix oldQname = self.attr.name self.attr.prefix = newPrefix checkAttribute(clone, 'prefix', oldPrefix) checkAttribute(clone, 'name', oldQname) def checkImportNode(self): foreignDoc = self.implementation.createDocument(None, 'foo', None) clone = foreignDoc.importNode(self.attr, 0) deepClone = foreignDoc.importNode(self.attr, 1) assert not isSameNode(self.attr, clone), "Clone is same as original." assert not isSameNode(self.attr, deepClone), ( "Clone is same as original.") checkAttributeSameNode(clone, 'ownerDocument', foreignDoc) checkAttributeSameNode(deepClone, 'ownerDocument', foreignDoc) checkAttribute(clone, 'parentNode', None) checkAttribute(deepClone, 'parentNode', None) checkAttribute(clone, 'nodeType', self.attr.nodeType) checkAttribute(deepClone, 'nodeType', self.attr.nodeType) checkAttribute(clone, 'name', self.attr.name) checkAttribute(deepClone, 'name', self.attr.name) checkAttribute(clone, 'value', self.attr.value) checkAttribute(deepClone, 'value', self.attr.value) checkAttribute(clone, 'specified', 1) checkAttribute(deepClone, 'specified', 1) checkAttribute(clone, 'nodeName', self.attr.nodeName) checkAttribute(deepClone, 'nodeName', self.attr.nodeName) checkAttribute(clone, 'nodeValue', self.attr.nodeValue) checkAttribute(deepClone, 'nodeValue', self.attr.nodeValue) checkLength(clone.childNodes, 1) # Subtree models value checkAttribute(clone.firstChild, 'nodeType', Node.TEXT_NODE) checkAttribute(clone.firstChild, 'data', self.attr.value) checkLength(deepClone.childNodes, 1) checkAttribute(deepClone.firstChild, 'nodeType', Node.TEXT_NODE) checkAttribute(deepClone.firstChild, 'data', self.attr.value) class AttrWriteTestCase(NodeWriteTestCaseBase): def setUp(self): self.attr = self.node = self.createDocument().createAttributeNS( self.TEST_NAMESPACE, self.TEST_QUALIFIED_NAME) self.attrNoNS = self.nodeNoNS = self.document.createAttribute( self.TEST_LOCAL_NAME) def checkAttrNodePrefixMultipleRefs(self): "changing the attribute prefix should change the name of other refs" # qualified name with different prefix newPrefix = 'foo' newQname = '%s:%s' % (newPrefix, self.TEST_LOCAL_NAME) self.attr.value = 'spam' self.document.documentElement.setAttributeNode(self.attr) attr2 = self.document.documentElement.getAttributeNodeNS( self.TEST_NAMESPACE, self.TEST_LOCAL_NAME) self.attr.prefix = newPrefix attr3 = self.document.documentElement.getAttributeNodeNS( self.TEST_NAMESPACE, self.TEST_LOCAL_NAME) # orig attr checkAttribute(self.attr, 'nodeName', newQname) # attr gotten before set checkAttribute(attr2, 'nodeName', newQname) # attr gotten after set checkAttribute(attr3, 'nodeName', newQname) def checkElementAttrPrefixMultipleRefs(self): "changing the attribute prefix should change the name of other refs" # qualified name with different prefix newPrefix = 'foo' newQname = '%s:%s' % (newPrefix, self.TEST_LOCAL_NAME) self.attr.value = 'spam' self.document.documentElement.setAttributeNode(self.attr) attr2 = self.document.documentElement.getAttributeNodeNS( self.TEST_NAMESPACE, self.TEST_LOCAL_NAME) # change the prefix and value of the attr. Since we're giving the same # localname and namespaceURI, the existing attr should be changed. self.document.documentElement.setAttributeNS(self.TEST_NAMESPACE, newQname, 'eggs') attr3 = self.document.documentElement.getAttributeNodeNS( self.TEST_NAMESPACE, self.TEST_LOCAL_NAME) # element attr assert self.document.documentElement.getAttributeNS( self.TEST_NAMESPACE, self.TEST_LOCAL_NAME) == 'eggs', ( "changing prefix and value on attr didn't change original attr") # orig attr checkAttribute(self.attr, 'nodeName', newQname) # attr gotten before set checkAttribute(attr2, 'nodeName', newQname) # attr gotten after set checkAttribute(attr3, 'nodeName', newQname) # --- Default attributes class DefaultAttrTestCase(TestCaseBase): def setUp(self): self.document = self.parse(""" ]> """ % TEST_NAMESPACE) def checkCreateElementNS(self): el = self.document.createElementNS(TEST_NAMESPACE, 'doc') assert el.hasAttribute('foo'), ( 'Newly created Element Node should have default attribute.') assert el.getAttribute('foo') == 'bar', ( "Wrong value of default attribute found, expected 'bar', " "found %s" % el.getAttribute('foo')) checkAttribute(el.getAttributeNode('foo'), 'specified', 0) def checkImportNode(self): attr = self.document.documentElement.getAttributeNode('foo') newDoc = self.implementation.createDocument(None, 'baz', None) importedAttr = newDoc.importNode(attr, 0) checkAttribute(importedAttr, 'specified', 1) def checkImportNodeFromDefault(self): newDoc = self.implementation.createDocument(None, 'baz', None) el = newDoc.importNode(self.document.documentElement, 0) assert not el.hasAttribute('foo'), ( "Default attribute retained when importing into document that " "doesn't specify the default attribute.") def checkImportNodeToDefault(self): newDoc = self.implementation.createDocument(None, 'baz', None) newEl = newDoc.createElementNS(TEST_NAMESPACE, 'doc') el = self.document.importNode(newEl, 0) assert el.hasAttribute('foo'), ( 'Imported Element Node should have default attribute.') assert el.getAttribute('foo') == 'bar', ( "Wrong value of default attribute found, expected 'bar', " "found %s" % repr(el.getAttribute('foo'))) checkAttribute(el.getAttributeNode('foo'), 'specified', 0) class DefaultAttrWithPrefixTestCase(TestCaseBase): pass # XXX removed until we can verify default attributes in DOM spec ## def setUp(self): ## self.document = self.parse(""" ## ## ## ]> ## ## """ % TEST_NAMESPACE) ## def checkHasAttributeNS(self): ## el = self.document.documentElement ## assert el.hasAttributeNS(TEST_NAMESPACE, 'foo'), ( ## 'Default attribute not found.') ## def checkGetAttributeNS(self): ## el = self.document.documentElement ## assert el.getAttributeNS(TEST_NAMESPACE, 'foo') == 'bar', ( ## "Wrong value of default attribute found, expected 'bar', " ## "found %s" % repr(el.getAttributeNS(TEST_NAMESPACE, 'foo'))) ## def checkCreateElementNS(self): ## el = self.document.createElementNS(TEST_NAMESPACE, 'doc') ## assert el.hasAttributeNS(TEST_NAMESPACE, 'foo'), ( ## 'Newly created Element Node should have default attribute.') ## assert el.getAttributeNS(TEST_NAMESPACE, 'foo') == 'bar', ( ## "Wrong value of default attribute found, expected 'bar', " ## "found %s" % el.getAttributeNS(TEST_NAMESPACE, 'foo')) ## checkAttribute(el.getAttributeNodeNS(TEST_NAMESPACE, 'foo'), ## 'specified', 0) ## def checkImportNodeToDefault(self): ## newDoc = self.implementation.createDocument(None, 'baz', None) ## newEl = newDoc.createElementNS(TEST_NAMESPACE, 'prefix:doc') ## el = self.document.importNode(newEl, 0) ## assert el.hasAttributeNS(TEST_NAMESPACE, 'foo'), ( ## 'Imported Element Node should have default attribute.') ## assert el.getAttributeNS(TEST_NAMESPACE, 'foo') == 'bar', ( ## "Wrong value of default attribute found, expected 'bar', " ## "found %s" % repr(el.getAttributeNS(TEST_NAMESPACE, 'foo'))) ## checkAttribute(el.getAttributeNodeNS(TEST_NAMESPACE, 'foo'), ## 'specified', 0) ## def checkChangePrefixUnspecified(self): ## attr = self.document.documentElement.getAttributeNodeNS(TEST_NAMESPACE, ## 'foo') ## attr.prefix = 'test' ## # Changing the prefix of a default attribute shouldn't make a new ## # unspecified (default) attribute node appear. ## # TODO: It turns out this may be a hole in the spec. See PXML(60)[]: ## # http://www.zope.org/Members/karl/ParsedXML/ParsedXMLTracker/60 ## # Waiting for consensus from DOM WG. Changing the prefix *should* make ## # a new Attr node appear it seems. I am not convinced yet. ## assert attr.ownerElement.attributes.length == 1, ( ## "Changing the prefix of a default attribute caused a new default " ## "attribute node to be created.") ## # The specified flag shouldn't change; we didn't change the value ## checkAttribute(attr, 'specified', 0) ## def checkChangePrefixSpecified(self): ## self.document.documentElement.setAttributeNS(TEST_NAMESPACE, 'foo', ## 'newValue') ## attr = self.document.documentElement.getAttributeNodeNS(TEST_NAMESPACE, ## 'foo') ## attr.prefix = 'test' ## # Changing the prefix of a specified attribute shouldn't make a new ## # unspecified (default) attribute node appear. ## assert attr.ownerElement.attributes.length == 2, ( ## "Changing the prefix of a specified attribute caused a new " ## "default attribute node to be created.") ## def checkRemoveAttributeNS(self): ## el = self.document.documentElement ## # Replace default with specified attr ## el.setAttributeNS(TEST_NAMESPACE, 'foo', 'baz') ## el.removeAttributeNS(TEST_NAMESPACE, 'foo') ## assert el.hasAttributeNS(TEST_NAMESPACE, 'foo'), ( ## 'Removing specified attribute should ' ## 'bring back default attribute.') ## assert el.getAttributeNS(TEST_NAMESPACE, 'foo') == 'bar', ( ## "Wrong value of default attribute foud, expected 'bar', " ## "found %s" % repr(el.getAttributeNS(TEST_NAMESPACE, 'foo'))) ## checkAttribute(el.getAttributeNodeNS(TEST_NAMESPACE, 'foo'), ## 'specified', 0) ## def checkRemoveAttributeNode(self): ## el = self.document.documentElement ## newAttr = self.document.createAttributeNS(TEST_NAMESPACE, 'foo') ## newAttr.value = 'baz' ## # Replace default with specified attr ## el.setAttributeNodeNS(newAttr) ## el.removeAttributeNode(newAttr) ## assert el.hasAttributeNS(TEST_NAMESPACE, 'foo'), ( ## 'Removing specified attribute should bring back default ' ## 'attribute.') ## assert el.getAttributeNS(TEST_NAMESPACE, 'foo') == 'bar', ( ## "Wrong value of default attribute found, expected 'bar', " ## "found %s" % repr(el.getAttributeNS(TEST_NAMESPACE, 'foo'))) ## checkAttribute(el.getAttributeNodeNS(TEST_NAMESPACE, 'foo'), ## 'specified', 0) ## def checkRemoveNamedItemNS(self): ## el = self.document.documentElement ## # Replace default with specified attr ## el.setAttributeNS(TEST_NAMESPACE, 'foo', 'baz') ## el.attributes.removeNamedItemNS(TEST_NAMESPACE, 'foo') ## assert el.hasAttributeNS(TEST_NAMESPACE, 'foo'), \ ## 'Removing specified attribute should bring back default attribute.' ## assert el.getAttributeNS(TEST_NAMESPACE, 'foo') == 'bar', ( ## "Wrong value of default attribute found, expected 'bar', found %s" ## % repr(el.getAttributeNS(TEST_NAMESPACE, 'foo'))) ## checkAttribute(el.getAttributeNodeNS(TEST_NAMESPACE, 'foo'), ## 'specified', 0) ## def checkSetAttributeNS(self): ## el = self.document.documentElement ## el.setAttributeNS(TEST_NAMESPACE, 'foo', 'baz') ## checkAttribute(el.getAttributeNodeNS(TEST_NAMESPACE, 'foo'), ## 'specified', 1) ## def checkSetAttributeNodeNS(self): ## el = self.document.documentElement ## newAttr = self.document.createAttributeNS(TEST_NAMESPACE, 'foo') ## newAttr.value = 'baz' ## el.setAttributeNode(newAttr) ## checkAttribute(el.getAttributeNodeNS(TEST_NAMESPACE, 'foo'), ## 'specified', 1) # --- DocumentFragment class DocumentFragmentReadTestCase(NodeReadTestCaseBase): def setUp(self): self.docfrag = self.createDocument().createDocumentFragment() self.node = self.docfrag def checkImportNode(self): foreignDoc = self.implementation.createDocument(None, 'foo', None) frag = self.docfrag frag.appendChild(self.document.createComment('foo')) frag.appendChild(self.document.createTextNode('bar')) clone = foreignDoc.importNode(frag, 0) deepClone = foreignDoc.importNode(frag, 1) assert not isSameNode(frag, clone), "Clone is same Node as original." assert not isSameNode(frag, deepClone), ( "Clone is same Node as original.") checkAttributeSameNode(clone, 'ownerDocument', foreignDoc) checkAttributeSameNode(deepClone, 'ownerDocument', foreignDoc) checkAttribute(clone, 'parentNode', None) checkAttribute(deepClone, 'parentNode', None) checkLength(clone.childNodes, 0) checkLength(deepClone.childNodes, frag.childNodes.length) for i in range(deepClone.childNodes.length): checkAttribute(deepClone.childNodes.item(i), 'nodeType', frag.childNodes.item(i).nodeType) checkAttribute(deepClone.childNodes.item(i), 'data', frag.childNodes.item(i).data) checkAttributeSameNode(deepClone.childNodes.item(i), 'ownerDocument', foreignDoc) class DocumentFragmentWriteTestCase(NodeWriteTestCaseBase): def setUp(self): self.docfrag = self.createDocument().createDocumentFragment() self.node = self.docfrag # --- NamedNodeMap class NamedNodeMapWriteTestCase(TestCaseBase): TEST_NAMESPACE = NodeReadTestCaseBase.TEST_NAMESPACE TEST_PREFIX = NodeReadTestCaseBase.TEST_PREFIX TEST_LOCAL_NAME = NodeReadTestCaseBase.TEST_LOCAL_NAME TEST_QUALIFIED_NAME = NodeReadTestCaseBase.TEST_QUALIFIED_NAME def setUp(self): self.map = self.createDocument().createElement("foo")._get_attributes() self.attribute = self.document.createAttributeNS(self.TEST_NAMESPACE, self.TEST_QUALIFIED_NAME) self.attribute.value = "attrValue" self.map.setNamedItemNS(self.attribute) def checkGetNamedItemNS(self): node = self.map.getNamedItemNS(self.TEST_NAMESPACE, self.TEST_LOCAL_NAME) assert node is not None, "getNamedItemNS didn't retrieve attribute." assert isSameNode(node, self.attribute), ( "getNamedItemNS retrieved incorrect attribute.") def checkGetNamedItemNSWrongNamespace(self): node = self.map.getNamedItemNS('uri:foo', self.TEST_LOCAL_NAME) assert node is None, "getNamedItemNS returned an attribute." def checkGetNamedItemNSWrongLocalname(self): node = self.map.getNamedItemNS(self.TEST_NAMESPACE, 'bar') assert node is None, "getNamedItemNS returned an attribute." def checkRemoveNamedItemNS(self): node = self.map.removeNamedItemNS(self.TEST_NAMESPACE, self.TEST_LOCAL_NAME) assert node is not None, ( "removeNamedItemNS didn't return an attribute.") assert isSameNode(node, self.attribute), ( "removeNamedItemNS returned incorrect attribute.") assert self.map.getNamedItemNS(self.TEST_NAMESPACE, self.TEST_LOCAL_NAME) is None, "Attribute was not removed." checkLength(self.map, 0) def checkRemoveNamedItemNSNotFound(self): # Exceptions try: self.map.removeNamedItemNS('uri:foo', 'bar:baz') except xml.dom.NotFoundErr: pass else: assert 0, "Removal of non-existent item succeeded." def checkSetNamedItemNS(self): newAttr = self.document.createAttributeNS(self.TEST_NAMESPACE, 'qname:someAttr') newAttr.value = 'spam' retVal = self.map.setNamedItemNS(newAttr) assert retVal is None, "setNamedItemNS returned %s" % repr(retVal) checkLength(self.map, 2) assert isSameNode(self.map.getNamedItemNS(self.TEST_NAMESPACE, 'someAttr'), newAttr), ( "setNamedItemNS store seems to have failed, can't retrieve.") def checkSetNamedItemNSReplaceExisting(self): newAttr = self.document.createAttributeNS(self.TEST_NAMESPACE, 'qname:someAttr') self.map.setNamedItemNS(newAttr) anotherAttr = self.document.createAttributeNS(self.TEST_NAMESPACE, 'anotherQN:someAttr') anotherAttr.value = 'eggs' retVal = self.map.setNamedItemNS(newAttr) assert retVal is not None, "setNamedItemNS returned None" assert isSameNode(retVal, newAttr), ( "setNamedItemNS didn't return replaced Node.") checkLength(self.map, 2) def checkSetNamedItemNSWrongDocument(self): newDoc = self.implementation.createDocument(None, 'foo', None) foreignAttr = newDoc.createAttributeNS(self.TEST_NAMESPACE, self.TEST_QUALIFIED_NAME) try: self.map.setNamedItem(foreignAttr) except xml.dom.WrongDocumentErr: pass else: assert 0, "Was allowed to add foreign Node to NamedNodeMap." def checkSetNamedItemNSAlreadyInUse(self): el = self.document.createElement('someElement') attr = self.document.createAttributeNS(self.TEST_NAMESPACE, self.TEST_QUALIFIED_NAME) el.setAttributeNode(attr) try: self.map.setNamedItem(attr) except xml.dom.InuseAttributeErr: pass else: assert 0, ( "Was allowed to add attribute already in use to NamedNodeMap.") def checkSetNamedItemNSHierarchyRequestErr(self): # See DOM erratum core-4. element = self.document.createElementNS(TEST_NAMESPACE, 'foo:bar') try: self.map.setNamedItemNS(element) except xml.dom.HierarchyRequestErr: pass else: assert 0, ( "Was allowed to add a Node Type not belonging in this " "NamedNodeMap (an Element Node to a map of attributes).") cases = buildCases(__name__, 'Core', '2.0') ParsedXML/tests/domapi/CoreLvl3.py0100644000175200017500000000247707274131366016767 0ustar faasseninfrae"""Test cases for DOM Core Level 3.""" import xml.dom import Base class WhitespaceInElementContentTestCase(Base.TestCaseBase): def checkWhiteSpaceInElementContent(self): TEXT = """ ]> """ doc = self.parse(TEXT) for node in doc.documentNode.childNodes: if node.nodeType == xml.dom.Node.TEXT_NODE: if not node.isWhitespaceInElementContent: self.fail("founc whitespace node not identified" " as whitespace-in-element-contnet") def checkWhiteSpaceInUnknownContent(self, subset=""): TEXT = """ """ % subset doc = self.parse(TEXT) for node in doc.documentNode.childNodes: if node.nodeType == xml.dom.Node.TEXT_NODE: if node.isWhitespaceInElementContent: self.fail("founc whitespace node in mixed content marked" " as whitespace-in-element-contnet") def checkWhiteSpaceInMixedContent(self): assert 0 self.checkWhiteSpaceInUnknownContent("""[ ]""") cases = Base.buildCases(__name__, 'Core', '3.0') ParsedXML/tests/domapi/Load3.py0100644000175200017500000002437107301013547016264 0ustar faasseninfrae############################################################################## # # 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. # ############################################################################## """Tests for the 'Load' part of the Load/Save component from DOM Level 3. Note that the Load/Save component is a working draft and not a final recommendation. """ import xml.dom import Base from Products.ParsedXML.DOM import LoadSave from Products.ParsedXML.StrIO import StringIO class BuilderTestCaseBase(Base.TestCaseBase): def createBuilder(self): return self.implementation.createDOMBuilder() class BuilderFeatureConformanceTestCase(BuilderTestCaseBase): """Test that the DOMBuilder has the defaults and allows setting all features required by the W3C specification. The features are not exercised, but every value that is required to be supported is tested and set. """ FEATURES = { # feature-name: (default, must-support-true, must-support-false) "namespaces": (1, 1, 0), "namespace-declarations": (1, 1, 0), "validation": (0, 0, 1), "external-general-entities": (1, 1, 0), "external-parameter-entities": (1, 1, 0), "validate-if-cm": (0, 0, 1), "create-entity-ref-nodes": (1, 1, 0), "entity-nodes": (1, 1, 0), "white-space-in-element-content": (1, 1, 0), "cdata-nodes": (1, 1, 0), "comments": (1, 1, 1), "charset-overrides-xml-encoding": (1, 1, 1), } def checkFeatureDefaults(self): for item in self.FEATURES.items(): feature, (default, xxx, xxx) = item b = self.createBuilder() value = b.getFeature(feature) and 1 or 0 self.assert_(value == default, "default feature value not right") def checkRequiredFeatureSettings(self): for item in self.FEATURES.items(): feature, (xxx, require_true, require_false) = item b = self.createBuilder() if require_true: self.assert_(b.canSetFeature(feature, 1), "builder indicates feature cannot be enabled") b.setFeature(feature, 1) self.assert_(b.getFeature(feature), "enabling feature failed") if require_false: self.assert_(b.canSetFeature(feature, 0), "builder indicates feature cannot be disabled") b.setFeature(feature, 0) self.assert_(not b.getFeature(feature), "disabling feature failed") def checkSupportsFeatures(self): b = self.createBuilder() for feature in self.FEATURES.keys(): self.assert_(b.supportsFeature(feature), "builder reports non-support for required feature") def checkEntityNodesFeatureSideEffect(self): b = self.createBuilder() b.setFeature("entity-nodes", 0) self.assert_(not b.getFeature("create-entity-ref-nodes"), "setting entity-nodes to false should turn off" " create-entity-ref-nodes") def checkUnknownFeature(self): b = self.createBuilder() self.assertRaises(xml.dom.NotFoundErr, b.setFeature, "non-existant-feature", 0) self.assertRaises(xml.dom.NotFoundErr, b.getFeature, "non-existant-feature") self.assert_(not b.supportsFeature("non-existant-feature"), "expected non-existant-feature to raise" " xml.dom.NotFoundErr") self.assert_(not b.canSetFeature("non-existant-feature", 0), "builder allows setting of non-existant feature" " to false") self.assert_(not b.canSetFeature("non-existant-feature", 1), "builder allows setting of non-existant feature" " to true") def checkWhiteSpaceInElementContentDiscarded(self): TEXT = """ ]> """ doc = self._parse(TEXT, {"white-space-in-element-content": 0}) for node in doc.documentElement.childNodes: if node.nodeType == xml.dom.Node.TEXT_NODE: self.fail("founc whitespace-in-element-content node which" " should bave been excluded") def checkCommentsOmitted(self): doc = self._parse("", {"comments": 0}) self.assert_(doc.documentElement.childNodes.length == 0, "comment node was returned as part of the document") def checkCDATAAsText(self): doc = self._parse(">]]>", {"cdata-nodes": 0}) self.assert_(doc.documentElement.childNodes[0].data == "<>") self.assert_(doc.documentElement.childNodes.length == 1) def checkWithoutNamespaces(self): doc = self._parse("" " " "", {"namespaces": 0}) docelem = doc.documentElement self.assert_(docelem.namespaceURI is None) self.assert_(docelem.prefix is None) self.assert_(docelem.getAttributeNode("xmlns").namespaceURI is None) self.assert_(docelem.getAttributeNode("xmlns").prefix is None) self.assert_(docelem.getAttributeNode("tal:attr").namespaceURI is None) self.assert_(docelem.getAttributeNode("tal:attr").prefix is None) elem = docelem.firstChild self.assert_(elem.namespaceURI is None) self.assert_(elem.prefix is None) def checkWithoutNamespaceDeclarations(self): doc = self._parse("" "" "", {"namespace-declarations": 0}) docelem = doc.documentElement self.failIf(docelem.hasAttribute("xmlns")) self.failIf(docelem.hasAttribute("xmlns:tal")) self.assert_(docelem.attributes.length == 1) # We can't just name this parse(), since the framework overwrites # that name on the actual instances. # def _parse(self, source, flags={}): b = self.createBuilder() for feature, value in flags.items(): b.setFeature(feature, value) fp = StringIO(source) inpsrc = LoadSave.DOMInputSource() inpsrc.byteStream = fp return b.parseDOMInputSource(inpsrc) cases = Base.buildCases(__name__, "Load", "3.0") ParsedXML/tests/domapi/TraversalLvl2.py0100644000175200017500000005751107274131366020040 0ustar faasseninfrae############################################################################## # # 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. # ############################################################################## from Base import * import xml.dom from xml.dom import Node # --- NodeFilter interface. Should this be in xml.dom.__init__? class NodeFilter: # Constants returned by acceptNode FILTER_ACCEPT = 1 FILTER_REJECT = 2 FILTER_SKIP = 3 # Constants for whatToShow SHOW_ALL = 0xFFFFFFFF SHOW_ELEMENT = 0x00000001 SHOW_ATTRIBUTE = 0x00000002 SHOW_TEXT = 0x00000004 SHOW_CDATA_SECTION = 0x00000008 SHOW_ENTITY_REFERENCE = 0x00000010 SHOW_ENTITY = 0x00000020 SHOW_PROCESSING_INSTRUCTION = 0x00000040 SHOW_COMMENT = 0x00000080 SHOW_DOCUMENT = 0x00000100 SHOW_DOCUMENT_TYPE = 0x00000200 SHOW_DOCUMENT_FRAGMENT = 0x00000400 SHOW_NOTATION = 0x00000800 def acceptNode(self, node): # By default, accept return self.FILTER_ACCEPT # --- DocumentTraversal class DocumentTraversalReadTestCase(TestCaseBase): def setUp(self): self.createDocumentNS() def checkCreateNodeIterator(self): root = self.document whatToShow = NodeFilter.SHOW_ALL filter = NodeFilter() iterator = self.document.createNodeIterator(root, whatToShow, filter, 1) checkAttributeSameNode(iterator, 'root', root) checkAttribute(iterator, 'whatToShow', whatToShow) assert iterator.filter is filter, ( "Created iterator has got a different filter object. Expected %s, " "found %s." % (repr(filter), repr(iterator.filter))) checkAttribute(iterator, 'expandEntityReferences', 1) def checkCreateNodeIteratorNoRoot(self): try: self.document.createNodeIterator(None, NodeFilter.SHOW_ALL, None, 0) except xml.dom.NotSupportedErr: pass else: assert 0, "Was allowed to create a NodeIterator without a root." def checkCreateTreeWalker(self): root = self.document whatToShow = NodeFilter.SHOW_ALL filter = NodeFilter() walker = self.document.createTreeWalker(root, whatToShow, filter, 1) checkAttributeSameNode(walker, 'root', root) checkAttribute(walker, 'whatToShow', whatToShow) assert walker.filter is filter, ( "Created walker has got a different filter object. Expected %s, " "found %s." % (repr(filter), repr(walker.filter))) checkAttribute(walker, 'expandEntityReferences', 1) def checkCreateTreeWalkerNoRoot(self): try: self.document.createTreeWalker(None, NodeFilter.SHOW_ALL, None, 0) except xml.dom.NotSupportedErr: pass else: assert 0, "Was allowed to create a TreeWalker without a root." # --- NodeIterator class NodeIteratorTestCase(TestCaseBase): def setUp(self): # Create a tree of elements. Alphabetic order denotes document order. docType = self.implementation.createDocumentType('A', None, None) self.document = doc = self.implementation.createDocument(None, 'A', docType) self.A = a = doc.documentElement self.B = a.appendChild(doc.createTextNode('B')) self.C = c = a.appendChild(doc.createElement('C')) self.D = c.appendChild(doc.createCDATASection('D')) self.E = c.appendChild(doc.createProcessingInstruction('E', 'A PI')) self.F = a.appendChild(doc.createComment('F')) self.G = a.appendChild(doc.createTextNode('G')) self.all = (doc, docType, a, self.B, c, self.D, self.E, self.F, self.G) def iterate(self, iterator, expectedNodes): all = expectedNodes[:] while 1: nextNode = iterator.nextNode() if nextNode is None: assert not all, ( "nextNode returned None before end, still expected to " "see %s." % `all`) break assert all, ( "nextNode returned %s when we should've gotten None." % `nextNode`) expect = all.pop(0) assert isSameNode(expect, nextNode), ( "nextNode returned %s, expected %s." % (`nextNode`, `expect`)) all = expectedNodes[:] while 1: previousNode = iterator.previousNode() if previousNode is None: assert not all, ( "previousNode returned None before end, still expected to " "see %s." % `all`) break assert all, ( "previousNode returned %s when we should've gotten None." % `previousNode`) expect = all.pop() assert isSameNode(expect, previousNode), ( "previousNode returned %s, expected %s." % (`previousNode`, `expect`)) def checkIteratorNoFilter(self): iterator = self.document.createNodeIterator(self.document, NodeFilter.SHOW_ALL, None, 0) self.iterate(iterator, list(self.all)) def checkIteratorOnlyTextNodes(self): iterator = self.document.createNodeIterator(self.document, NodeFilter.SHOW_TEXT, None, 0) self.iterate(iterator, [self.B, self.G]) def checkIteratorAllButTextNodes(self): iterator = self.document.createNodeIterator(self.document, NodeFilter.SHOW_ALL ^ NodeFilter.SHOW_TEXT, None, 0) self.iterate(iterator, list(self.all[:3] + self.all[4:8])) def checkIteratorFilterSkipC(self): class SkipCFilter(NodeFilter): def acceptNode(self, node): if node.nodeName == 'C': return self.FILTER_SKIP else: return self.FILTER_ACCEPT iterator = self.document.createNodeIterator(self.document, NodeFilter.SHOW_ALL, SkipCFilter(), 0) self.iterate(iterator, list(self.all[:4] + self.all[5:])) def checkIteratorFilterRejectC(self): class RejectCFilter(NodeFilter): def acceptNode(self, node): if node.nodeName == 'C': return self.FILTER_REJECT else: return self.FILTER_ACCEPT iterator = self.document.createNodeIterator(self.document, NodeFilter.SHOW_ALL, RejectCFilter(), 0) self.iterate(iterator, list(self.all[:4] + self.all[5:])) def checkIteratorOnlyTextNodesFilterSkipG(self): class SkipGFilter(NodeFilter): def acceptNode(self, node): if node.nodeValue == 'G': return self.FILTER_SKIP else: return self.FILTER_ACCEPT iterator = self.document.createNodeIterator(self.document, NodeFilter.SHOW_TEXT, SkipGFilter(), 0) self.iterate(iterator, [self.B]) def checkIteratorPreviousNode(self): iterator = self.document.createNodeIterator(self.document, NodeFilter.SHOW_ALL, None, 0) assert iterator.previousNode() is None, ( "previousNode on a fresh iterator did not return None.") def checkIteratorNextNodeInvalidState(self): iterator = self.document.createNodeIterator(self.document, NodeFilter.SHOW_ALL, None, 0) iterator.detach() try: iterator.nextNode() except xml.dom.InvalidStateErr: pass else: assert 0, ( "Was allowed to call nextNode() on a detached NodeIterator.") def checkIteratorPreviousNodeInvalidState(self): iterator = self.document.createNodeIterator(self.document, NodeFilter.SHOW_ALL, None, 0) iterator.detach() try: iterator.previousNode() except xml.dom.InvalidStateErr: pass else: assert 0, ( "Was allowed to call previousNode() on a detached " "NodeIterator.") def checkIteratorFilterException(self): class ExceptionFilter(NodeFilter): def acceptNode(self, node): raise KeyError, ( "Test exception to see if it will propagate.") iterator = self.document.createNodeIterator(self.document, NodeFilter.SHOW_ALL, ExceptionFilter(), 0) try: iterator.nextNode() except KeyError: pass else: assert 0, "NodeIterator caught exception raised in filter." # -- TreeWalker class TreeWalkerTestCase(TestCaseBase): def setUp(self): # Create a tree of elements. Alphabetic order denotes document order. docType = self.implementation.createDocumentType('A', None, None) self.document = doc = self.implementation.createDocument(None, 'A', docType) self.A = a = doc.documentElement self.B = a.appendChild(doc.createTextNode('B')) self.C = c = a.appendChild(doc.createElement('C')) self.D = c.appendChild(doc.createCDATASection('D')) self.E = c.appendChild(doc.createProcessingInstruction('E', 'A PI')) self.F = a.appendChild(doc.createComment('F')) self.G = a.appendChild(doc.createTextNode('G')) self.all = (doc, docType, a, self.B, c, self.D, self.E, self.F, self.G) def iterate(self, walker, advanceMethod, retreatMethod, expectedNodesNext, expectedNodesPrevious = None): "Exercise methods given in advanceMethod, retreatMethod" if not expectedNodesPrevious: expectedNodesPrevious = expectedNodesNext all = expectedNodesNext[:] current = walker.currentNode while 1: if current is None: assert not all, ( "%s returned None before end, still expected to " "see %s. TreeWalker.currentNode is %s." % ( advanceMethod, `all`, `walker.currentNode`)) break assert all, ( "%s returned %s when we should've gotten None. " "TreeWalker.currentNode is %s." % ( advanceMethod, `current`, `walker.currentNode`)) expect = all.pop(0) assert isSameNode(expect, current), ( "%s returned %s, expected %s. TreeWalker.currentNode is " "%s." % (advanceMethod, `current`, `expect`, `walker.currentNode`)) current = getattr(walker, advanceMethod)() all = expectedNodesPrevious[:] current = walker.currentNode while 1: if current is None: assert not all, ( "%s returned None before end, still expected to " "see %s. TreeWalker.currentNode is %s." % ( retreatMethod, `all`, `walker.currentNode`)) break assert all, ( "%s returned %s when we should've gotten None. " "TreeWalker.currentNode is %s." % ( retreatMethod, `current`, `walker.currentNode`)) expect = all.pop() assert isSameNode(expect, current), ( "%s returned %s, expected %s. " "TreeWalker.currentNode is %s." % ( retreatMethod, `current`, `expect`, `walker.currentNode`)) current = getattr(walker, retreatMethod)() def checkWalkerNoFilterIterate(self): walker = self.document.createTreeWalker(self.document, NodeFilter.SHOW_ALL, None, 0) self.iterate(walker, "nextNode", "previousNode", list(self.all)) def checkWalkerOnlyTextNodesIterate(self): walker = self.document.createTreeWalker(self.document, NodeFilter.SHOW_TEXT, None, 0) self.iterate(walker, "nextNode", "previousNode", [self.document, self.B, self.G], [self.B, self.G]) def checkWalkerAllButTextNodesIterate(self): walker = self.document.createTreeWalker(self.document, NodeFilter.SHOW_ALL ^ NodeFilter.SHOW_TEXT, None, 0) self.iterate(walker, "nextNode", "previousNode", list(self.all[:3] + self.all[4:8])) def checkWalkerFilterSkipCIterate(self): class SkipCFilter(NodeFilter): def acceptNode(self, node): if node.nodeName == 'C': return self.FILTER_SKIP else: return self.FILTER_ACCEPT walker = self.document.createTreeWalker(self.document, NodeFilter.SHOW_ALL, SkipCFilter(), 0) self.iterate(walker, "nextNode", "previousNode", list(self.all[:4] + self.all[5:])) def checkWalkerFilterRejectCIterate(self): class RejectCFilter(NodeFilter): def acceptNode(self, node): if node.nodeName == 'C': return self.FILTER_REJECT else: return self.FILTER_ACCEPT walker = self.document.createTreeWalker(self.document, NodeFilter.SHOW_ALL, RejectCFilter(), 0) self.iterate(walker, "nextNode", "previousNode", list(self.all[:4] + self.all[7:])) def checkWalkerOnlyTextNodesFilterSkipG(self): class SkipGFilter(NodeFilter): def acceptNode(self, node): if node.nodeValue == 'G': return self.FILTER_SKIP else: return self.FILTER_ACCEPT walker = self.document.createTreeWalker(self.document, NodeFilter.SHOW_TEXT, SkipGFilter(), 0) self.iterate(walker, "nextNode", "previousNode", [self.document, self.B], [self.B,]) def checkWalkerNoFilterParentNodeFirstChild(self): walker = self.document.createTreeWalker(self.document, NodeFilter.SHOW_ALL, None, 0) assert walker.parentNode() is None, ( "parentNode on a fresh walker did not return None.") walker.firstChild() # doctype walker.nextSibling() # A walker.firstChild() # B walker.nextSibling() # C walker.firstChild() # D self.iterate(walker, "parentNode", "firstChild", [self.D, self.C, self.A, self.document], [self.document.doctype, self.document],) def checkWalkerOnlyTextNodesParentNodeFirstChild(self): walker = self.document.createTreeWalker(self.document, NodeFilter.SHOW_TEXT, None, 0) self.iterate(walker, "firstChild", "parentNode", [self.document]) def checkWalkerAllButTextNodesParentNodeFirstChild(self): walker = self.document.createTreeWalker(self.document, NodeFilter.SHOW_ALL ^ NodeFilter.SHOW_TEXT, None, 0) walker.firstChild() # doctype walker.nextSibling() # A self.iterate(walker, "firstChild", "parentNode", [self.A, self.C, self.D], [self.document, self.A, self.C, self.D],) # "first visible child" might be seen to imply "first child that # is visible", rather than "first visible descendent", but the # examples skip to descendents. def checkWalkerFilterSkipCFirstChild(self): class SkipCFilter(NodeFilter): def acceptNode(self, node): if node.nodeName == 'C': return self.FILTER_SKIP else: return self.FILTER_ACCEPT self.A.removeChild(self.B) walker = self.document.createTreeWalker(self.document, NodeFilter.SHOW_ALL, SkipCFilter(), 0) walker.firstChild() # doctype walker.nextSibling() # A self.iterate(walker, "firstChild", "parentNode", [self.A, self.D], [self.document, self.A, self.D]) # also checks parentNode robustness under currentNode move def checkWalkerFilterSkipCParentNode(self): class SkipCFilter(NodeFilter): def acceptNode(self, node): if node.nodeName == 'C': return self.FILTER_SKIP else: return self.FILTER_ACCEPT walker = self.document.createTreeWalker(self.document, NodeFilter.SHOW_ALL, SkipCFilter(), 0) walker.firstChild() # doctype walker.nextSibling() # A walker.firstChild() # B self.C.appendChild(self.B) self.iterate(walker, "parentNode", "firstChild", [self.B, self.A, self.document], [self.document.doctype, self.document]) def checkWalkerFilterRejectCFirstChild(self): class RejectCFilter(NodeFilter): def acceptNode(self, node): if node.nodeName == 'C': return self.FILTER_REJECT else: return self.FILTER_ACCEPT self.A.removeChild(self.B) walker = self.document.createTreeWalker(self.document, NodeFilter.SHOW_ALL, RejectCFilter(), 0) walker.firstChild() # doctype walker.nextSibling() # A self.iterate(walker, "firstChild", "parentNode", [self.A, self.F], [self.document, self.A, self.F]) # also tests parentNode robustness under currentNode move def checkWalkerFilterRejectCParentNode(self): class RejectCFilter(NodeFilter): def acceptNode(self, node): if node.nodeName == 'C': return self.FILTER_REJECT else: return self.FILTER_ACCEPT walker = self.document.createTreeWalker(self.document, NodeFilter.SHOW_ALL, RejectCFilter(), 0) walker.firstChild() # doctype walker.nextSibling() # A walker.firstChild() # B self.C.appendChild(self.B) self.iterate(walker, "parentNode", "firstChild", [self.B, self.A, self.document], [self.document.doctype, self.document]) def checkWalkerOnlyTextNodesParentNodeFirstChildFilterSkipB(self): class SkipBFilter(NodeFilter): def acceptNode(self, node): if node.nodeValue == 'B': return self.FILTER_SKIP else: return self.FILTER_ACCEPT walker = self.document.createTreeWalker(self.document, NodeFilter.SHOW_TEXT, SkipBFilter(), 0) self.iterate(walker, "firstChild", "parentNode", [self.document, self.G]) def checkWalkerNoFilterNextSiblingPreviousSibling(self): walker = self.document.createTreeWalker(self.document, NodeFilter.SHOW_ALL, None, 0) assert walker.previousSibling() is None, ( "previousSibling on a fresh walker did not return None.") # move to B to make more interesting walker.firstChild() # doctype walker.nextSibling() # A walker.firstChild() # B self.iterate(walker, "nextSibling", "previousSibling", [self.B, self.C, self.F, self.G]) def checkWalkerNoFilterLastChild(self): walker = self.document.createTreeWalker(self.document, NodeFilter.SHOW_ALL, None, 0) # move to A to make more interesting walker.firstChild() # doctype walker.nextSibling() # A retNode = walker.lastChild() assert isSameNode(retNode, walker.currentNode) assert isSameNode(self.G, walker.currentNode) def checkWalkerPreviousNode(self): walker = self.document.createTreeWalker(self.document, NodeFilter.SHOW_ALL, None, 0) assert walker.previousNode() is None, ( "previousNode on a fresh walker did not return None.") def checkCurrentNodeNoneNotSupported(self): walker = self.document.createTreeWalker(self.document, NodeFilter.SHOW_ALL, None, 0) try: walker.currentNode = None except xml.dom.NotSupportedErr: pass else: assert 0, "Was allowed to set currentNode to None." cases = buildCases(__name__, 'Traversal', '2.0') ParsedXML/tests/domapi/XMLLvl1.py0100644000175200017500000003547307274131366016537 0ustar faasseninfrae############################################################################## # # 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. # ############################################################################## from Base import * from CoreLvl1 import NodeReadTestCaseBase, NodeWriteTestCaseBase from CoreLvl1 import TextReadTestCase, TextWriteTestCase TextReadTestCaseBase = TextReadTestCase TextWriteTestCaseBase = TextWriteTestCase del TextReadTestCase del TextWriteTestCase import xml.dom from xml.dom import Node # --- DocumentType class DocumentTypeReadTestCase(NodeReadTestCaseBase): def setUp(self): self.doctype = self.node = self.implementation.createDocumentType( 'foo', None, None) self.expectedType = Node.DOCUMENT_TYPE_NODE doc = self.parse(""" ]> """) self.doctypeInternalSubset = doc.doctype def checkName(self): checkAttribute(self.doctype, 'name', 'foo') checkReadOnly(self.doctype, 'name') def checkEmptyEntities(self): assert self.doctype.entities.length == 0 def checkEntitiesInternalSubset(self): checkLength(self.doctypeInternalSubset.entities, 3) entity = self.doctypeInternalSubset.entities.getNamedItem( 'internalParsedE') def checkEntitiesRemoveReadOnly(self): try: self.doctypeInternalSubset.entities.removeNamedItem( 'internalParsedE') except xml.dom.NoModificationAllowedErr: pass else: assert 0, 'Was allowed to remove entity.' def checkEntitiesSetReadOnly(self): entity = self.doctypeInternalSubset.entities.item(0) try: self.doctypeInternalSubset.entities.setNamedItem(entity) except xml.dom.NoModificationAllowedErr: pass else: assert 0, 'Was allowed to set entity.' def checkEmptyNotations(self): assert self.doctype.notations.length == 0 def checkNotationsInternalSubset(self): checkLength(self.doctypeInternalSubset.notations, 1) notation = self.doctypeInternalSubset.notations.getNamedItem( 'aNotation') def checkNotationsRemoveReadOnly(self): try: self.doctypeInternalSubset.notations.removeNamedItem( 'aNotation') except xml.dom.NoModificationAllowedErr: pass else: assert 0, 'Was allowed to remove notation.' def checkNotationsSetReadOnly(self): notation = self.doctypeInternalSubset.notations.item(0) try: self.doctypeInternalSubset.notations.setNamedItem(notation) except xml.dom.NoModificationAllowedErr: pass else: assert 0, 'Was allowed to set notation.' def checkCloneNode(self): # TODO: Implementation dependent, what should we test? pass class DocumentTypeWriteTestCase(NodeWriteTestCaseBase): def setUp(self): self.createDocument() # Needed for Node tests self.doctype = self.node = self.implementation.createDocumentType( 'foo', None, None) # --- ProcessingInstruction class ProcessingInstructionReadTestCase(NodeReadTestCaseBase): def setUp(self): self.pi = self.createDocument().createProcessingInstruction("pit", "pid") self.node = self.pi self.expectedType = Node.PROCESSING_INSTRUCTION_NODE def checkGetTarget(self): checkAttribute(self.pi, "target", "pit") def checkGetData(self): checkAttribute(self.pi, "data", "pid") def checkCloneNode(self): clone = self.pi.cloneNode(0) deepClone = self.pi.cloneNode(1) assert not isSameNode(self.pi, clone), "Clone is same as original." assert not isSameNode(self.pi, deepClone), "Clone is same as original." checkAttribute(clone, 'parentNode', None) checkAttribute(deepClone, 'parentNode', None) checkAttribute(clone, 'nodeType', self.pi.nodeType) checkAttribute(deepClone, 'nodeType', self.pi.nodeType) checkAttribute(clone, 'data', self.pi.data) checkAttribute(deepClone, 'data', self.pi.data) checkAttribute(clone, 'target', self.pi.target) checkAttribute(deepClone, 'target', self.pi.target) checkLength(clone.childNodes, 0) checkLength(deepClone.childNodes, 0) class ProcessingInstructionWriteTestCase(NodeWriteTestCaseBase): def setUp(self): self.pi = self.createDocument().createProcessingInstruction("pit", "pid") self.node = self.pi def checkSetData(self): self.pi._set_data("uggg") checkAttribute(self.pi, "data", "uggg") # --- CDATASection class CDATASectionReadTestCase(TextReadTestCaseBase): def setUp(self): self.chardata = self.node = self.createDocument().createCDATASection( "com") self.expectedType = Node.CDATA_SECTION_NODE class CDATASectionWriteTestCase(TextWriteTestCaseBase): def setUp(self): self.chardata = self.node = self.createDocument().createCDATASection( "com") # --- EntityReference class EntityReferenceReadTestCase(NodeReadTestCaseBase): def setUp(self): self.entref = self.node = self.createDocument().createEntityReference( "eref") self.expectedType = Node.ENTITY_REFERENCE_NODE self.expectedNodeName = 'eref' def checkCloneNode(self): pass # TODO: Fill in meaningful test here. class EntityReferenceWriteTestCase(NodeWriteTestCaseBase): def setUp(self): self.entref = self.node = self.createDocument().createEntityReference( "eref") # TODO: An ENTITY_REFERENCE_NODE Node will have childNodes when the # entity it refers to has childNodes. We need entities first before we write # tests for that. # --- Entity class EntityReadTestCase(NodeReadTestCaseBase): def setUp(self): doc = self.document = self.parse(""" ]> """) self.node = self.internalParsed = doc.doctype.entities.getNamedItem( 'internalParsedE') self.publicUnparsed = doc.doctype.entities.getNamedItem( 'publicUnparsedE') self.systemUnparsed = doc.doctype.entities.getNamedItem( 'systemUnparsedE') self.expectedNodeName = 'internalParsedE' self.expectedType = Node.ENTITY_NODE def checkPublicIdReadOnly(self): checkReadOnly(self.node, 'publicId') def checkPublicIdInternalParsed(self): checkAttribute(self.internalParsed, 'publicId', None) def checkPublicIdPublicUnparsed(self): checkAttribute(self.publicUnparsed, 'publicId', 'uri:public') def checkPublicIdSystemUnparsed(self): checkAttribute(self.systemUnparsed, 'publicId', None) def checkSystemIdReadOnly(self): checkReadOnly(self.node, 'systemId') def checkSystemIdInternalParsed(self): checkAttribute(self.internalParsed, 'systemId', None) def checkSystemIdPublicUnparsed(self): checkAttribute(self.publicUnparsed, 'systemId', 'uri:system') def checkSystemIdSystemUnparsed(self): checkAttribute(self.systemUnparsed, 'systemId', 'uri:system') def checkNotationNameReadOnly(self): checkReadOnly(self.node, 'notationName') def checkNotationNameInternalParsed(self): checkAttribute(self.internalParsed, 'notationName', None) def checkNotationNamePublicUnparsed(self): checkAttribute(self.publicUnparsed, 'notationName', 'aNotation') def checkNotationNameSystemUnparsed(self): checkAttribute(self.systemUnparsed, 'notationName', 'aNotation') def checkSubTreeInternalParsed(self): entity = self.internalParsed assert entity.hasChildNodes(), ( 'Internal Parsed Entity has no subtree representing the value.') checkAttribute(entity.firstChild, 'nodeType', Node.TEXT_NODE) checkAttribute(entity.firstChild, 'data', 'Entity text') checkReadOnly(entity.firstChild, 'data') def checkSubTreePublicUnparsed(self): assert not self.publicUnparsed.hasChildNodes(), ( 'An unparsed entity should not have a sub-tree.') def checkSubTreeSystemUnparsed(self): assert not self.systemUnparsed.hasChildNodes(), ( 'An unparsed entity should not have a sub-tree.') class EntityWriteTestCase(NodeWriteTestCaseBase): def setUp(self): doc = self.document = self.parse(""" ]> """) self.node = doc.doctype.entities.getNamedItem('internalParsedE') # --- Notation class NotationReadTestCase(NodeReadTestCaseBase): def setUp(self): doc = self.document = self.parse(""" ]> """) self.node = self.publicExternal = doc.doctype.notations.getNamedItem( 'publicExternalN') self.systemExternal = doc.doctype.notations.getNamedItem( 'systemExternalN') self.public = doc.doctype.notations.getNamedItem('publicN') self.expectedNodeName = 'publicExternalN' self.expectedType = Node.NOTATION_NODE def checkPublicIdReadOnly(self): checkReadOnly(self.node, 'publicId') def checkPublicIdPublicExternal(self): checkAttribute(self.publicExternal, 'publicId', 'uri:public') def checkPublicIdSystemExternal(self): checkAttribute(self.systemExternal, 'publicId', None) def checkPublicIdPublic(self): checkAttribute(self.public, 'publicId', 'uri:public') def checkSystemIdReadOnly(self): checkReadOnly(self.node, 'systemId') def checkSystemIdPublicExternal(self): checkAttribute(self.publicExternal, 'systemId', 'uri:system') def checkSystemIdSystemExternal(self): checkAttribute(self.systemExternal, 'systemId', 'uri:system') def checkSystemIdPublic(self): checkAttribute(self.public, 'systemId', None) class NotationWriteTestCase(NodeWriteTestCaseBase): def setUp(self): doc = self.document = self.parse(""" ]> """) self.node = doc.doctype.notations.getNamedItem('aNotation') cases = buildCases(__name__, 'XML', '1.0') ParsedXML/tests/domapi/XMLLvl2.py0100644000175200017500000002222607274131366016530 0ustar faasseninfrae############################################################################## # # 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. # ############################################################################## from Base import * import CoreLvl2 TextReadTestCaseBase = CoreLvl2.TextReadTestCase TextWriteTestCaseBase = CoreLvl2.TextWriteTestCase NodeReadTestCaseBase = CoreLvl2.NodeReadTestCaseBase NodeWriteTestCaseBase = CoreLvl2.NodeWriteTestCaseBase del CoreLvl2 import xml.dom from xml.dom import Node # --- DocumentType class DocumentTypeReadTestCase(NodeReadTestCaseBase): def setUp(self): self.doctype = self.node = self.implementation.createDocumentType( 'foo:bar', 'uri:foo', 'uri:bar') def checkInternalSubset(self): # The DOM Level 2 recommendation is not clear on the value of the # internalSubset attribute when there isn't one; this test relies # on a clarification from Joe Kesselman: # # http://lists.w3.org/Archives/Public/www-dom/2001AprJun/0009.html # checkAttribute(self.doctype, 'internalSubset', None) checkReadOnly(self.doctype, 'internalSubset') def checkPublicId(self): checkAttribute(self.doctype, 'publicId', 'uri:foo') checkReadOnly(self.doctype, 'publicId') def checkSystemId(self): checkAttribute(self.doctype, 'systemId', 'uri:bar') checkReadOnly(self.doctype, 'systemId') def checkImportNode(self): foreignDoc = self.implementation.createDocument(None, 'foo', None) try: foreignDoc.importNode(self.doctype, 0) except xml.dom.NotSupportedErr: pass else: assert 0, "Was allowed to import a Document Type Node." class DocumentTypeWriteTestCase(NodeWriteTestCaseBase): def setUp(self): self.doctype = self.node = self.implementation.createDocumentType( 'foo:bar', 'uri:foo', 'uri:bar') # --- ProcessingInstruction class ProcessingInstructionReadTestCase(NodeReadTestCaseBase): def setUp(self): self.pi = self.createDocument().createProcessingInstruction("pit", "pid") self.node = self.pi def checkImportNode(self): foreignDoc = self.implementation.createDocument(None, 'foo', None) clone = foreignDoc.importNode(self.pi, 0) deepClone = foreignDoc.importNode(self.pi, 1) assert not isSameNode(self.pi, clone), "Clone is same as original." assert not isSameNode(self.pi, deepClone), "Clone is same as original." checkAttributeSameNode(clone, 'ownerDocument', foreignDoc) checkAttributeSameNode(deepClone, 'ownerDocument', foreignDoc) checkAttribute(clone, 'parentNode', None) checkAttribute(deepClone, 'parentNode', None) checkAttribute(clone, 'nodeType', self.pi.nodeType) checkAttribute(deepClone, 'nodeType', self.pi.nodeType) checkAttribute(clone, 'data', self.pi.data) checkAttribute(deepClone, 'data', self.pi.data) checkAttribute(clone, 'target', self.pi.target) checkAttribute(deepClone, 'target', self.pi.target) checkLength(clone.childNodes, 0) checkLength(deepClone.childNodes, 0) class ProcessingInstructionWriteTestCase(NodeWriteTestCaseBase): def setUp(self): self.pi = self.createDocument().createProcessingInstruction("pit", "pid") self.node = self.pi # --- CDATASection class CDATASectionReadTestCase(TextReadTestCaseBase): def setUp(self): self.chardata = self.node = self.createDocument().createCDATASection( "com") class CDATASectionWriteTestCase(TextWriteTestCaseBase): def setUp(self): self.chardata = self.node = self.createDocument().createCDATASection( "com") # --- EntityReference class EntityReferenceReadTestCase(NodeReadTestCaseBase): def setUp(self): self.entref = self.node = self.createDocument().createEntityReference( "eref") def checkImportNode(self): pass # TODO: Fill in meaningful test here. class EntityReferenceWriteTestCase(NodeWriteTestCaseBase): def setUp(self): self.entref = self.node = self.createDocument().createEntityReference( "eref") # --- Entity class EntityReadTestCase(NodeReadTestCaseBase): def setUp(self): doc = self.document = self.parse(""" ]> """) self.node = doc.doctype.entities.getNamedItem('internalParsedE') class EntityWriteTestCase(NodeWriteTestCaseBase): def setUp(self): doc = self.document = self.parse(""" ]> """) self.node = doc.doctype.entities.getNamedItem('internalParsedE') # --- Notation class NotationReadTestCase(NodeReadTestCaseBase): def setUp(self): doc = self.document = self.parse(""" ]> """) self.node = doc.doctype.notations.getNamedItem('aNotation') class NotationWriteTestCase(NodeWriteTestCaseBase): def setUp(self): doc = self.document = self.parse(""" ]> """) self.node = doc.doctype.notations.getNamedItem('aNotation') cases = buildCases(__name__, 'XML', '2.0') ParsedXML/tests/domapi/__init__.py0100644000175200017500000001532407274131366017070 0ustar faasseninfrae############################################################################## # # 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. # ############################################################################## """A suite of unit tests for the Python DOM API. This suite will test a DOM API for compliance with the DOM API, level 2. It assumes that the DOM tested supports at least both the Core and XML features. It requires PyUnit; see http://pyunit.sourceforge.net/. Example for the python minidom (which is an incomplete implementation): from xml.dom.minidom import DOMImplementation, parseString from domapi import DOMImplementationTestSuite def MiniDomParseString(self, xml): return parseString(xml) def test_suite(): '''Return a test suite for the Zope testing framework.''' return DOMImplementationTestSuite(DOMImplementation(), MiniDomParseString) if __name__ == '__main__': import unittest unittest.TextTestRunner().run(test_suite()) """ import unittest import CoreLvl1, CoreLvl2, CoreLvl3, XMLLvl1, XMLLvl2, TraversalLvl2, Load3 cases = ( CoreLvl1.cases + CoreLvl2.cases + CoreLvl3.cases + XMLLvl1.cases + XMLLvl2.cases + TraversalLvl2.cases + Load3.cases ) def DOMImplementationTestSuite(implementation, parseMethod, verbose=0): """ Create a testsuite for DOM lvl 2 compliance, given a DOM Implementation. To test a DOM implementation, hand in a DOMImplementation object, and a method that will take a string holding an XML document and returns a Document Node created from the XML. Then run the returned unittest testsuite. Note that the signature of the parse method is (self, xmlString) and should parse the xml string with namespaces turned on. It will be used to create Nodes which normally cannot be created using the DOM API, like Notations and Entities. """ # First test for minimal feature support assert (implementation.hasFeature('Core', '2.0') and implementation.hasFeature('XML', '2.0')), ( "This DOMImplementation doesn't feature the level 2 Core and XML API.") suite = unittest.TestSuite() # The minimal set of features that should return 1 on hasFeature. # ('Core', '1.0') was never defined for DOM level 1, it was implicit. Most # DOM level 2 implementations return true, but this is a courtesy. supportedFeatures = { ('Core', None): 1, ('Core', '2.0'): 1, ('XML', None): 1, ('XML', '1.0'): 1, ('XML', '2.0'): 1, } for case, feature, version in cases: if implementation.hasFeature(feature, version): case.implementation = implementation case.parse = parseMethod suite.addTest(unittest.makeSuite(case, 'check')) supportedFeatures[(feature, version)] = 1 supportedFeatures[(feature, None)] = 1 else: if verbose: print ("Test %s skipped: DOM feature not supported.\n" % case.__name__) # Record supported features. CoreLvl1.DOMImplementationReadTestCase.supportedFeatures = ( supportedFeatures.keys()) CoreLvl2.NodeReadTestCaseBase.supportedFeatures = ( supportedFeatures.keys()) return suite ParsedXML/tests/.cvsignore0100644000175200017500000000001007274131544015466 0ustar faasseninfraeout.txt ParsedXML/tests/README0100644000175200017500000000365407367624277014404 0ustar faasseninfraeParsed XML test README Using the test suite This directory holds our test suite. Usually, it can be invoked with "python domtester.py". Appending an -h argument will return a usage string. To run the domtester, you need to be able to find Zope's unit testing framework and mount the ZODB, so you need to make sure Zope's lib/python can be found. Adding Zope's lib/python to your python path, either going through sys.path or adding it to the PYTHONPATH environment variable. For instance, if you're running bash, all you have to type is this:: export PYTHONPATH=/path/to/Zope/lib/python The ZODB must also be mountable, so if you're not running ZEO, the server must be stopped while the tests run. Upon completion, the tester will report how many tests failed, and put more detailed output in out.txt. Running tests individually You can also run each test individually, for instance:: python test_dom.py Again you have to make sure Zope's lib/python can be found. There's also a very simple test_all.py that runs all the individual tests in a row; doing the same thing as domtester.py does but without some of the conveniences. Debugging with the test suite If you want to contribute changes to ParsedXML, please run the test suite to make sure that your changes don't break anything. The tests themselves are in test_domapi.py. The test suite checks for compliance with the Python IDL mapping with the DOM specification. As of this writing nearly all of DOM level 2 is tested, along with a few level 3 interfaces. Some Parsed XML specific tests are run as well, if the implementation supports those features, such as persistence, parsing, and printing. The suite is very useful for testing extensions to Parsed XML that provide full DOM capabilities. We run the tests on both our ManageableDOM and DOM layers - if it works for DOM, it should work for ManageableDOM, which proxies the entire DOM interface. ParsedXML/tests/__init__.py0100644000175200017500000000003007367624277015616 0ustar faasseninfrae# make this a package ParsedXML/tests/domloader.py0100644000175200017500000001037307367624277016040 0ustar faasseninfrae############################################################################## # # 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. # ############################################################################## from Products.ParsedXML.DOM import ExpatBuilder def main(): import getopt import sys namespaces = 0 opts, args = getopt.getopt(sys.argv[1:], "n") if opts: namespaces = 1 if args: file = args[0] else: file = sys.stdin doc = ExpatBuilder.parse(file, namespaces=namespaces) print doc for node in doc.documentElement.childNodes: print (node.nodeType, node.nodeName, (node.namespaceURI, node.localName), node.nodeValue) if __name__ == "__main__": main() ParsedXML/tests/domtester.py0100755000175200017500000002170407404661661016071 0ustar faasseninfrae############################################################################## # # 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. # ############################################################################## USAGE = '''\ %(program)s -- Test script for DOM implementations. usage: %(program)s [-h] [implementations...] Parameters: -g Use the Tkinter GUI from unittestgui, if available. -h Print this help text. -x Treat the list of tests as tests to exclude rather than include. tests List of tests to execute. By default, all known testcases are run. Known tests include: - DOM the basic DOM - ParsedXML the persistent/wrapped Zope DOM - Printer the DOM-to-XML Printer - Parser the Expat parser and DOM builder - Persistence persistence of the managed DOM - Truthable checks for truth tests - Acquisition checks for acquisition-related integrity failure ''' import getopt import os import sys import imp import unittest import Products.ParsedXML impls = ( ('DOM', 'test_dom'), ('ParsedXML', 'test_wrappeddom'), ('Printer', 'test_printer'), ('Parser', 'test_parser'), ('Persistence', 'test_persistence'), ('Truthable', 'test_truthable'), ('UserAcquisition', 'test_acquisition'), # known parenting bug, also causes errors in DOM tests ('Acquisition', 'test_aqpain'), ('ZopeInterface', 'test_zopeinterface'), # FIXME: this is causing a segfault with debian's python 2.1, though # not with a manually compiled python.. need to look into this # ('Refcounts', 'test_collection'), ('ODB', 'test_ODB'), ('elementId', 'test_elementid'), ) def main(): program = os.path.basename(sys.argv[0]) impls_to_exclude = None gui = 0 try: opts, impls_to_test = getopt.getopt( sys.argv[1:], "dghx", ["disable-gc", "gui", "help", "exclude"]) except getopt.error: sys.stdout = sys.stderr print USAGE % {"program": program} sys.exit(2) for opt, arg in opts: if opt in ("-x", "--exclude"): impls_to_exclude = impls_to_test impls_to_test = [] elif opt in ("-d", "--disable-gc"): try: import gc except ImportError: # nothing to disable pass else: gc.disable() elif opt in ("-g", "--gui"): gui = 1 elif opt in ("-h", "--help"): print USAGE % {"program": program} sys.exit() # Make a backup, so you can see differences between runs. if os.path.exists('out.txt'): if os.path.exists('out.txt.bak'): os.unlink('out.txt.bak') os.rename('out.txt', 'out.txt.bak') if gui: run_tests = run_tests_gui else: run_tests = run_tests_text if run_tests(impls_to_test, impls_to_exclude): sys.exit(1) def run_tests_gui(include, exclude): try: import unittestgui except ImportError: sys.stderr.write( "unittestgui module not installed; install that module from\n" "PyUNIT and try again.\n") return 1 else: unittestgui.main("__main__.all_suites") return 0 def run_tests_text(include, exclude): errs = 0 outf = open("out.txt", "w") stdout = sys.stdout for implname, filename in impls: if include and implname not in include: continue elif exclude and implname in exclude: continue sys.stdout = outf print "===== %s =====\n" % implname try: # Import test file and retrieve test suite. testSuite = load_suite(filename) errs = errs + run_suite(testSuite, implname, outf) finally: sys.stdout = stdout outf.close() return errs def load_suite(filename): path = os.path.join(sys.modules['Products.ParsedXML'].__path__[0], 'tests') file, pathname, desc = imp.find_module(filename, [path]) module = imp.load_module(filename, file, pathname, desc) file.close() return module.test_suite() def all_suites(): suite = unittest.TestSuite() for name, module in impls: suite.addTest(load_suite(module)) return suite def run_suite(testSuite, implname, outf=None): if outf is None: outf = sys.stdout if hasattr(unittest, 'JUnitTextTestRunner'): # Prefer the non-verbose version. runner = unittest.JUnitTextTestRunner(outf) else: runner = unittest.TextTestRunner(outf) result = runner.run(testSuite) print "\n\n" if result.errors: print "Errors:" map(print_error, result.errors) print if result.failures: print "Failures:" map(print_error, result.failures) print newerrs = len(result.errors) + len(result.failures) if newerrs: sys.stderr.write("%s: %d errors, %d failures\n" % (implname, len(result.errors), len(result.failures))) return newerrs def print_error(info): testcase, (type, e, tb) = info print " %s.%s.%s" % (testcase.__class__.__module__, testcase.__class__.__name__, tb.tb_frame.f_code.co_name) if __name__ == "__main__": main() ParsedXML/tests/profParse.py0100644000175200017500000000241007367624277016024 0ustar faasseninfrae#! /usr/bin/env python1.5 import getopt import os import profile import pstats import sys from Products.ParsedXML.DOM import Core, ExpatBuilder FILE = os.path.join(sys.modules['Products.ParsedXML'].__path__[0], 'tests', 'xml', '4ohn4ktj.xml') PROFILEDATA = "@parsefile.prof" def parsefile(filename, namespaces): ExpatBuilder.parse(filename, namespaces=namespaces) _getattr_counts = {} def main(): namespaces = 1 profiledata = None proflines = 20 filename = FILE opts, args = getopt.getopt(sys.argv[1:], "nd:p:") for opt, arg in opts: if opt == "-n": namespaces = not namespaces elif opt == "-p": proflines = int(arg) elif opt == "-d": profiledata = arg if len(args) >= 2: print "One file at a time, please!" sys.exit(2) elif args: filename = args[0] profile.run('parsefile(%s, %s)' % (`filename`, namespaces), profiledata or PROFILEDATA) p = pstats.Stats(profiledata or PROFILEDATA) p.strip_dirs().sort_stats('time').print_stats(proflines) #p.print_callers(proflines) #p.strip_dirs().sort_stats('cum').print_stats(proflines) if not profiledata: os.unlink(PROFILEDATA) if __name__ == "__main__": main() ParsedXML/tests/profPrinter.py0100755000175200017500000000265207367624277016410 0ustar faasseninfraeimport getopt import os import profile import pstats import sys from Products.ParsedXML.DOM import Core, ExpatBuilder from Products.ParsedXML.ExtraDOM import writeStream FILE = os.path.join(sys.modules['Products.ParsedXML'].__path__[0], 'tests', 'xml', '4ohn4ktj.xml') PROFILEDATA = "@parsefile.prof" def parsefile(filename, namespaces): return ExpatBuilder.parse(filename, namespaces=namespaces) def printDOM(document): writeStream(document) _getattr_counts = {} def main(): namespaces = 1 profiledata = None proflines = 20 filename = FILE opts, args = getopt.getopt(sys.argv[1:], "nd:p:") for opt, arg in opts: if opt == "-n": namespaces = not namespaces elif opt == "-p": proflines = int(arg) elif opt == "-d": profiledata = arg if len(args) >= 2: print "One file at a time, please!" sys.exit(2) elif args: filename = args[0] doc = parsefile(filename, namespaces) profiler = profile.Profile() profiler.runctx('printDOM(doc)', locals(), globals()) profiler.dump_stats(profiledata or PROFILEDATA) p = pstats.Stats(profiledata or PROFILEDATA) p.strip_dirs().sort_stats('time').print_stats(proflines) #p.print_callers(proflines) #p.strip_dirs().sort_stats('cum').print_stats(proflines) if not profiledata: os.unlink(PROFILEDATA) if __name__ == "__main__": main() ParsedXML/tests/profPyXMLParse.py0100644000175200017500000000254407367624277016726 0ustar faasseninfraeimport getopt import os import profile import pstats import sys import Products.ParsedXML from xml.dom.ext.reader import PyExpat FILE = os.path.join(sys.modules['Products.ParsedXML'].__path__[0], 'tests', 'xml', '4ohn4ktj.xml') PROFILEDATA = "@parsefile.prof" def parsefile(filename, namespaces): if not namespaces: print "PyXML reader only parses with namespaces" sys.exit(2) reader = PyExpat.Reader() return reader.fromUri(filename) _getattr_counts = {} def main(): namespaces = 1 profiledata = None proflines = 20 filename = FILE opts, args = getopt.getopt(sys.argv[1:], "nd:p:") for opt, arg in opts: if opt == "-n": namespaces = not namespaces elif opt == "-p": proflines = int(arg) elif opt == "-d": profiledata = arg if len(args) >= 2: print "One file at a time, please!" sys.exit(2) elif args: filename = args[0] profile.run('parsefile(%s, %s)' % (`filename`, namespaces), profiledata or PROFILEDATA) p = pstats.Stats(profiledata or PROFILEDATA) p.strip_dirs().sort_stats('time').print_stats(proflines) #p.print_callers(proflines) #p.strip_dirs().sort_stats('cum').print_stats(proflines) if not profiledata: os.unlink(PROFILEDATA) if __name__ == "__main__": main() ParsedXML/tests/profPyXMLPrinter.py0100644000175200017500000000265207367624277017277 0ustar faasseninfraeimport getopt import os import profile import pstats import sys from Products.ParsedXML.ExtraDOM import writeStream FILE = os.path.join(sys.modules['Products.ParsedXML'].__path__[0], 'tests', 'xml', '4ohn4ktj.xml') PROFILEDATA = "@parsefile.prof" def parsefile(filename, namespaces): from xml.dom.ext.reader import PyExpat reader = PyExpat.Reader() return reader.fromUri(filename) def printDOM(document): writeStream(document) _getattr_counts = {} def main(): namespaces = 1 profiledata = None proflines = 20 filename = FILE opts, args = getopt.getopt(sys.argv[1:], "nd:p:") for opt, arg in opts: if opt == "-n": namespaces = not namespaces elif opt == "-p": proflines = int(arg) elif opt == "-d": profiledata = arg if len(args) >= 2: print "One file at a time, please!" sys.exit(2) elif args: filename = args[0] doc = parsefile(filename, namespaces) profiler = profile.Profile() profiler.runctx('printDOM(doc)', locals(), globals()) profiler.dump_stats(profiledata or PROFILEDATA) p = pstats.Stats(profiledata or PROFILEDATA) p.strip_dirs().sort_stats('time').print_stats(proflines) #p.print_callers(proflines) #p.strip_dirs().sort_stats('cum').print_stats(proflines) if not profiledata: os.unlink(PROFILEDATA) if __name__ == "__main__": main() ParsedXML/tests/test_ODB.py0100644000175200017500000001232207367624277015531 0ustar faasseninfrae############################################################################## # # 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. # ############################################################################## "Test some ODB interactions." import unittest import ZODB # for Persistent from Products.ParsedXML import ParsedXML class ODBTestCase(unittest.TestCase): def setUp(self): self.document = ParsedXML.ParsedXML('foo') def shotgunTpStuff(self, node): "assert that the Tp* functions work" children = node.childNodes tpVals = node.tpValues() for i in range(children.length): assert children.item(i).isSameNode(tpVals[i]) for i in range(children.length): assert children.item(i).tpURL() == str(i) assert children.item(i).tpId() == str(i) for node in tpVals: self.shotgunTpStuff(node) def checkTpStuff(self): "check that the Tp* functions work" self.document.documentElement.appendChild( self.document.createElement('zero')) self.document.documentElement.appendChild( self.document.createElement('one')) self.document.documentElement.firstChild.appendChild( self.document.createElement('zero-zero')) self.document.documentElement.firstChild.appendChild( self.document.createElement('zero-one')) self.shotgunTpStuff(self.document.documentElement) def test_suite(): """Return a test suite for the Zope testing framework.""" return unittest.makeSuite(ODBTestCase, 'check') def main(): unittest.TextTestRunner().run(test_suite()) if __name__ == '__main__': main() ParsedXML/tests/test_acquisition.py0100644000175200017500000001567007417347741017460 0ustar faasseninfrae############################################################################## # # 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. # ############################################################################## "test that the ParsedXML DOM object acquire implicitly" # this suite isn't done that well. We could probably just mount a db. # We currently have to have a Zope instance # to mount; we need a persistent container & Zope traversal to acquire # properly, because we don't want to acquire through the transient # proxy objects. import unittest import ZODB # for Persistent from Products.ParsedXML import ParsedXML def checkAcquire(aqer, aqee, name): "check that acquisition of name from aqee to aqer happens" assert hasattr(aqer, name) assert getattr(aqer, name) == getattr(aqee, name) assert getattr(aqer, name) is getattr(aqee, name) def checkAcquireNot(aqer, aqee, name): "check that acquisition of name from aqee to aqer doesn't happen" assert getattr(aqer, name) != getattr(aqee, name) assert getattr(aqer, name) is not getattr(aqee, name) class WrappedAcquisitionTestCase(unittest.TestCase): def setUp(self): # we need a doc in a container that supports # restrictedTraverse and getPhysicalPath to have a proper # acquisition chain. import OFS.Application self.app = OFS.Application.Application() self.tmpId = 'TempParsedXMLUnitTestInstance' self.app._setObject(self.tmpId, ParsedXML.ParsedXML(self.tmpId)) self.doc = getattr(self.app, self.tmpId) self.app.string = 'a string' self.app.firstChild = "a string that shouldn't be acquired" elt1 = self.doc.createElement('eggs') elt2 = self.doc.createElement('ham') self.doc.documentElement.appendChild(elt1) self.doc.documentElement.appendChild(elt2) self.doc.documentElement.setAttribute('color', 'green') def _acquisitionTest(self, DOMObj): checkAcquire(DOMObj, self.app, 'string') checkAcquireNot(DOMObj, self.app, 'firstChild') def checkTraversalAcquisition(self): "make sure we can acquire through DOM traversal" self._acquisitionTest(self.doc) self._acquisitionTest(self.doc.documentElement) self._acquisitionTest(self.doc.documentElement.firstChild) self._acquisitionTest(self.doc.documentElement.firstChild.nextSibling) self._acquisitionTest(self.doc.documentElement.ownerDocument) self._acquisitionTest(self.doc.documentElement.getAttributeNode( 'color')) def checkMethodAcquisition(self): "make sure we acquire through proxied DOM methods" elt = self.doc.createElement('foo') self._acquisitionTest(self.doc.documentElement.appendChild(elt)) def checkNodeListAcquisition(self): "make sure we can acquire through a NodeList" self._acquisitionTest(self.doc.documentElement.childNodes.item(0)) def checkNamedNodeMapAcquisition(self): "make sure we can acquire through a NamedNodeMap" self._acquisitionTest( self.doc.documentElement.attributes.getNamedItem('color')) def test_suite(): """Return a test suite for the Zope testing framework.""" suite = unittest.TestSuite() suite.addTest(unittest.makeSuite(WrappedAcquisitionTestCase, 'check')) return suite def main(): unittest.TextTestRunner().run(test_suite()) if __name__ == "__main__": main() ParsedXML/tests/test_all.py0100644000175200017500000000272207471017163015662 0ustar faasseninfraeimport unittest from Products.ParsedXML.tests import test_dom from Products.ParsedXML.tests import test_wrappeddom from Products.ParsedXML.tests import test_printer from Products.ParsedXML.tests import test_parser from Products.ParsedXML.tests import test_persistence from Products.ParsedXML.tests import test_truthable from Products.ParsedXML.tests import test_acquisition from Products.ParsedXML.tests import test_aqpain from Products.ParsedXML.tests import test_zopeinterface from Products.ParsedXML.tests import test_collection from Products.ParsedXML.tests import test_ODB from Products.ParsedXML.tests import test_elementid def test_suite(): suite = unittest.TestSuite() suite.addTest(test_dom.test_suite()) suite.addTest(test_wrappeddom.test_suite()) suite.addTest(test_printer.test_suite()) suite.addTest(test_parser.test_suite()) suite.addTest(test_persistence.test_suite()) suite.addTest(test_truthable.test_suite()) suite.addTest(test_acquisition.test_suite()) suite.addTest(test_aqpain.test_suite()) suite.addTest(test_zopeinterface.test_suite()) suite.addTest(test_collection.test_suite()) suite.addTest(test_ODB.test_suite()) suite.addTest(test_elementid.test_suite()) return suite def main(): if hasattr(unittest, 'JUnitTextTestRunner'): unittest.JUnitTextTestRunner().run(test_suite()) else: unittest.TextTestRunner(verbosity=0).run(test_suite()) if __name__ == '__main__': main() ParsedXML/tests/test_aqpain.py0100755000175200017500000000414607367624277016406 0ustar faasseninfrae"""Test that checks the fragility of using acquistion wrappers to indicate tree hierarchy. The current implementation of the DOM uses acquisition wrappers to store references to a node's parent node. While this allows very efficient access to the parent, it is fragile in the case of multiple wrappers referring to the same node. If client code holds two wrappers for a node and modifies the node's position in the tree using one of them, the other will store incorrect information on the shape of the tree. For acquisition to be used to adequately be used to present the containment hierarchy for a node, a complete chain of wrappers would need to be constructed each time a node is reparented, starting from the outermost node in the ancestor chain. Application code would need to be wary that old references to a node are replaced by the new wrapper. The Python DOM API makes no such requirement at the present time, nor should it need to. This script shows a contrived example that exercises this DOM bug. While this particular code is unlikely in real applications, the ease with which multiple acquisition wrappers can be produced in more complex application code is easy to see. """ import unittest from Products.ParsedXML.DOM.ExpatBuilder import ExpatBuilder from Products.ParsedXML.Printer import PrintVisitor class AcquisitionPain(unittest.TestCase): def setUp(self): self.doc = ExpatBuilder().parseString("") self.printer = PrintVisitor(self.doc) def checkParentReferenceIntegrity(self): e1a = self.doc.documentElement.firstChild e1b = self.doc.documentElement.firstChild e2 = e1b.nextSibling e2.appendChild(e1b) assert e1a.parentNode.isSameNode(e1b.parentNode), \ "Two references to the same node return different parent nodes." def test_suite(): """Return a test suite for the Zope testing framework.""" suite = unittest.TestSuite() suite.addTest(unittest.makeSuite(AcquisitionPain, 'check')) return suite def main(): unittest.TextTestRunner().run(test_suite()) if __name__ == "__main__": main() ParsedXML/tests/test_collection.py0100644000175200017500000001374307367624277017270 0ustar faasseninfrae############################################################################## # # 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. # ############################################################################## "Tests for garbage collection." import unittest import ZODB # for Persistent import os import string import sys from Products.ParsedXML import ParsedXML, DOM import App.ApplicationManager class ReferenceTestCase(unittest.TestCase): def setUp(self): self.dbman = App.ApplicationManager.DebugManager() def getRefcounts(self, ob): "return number of refcounts for instances of ob's class" name = '%s.%s' % (ob.__module__, ob.__class__.__name__) for i in self.dbman.refcount(): if i[1] == name: return i[0] return 0 def checkParsedXMLCollect(self): "see if refcounts from ParsedXML product init are released" doc = ParsedXML.ParsedXML('foo') refcounts1 = self.getRefcounts(doc) doc = ParsedXML.ParsedXML('foo') refcounts2 = self.getRefcounts(doc) assert refcounts2 == refcounts1, ( "ParsedXML leaked %d refcounts" % (refcounts2 - refcounts1)) def checkDOMParseCollect(self): "see if refcounts from DOM parse creation are released" testDir = os.path.join( sys.modules['Products.ParsedXML'].__path__[0], 'tests') filename = os.path.join(testDir, 'xml', '4ohn4ktj.xml') doc = DOM.ExpatBuilder.parse(filename) refcounts1 = self.getRefcounts(doc) doc = DOM.ExpatBuilder.parse(filename) refcounts2 = self.getRefcounts(doc) assert refcounts2 == refcounts1, ( "DOM parse leaked %d refcounts" % (refcounts2 - refcounts1)) def checkDOMCreateCollect(self): "see if refcounts from DOM creation are released" doc = DOM.theDOMImplementation.createDocument(None, 'doc', None) refcounts1 = self.getRefcounts(doc) doc = DOM.theDOMImplementation.createDocument(None, 'doc', None) refcounts2 = self.getRefcounts(doc) assert refcounts2 == refcounts1, ( "DOM parse leaked %d refcounts" % (refcounts2 - refcounts1)) def test_suite(): """Return a test suite for the Zope testing framework.""" suite = unittest.TestSuite() suite.addTest(unittest.makeSuite(ReferenceTestCase, 'check')) return suite def main(): unittest.TextTestRunner().run(test_suite()) if __name__ == "__main__": main() ParsedXML/tests/test_dom.py0100644000175200017500000001037707367624277015714 0ustar faasseninfrae############################################################################## # # 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. # ############################################################################## import unittest from Products.ParsedXML import DOM from Products.ParsedXML.DOM import ExpatBuilder from Products.ParsedXML.StrIO import StringIO from domapi import DOMImplementationTestSuite def DOMParseString(self, xml): file = StringIO(xml) return ExpatBuilder.parse(file) def test_suite(): """Return a test suite for the Zope testing framework.""" return DOMImplementationTestSuite(DOM.theDOMImplementation, DOMParseString) def main(): unittest.TextTestRunner().run(test_suite()) if __name__ == '__main__': main() ParsedXML/tests/test_elementid.py0100644000175200017500000001474507403744007017067 0ustar faasseninfrae############################################################################## # # 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. # ############################################################################## import unittest from Products.ParsedXML import DOM from Products.ParsedXML.DOM import ExpatBuilder from Products.ParsedXML.StrIO import StringIO from domapi import DOMImplementationTestSuite def DOMParseString(xml): file = StringIO(xml) return ExpatBuilder.parse(file) def get_element_ids(node): result = [] if node.nodeType == node.ELEMENT_NODE: result.append(node.elementId) for child in node.childNodes: result.extend(get_element_ids(child)) return result def check_unique_ids(node): element_ids = get_element_ids(node) element_ids.sort() last = element_ids[0] for element_id in element_ids[1:]: assert last != element_id,\ 'Found at least one double element_id: %s' % element_id last = element_id class ElementIdTestCase(unittest.TestCase): def setUp(self): self.doc = DOMParseString('''

Test

Another test

Foohey

''') def checkElementIdsAfterParse(self): element_ids = get_element_ids(self.doc) for i in xrange(len(element_ids)): assert i == element_ids[i] def checkElementIdsAfterAppend(self): element = self.doc.createElement('foo') self.doc.documentElement.appendChild(element) check_unique_ids(self.doc) def checkElementIdsAfterAppend2(self): element = self.doc.createElement('foo') self.doc.documentElement.insertBefore( element, self.doc.documentElement.childNodes[0]) check_unique_ids(self.doc) def checkCloneNodeShallow(self): cloned = self.doc.documentElement.cloneNode(0) self.doc.documentElement.appendChild(cloned) check_unique_ids(self.doc) def checkCloneNodeDeep(self): cloned = self.doc.documentElement.cloneNode(1) self.doc.documentElement.appendChild(cloned) check_unique_ids(self.doc) def checkImportNodeShallow(self): otherdoc = DOMParseString(''' ''') imported = self.doc.importNode( otherdoc.documentElement, 0) self.doc.documentElement.appendChild(imported) check_unique_ids(self.doc) def checkImportNodeDeep(self): otherdoc = DOMParseString(''' ''') imported = self.doc.importNode( otherdoc.documentElement, 1) self.doc.documentElement.appendChild(imported) check_unique_ids(self.doc) def test_suite(): suite = unittest.TestSuite() suite.addTest(unittest.makeSuite(ElementIdTestCase, 'check')) return suite def main(): unittest.TextTestRunner().run(test_suite()) if __name__ == "__main__": main() ParsedXML/tests/test_parser.py0100644000175200017500000005122707600633531016407 0ustar faasseninfrae############################################################################## # # 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. # ############################################################################## import unittest import ZODB # for Persistent import os import string import sys from domapi.Base import checkAttribute from Products.ParsedXML import ParsedXML, Printer, ExtraDOM, DOM from Products.ParsedXML.StrIO import StringIO # the printer is a convenient way to track changes made by the parser from test_printer import printElement, checkOutput class ParsedXMLTestCaseBase(unittest.TestCase): def shotgunParse(self, doc, namespaces = 1): "parse and print every node in the document" # first we parse a print of the document, to avoid errors from # comparing before and after infospace-lossyness docStr = StringIO(ExtraDOM.writeStream(doc).getvalue()) doc = ExtraDOM.parseFile(doc, docStr, namespaces) from Products.ParsedXML.DOM.Traversal import NodeFilter nodes = [] iterator = doc.createNodeIterator(doc, NodeFilter.SHOW_ALL, None, 0) # parse from the bottom up because parsing a node replaces children # it'd be simpler to not store a list of nodes, but this way we # miss possible iterator bugs while iterator.nextNode(): pass node = iterator.previousNode() while node: if node.nodeType != DOM.Core.Node.DOCUMENT_TYPE_NODE: nodes.append(node) node = iterator.previousNode() # parse print of each node and compare printed doc, node. for node in nodes: docStrIn = ExtraDOM.writeStream(doc).getvalue() nodeStrIn = ExtraDOM.writeStream(node).getvalue() ExtraDOM.parseFile(node, StringIO(nodeStrIn), namespaces) nodeStrOut = ExtraDOM.writeStream(node).getvalue() docStrOut = ExtraDOM.writeStream(doc).getvalue() checkOutput(nodeStrIn, nodeStrOut, "parsing print of node %s changed node print" % node) checkOutput(docStrIn, docStrOut, "parsing print of node %s changed doc print" % node) class ParseOasisXMLTestSaTestCase(ParsedXMLTestCaseBase): # set this to true to generate new output files generate = 0 def checkParse001(self): self._checkParse("001.xml") def checkParse002(self): self._checkParse("002.xml") def checkParse003(self): self._checkParse("003.xml") def checkParse004(self): self._checkParse("004.xml") def checkParse005(self): self._checkParse("005.xml") def checkParse006(self): self._checkParse("006.xml") def checkParse007(self): self._checkParse("007.xml") def checkParse008(self): self._checkParse("008.xml") def checkParse009(self): self._checkParse("009.xml") def checkParse010(self): self._checkParse("010.xml") def checkParse011(self): self._checkParse("011.xml") # This test fails when we use namespaces to determine valid tagnames. # We want to parse namespaces always. #def checkParse012(self): # self._checkParse("012.xml") def checkParse013(self): self._checkParse("013.xml") def checkParse014(self): self._checkParse("014.xml") def checkParse015(self): self._checkParse("015.xml") def checkParse016(self): self._checkParse("016.xml") def checkParse017(self): self._checkParse("017.xml") def checkParse018(self): self._checkParse("018.xml") def checkParse019(self): self._checkParse("019.xml") def checkParse020(self): self._checkParse("020.xml") def checkParse021(self): self._checkParse("021.xml") def checkParse022(self): self._checkParse("022.xml") def checkParse023(self): self._checkParse("023.xml") def checkParse024(self): self._checkParse("024.xml") def checkParse025(self): self._checkParse("025.xml") def checkParse026(self): self._checkParse("026.xml") def checkParse027(self): self._checkParse("027.xml") def checkParse028(self): self._checkParse("028.xml") def checkParse029(self): self._checkParse("029.xml") def checkParse030(self): self._checkParse("030.xml") def checkParse031(self): self._checkParse("031.xml") def checkParse032(self): self._checkParse("032.xml") def checkParse033(self): self._checkParse("033.xml") def checkParse034(self): self._checkParse("034.xml") def checkParse035(self): self._checkParse("035.xml") def checkParse036(self): self._checkParse("036.xml") def checkParse037(self): self._checkParse("037.xml") def checkParse038(self): self._checkParse("038.xml") def checkParse039(self): self._checkParse("039.xml") def checkParse040(self): self._checkParse("040.xml") def checkParse041(self): self._checkParse("041.xml") def checkParse042(self): self._checkParse("042.xml") def checkParse043(self): self._checkParse("043.xml") def checkParse044(self): self._checkParse("044.xml") def checkParse045(self): self._checkParse("045.xml") def checkParse046(self): self._checkParse("046.xml") def checkParse047(self): self._checkParse("047.xml") def checkParse048(self): self._checkParse("048.xml") def checkParse049(self): self._checkParse("049.xml") def checkParse050(self): self._checkParse("050.xml") # TODO: replace when we get unicode #def checkParse051(self): # self._checkParse("051.xml") def checkParse052(self): self._checkParse("052.xml") def checkParse053(self): self._checkParse("053.xml") def checkParse054(self): self._checkParse("054.xml") def checkParse055(self): self._checkParse("055.xml") def checkParse056(self): self._checkParse("056.xml") def checkParse057(self): self._checkParse("057.xml") def checkParse058(self): self._checkParse("058.xml") def checkParse059(self): self._checkParse("059.xml") def checkParse060(self): self._checkParse("060.xml") def checkParse061(self): self._checkParse("061.xml") def checkParse062(self): self._checkParse("062.xml") # TODO: replace when we get unicode #def checkParse063(self): # self._checkParse("063.xml") def checkParse064(self): self._checkParse("064.xml") def checkParse065(self): self._checkParse("065.xml") def checkParse066(self): self._checkParse("066.xml") def checkParse067(self): self._checkParse("067.xml") def checkParse068(self): self._checkParse("068.xml") def checkParse069(self): self._checkParse("069.xml") def checkParse070(self): self._checkParse("070.xml") def checkParse071(self): self._checkParse("071.xml") def checkParse072(self): self._checkParse("072.xml") def checkParse073(self): self._checkParse("073.xml") def checkParse074(self): self._checkParse("074.xml") def checkParse075(self): self._checkParse("075.xml") def checkParse076(self): self._checkParse("076.xml") def checkParse077(self): self._checkParse("077.xml") def checkParse078(self): self._checkParse("078.xml") def checkParse079(self): self._checkParse("079.xml") def checkParse080(self): self._checkParse("080.xml") def checkParse081(self): self._checkParse("081.xml") def checkParse082(self): self._checkParse("082.xml") def checkParse083(self): self._checkParse("083.xml") def checkParse084(self): self._checkParse("084.xml") def checkParse085(self): self._checkParse("085.xml") def checkParse086(self): self._checkParse("086.xml") def checkParse087(self): self._checkParse("087.xml") def checkParse088(self): self._checkParse("088.xml") def checkParse089(self): self._checkParse("089.xml") def checkParse090(self): self._checkParse("090.xml") def checkParse091(self): self._checkParse("091.xml") def checkParse092(self): self._checkParse("092.xml") def checkParse093(self): self._checkParse("093.xml") def checkParse094(self): self._checkParse("094.xml") def checkParse095(self): self._checkParse("095.xml") def checkParse096(self): self._checkParse("096.xml") def checkParse097(self): self._checkParse("097.xml") def checkParse098(self): self._checkParse("098.xml") def checkParse099(self): self._checkParse("099.xml") def checkParse100(self): self._checkParse("100.xml") def checkParse101(self): self._checkParse("101.xml") def checkParse102(self): self._checkParse("102.xml") def checkParse103(self): self._checkParse("103.xml") def checkParse104(self): self._checkParse("104.xml") def checkParse105(self): self._checkParse("105.xml") def checkParse106(self): self._checkParse("106.xml") def checkParse107(self): self._checkParse("107.xml") def checkParse108(self): self._checkParse("108.xml") def checkParse109(self): self._checkParse("109.xml") def checkParse110(self): self._checkParse("110.xml") def checkParse111(self): self._checkParse("111.xml") def checkParse112(self): self._checkParse("112.xml") def checkParse113(self): self._checkParse("113.xml") def checkParse114(self): self._checkParse("114.xml") def checkParse115(self): self._checkParse("115.xml") def checkParse116(self): self._checkParse("116.xml") def checkParse117(self): self._checkParse("117.xml") def checkParse118(self): self._checkParse("118.xml") def checkParse119(self): self._checkParse("119.xml") def _checkParse(self, iterFileName): testDir = os.path.join(sys.modules['Products.ParsedXML'].__path__[0], 'tests') saDir = os.path.join(testDir, 'xml', 'conf', 'xmltest', 'sa') outDir = os.path.join(saDir, 'ParsedXMLTestOut') # Read the test input inFilename = os.path.join(saDir, iterFileName) inFile = open(inFilename).read() doc = ParsedXML.ParsedXML('foo', inFile) # Read the output to test against outFilename = os.path.join(outDir, iterFileName) outFile = open(outFilename).read() # FIXME: if the next line is enabled, the tests will succeed # with python 2.1. Unfortunately the whole testsuite will # segfault at about test 23 (it'll vary) # outFile = unicode(outFile) # Print the DOM, and compare against the expected output. output = printElement(doc) # All line separators are supposed to normalize to Unix-style # (XML 1.0, section 2.11). ## outFile = string.replace(outFile, "\r\n", "\n") ## outFile = string.replace(outFile, "\r", "\n") if self.generate: # re-generate the expected output file, but only if it changed if outFile != output: fp = open(outFilename, "w") fp.write(output) fp.close() else: checkOutput(repr(outFile), repr(output)) self.shotgunParse(doc.getDOMObj()) class ParseTestCase(ParsedXMLTestCaseBase): def checkParseException(self): "assert exception & exception args are correct" from xml.parsers import expat text = "\nfoobar<" # parse error line 2 column 7 try: ParsedXML.ParsedXML('foo', text) except expat.error, e: assert e.lineno == 2, ( "parse exception give wrong line number. Wanted %s got %s" % (2, e.lineno)) assert e.offset == 7, ( "parse exception give wrong column number. Wanted %s got %s" % (7, e.offset)) else: assert 0, "parse of malformed XML doesn't raise properly" def checkSubnodeParseException(self): "assert exception & exception args are correct" from xml.parsers import expat docText = "" subText = "\nfoobar<" # parse error line 2 column 7 doc = ParsedXML.ParsedXML('foo', docText) try: doc.documentElement.firstChild.parseXML(StringIO(subText)) except expat.error, e: assert e.lineno == 2, ( "parse exception gives wrong line number. Wanted %s, got %s" % (2, e.lineno)) assert e.offset == 7, ( "parse exception gives wrong offset. Wanted %s, got %s" % (7, e.offset)) else: assert 0, "parse of malformed XML doesn't raise properly" class Lvl2ParseTestCase(ParsedXMLTestCaseBase): def checkNamespaceAttrOfDocumentElement(self): """we should be able to parse an element that uses a namespace declared on the element itself""" inStr = '\n' \ '\n' doc = ParsedXML.ParsedXML('foo', inStr) self.shotgunParse(doc.getDOMObj()) def checkNamespaceAttrOfElement(self): """we should be able to parse an element that uses a namespace declared on the element itself""" inStr = '\n' \ '\n' doc = ParsedXML.ParsedXML('foo', inStr) self.shotgunParse(doc.getDOMObj()) def checkSubnodeAncestorNamespace(self): """we should be able to parse a subtree that uses a namespace declared on an ancestor that we don't parse""" inStr = ('\n' '' '' '\n') doc = ParsedXML.ParsedXML('foo', inStr) self.shotgunParse(doc.getDOMObj()) def checkSubnodeParseXMLNamepsaceDecl(self): """Check that we can parse at a subnode with an xml ns decl attr, and that parsing a subnode's output doesn't change the document. The external entity parser that the fragment builder uses likes to add this namespace, so we want to make sure we don't break anything that uses it.""" inStr = '' doc = ParsedXML.ParsedXML('foo', inStr) self.shotgunParse(doc.getDOMObj()) def checkSubnodeParseXMLNamepsace(self): """Check that we can parse at a subnode with an xml ns attr, and that parsing a subnode's output doesn't change the document. The external entity parser that the fragment builder uses likes to add this namespace, so we want to make sure we don't break anything that uses it.""" # we should use a real XML name here, it's not an error if the # parser notices that we're abusign the xml namespace inStr = '' doc = ParsedXML.ParsedXML('foo', inStr) self.shotgunParse(doc.getDOMObj()) def checkXMLNSPrefixParse(self): "check that xmlns prefix attrs are parsed properly" inStr = '' doc = ParsedXML.ParsedXML('foo', inStr) attr = doc.documentElement.attributes.item(0) checkAttribute(attr, 'prefix', 'xmlns') checkAttribute(attr, 'localName', 'spamNS') checkAttribute(attr, 'namespaceURI', 'http://www.w3.org/2000/xmlns/') checkAttribute(attr, 'value', 'uri:test_namespace') def checkXMLNSParse(self): "check that xmlns attrs are parsed properly" inStr = '' doc = ParsedXML.ParsedXML('foo', inStr) attr = doc.documentElement.attributes.item(0) checkAttribute(attr, 'prefix', 'xmlns') checkAttribute(attr, 'localName', None) checkAttribute(attr, 'namespaceURI', 'http://www.w3.org/2000/xmlns/') checkAttribute(attr, 'value', 'uri:test_namespace') def checkNoNSParse(self): """check that attrs parsed with no NS but with NS aware parse can be retrieved with NS of None""" inStr = '' doc = ParsedXML.ParsedXML('foo', inStr) assert doc.documentElement.getAttributeNS(None, 'version'), ( "NS-free attribute not gotten by NS-free getAttributeNS") def test_suite(): """Return a test suite for the Zope testing framework.""" suite = unittest.TestSuite() suite.addTest(unittest.makeSuite(ParseOasisXMLTestSaTestCase, 'check')) suite.addTest(unittest.makeSuite(ParseTestCase, 'check')) suite.addTest(unittest.makeSuite(Lvl2ParseTestCase, 'check')) return suite def main(): unittest.TextTestRunner(verbosity=3).run(test_suite()) if __name__ == "__main__": main() ParsedXML/tests/test_persistence.py0100644000175200017500000002256207367624277017460 0ustar faasseninfrae############################################################################## # # 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. # ############################################################################## # DB stuff copied from testBTrees.py import unittest import ZODB # for Persistent import glob import os import sys from Products.ParsedXML import ParsedXML from Products.ParsedXML.StrIO import StringIO import unittest class PersistenceTestCase(unittest.TestCase): implementation = ParsedXML.theDOMImplementation def openDB(self): from ZODB.FileStorage import FileStorage from ZODB.DB import DB storage = FileStorage(self.dbName) db = DB(storage) self.db = db.open().root() def closeDB(self): get_transaction().commit() self.document = None self.db._p_jar._db.close() self.db = None def getAppDocument(self): "put the document that startup put in the db in self.document" self.document = self.db['doc'] def cycleDB(self): """close and open the db and replace self.document. Any nonpersistent changes to self.document should be lost.""" self.closeDB() self.openDB() self.getAppDocument() def delDB(self): map(os.unlink, glob.glob("fs_tmp__*")) def setUp(self): """open db, create a document in the db, set self.document to it""" self.dbName = 'fs_tmp__%s' % os.getpid() self.openDB() self.db['doc'] = ParsedXML.ParsedXML('foo') get_transaction().commit() self.document = self.db['doc'] def tearDown(self): self.closeDB() self.delDB() def checkIDPersistence(self): "assert that changing the ID persists over transactions" self.document._setId('newId') self.cycleDB() assert self.document.getId() == 'newId' def checkParsedXMLDOMPersistence(self): "assert that a Parsed XML DOM edit persists over transactions" elt = self.document.createElement('elt') self.document.firstChild.appendChild(elt) self.cycleDB() childLen = self.document.firstChild.childNodes.length assert childLen == 1, "DOM edit didn't persist" def checkDOMPersistence(self): "assert that a DOM edit persists over transactions" doc = ParsedXML.createDOMDocument() import OFS.SimpleItem si = self.db['si'] = OFS.SimpleItem.SimpleItem() si.doc = doc elt = si.doc.createElement('elt') si.doc.firstChild.appendChild(elt) self.cycleDB() # not using the normal db document, must grab ourselves si = self.db['si'] childLen = si.doc.firstChild.childNodes.length assert childLen == 1, "DOM edit didn't persist" def checkParsePersistence(self): "assert that a parse persists over transactions" testDir = os.path.join( sys.modules['Products.ParsedXML'].__path__[0], 'tests') filename = os.path.join(testDir, 'xml', '4ohn4ktj.xml') file = open(filename) self.document.parseXML(filename) file.close() childLen = self.document.firstChild.childNodes.length self.cycleDB() childLen1 = self.document.firstChild.childNodes.length assert childLen == childLen1, "parse didn't persist" def checkSubnodeParsePersistence(self): "assert that a subnode parse persists over transactions" docString = '' subNodeString = 'bar' self.document.documentElement.parseXML(StringIO(subNodeString)) self.cycleDB() childLen = self.document.documentElement.childNodes.length assert childLen == 1, "parse on subnode didn't persist" # right now it's too annoying to get parsing to work at a transient # document proxy, but it could be less aggravating if we had a better # way to get at the persistent document. #def checkTransientDocumentParsePersistence(self): # """assert that a parse of a transient proxy of the document # persists over transactions""" # docStringBefore = '' # docStringAfter = 'bar' # self.document.documentElement.ownerDocument.parseXML( # StringIO(docStringAfter)) # self.cycleDB() # childLen = self.document.documentElement.childNodes.length # assert childLen == 1, "parse on subnode didn't persist" # def checkTheseDamnTests(self): # "assert that I understand how these tests should work" # docString = 'fff' # self.document.parseXML(StringIO(docString)) # get_transaction().commit() # # db and doc length now 1 # self.document.documentElement.removeChild( # self.document.documentElement.firstChild) # # doc length 0, db length 1 # # do what closeDB and openDB do, but *don't commit* # # so the above edit shouldn't stay. # #closeDB but don't commit # #get_transaction().commit() # self.document = None # self.db._p_jar._db.close() # self.db = None # #openDB # from ZODB.FileStorage import FileStorage # from ZODB.DB import DB # storage = FileStorage(self.dbName) # db = DB(storage) # self.db = db.open().root() # self.getAppDocument() # get_transaction().commit() # assert self.document.documentElement.childNodes.length == 1, ( # "these tests are faulty") def test_suite(): """Return a test suite for the Zope testing framework.""" return unittest.makeSuite(PersistenceTestCase, 'check') def main(): unittest.TextTestRunner().run(test_suite()) if __name__ == '__main__': main() ParsedXML/tests/test_prettyprinter.py0100644000175200017500000002414707471161751020055 0ustar faasseninfrae############################################################################## # # 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. # ############################################################################## import unittest import ZODB # for Persistent import string # FIXME: could test with Core DOM instead, do we want to? from Products.ParsedXML import ParsedXML, PrettyPrinter from Products.ParsedXML.StrIO import StringIO def printElement(element, encoding = None, html = 0, contentType = None): output = StringIO() PrettyPrinter.PrintVisitor(element, output, encoding, html, contentType)() return output.getvalue() def checkOutput(wanted, got, message="Bad output"): assert wanted == got, \ ("%s. Wanted:\n%s[[EOF]]\nGot:\n%s[[EOF]]\n" % (message, wanted, got)) class PrintTestBase(unittest.TestCase): implementation = ParsedXML.theDOMImplementation def parse(self, xml): return ParsedXML.ParsedXML('foo', xml) class PrintTestCase(PrintTestBase): def checkAttrOrder(self): inStr = '\n\n' doc = self.parse(inStr) output = printElement(doc) checkOutput(inStr, output, "attribute order not preserved") def checkDefaultAttrSkipped(self): inStr = '' \ ']>' outStr = '\n\n' doc = self.parse(inStr) output = printElement(doc) checkOutput(outStr, output, "default attribute printed") def checkAttrEntRefExpansion(self): "entity references must be expanded in attributes" doc = self.implementation.createDocument(None, 'root', None) attr = doc.createAttribute("attrName") # this is a text string; &test; is not an entity reference, # so its & should be converted to the proper ref on printing, # as should the & and < and >. attr.value = "&test; &<>" # this reference should be expanded to the empty string attr.appendChild(doc.createEntityReference('foo')) doc.documentElement.setAttributeNode(attr) outStr = '' output = printElement(doc.documentElement) checkOutput(outStr, output, "improper attr entity expansion") def checkTextEntRefExpansion(self): "only some entity references should be expanded in text" doc = self.implementation.createDocument(None, 'root', None) # &< must be converted to the proper reference; > should not. text = doc.createTextNode("&<>]]>") outStr = '&<>]]>' output = printElement(text) checkOutput(outStr, output, "improper text entity expansion") #TODO: check for expansion of entity refs in other contexts; #currently we're expanding aggressively, but it's not a priority #because the parser gets to play around with refs too class HTMLPrintTestCase(PrintTestBase): def checkMinimize(self): inStr = ('



' + '

') outStr = ('



' + '

\n') doc = self.parse(inStr) output = printElement(doc, encoding = None, html = 1) checkOutput(outStr, output, "improper HTML minimization") def checkCapitalize(self): inStr = ('
\n') doc = self.parse(inStr) output = printElement(doc, encoding = None, html = 1, contentType = 'html') checkOutput(string.upper(inStr), output, "improper HTML contenttype HTML capitalization") output = printElement(doc, encoding = None, html = 1, contentType = 'xml') checkOutput(string.lower(inStr), output, "improper XML contenttype HTML capitalization") class Lvl2PrintTestCase(PrintTestBase): def checkNamespacePrint(self): outStr = '\n' \ '\n' \ '\n' doc = self.parse(outStr) output = printElement(doc) checkOutput(outStr, output) def checkNamespaceAttrOrder(self): inStr = ('\n' '' ' ' '\n') doc = self.parse(inStr) output = printElement(doc) checkOutput(inStr, output, "attribute order not preserved") def checkHierarchicalElementNamespacePrint(self): # print new ns, don't print ns printed by ancestor outStr = ('\n' '' ' ' ' ' ' ' ' ' ' ' '\n') doc = self.parse(outStr) output = printElement(doc) checkOutput(outStr, output) def checkDefaultNamespacePrint(self): outStr = ('\n' '' '\n') doc = self.parse(outStr) output = printElement(doc) checkOutput(outStr, output) def checkDefaultAndPrefixNamespacePrint(self): # try and tickle a namespace printing bug outStr = ('\n' '' ' ' ' ' ' ' ' ' ' ' ' ' '\n') doc = self.parse(outStr) output = printElement(doc) checkOutput(outStr, output) def test_suite(): """Return a test suite for the Zope testing framework.""" suite = unittest.TestSuite() suite.addTest(unittest.makeSuite(PrintTestCase, 'check')) suite.addTest(unittest.makeSuite(HTMLPrintTestCase, 'check')) suite.addTest(unittest.makeSuite(Lvl2PrintTestCase, 'check')) return suite def main(): unittest.TextTestRunner().run(test_suite()) if __name__ == '__main__': main() ParsedXML/tests/test_printer.py0100644000175200017500000002413307367624277016613 0ustar faasseninfrae############################################################################## # # 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. # ############################################################################## import unittest import ZODB # for Persistent import string # FIXME: could test with Core DOM instead, do we want to? from Products.ParsedXML import ParsedXML, Printer from Products.ParsedXML.StrIO import StringIO def printElement(element, encoding = None, html = 0, contentType = None): output = StringIO() Printer.PrintVisitor(element, output, encoding, html, contentType)() return output.getvalue() def checkOutput(wanted, got, message="Bad output"): assert wanted == got, \ ("%s. Wanted:\n%s[[EOF]]\nGot:\n%s[[EOF]]\n" % (message, wanted, got)) class PrintTestBase(unittest.TestCase): implementation = ParsedXML.theDOMImplementation def parse(self, xml): return ParsedXML.ParsedXML('foo', xml) class PrintTestCase(PrintTestBase): def checkAttrOrder(self): inStr = '\n\n' doc = self.parse(inStr) output = printElement(doc) checkOutput(inStr, output, "attribute order not preserved") def checkDefaultAttrSkipped(self): inStr = '' \ ']>' outStr = '\n\n' doc = self.parse(inStr) output = printElement(doc) checkOutput(outStr, output, "default attribute printed") def checkAttrEntRefExpansion(self): "entity references must be expanded in attributes" doc = self.implementation.createDocument(None, 'root', None) attr = doc.createAttribute("attrName") # this is a text string; &test; is not an entity reference, # so its & should be converted to the proper ref on printing, # as should the & and < and >. attr.value = "&test; &<>" # this reference should be expanded to the empty string attr.appendChild(doc.createEntityReference('foo')) doc.documentElement.setAttributeNode(attr) outStr = '' output = printElement(doc.documentElement) checkOutput(outStr, output, "improper attr entity expansion") def checkTextEntRefExpansion(self): "only some entity references should be expanded in text" doc = self.implementation.createDocument(None, 'root', None) # &< must be converted to the proper reference; > should not. text = doc.createTextNode("&<>]]>") outStr = '&<>]]>' output = printElement(text) checkOutput(outStr, output, "improper text entity expansion") #TODO: check for expansion of entity refs in other contexts; #currently we're expanding aggressively, but it's not a priority #because the parser gets to play around with refs too class HTMLPrintTestCase(PrintTestBase): def checkMinimize(self): inStr = ('



' + '

') outStr = ('



' + '

\n') doc = self.parse(inStr) output = printElement(doc, encoding = None, html = 1) checkOutput(outStr, output, "improper HTML minimization") def checkCapitalize(self): inStr = ('
\n') doc = self.parse(inStr) output = printElement(doc, encoding = None, html = 1, contentType = 'html') checkOutput(string.upper(inStr), output, "improper HTML contenttype HTML capitalization") output = printElement(doc, encoding = None, html = 1, contentType = 'xml') checkOutput(string.lower(inStr), output, "improper XML contenttype HTML capitalization") class Lvl2PrintTestCase(PrintTestBase): def checkNamespacePrint(self): outStr = '\n' \ '\n' \ '\n' doc = self.parse(outStr) output = printElement(doc) checkOutput(outStr, output) def checkNamespaceAttrOrder(self): inStr = ('\n' '' ' ' '\n') doc = self.parse(inStr) output = printElement(doc) checkOutput(inStr, output, "attribute order not preserved") def checkHierarchicalElementNamespacePrint(self): # print new ns, don't print ns printed by ancestor outStr = ('\n' '' ' ' ' ' ' ' ' ' ' ' '\n') doc = self.parse(outStr) output = printElement(doc) checkOutput(outStr, output) def checkDefaultNamespacePrint(self): outStr = ('\n' '' '\n') doc = self.parse(outStr) output = printElement(doc) checkOutput(outStr, output) def checkDefaultAndPrefixNamespacePrint(self): # try and tickle a namespace printing bug outStr = ('\n' '' ' ' ' ' ' ' ' ' ' ' ' ' '\n') doc = self.parse(outStr) output = printElement(doc) checkOutput(outStr, output) def test_suite(): """Return a test suite for the Zope testing framework.""" suite = unittest.TestSuite() suite.addTest(unittest.makeSuite(PrintTestCase, 'check')) suite.addTest(unittest.makeSuite(HTMLPrintTestCase, 'check')) suite.addTest(unittest.makeSuite(Lvl2PrintTestCase, 'check')) return suite def main(): unittest.TextTestRunner().run(test_suite()) if __name__ == '__main__': main() ParsedXML/tests/test_pyxmldom.py0100644000175200017500000001030407367624277016774 0ustar faasseninfrae############################################################################## # # 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. # ############################################################################## import unittest from domapi import DOMImplementationTestSuite from xml.dom import ext, implementation from xml.dom.ext.reader import PyExpat def DOMParseString(self, xml): reader = PyExpat.Reader() return reader.fromString(xml) def test_suite(): """Return a test suite for the Zope testing framework.""" return DOMImplementationTestSuite(implementation, DOMParseString) def main(): unittest.TextTestRunner().run(test_suite()) if __name__ == "__main__": main() ParsedXML/tests/test_truthable.py0100644000175200017500000001254607367624277017127 0ustar faasseninfrae############################################################################## # # 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. # ############################################################################## "tests to make sure that DOM objects support truth testing" import unittest import ZODB # for Persistent from Products.ParsedXML import ParsedXML, DOM from operator import truth class WrappedTruthableTestCaseBase(unittest.TestCase): def setUp(self): self.document = doc = ParsedXML.ParsedXML('foo') self.floating_element = doc.createElement("per") self.attached_element = doc.documentElement class DOMTruthableTestCaseBase(unittest.TestCase): def setUp(self): self.document = doc = DOM.theDOMImplementation.createDocument( None, 'root', None) self.floating_element = doc.createElement("per") self.attached_element = doc.documentElement class TruthableTestCaseTests: def checkFloatingTruthable(self): assert truth(self.floating_element) == 1 def checkDOMTruthable(self): assert truth(self.document) == 1 assert truth(self.document.documentElement.parentNode) == 1 def checkAttachedTruthable(self): assert truth(self.attached_element) == 1 class DOMTruthableTestCase(DOMTruthableTestCaseBase, TruthableTestCaseTests): pass class WrappedTruthableTestCase(WrappedTruthableTestCaseBase, TruthableTestCaseTests): pass def test_suite(): """Return a test suite for the Zope testing framework.""" suite = unittest.TestSuite() suite.addTest(unittest.makeSuite(DOMTruthableTestCase, 'check')) suite.addTest(unittest.makeSuite(WrappedTruthableTestCase, 'check')) return suite def main(): unittest.TextTestRunner().run(test_suite()) if __name__ == "__main__": main() ParsedXML/tests/test_wrappeddom.py0100644000175200017500000001031207367624277017264 0ustar faasseninfrae############################################################################## # # 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. # ############################################################################## import unittest import ZODB # for Persistent from Products.ParsedXML import ParsedXML from domapi import DOMImplementationTestSuite def ParsedXMLParseString(self, xml): return ParsedXML.ParsedXML('foo', xml) def test_suite(): """Return a test suite for the Zope testing framework.""" return DOMImplementationTestSuite(ParsedXML.theDOMImplementation, ParsedXMLParseString) def main(): unittest.TextTestRunner().run(test_suite()) if __name__ == '__main__': main() ParsedXML/tests/test_zopeinterface.py0100644000175200017500000001427507367624277017774 0ustar faasseninfrae############################################################################## # # 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. # ############################################################################## """Test that some Zope interfaces are supported properly.""" import unittest import ZODB # for Persistent from Products.ParsedXML import ParsedXML from Products.ParsedXML.StrIO import StringIO def assertSize(doc): "assert that the document size what's reported by len" gs = doc.get_size() l = len(str(doc)) assert gs == l, "get_size reports %d while len reports %d" % (gs, l) class GetSizeTestCase(unittest.TestCase): "test that get_size works. We only test on the persistent Document." def setUp(self): self.document = ParsedXML.ParsedXML('foo') def checkGetSize(self): "assert that get_size works" assertSize(self.document) def checkGetSizeParse(self): "assert that get_size works after a parse" inStr = 'text' self.document.parseXML(StringIO(inStr)) assertSize(self.document) self.document.documentElement.parseXML(StringIO(inStr)) assertSize(self.document) def checkGetSizeDOMMethods(self): "assert that get_size works after some DOM method manipulations" self.document.documentElement.appendChild( self.document.createElement('spam')) assertSize(self.document) self.document.documentElement.appendChild( self.document.createTextNode('spam')) assertSize(self.document) self.document.documentElement.appendChild( self.document.createTextNode('spam')) assertSize(self.document) self.document.normalize() assertSize(self.document) self.document.documentElement.setAttribute('eggs', 'ham') assertSize(self.document) def checkgetSizeDOMAttributess(self): "assert that get_size works after some DOM attribute manipulations" self.document.documentElement.appendChild( self.document.createTextNode('spam')) self.document.documentElement.firstChild.data = "spamspamspam" assertSize(self.document) self.document.documentElement.setAttribute('eggs', 'ham') self.document.documentElement.attributes.item(0).value = 'spam' assertSize(self.document) def test_suite(): """Return a test suite for the Zope testing framework.""" suite = unittest.TestSuite() suite.addTest(unittest.makeSuite(GetSizeTestCase, 'check')) return suite def main(): unittest.TextTestRunner().run(test_suite()) if __name__ == "__main__": main() ParsedXML/tests/xml/0040755000175200017500000000000007600634640014300 5ustar faasseninfraeParsedXML/tests/xml/conf/0040755000175200017500000000000007600634640015225 5ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/0040755000175200017500000000000007600634640016725 5ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/0040755000175200017500000000000007600634640017330 5ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/0040755000175200017500000000000007600634640020137 5ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/001.xml0100644000175200017500000000001307274131376021155 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/002.xml0100644000175200017500000000001307274131376021156 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/003.xml0100644000175200017500000000001307274131376021157 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/004.xml0100644000175200017500000000002307274131376021161 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/005.xml0100644000175200017500000000002307274131376021162 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/006.xml0100644000175200017500000000002307274131376021163 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/007.xml0100644000175200017500000000001407274131376021164 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/out/008.xml0100644000175200017500000000003707274131376021172 0ustar faasseninfrae&<>"'ParsedXML/tests/xml/conf/xmltest/sa/out/009.xml0100644000175200017500000000001407274131376021166 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/out/010.xml0100644000175200017500000000002307274131376021156 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/011.xml0100644000175200017500000000003307274131376021160 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/012.xml0100644000175200017500000000002207274131376021157 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/013.xml0100644000175200017500000000003607274131376021165 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/014.xml0100644000175200017500000000005307274131376021165 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/015.xml0100644000175200017500000000005307274131376021166 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/016.xml0100644000175200017500000000002207274131376021163 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/017.xml0100644000175200017500000000004207274131376021166 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/out/018.xml0100644000175200017500000000002607274131376021171 0ustar faasseninfrae<foo>ParsedXML/tests/xml/conf/xmltest/sa/out/019.xml0100644000175200017500000000002407274131376021170 0ustar faasseninfrae<&ParsedXML/tests/xml/conf/xmltest/sa/out/020.xml0100644000175200017500000000003207274131376021157 0ustar faasseninfrae<&]>]ParsedXML/tests/xml/conf/xmltest/sa/out/021.xml0100644000175200017500000000001307274131376021157 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/022.xml0100644000175200017500000000001307274131376021160 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/023.xml0100644000175200017500000000001307274131376021161 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/024.xml0100644000175200017500000000002607274131376021166 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/025.xml0100644000175200017500000000004107274131376021164 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/026.xml0100644000175200017500000000004107274131376021165 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/027.xml0100644000175200017500000000004107274131376021166 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/028.xml0100644000175200017500000000001307274131376021166 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/029.xml0100644000175200017500000000001307274131376021167 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/030.xml0100644000175200017500000000001307274131376021157 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/031.xml0100644000175200017500000000001307274131376021160 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/032.xml0100644000175200017500000000001307274131376021161 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/033.xml0100644000175200017500000000001307274131376021162 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/034.xml0100644000175200017500000000001307274131376021163 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/035.xml0100644000175200017500000000001307274131376021164 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/036.xml0100644000175200017500000000002607274131376021171 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/037.xml0100644000175200017500000000001307274131376021166 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/038.xml0100644000175200017500000000001307274131376021167 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/039.xml0100644000175200017500000000002607274131376021174 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/040.xml0100644000175200017500000000004507274131376021165 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/041.xml0100644000175200017500000000002207274131376021161 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/042.xml0100644000175200017500000000001407274131376021163 0ustar faasseninfraeAParsedXML/tests/xml/conf/xmltest/sa/out/043.xml0100644000175200017500000000003007274131376021162 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/044.xml0100644000175200017500000000016407274131376021173 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/out/045.xml0100644000175200017500000000002307274131376021166 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/046.xml0100644000175200017500000000003307274131376021170 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/047.xml0100644000175200017500000000002207274131376021167 0ustar faasseninfraeX YParsedXML/tests/xml/conf/xmltest/sa/out/048.xml0100644000175200017500000000001407274131376021171 0ustar faasseninfrae]ParsedXML/tests/xml/conf/xmltest/sa/out/049.xml0100644000175200017500000000001507274131376021173 0ustar faasseninfrae£ParsedXML/tests/xml/conf/xmltest/sa/out/050.xml0100644000175200017500000000003207274131376021162 0ustar faasseninfraeเจมส์ParsedXML/tests/xml/conf/xmltest/sa/out/051.xml0100644000175200017500000000004307274131376021165 0ustar faasseninfrae<เจมส์>ParsedXML/tests/xml/conf/xmltest/sa/out/052.xml0100644000175200017500000000002307274131376021164 0ustar faasseninfrae𐀀􏿽ParsedXML/tests/xml/conf/xmltest/sa/out/053.xml0100644000175200017500000000002207274131376021164 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/054.xml0100644000175200017500000000001307274131376021165 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/055.xml0100644000175200017500000000002607274131376021172 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/056.xml0100644000175200017500000000001407274131376021170 0ustar faasseninfraeAParsedXML/tests/xml/conf/xmltest/sa/out/057.xml0100644000175200017500000000001307274131376021170 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/058.xml0100644000175200017500000000002407274131376021173 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/059.xml0100644000175200017500000000016407274131376021201 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/out/060.xml0100644000175200017500000000002207274131376021162 0ustar faasseninfraeX YParsedXML/tests/xml/conf/xmltest/sa/out/061.xml0100644000175200017500000000001507274131376021165 0ustar faasseninfrae£ParsedXML/tests/xml/conf/xmltest/sa/out/062.xml0100644000175200017500000000003207274131376021165 0ustar faasseninfraeเจมส์ParsedXML/tests/xml/conf/xmltest/sa/out/063.xml0100644000175200017500000000004307274131376021170 0ustar faasseninfrae<เจมส์>ParsedXML/tests/xml/conf/xmltest/sa/out/064.xml0100644000175200017500000000002307274131376021167 0ustar faasseninfrae𐀀􏿽ParsedXML/tests/xml/conf/xmltest/sa/out/065.xml0100644000175200017500000000001307274131376021167 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/066.xml0100644000175200017500000000002707274131376021175 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/067.xml0100644000175200017500000000002007274131376021167 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/out/068.xml0100644000175200017500000000002007274131376021170 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/out/069.xml0100644000175200017500000000001307274131376021173 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/070.xml0100644000175200017500000000001307274131376021163 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/071.xml0100644000175200017500000000001307274131376021164 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/072.xml0100644000175200017500000000001307274131376021165 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/073.xml0100644000175200017500000000001307274131376021166 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/074.xml0100644000175200017500000000001307274131376021167 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/075.xml0100644000175200017500000000001307274131377021171 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/076.xml0100644000175200017500000000001307274131377021172 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/077.xml0100644000175200017500000000001307274131377021173 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/078.xml0100644000175200017500000000002107274131377021173 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/079.xml0100644000175200017500000000002107274131377021174 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/080.xml0100644000175200017500000000002107274131377021164 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/081.xml0100644000175200017500000000004707274131377021175 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/082.xml0100644000175200017500000000001307274131377021167 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/083.xml0100644000175200017500000000001307274131377021170 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/084.xml0100644000175200017500000000001307274131377021171 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/085.xml0100644000175200017500000000001307274131377021172 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/086.xml0100644000175200017500000000001307274131377021173 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/087.xml0100644000175200017500000000002607274131377021200 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/088.xml0100644000175200017500000000002607274131377021201 0ustar faasseninfrae<foo>ParsedXML/tests/xml/conf/xmltest/sa/out/089.xml0100644000175200017500000000002707274131377021203 0ustar faasseninfrae𐀀􏿽􏿿ParsedXML/tests/xml/conf/xmltest/sa/out/090.xml0100644000175200017500000000001307274131377021166 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/091.xml0100644000175200017500000000002107274131377021166 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/092.xml0100644000175200017500000000010107274131377021166 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/out/093.xml0100644000175200017500000000003207274131377021172 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/out/094.xml0100644000175200017500000000002407274131377021174 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/095.xml0100644000175200017500000000002507274131377021176 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/096.xml0100644000175200017500000000002407274131377021176 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/097.xml0100644000175200017500000000002307274131377021176 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/098.xml0100644000175200017500000000002507274131377021201 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/099.xml0100644000175200017500000000001307274131377021177 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/100.xml0100644000175200017500000000001307274131377021156 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/101.xml0100644000175200017500000000001307274131377021157 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/102.xml0100644000175200017500000000002607274131377021164 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/103.xml0100644000175200017500000000002607274131377021165 0ustar faasseninfrae<doc>ParsedXML/tests/xml/conf/xmltest/sa/out/104.xml0100644000175200017500000000002307274131377021163 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/105.xml0100644000175200017500000000002607274131377021167 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/106.xml0100644000175200017500000000002707274131377021171 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/107.xml0100644000175200017500000000002707274131377021172 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/108.xml0100644000175200017500000000002307274131377021167 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/109.xml0100644000175200017500000000002007274131377021165 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/110.xml0100644000175200017500000000002407274131377021161 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/111.xml0100644000175200017500000000002307274131377021161 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/112.xml0100644000175200017500000000002207274131377021161 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/113.xml0100644000175200017500000000001307274131377021162 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/out/114.xml0100644000175200017500000000002407274131377021165 0ustar faasseninfrae&foo;ParsedXML/tests/xml/conf/xmltest/sa/out/115.xml0100644000175200017500000000001407274131377021165 0ustar faasseninfraevParsedXML/tests/xml/conf/xmltest/sa/out/116.xml0100644000175200017500000000002007274131377021163 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/out/117.xml0100644000175200017500000000001407274131377021167 0ustar faasseninfrae]ParsedXML/tests/xml/conf/xmltest/sa/out/118.xml0100644000175200017500000000001507274131377021171 0ustar faasseninfrae]]ParsedXML/tests/xml/conf/xmltest/sa/out/119.xml0100644000175200017500000000001307274131377021170 0ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/001.xml0100644000175200017500000000007407274131371020350 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/002.xml0100644000175200017500000000007507274131371020352 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/003.xml0100644000175200017500000000007507274131371020353 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/004.xml0100644000175200017500000000014607274131371020353 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/005.xml0100644000175200017500000000015007274131371020347 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/006.xml0100644000175200017500000000014607274131371020355 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/007.xml0100644000175200017500000000010107274131371020345 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/008.xml0100644000175200017500000000012507274131371020354 0ustar faasseninfrae ]> &<>"' ParsedXML/tests/xml/conf/xmltest/sa/009.xml0100644000175200017500000000010207274131371020350 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/010.xml0100644000175200017500000000014707274131371020351 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/011.xml0100644000175200017500000000020007274131371020340 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/012.xml0100644000175200017500000000014407274131371020350 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/013.xml0100644000175200017500000000017407274131371020354 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/014.xml0100644000175200017500000000022607274131371020353 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/015.xml0100644000175200017500000000022607274131371020354 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/016.xml0100644000175200017500000000010207274131371020346 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/017.xml0100644000175200017500000000012307274131371020352 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/018.xml0100644000175200017500000000011507274131371020354 0ustar faasseninfrae ]> ]]> ParsedXML/tests/xml/conf/xmltest/sa/019.xml0100644000175200017500000000011207274131371020352 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/020.xml0100644000175200017500000000011507274131371020345 0ustar faasseninfrae ]> ]]]> ParsedXML/tests/xml/conf/xmltest/sa/021.xml0100644000175200017500000000011607274131371020347 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/022.xml0100644000175200017500000000012007274131371020343 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/023.xml0100644000175200017500000000011707274131371020352 0ustar faasseninfrae ]> &e; ParsedXML/tests/xml/conf/xmltest/sa/024.xml0100644000175200017500000000016407274131371020355 0ustar faasseninfrae "> ]> &e; ParsedXML/tests/xml/conf/xmltest/sa/025.xml0100644000175200017500000000014407274131371020354 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/026.xml0100644000175200017500000000014007274131371020351 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/027.xml0100644000175200017500000000013607274131371020357 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/028.xml0100644000175200017500000000012307274131371020354 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/029.xml0100644000175200017500000000012307274131371020355 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/030.xml0100644000175200017500000000012507274131371020347 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/031.xml0100644000175200017500000000014407274131371020351 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/032.xml0100644000175200017500000000014407274131371020352 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/033.xml0100644000175200017500000000016507274131371020356 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/034.xml0100644000175200017500000000006707274131371020360 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/035.xml0100644000175200017500000000007007274131371020353 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/036.xml0100644000175200017500000000011107274131371020350 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/037.xml0100644000175200017500000000012007274131371020351 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/038.xml0100644000175200017500000000012007274131371020352 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/039.xml0100644000175200017500000000011107274131371020353 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/040.xml0100644000175200017500000000017507274131371020355 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/041.xml0100644000175200017500000000015107274131371020350 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/042.xml0100644000175200017500000000014207274131371020351 0ustar faasseninfrae ]> A ParsedXML/tests/xml/conf/xmltest/sa/043.xml0100644000175200017500000000015407274131371020355 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/044.xml0100644000175200017500000000027307274131371020360 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/045.xml0100644000175200017500000000017007274131371020355 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/046.xml0100644000175200017500000000017007274131371020356 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/047.xml0100644000175200017500000000010007274131371020350 0ustar faasseninfrae ]> X Y ParsedXML/tests/xml/conf/xmltest/sa/048.xml0100644000175200017500000000007507274131372020365 0ustar faasseninfrae ]> ] ParsedXML/tests/xml/conf/xmltest/sa/049.xml0100644000175200017500000000017407274131372020366 0ustar faasseninfrae<!DOCTYPE doc [ <!ELEMENT doc (#PCDATA)> ]> <doc></doc> ParsedXML/tests/xml/conf/xmltest/sa/050.xml0100644000175200017500000000020407274131372020350 0ustar faasseninfrae<!DOCTYPE doc [ <!ELEMENT doc (#PCDATA)> ]> <doc>@!*L</doc> ParsedXML/tests/xml/conf/xmltest/sa/051.xml0100644000175200017500000000021407274131372020352 0ustar faasseninfrae<!DOCTYPE @!*L [ <!ELEMENT @!*L (#PCDATA)> ]> <@!*L></@!*L> ParsedXML/tests/xml/conf/xmltest/sa/052.xml0100644000175200017500000000010407274131372020351 0ustar faasseninfrae ]> 𐀀􏿽 ParsedXML/tests/xml/conf/xmltest/sa/053.xml0100644000175200017500000000014107274131372020353 0ustar faasseninfrae"> ]> &e; ParsedXML/tests/xml/conf/xmltest/sa/054.xml0100644000175200017500000000011007274131372020350 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/055.xml0100644000175200017500000000011207274131372020353 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/056.xml0100644000175200017500000000015007274131372020356 0ustar faasseninfrae ]> A ParsedXML/tests/xml/conf/xmltest/sa/057.xml0100644000175200017500000000006707274131372020366 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/058.xml0100644000175200017500000000015707274131372020367 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/059.xml0100644000175200017500000000034307274131372020365 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/060.xml0100644000175200017500000000010307274131372020347 0ustar faasseninfrae ]> X Y ParsedXML/tests/xml/conf/xmltest/sa/061.xml0100644000175200017500000000010207274131372020347 0ustar faasseninfrae ]> £ ParsedXML/tests/xml/conf/xmltest/sa/062.xml0100644000175200017500000000012707274131372020357 0ustar faasseninfrae ]> เจมส์ ParsedXML/tests/xml/conf/xmltest/sa/063.xml0100644000175200017500000000015407274131372020360 0ustar faasseninfrae ]> <เจมส์> ParsedXML/tests/xml/conf/xmltest/sa/064.xml0100644000175200017500000000011707274131372020360 0ustar faasseninfrae ]> 𐀀􏿽 ParsedXML/tests/xml/conf/xmltest/sa/065.xml0100644000175200017500000000012107274131372020354 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/066.xml0100644000175200017500000000023307274131372020361 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/067.xml0100644000175200017500000000010107274131372020354 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/068.xml0100644000175200017500000000012407274131372020362 0ustar faasseninfrae ]> &e; ParsedXML/tests/xml/conf/xmltest/sa/069.xml0100644000175200017500000000013507274131372020365 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/070.xml0100644000175200017500000000012107274131372020350 0ustar faasseninfrae"> %e; ]> ParsedXML/tests/xml/conf/xmltest/sa/071.xml0100644000175200017500000000013207274131372020353 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/072.xml0100644000175200017500000000013507274131372020357 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/073.xml0100644000175200017500000000013607274131372020361 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/074.xml0100644000175200017500000000013607274131372020362 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/075.xml0100644000175200017500000000014007274131372020356 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/076.xml0100644000175200017500000000030007274131372020355 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/077.xml0100644000175200017500000000013507274131372020364 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/078.xml0100644000175200017500000000014407274131372020365 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/079.xml0100644000175200017500000000014507274131372020367 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/080.xml0100644000175200017500000000013707274131372020360 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/081.xml0100644000175200017500000000021407274131372020355 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/082.xml0100644000175200017500000000013207274131372020355 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/083.xml0100644000175200017500000000014507274131372020362 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/084.xml0100644000175200017500000000006607274131372020365 0ustar faasseninfrae]> ParsedXML/tests/xml/conf/xmltest/sa/085.xml0100644000175200017500000000014607274131372020365 0ustar faasseninfrae "> ]> &e; ParsedXML/tests/xml/conf/xmltest/sa/086.xml0100644000175200017500000000014407274131372020364 0ustar faasseninfrae "> ]> &e; ParsedXML/tests/xml/conf/xmltest/sa/087.xml0100644000175200017500000000015307274131372020365 0ustar faasseninfrae ]> &e; ParsedXML/tests/xml/conf/xmltest/sa/088.xml0100644000175200017500000000012707274131372020367 0ustar faasseninfrae "> ]> &e; ParsedXML/tests/xml/conf/xmltest/sa/089.xml0100644000175200017500000000015407274131372020370 0ustar faasseninfrae ]> &e; ParsedXML/tests/xml/conf/xmltest/sa/090.xml0100644000175200017500000000022607274131372020360 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/091.xml0100644000175200017500000000026507274131372020364 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/092.xml0100644000175200017500000000014607274131372020363 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/093.xml0100644000175200017500000000007407274131373020365 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/094.xml0100644000175200017500000000016007274131373020362 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/095.xml0100644000175200017500000000021507274131373020364 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/096.xml0100644000175200017500000000014307274131373020365 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/097.xml0100644000175200017500000000023507274131373020370 0ustar faasseninfrae %e; ]> ParsedXML/tests/xml/conf/xmltest/sa/098.xml0100644000175200017500000000010707274131373020367 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/099.xml0100644000175200017500000000014407274131373020371 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/100.xml0100644000175200017500000000014507274131373020351 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/101.xml0100644000175200017500000000012107274131373020344 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/102.xml0100644000175200017500000000014707274131373020355 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/103.xml0100644000175200017500000000010507274131373020350 0ustar faasseninfrae ]> <doc> ParsedXML/tests/xml/conf/xmltest/sa/104.xml0100644000175200017500000000014507274131373020355 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/105.xml0100644000175200017500000000015007274131373020352 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/106.xml0100644000175200017500000000015107274131373020354 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/107.xml0100644000175200017500000000015107274131374020356 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/108.xml0100644000175200017500000000017107274131374020361 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/109.xml0100644000175200017500000000014207274131374020360 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/110.xml0100644000175200017500000000020107274131374020344 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/111.xml0100644000175200017500000000017307274131374020355 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/112.xml0100644000175200017500000000013107274131374020350 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/113.xml0100644000175200017500000000013307274131374020353 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/114.xml0100644000175200017500000000014007274131374020352 0ustar faasseninfrae "> ]> &e; ParsedXML/tests/xml/conf/xmltest/sa/115.xml0100644000175200017500000000014707274131374020362 0ustar faasseninfrae ]> &e1; ParsedXML/tests/xml/conf/xmltest/sa/116.xml0100644000175200017500000000011207274131374020353 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/117.xml0100644000175200017500000000012607274131374020361 0ustar faasseninfrae ]> ] ParsedXML/tests/xml/conf/xmltest/sa/118.xml0100644000175200017500000000012707274131374020363 0ustar faasseninfrae ]> ] ParsedXML/tests/xml/conf/xmltest/sa/119.xml0100644000175200017500000000010207274131374020355 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/0040755000175200017500000000000007600634640022457 5ustar faasseninfraeParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/001.xml0100644000175200017500000000003607274131375023501 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/002.xml0100644000175200017500000000003607274131375023502 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/003.xml0100644000175200017500000000003607274131375023503 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/004.xml0100644000175200017500000000004607274131375023505 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/005.xml0100644000175200017500000000004607274131375023506 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/006.xml0100644000175200017500000000004607274131375023507 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/007.xml0100644000175200017500000000004407274131375023506 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/008.xml0100644000175200017500000000005707274131375023513 0ustar faasseninfrae &<>"' ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/009.xml0100644000175200017500000000004407274131375023510 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/010.xml0100644000175200017500000000004607274131375023502 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/011.xml0100644000175200017500000000005607274131375023504 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/012.xml0100644000175200017500000000004507274131375023503 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/013.xml0100644000175200017500000000006107274131375023502 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/014.xml0100644000175200017500000000007607274131375023511 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/015.xml0100644000175200017500000000007607274131375023512 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/016.xml0100644000175200017500000000005207274131375023505 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/017.xml0100644000175200017500000000007207274131375023510 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/018.xml0100644000175200017500000000006407274131375023512 0ustar faasseninfrae ]]> ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/019.xml0100644000175200017500000000006107274131375023510 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/020.xml0100644000175200017500000000006407274131375023503 0ustar faasseninfrae ]]]> ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/021.xml0100644000175200017500000000006507274131375023505 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/022.xml0100644000175200017500000000006707274131375023510 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/023.xml0100644000175200017500000000013107274131375023501 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/024.xml0100644000175200017500000000021007274131375023500 0ustar faasseninfrae "> ]> ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/025.xml0100644000175200017500000000005707274131375023512 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/026.xml0100644000175200017500000000005707274131375023513 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/027.xml0100644000175200017500000000005707274131375023514 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/028.xml0100644000175200017500000000003607274131375023512 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/029.xml0100644000175200017500000000003607274131375023513 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/030.xml0100644000175200017500000000003607274131375023503 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/031.xml0100644000175200017500000000003607274131375023504 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/032.xml0100644000175200017500000000003607274131375023505 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/033.xml0100644000175200017500000000003607274131375023506 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/034.xml0100644000175200017500000000003607274131375023507 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/035.xml0100644000175200017500000000003607274131375023510 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/036.xml0100644000175200017500000000005107274131375023506 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/037.xml0100644000175200017500000000005607274131375023514 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/038.xml0100644000175200017500000000005607274131375023515 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/039.xml0100644000175200017500000000005107274131375023511 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/040.xml0100644000175200017500000000007007274131375023502 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/041.xml0100644000175200017500000000004507274131375023505 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/042.xml0100644000175200017500000000004407274131375023505 0ustar faasseninfrae A ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/043.xml0100644000175200017500000000005307274131375023506 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/044.xml0100644000175200017500000000012307274131375023505 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/045.xml0100644000175200017500000000003607274131375023511 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/046.xml0100644000175200017500000000003607274131375023512 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/047.xml0100644000175200017500000000004607274131375023514 0ustar faasseninfrae X Y ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/048.xml0100644000175200017500000000004407274131375023513 0ustar faasseninfrae ] ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/049.xml0100644000175200017500000000004507274131375023515 0ustar faasseninfrae £ ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/050.xml0100644000175200017500000000006207274131375023504 0ustar faasseninfrae เจมส์ ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/051.xml0100644000175200017500000000005207274131375023504 0ustar faasseninfrae <เจมส์/> ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/052.xml0100644000175200017500000000005307274131375023506 0ustar faasseninfrae 𐀀􏿽 ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/053.xml0100644000175200017500000000016307274131375023511 0ustar faasseninfrae "> ]> ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/054.xml0100644000175200017500000000003607274131375023511 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/055.xml0100644000175200017500000000005107274131375023507 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/056.xml0100644000175200017500000000004407274131375023512 0ustar faasseninfrae A ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/057.xml0100644000175200017500000000003607274131375023514 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/058.xml0100644000175200017500000000004707274131375023517 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/059.xml0100644000175200017500000000016307274131375023517 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/060.xml0100644000175200017500000000004607274131375023507 0ustar faasseninfrae X Y ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/061.xml0100644000175200017500000000004507274131375023507 0ustar faasseninfrae £ ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/062.xml0100644000175200017500000000006207274131375023507 0ustar faasseninfrae เจมส์ ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/063.xml0100644000175200017500000000005207274131375023507 0ustar faasseninfrae <เจมส์/> ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/064.xml0100644000175200017500000000005307274131375023511 0ustar faasseninfrae 𐀀􏿽 ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/065.xml0100644000175200017500000000013607274131375023514 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/066.xml0100644000175200017500000000027607274131375023522 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/067.xml0100644000175200017500000000004407274131375023514 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/068.xml0100644000175200017500000000014407274131375023516 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/069.xml0100644000175200017500000000015207274131375023516 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/070.xml0100644000175200017500000000003607274131375023507 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/071.xml0100644000175200017500000000003607274131375023510 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/072.xml0100644000175200017500000000003607274131375023511 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/073.xml0100644000175200017500000000003607274131375023512 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/074.xml0100644000175200017500000000003607274131375023513 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/075.xml0100644000175200017500000000003607274131375023514 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/076.xml0100644000175200017500000000031307274131375023513 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/077.xml0100644000175200017500000000003607274131375023516 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/078.xml0100644000175200017500000000004407274131375023516 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/079.xml0100644000175200017500000000004407274131375023517 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/080.xml0100644000175200017500000000003607274131375023510 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/081.xml0100644000175200017500000000006607274131375023514 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/082.xml0100644000175200017500000000003607274131375023512 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/083.xml0100644000175200017500000000003607274131375023513 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/084.xml0100644000175200017500000000003607274131375023514 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/085.xml0100644000175200017500000000015707274131375023521 0ustar faasseninfrae "> ]> ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/086.xml0100644000175200017500000000015507274131375023520 0ustar faasseninfrae "> ]> ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/087.xml0100644000175200017500000000017707274131375023525 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/088.xml0100644000175200017500000000015607274131375023523 0ustar faasseninfrae "> ]> <foo> ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/089.xml0100644000175200017500000000020707274131375023521 0ustar faasseninfrae ]> 𐀀􏿽􏿿 ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/090.xml0100644000175200017500000000024107274131375023507 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/091.xml0100644000175200017500000000030007274131375023504 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/092.xml0100644000175200017500000000007107274131375023512 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/093.xml0100644000175200017500000000004607274131375023515 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/094.xml0100644000175200017500000000003607274131375023515 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/095.xml0100644000175200017500000000005007274131375023512 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/096.xml0100644000175200017500000000003607274131375023517 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/097.xml0100644000175200017500000000003607274131375023520 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/098.xml0100644000175200017500000000005507274131375023522 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/099.xml0100644000175200017500000000003607274131375023522 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/100.xml0100644000175200017500000000016207274131375023501 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/101.xml0100644000175200017500000000013607274131375023503 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/102.xml0100644000175200017500000000004407274131375023502 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/103.xml0100644000175200017500000000005307274131375023503 0ustar faasseninfrae <doc> ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/104.xml0100644000175200017500000000004607274131375023506 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/105.xml0100644000175200017500000000004607274131375023507 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/106.xml0100644000175200017500000000004607274131375023510 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/107.xml0100644000175200017500000000004607274131375023511 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/108.xml0100644000175200017500000000020207274131375023504 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/109.xml0100644000175200017500000000004307274131375023510 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/110.xml0100644000175200017500000000021407274131375023500 0ustar faasseninfrae ]> ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/111.xml0100644000175200017500000000004607274131375023504 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/112.xml0100644000175200017500000000004707274131375023506 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/113.xml0100644000175200017500000000003607274131375023505 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/114.xml0100644000175200017500000000020007274131375023477 0ustar faasseninfrae "> ]> ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/115.xml0100644000175200017500000000016507274131375023512 0ustar faasseninfrae ]> v ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/116.xml0100644000175200017500000000006007274131375023505 0ustar faasseninfrae ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/117.xml0100644000175200017500000000014307274131375023510 0ustar faasseninfrae ]> ] ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/118.xml0100644000175200017500000000014507274131375023513 0ustar faasseninfrae ]> ]] ParsedXML/tests/xml/conf/xmltest/sa/ParsedXMLTestOut/119.xml0100644000175200017500000000005707274131375023516 0ustar faasseninfrae ParsedXML/tests/xml/conf/README.ParsedXML0100644000175200017500000000017507274131370017702 0ustar faasseninfraeThese tests are from the Oasis Open conformance suite, found at .ParsedXML/tests/xml/4ohn4ktj.xml0100644000175200017500000000722707274131367016501 0ustar faasseninfrae
sample1 a simple invoice
01786 2025-03-17 55377 2025-03-15 GJ03405 DAVE 1 2025-03-17 K5211(34) 23 23
SHIPWRIGHT RESTAURANTS LIMITED 125 NORTH SERVICE ROAD W WESTLAKE ACCESS NORTH BAY L8B1O5 ONTARIO CANADA ATTN: PAULINE DEGRASSI 1 CS DM 5309 #1013 12 OZ.MUNICH STEIN 37.72 37.72 6 DZ ON 6420 PROVINCIAL DINNER FORK 17.98 107.88 72 EA JR20643 PLASTIC HANDLED STEAK KNIFE .81 58.32 6 DZ ON 6410 PROVINCIAL TEASPOONS 12.16 72.96 0 DZ ON 6411 PROVINCIAL RD BOWL SPOON 6 17.98 0.00 1 EA DO 3218 34 OZ DUAL DIAL SCALE AM3218 70.00 5.0 66.50 1 CS DM 195 20 OZ.BEER PUB GLASS 55.90 55.90 399.28 3.50 23.75 29.61 33.84 33.84 486.48
ParsedXML/www/0040755000175200017500000000000007600634640013162 5ustar faasseninfraeParsedXML/www/pxml.gif0100644000175200017500000000022607235322216014623 0ustar faasseninfraeGIF87aC;0,K 2k^j]waen C}F\0sbJ`ɳ4K5k%REz;