"cunkel xml utils" minidom = __import__('xml.dom.minidom', {}, {}, ['getDOMImplementation']) getDOMImplementation = minidom.getDOMImplementation class Maker(object): """Callable object to create elements within an XML document. parent = Maker(document, 'parent'); child = Maker(document, 'child'); node = parent({'a' : 'b'}, [child(str(x)) for x in xrange(0,2)]) node.toprettyxml(' ') --> 0 1 """ def __init__(self, document, tag=None): """Maker(document, tag) --> callable object to make tag elements within the XML DOM Document object document. If tag is None, the resulting object object will create a document fragment instead of an element when called. """ self.__document=document self.__tag=tag def __getattr__(self, tag): # Don't make python reserved names this way. if tag.startswith("__") and tag.endswith("__"): raise AttributeError maker=Maker(self.__document, self.__tag + ":" + tag) self.__dict__[tag]=maker return maker def __call__(self, *children): if self.__tag is None: node=self.__document.createDocumentFragment() else: node=self.__document.createElement(self.__tag) self.__insertchildren(node, children) return node def __insertchildren(self, node, children): for child in children: if type(child) in (str,unicode): node.appendChild(self.__document.createTextNode(child)) elif type(child) is dict: setattrs(node, child) elif type(child) in (list,tuple): self.__insertchildren(node, child) elif child is not None: node.appendChild(child) class UniversalMaker(object): def __init__(self, document): self.__document=document self.__fragment=Maker(document) def __getattr__(self, tag): # Don't make python reserved names this way. if tag.startswith("__") and tag.endswith("__"): raise AttributeError maker=Maker(self.__document, tag) self.__dict__[tag]=maker return maker def __call__(self, *args): return self.__fragment(*args) class UninstantiatedElement(object): def __init__(self, tag, *contents): self.__tag=tag self.__contents=list(*contents) def asDocument(self, impl=None, ns=None, dt=None): if impl is None: impl=getDOMImplementation() document=impl.createDocument(ns, self.__tag, dt) node=document.documentElement self.__insertchildren(document, node, self.__contents) return document def append(self, contents): self.__contents.append(contents) def appendTo(self, node): node.appendChild(self.instantiate(node.ownerDocument)) def instantiate(self, document=None): if document is None: return self.asDocument() elif self.__tag is None: node=document.createDocumentFragment() else: node=document.createElement(self.__tag) self.__insertchildren(document, node, self.__contents) return node def __insertchildren(self, document, node, children): for child in children: if type(child) in (str,unicode): node.appendChild(document.createTextNode(child)) elif type(child) is dict: for attr in child: node.setAttribute(attr, child[attr]) elif type(child) in (list,tuple): self.__insertchildren(document, node, child) elif child is not None: if hasattr(child,"instantiate"): node.appendChild(child.instantiate(document)) else: node.appendChild(child) class DocumentTagMaker(object): def __init__(self, tag): self.__tag=tag def __getattr__(self, tag): # Don't make python reserved names this way. if tag.startswith("__") and tag.endswith("__"): raise AttributeError maker=DocumentTagMaker(self.__tag + ":" + tag) self.__dict__[tag]=maker return maker def __call__(self, *args): return UninstantiatedElement(self.__tag, args) class DocMaker(object): def __init__(self): self.__fragMaker=DocumentTagMaker(None) def __getattr__(self, tag): # Don't make python reserved names this way. if tag.startswith("__") and tag.endswith("__"): raise AttributeError maker=DocumentTagMaker(tag) self.__dict__[tag]=maker return maker def __call__(self, *args): return self.__fragMaker(*args) xhtmlUri = "http://www.w3.org/1999/xhtml" xhtmlStrict = getDOMImplementation().createDocumentType( "html", "-//W3C//DTD XHTML 1.0 Strict//EN", "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd") xhtmlTransitional = getDOMImplementation().createDocumentType( "html", "-//W3C//DTD XHTML 1.0 Transitional//EN", "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd") xhtmlFrameset = getDOMImplementation().createDocumentType( "html", "-//W3C//DTD XHTML 1.0 Frameset//EN", "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd") xhtmlAttrs = {"xmlns": xhtmlUri, "xml:lang": "en", "lang": "en"} def getChildrenByTagName(elem, name): return [child for child in elem.childNodes if child.nodeType==child.ELEMENT_NODE and child.nodeName==name] def getUniqueChildByTagName(elem, name): children = getChildrenByTagName(elem, name) assert len(children) <= 1 if len(children)==0: return None else: return children[0] def getTextOf(node): return getText(node.childNodes) def getText(nodelist): return "".join([node.data for node in nodelist if node.nodeType==node.TEXT_NODE]) def combineTextNodes(elem): child = elem.firstChild while child is not None: if child.nodeType==child.ELEMENT_NODE: combineTextNodes(child) elif child.nodeType==child.TEXT_NODE: prev=child.previousSibling if prev is not None and prev.nodeType==prev.TEXT_NODE: combined=elem.ownerDocument.createTextNode(prev.nodeValue+child.nodeValue) elem.removeChild(prev) elem.replaceChild(combined,child) child=combined child=child.nextSibling def normalizeTextNodes(elem): child=elem.firstChild while child is not None: if child.nodeType==child.TEXT_NODE: strippedText=child.nodeValue.strip() if strippedText=="": next=child.nextSibling elem.removeChild(child) child=next else: stripped=elem.ownerDocument.createTextNode(strippedText) elem.replaceChild(stripped,child) child=stripped.nextSibling else: if child.nodeType==child.ELEMENT_NODE: normalizeTextNodes(child) child=child.nextSibling def normalizeDocument(doc): combineTextNodes(doc) normalizeTextNodes(doc) def setAttrs(element, attrs): for attr in attrs: element.setAttribute(attr, attrs[attr])