def startElement(self, name: str, attrs: AttributesImpl) -> None: """Start Element.""" self.output.append(1) self.append_string(name) for attr_name, attr_value in sorted( attrs.items()): # type: ignore[no-untyped-call] if attr_name not in self._attribute_blacklist: self.append_string(attr_name) self.append_string(attr_value)
def startElementNS(self, uri_localname, qname, attrs): (uri, localname) = uri_localname try: start_handler = self._startElementHandlers[(uri, localname)] except KeyError: raise ElementError("unknown element %s for namespace %s" % (localname, uri or NameSpace)) attrs = AttributesImpl(dict((attrs.getQNameByName(name), value) for name, value in attrs.items())) try: self.current = self.current.appendChild(start_handler(self.current, attrs)) except Exception as e: raise type(e)("line %d: %s" % (self._locator.getLineNumber(), str(e)))
def startElementNS(self, uri_localname, qname, attrs): (uri, localname) = uri_localname try: start_handler = self._startElementHandlers[(uri, localname)] except KeyError: raise ElementError("unknown element %s for namespace %s" % (localname, uri or NameSpace)) attrs = AttributesImpl( dict((attrs.getQNameByName(name), value) for name, value in attrs.items())) try: self.current = self.current.appendChild( start_handler(self.current, attrs)) except Exception as e: raise type(e)("line %d: %s" % (self._locator.getLineNumber(), str(e)))
class Element(object): """ Base class for all element types. This class is inspired by the class of the same name in the Python standard library's xml.dom package. One important distinction is that the standard DOM element is used to represent the structure of a document at a much finer level of detail than here. For example, in the case of the standard DOM element, each XML attribute is its own element being a child node of its tag, while here they are simply stored as attributes of the tag element itself. Despite the differences, the documentation for the xml.dom package, particularly that of the Element class and it's parent, the Node class, is useful as supplementary material in understanding how to use this class. """ # XML tag names are case sensitive: compare with ==, !=, etc. tagName = None validattributes = frozenset() validchildren = frozenset() def __init__(self, attrs = None): """ Construct an element. The argument is a sax.xmlreader.AttributesImpl object (see the xml.sax documentation, but it's basically a dictionary-like thing) used to set the element attributes. """ self.parentNode = None if attrs is None: self.attributes = AttributesImpl({}) elif set(attrs.keys()) <= self.validattributes: self.attributes = attrs else: raise ElementError("%s element does not have attribute(s) %s" % (self.tagName, ", ".join("'%s'" % key for key in set(attrs.keys()) - self.validattributes))) self.childNodes = [] self.pcdata = None def start_tag(self, indent): """ Generate the string for the element's start tag. """ s = indent + u"<" + self.tagName for keyvalue in self.attributes.items(): s += u" %s=\"%s\"" % keyvalue s += u">" return s def end_tag(self, indent): """ Generate the string for the element's end tag. """ return indent + u"</" + self.tagName + u">" def appendChild(self, child): """ Add a child to this element. The child's parentNode attribute is updated, too. """ self.childNodes.append(child) child.parentNode = self self._verifyChildren(len(self.childNodes) - 1) return child def insertBefore(self, newchild, refchild): """ Insert a new child node before an existing child. It must be the case that refchild is a child of this node; if not, ValueError is raised. newchild is returned. """ for i, childNode in enumerate(self.childNodes): if childNode is refchild: self.childNodes.insert(i, newchild) newchild.parentNode = self self._verifyChildren(i) return newchild raise ValueError(refchild) def removeChild(self, child): """ Remove a child from this element. The child element is returned, and it's parentNode element is reset. If the child will not be used any more, you should call its unlink() method to promote garbage collection. """ for i, childNode in enumerate(self.childNodes): if childNode is child: del self.childNodes[i] child.parentNode = None return child raise ValueError(child) def unlink(self): """ Break internal references within the document tree rooted on this element to promote garbage collection. """ self.parentNode = None for child in self.childNodes: child.unlink() del self.childNodes[:] def replaceChild(self, newchild, oldchild): """ Replace an existing node with a new node. It must be the case that oldchild is a child of this node; if not, ValueError is raised. newchild is returned. """ # .index() would use compare-by-value, we want # compare-by-id because we want to find the exact object, # not something equivalent to it. for i, childNode in enumerate(self.childNodes): if childNode is oldchild: self.childNodes[i].parentNode = None self.childNodes[i] = newchild newchild.parentNode = self self._verifyChildren(i) return newchild raise ValueError(oldchild) def getElements(self, filter): """ Return a list of elements below and including this element for which filter(element) returns True. """ l = reduce(lambda l, e: l + e.getElements(filter), self.childNodes, []) if filter(self): l.append(self) return l def getElementsByTagName(self, tagName): return self.getElements(lambda e: e.tagName == tagName) def getChildrenByAttributes(self, attrs): l = [] for c in self.childNodes: try: if reduce(lambda t, (k, v): t and (c.getAttribute(k) == v), attrs.iteritems(), True): l.append(c) except KeyError: pass return l def hasAttribute(self, attrname): return self.attributes.has_key(attrname) def getAttribute(self, attrname): return self.attributes[attrname] def setAttribute(self, attrname, value): # cafeful: this digs inside an AttributesImpl object and # modifies its internal data. probably not a good idea, # but I don't know how else to edit an attribute because # the stupid things don't export a method to do it. self.attributes._attrs[attrname] = unicode(value) def removeAttribute(self, attrname): # cafeful: this digs inside an AttributesImpl object and # modifies its internal data. probably not a good idea, # but I don't know how else to edit an attribute because # the stupid things don't export a method to do it. try: del self.attributes._attrs[attrname] except KeyError: pass def appendData(self, content): """ Add characters to the element's pcdata. """ if self.pcdata is not None: self.pcdata += content else: self.pcdata = content def _verifyChildren(self, i): """ Method used internally by some elements to verify that their children are from the allowed set and in the correct order following modifications to their child list. i is the index of the child that has just changed. """ pass def endElement(self): """ Method invoked by document parser when it encounters the end-of-element event. """ pass def write(self, fileobj = sys.stdout, indent = u""): """ Recursively write an element and it's children to a file. """ fileobj.write(self.start_tag(indent) + u"\n") for c in self.childNodes: if c.tagName not in self.validchildren: raise ElementError("invalid child %s for %s" % (c.tagName, self.tagName)) c.write(fileobj, indent + Indent) if self.pcdata is not None: fileobj.write(xmlescape(self.pcdata)) fileobj.write(u"\n") fileobj.write(self.end_tag(indent) + u"\n")
class Element(object): """ Base class for all element types. This class is inspired by the class of the same name in the Python standard library's xml.dom package. One important distinction is that the standard DOM element is used to represent the structure of a document at a much finer level of detail than here. For example, in the case of the standard DOM element, each XML attribute is its own element being a child node of its tag, while here they are simply stored as attributes of the tag element itself. Despite the differences, the documentation for the xml.dom package, particularly that of the Element class and it's parent, the Node class, is useful as supplementary material in understanding how to use this class. """ # XML tag names are case sensitive: compare with ==, !=, etc. tagName = None validchildren = frozenset() @classmethod def validattributes(cls): return frozenset(name for name in dir(cls) if isinstance(getattr(cls, name), attributeproxy)) def __init__(self, attrs = None): """ Construct an element. The argument is a sax.xmlreader.AttributesImpl object (see the xml.sax documentation, but it's basically a dictionary-like thing) used to set the element attributes. """ self.parentNode = None if attrs is None: self.attributes = AttributesImpl({}) elif set(attrs.keys()) <= self.validattributes(): self.attributes = attrs else: raise ElementError("%s element: invalid attribute(s) %s" % (self.tagName, ", ".join("'%s'" % key for key in set(attrs.keys()) - self.validattributes()))) self.childNodes = [] self.pcdata = None def start_tag(self, indent): """ Generate the string for the element's start tag. """ return u"%s<%s%s>" % (indent, self.tagName, u"".join(u" %s=\"%s\"" % keyvalue for keyvalue in self.attributes.items())) def end_tag(self, indent): """ Generate the string for the element's end tag. """ return u"%s</%s>" % (indent, self.tagName) def appendChild(self, child): """ Add a child to this element. The child's parentNode attribute is updated, too. """ self.childNodes.append(child) child.parentNode = self self._verifyChildren(len(self.childNodes) - 1) return child def insertBefore(self, newchild, refchild): """ Insert a new child node before an existing child. It must be the case that refchild is a child of this node; if not, ValueError is raised. newchild is returned. """ for i, childNode in enumerate(self.childNodes): if childNode is refchild: self.childNodes.insert(i, newchild) newchild.parentNode = self self._verifyChildren(i) return newchild raise ValueError(refchild) def removeChild(self, child): """ Remove a child from this element. The child element is returned, and it's parentNode element is reset. If the child will not be used any more, you should call its unlink() method to promote garbage collection. """ for i, childNode in enumerate(self.childNodes): if childNode is child: del self.childNodes[i] child.parentNode = None return child raise ValueError(child) def unlink(self): """ Break internal references within the document tree rooted on this element to promote garbage collection. """ self.parentNode = None for child in self.childNodes: child.unlink() del self.childNodes[:] def replaceChild(self, newchild, oldchild): """ Replace an existing node with a new node. It must be the case that oldchild is a child of this node; if not, ValueError is raised. newchild is returned. """ # .index() would use compare-by-value, we want # compare-by-id because we want to find the exact object, # not something equivalent to it. for i, childNode in enumerate(self.childNodes): if childNode is oldchild: self.childNodes[i].parentNode = None self.childNodes[i] = newchild newchild.parentNode = self self._verifyChildren(i) return newchild raise ValueError(oldchild) def getElements(self, filter): """ Return a list of elements below and including this element for which filter(element) returns True. """ l = reduce(lambda l, e: l + e.getElements(filter), self.childNodes, []) if filter(self): l.append(self) return l def getElementsByTagName(self, tagName): return self.getElements(lambda e: e.tagName == tagName) def getChildrenByAttributes(self, attrs): l = [] for c in self.childNodes: try: if reduce(lambda t, (k, v): t and (c.getAttribute(k) == v), attrs.iteritems(), True): l.append(c) except KeyError: pass return l def hasAttribute(self, attrname): return self.attributes.has_key(attrname) def getAttribute(self, attrname): return self.attributes[attrname] def setAttribute(self, attrname, value): # cafeful: this digs inside an AttributesImpl object and # modifies its internal data. probably not a good idea, # but I don't know how else to edit an attribute because # the stupid things don't export a method to do it. self.attributes._attrs[attrname] = unicode(value) def removeAttribute(self, attrname): # cafeful: this digs inside an AttributesImpl object and # modifies its internal data. probably not a good idea, # but I don't know how else to edit an attribute because # the stupid things don't export a method to do it. try: del self.attributes._attrs[attrname] except KeyError: pass def appendData(self, content): """ Add characters to the element's pcdata. """ if self.pcdata is not None: self.pcdata += content else: self.pcdata = content def _verifyChildren(self, i): """ Method used internally by some elements to verify that their children are from the allowed set and in the correct order following modifications to their child list. i is the index of the child that has just changed. """ pass def endElement(self): """ Method invoked by document parser when it encounters the end-of-element event. """ pass def write(self, fileobj = sys.stdout, indent = u""): """ Recursively write an element and it's children to a file. """ fileobj.write(self.start_tag(indent)) fileobj.write(u"\n") for c in self.childNodes: if c.tagName not in self.validchildren: raise ElementError("invalid child %s for %s" % (c.tagName, self.tagName)) c.write(fileobj, indent + Indent) if self.pcdata is not None: fileobj.write(xmlescape(self.pcdata)) fileobj.write(u"\n") fileobj.write(self.end_tag(indent)) fileobj.write(u"\n")