import gettext _ = gettext.gettext import _base class TreeWalker(_base.NonRecursiveTreeWalker): """Given that simpletree has no performant way of getting a node's next sibling, this implementation returns "nodes" as tuples with the following content: 1. The parent Node (Element, Document or DocumentFragment) 2. The child index of the current node in its parent's children list 3. A list used as a stack of all ancestors. It is a pair tuple whose first item is a parent Node and second item is a child index. """ def getNodeDetails(self, node): if isinstance(node, tuple): # It might be the root Node parent, idx, parents = node node = parent.childNodes[idx] # testing node.type allows us not to import treebuilders.simpletree if node.type in (1, 2): # Document or DocumentFragment return (_base.DOCUMENT,) elif node.type == 3: # DocumentType return _base.DOCTYPE, node.name, node.publicId, node.systemId elif node.type == 4: # TextNode return _base.TEXT, node.value elif node.type == 5: # Element attrs = {} for name, value in node.attributes.items(): if isinstance(name, tuple): attrs[(name[2],name[1])] = value else: attrs[(None,name)] = value return (_base.ELEMENT, node.namespace, node.name, attrs, node.hasContent()) elif node.type == 6: # CommentNode return _base.COMMENT, node.data else: return _node.UNKNOWN, node.type def getFirstChild(self, node): if isinstance(node, tuple): # It might be the root Node parent, idx, parents = node parents.append((parent, idx)) node = parent.childNodes[idx] else: parents = [] assert node.hasContent(), "Node has no children" return (node, 0, parents) def getNextSibling(self, node): assert isinstance(node, tuple), "Node is not a tuple: " + str(node) parent, idx, parents = node idx += 1 if len(parent.childNodes) > idx: return (parent, idx, parents) else: return None def getParentNode(self, node): assert isinstance(node, tuple) parent, idx, parents = node if parents: parent, idx = parents.pop() return parent, idx, parents else: # HACK: We could return ``parent`` but None will stop the algorithm the same way return None