def setAttributes(self, attrs=None): self.attrs = XAttributes(attrs)
class XElement: def __init__(self, name=None): self.children = [] self.setAttributes() self.text = "" self.setName(name) def clone(self, nodes_visited={}): if nodes_visited.has_key(self): raise "circular reference in XElement.clone()" nodes_visited[self] = None my_class = self.__class__ new_me = my_class() new_me.name = self.name new_me.text = self.text[:] new_me.attrs = XAttributes() for attr_name in self.attrs.keys(): for attr_value in self.attrs[attr_name]: new_me.attrs[attr_name] = attr_value for c in self.children: c_clone = c.clone(nodes_visited) new_me.linkTo(c_clone) return new_me def setName(self, name): self.name = name def setAttributes(self, attrs=None): self.attrs = XAttributes(attrs) def setChildren(self, children): self.children = [] for c in children: self.children.append(c) def hasAttributes(self, attr_list): return self.attrs.containsAttributes(attr_list) def getAttributes(self): return self.attrs def getAttribute(self, name, default_get=None): return self.attrs.getAttributeValue(name) def setText(self, text): self.text = text def initialize(self): pass def finalize(self, parent): pass def linkTo(self, element): if isinstance(element, XElement): self.children.append(element) else: raise "An XElement is required but %s was seen" % type(element) def cdata(self, text): self.text = self.text + text def printBFS(self, depth=0): print " " * depth, str(self) for node in self.children: node.printBFS(depth+1) def visit(self, depth): print " " * depth, str(self) def walkBFS(self, depth=0): self.doWalkBFS(depth) def doWalkBFS(self, depth=0): self.visit(depth) for node in self.children: node.doWalkBFS(depth+1) def getName(self): return self.name def getText(self): return self.text def getChildren(self, klass=None): if not klass: return self.children[:] children = [] if type(klass) == type(''): for node in self.children: if node.__class__.__name__ == klass: children.append(node) else: for node in self.children: if isinstance(node, klass): children.append(node) return children def getChildrenByName(self, name): return [x for x in self.children if x.getName() == name] def getChild(self, klass=None, pos=0): children = self.getChildren(klass) try: return children[pos] except: return None def __str__(self): return self.toXML(indent_text=" ") __repr__ = __str__ def toXML(self, **kw): """ Convert an XElement tree into XML. You may pass: indent - a starting indentation level (integer); defaults to 0. indent_text - text to use for each level of indentation (string); defaults to ' ' prologue - a list of strings to emit as the prologue; defaults to ['<?xml ...?>','<!-- XIR Tools; (c) 2001, George K. THiruvathukal -->'] This could be useful if you want to emit things like DTD and other stuff. """ indent = kw.get('indent', 0) indent_text = kw.get('indent_text', ' ') repr = '' # Emit the prologue if not indent: prologue = kw.get('prologue', XELEMENT_PROLOGUE) for text in prologue: repr = repr + text + '\n' # Output the element header (indented) repr = repr + indent_text * indent repr = repr + '<%s' % (self.name) # And its attributes on the same line. if self.attrs: attrs_keys = self.attrs.getAttributes().keys() attrs_keys.sort() for attr_name in attrs_keys: attr_value = self.attrs.getAttributeValue(attr_name) repr = repr + ' %s="%s"' % (attr_name, attr_value) repr = repr + '>\n' # Output #PCDATA. Observe that my approach does *not* preserve data # between nested elements. This could be considered a feature. # NB: self.text *needs* to be escapeed. Get from saxutils. t = self.text t.strip() if t: repr = repr + (indent_text * (indent + 1)) + t + '\n' for node in self.children: repr = repr + node.toXML(indent=indent+1, indent_text=indent_text) # Output the closing element; make sure the last thing written # emits a new line. repr = repr + indent_text * indent repr = repr + '</%s>' % (self.name) repr = repr + '\n' return repr