etisserant@0: # etisserant@0: # # minixsv, Release 0.3 etisserant@0: # file: minidomif.py etisserant@0: # etisserant@0: # XML interface class to minidom etisserant@0: # etisserant@0: # history: etisserant@0: # 2004-09-09 rl created etisserant@0: # 2004-09-22 rl XML interface classes completely re-designed etisserant@0: # 2004-09-23 rl added filename and line number support etisserant@0: # 2004-09-29 rl URL processing added etisserant@0: # 2004-10-01 rl URL processing improved etisserant@0: # 2004-10-12 rl XML text processing added etisserant@0: # etisserant@0: # Copyright (c) 2004 by Roland Leuthe. All rights reserved. etisserant@0: # etisserant@0: # -------------------------------------------------------------------- etisserant@0: # The minixsv XML schema validator is etisserant@0: # etisserant@0: # Copyright (c) 2004 by Roland Leuthe etisserant@0: # etisserant@0: # By obtaining, using, and/or copying this software and/or its etisserant@0: # associated documentation, you agree that you have read, understood, etisserant@0: # and will comply with the following terms and conditions: etisserant@0: # etisserant@0: # Permission to use, copy, modify, and distribute this software and etisserant@0: # its associated documentation for any purpose and without fee is etisserant@0: # hereby granted, provided that the above copyright notice appears in etisserant@0: # all copies, and that both that copyright notice and this permission etisserant@0: # notice appear in supporting documentation, and that the name of etisserant@0: # the author not be used in advertising or publicity etisserant@0: # pertaining to distribution of the software without specific, written etisserant@0: # prior permission. etisserant@0: # etisserant@0: # THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD etisserant@0: # TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- etisserant@0: # ABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR etisserant@0: # BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY etisserant@0: # DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, etisserant@0: # WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS etisserant@0: # ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE etisserant@0: # OF THIS SOFTWARE. etisserant@0: # -------------------------------------------------------------------- etisserant@0: etisserant@0: import urllib etisserant@0: from xmlifbase import * etisserant@0: from xml.parsers.expat import ExpatError etisserant@0: from xml.dom.expatbuilder import ExpatBuilderNS etisserant@0: from xml.dom.minidom import * etisserant@0: etisserant@0: etisserant@0: class MiniDomInterface (XmlInterfaceBase): etisserant@0: ##################################################### etisserant@0: # for description of the interface methods see xmlifbase.py etisserant@0: ##################################################### etisserant@0: etisserant@0: def __init__ (self, verbose): etisserant@0: XmlInterfaceBase.__init__ (self, verbose) etisserant@0: if self.verbose: etisserant@0: print "Using minidom interface module..." etisserant@0: etisserant@0: etisserant@0: def parse (self, file, baseUrl): etisserant@0: url = self._convertToUrl(file) etisserant@0: absUrl = self._convertToAbsUrl (url, baseUrl) etisserant@0: fp = urllib.urlopen (absUrl) etisserant@0: try: etisserant@0: builder = ExtExpatBuilderNS(file, url, absUrl) etisserant@0: tree = builder.parseFile(fp) etisserant@0: finally: etisserant@0: fp.close() etisserant@0: etisserant@0: return TreeWrapper(self, tree) etisserant@0: etisserant@0: etisserant@0: def parseString (self, text): etisserant@0: builder = ExtExpatBuilderNS("", "", "") etisserant@0: tree = builder.parseString (text) etisserant@0: return TreeWrapper (self, tree) etisserant@0: etisserant@0: etisserant@0: ######################################################### etisserant@0: # Wrapper class for minidom.Document class etisserant@0: etisserant@0: class TreeWrapper (TreeWrapperBase): etisserant@0: etisserant@0: def getRootNode (self): etisserant@0: return ElementWrapper (self.xmlIf, self, self.tree.documentElement) etisserant@0: etisserant@0: def insertSubtree (self, nextSiblingWrapper, file, baseUrl): etisserant@0: subTreeWrapper = self.xmlIf.extParse (file, baseUrl) etisserant@0: assert self.getRootNode().getLocalName() == subTreeWrapper.getRootNode().getLocalName(),\ etisserant@0: "%s: line %d: root node of include file %s does not match!" %(self.getRootNode().getUrl(), self.getRootNode().getStartLineNumber(), file) etisserant@0: etisserant@0: elementWrapperList = subTreeWrapper.getRootNode().getChildren() etisserant@0: for elementWrapper in elementWrapperList: etisserant@0: if nextSiblingWrapper != None: etisserant@0: self.tree.documentElement.insertBefore(elementWrapper.element, nextSiblingWrapper.element) etisserant@0: else: etisserant@0: self.tree.documentElement.appendChild(elementWrapper.element) etisserant@0: etisserant@0: etisserant@0: ######################################################### etisserant@0: # Wrapper class for minidom.Document class etisserant@0: etisserant@0: class ElementWrapper (ElementWrapperBase): etisserant@0: etisserant@0: def getTagName (self): etisserant@0: return self.element.tagName etisserant@0: etisserant@0: etisserant@0: def getLocalName (self): etisserant@0: # base method replaced (optimized method) etisserant@0: return self.element.localName etisserant@0: etisserant@0: etisserant@0: def getNamespaceURI (self): etisserant@0: # base method replaced (optimized method) etisserant@0: return self.element.namespaceURI etisserant@0: etisserant@0: etisserant@0: def getChildren (self, filterTag=None): etisserant@0: return map(lambda element: ElementWrapper(self.xmlIf, self.treeWrapper, element), self._getElemNodes(filterTag)) etisserant@0: etisserant@0: etisserant@0: def getElementsByTagName (self, filterTag=None): etisserant@0: if filterTag == None: etisserant@0: filterTag = '*' etisserant@0: return map(lambda element: ElementWrapper(self.xmlIf, self.treeWrapper, element), self.element.getElementsByTagName(filterTag)) etisserant@0: etisserant@0: etisserant@0: def removeChild (self, childElementWrapper): etisserant@0: self.element.removeChild(childElementWrapper.element) etisserant@0: etisserant@0: etisserant@0: def getAttributeDict (self): etisserant@0: """Return dictionary of attributes""" etisserant@0: attribDict = {} etisserant@0: for attrName, attrValue in self.element.attributes.items(): etisserant@0: attribDict[attrName] = attrValue etisserant@0: return attribDict etisserant@0: etisserant@0: etisserant@0: def getAttribute (self, attributeName): etisserant@0: if self.element.attributes.has_key (attributeName): etisserant@0: return self.element.getAttribute (attributeName) etisserant@0: else: etisserant@0: return None etisserant@0: etisserant@0: etisserant@0: def hasAttribute (self, attributeName): etisserant@0: return self.element.attributes.has_key (attributeName) etisserant@0: etisserant@0: etisserant@0: def setAttribute (self, attributeName, attributeValue): etisserant@0: if not self.hasAttribute(attributeName): etisserant@0: self.element.setAttributeNode (self.treeWrapper.tree.createAttribute (attributeName)) etisserant@0: self.element.setAttribute(attributeName, attributeValue) etisserant@0: etisserant@0: etisserant@0: ############################################################### etisserant@0: # Caution! Currently returns only the first text node!! etisserant@0: def getElementValue (self): etisserant@0: textNodes = self._getTextNodes () etisserant@0: if textNodes: etisserant@0: return textNodes[0].data etisserant@0: else: etisserant@0: return "" etisserant@0: etisserant@0: etisserant@0: ############################################################### etisserant@0: # Caution! Currently only sets the first text node!! etisserant@0: def setElementValue (self, value): etisserant@0: textNodes = self._getTextNodes() etisserant@0: if textNodes: etisserant@0: textNodes[0].data = value etisserant@0: etisserant@0: etisserant@0: ############################################################### etisserant@0: # PRIVATE methods etisserant@0: ############################################################### etisserant@0: etisserant@0: def _getTextNodes (self): etisserant@0: """Return list of TEXT nodes.""" etisserant@0: return filter (lambda e: (e.nodeType == Node.TEXT_NODE), # - only TEXT-NODES etisserant@0: self.element.childNodes) # from element's child nodes etisserant@0: etisserant@0: etisserant@0: def _getElemNodes (self, filterTag): etisserant@0: """Return list of ELEMENT nodes and check for tag name (if given).""" etisserant@0: return filter (lambda e: (e.nodeType == Node.ELEMENT_NODE) and # - only ELEMENTs etisserant@0: (not filterTag or filterTag == '*' or e.tagName == filterTag), # - if tagName given --> check tagName etisserant@0: self.element.childNodes) # from element's nodes etisserant@0: etisserant@0: etisserant@0: etisserant@0: ################################################### etisserant@0: # Expat builder class derived from ExpatBuilderNS etisserant@0: # extended to store related line numbers in the node object etisserant@0: etisserant@0: class ExtExpatBuilderNS (ExpatBuilderNS): etisserant@0: def __init__ (self, filePath, url, absUrl): etisserant@0: self.filePath = filePath etisserant@0: self.url = url etisserant@0: self.absUrl = absUrl etisserant@0: ExpatBuilderNS.__init__(self) etisserant@0: etisserant@0: def start_element_handler(self, name, attributes): etisserant@0: ExpatBuilderNS.start_element_handler(self, name, attributes) etisserant@0: self.curNode.url = self.url etisserant@0: self.curNode.absUrl = self.absUrl etisserant@0: self.curNode.filePath = self.filePath etisserant@0: self.curNode.startLineNumber = self.getParser().ErrorLineNumber etisserant@0: etisserant@0: def end_element_handler(self, name): etisserant@0: self.curNode.endLineNumber = self.getParser().ErrorLineNumber etisserant@0: ExpatBuilderNS.end_element_handler(self, name) etisserant@0: