minixsv/minidomif.py
author etisserant
Thu, 20 Sep 2007 17:38:27 +0200
changeset 100 4e3f5b320bc3
parent 0 b622defdfd98
permissions -rw-r--r--
fixed code gen crash when using own FB/F in FBD
#
# # minixsv, Release 0.3
# file: minidomif.py
#
# XML interface class to minidom
#
# history:
# 2004-09-09 rl   created
# 2004-09-22 rl   XML interface classes completely re-designed
# 2004-09-23 rl   added filename and line number support
# 2004-09-29 rl   URL processing added
# 2004-10-01 rl   URL processing improved
# 2004-10-12 rl   XML text processing added
#
# Copyright (c) 2004 by Roland Leuthe.  All rights reserved.
#
# --------------------------------------------------------------------
# The minixsv XML schema validator is
#
# Copyright (c) 2004 by Roland Leuthe
#
# By obtaining, using, and/or copying this software and/or its
# associated documentation, you agree that you have read, understood,
# and will comply with the following terms and conditions:
#
# Permission to use, copy, modify, and distribute this software and
# its associated documentation for any purpose and without fee is
# hereby granted, provided that the above copyright notice appears in
# all copies, and that both that copyright notice and this permission
# notice appear in supporting documentation, and that the name of
# the author not be used in advertising or publicity
# pertaining to distribution of the software without specific, written
# prior permission.
#
# THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
# TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT-
# ABILITY AND FITNESS.  IN NO EVENT SHALL THE AUTHOR
# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
# OF THIS SOFTWARE.
# --------------------------------------------------------------------

import urllib
from xmlifbase            import *
from xml.parsers.expat    import ExpatError
from xml.dom.expatbuilder import ExpatBuilderNS
from xml.dom.minidom      import *


class MiniDomInterface (XmlInterfaceBase):
    #####################################################
    # for description of the interface methods see xmlifbase.py
    #####################################################

    def __init__ (self, verbose):
        XmlInterfaceBase.__init__ (self, verbose)
        if self.verbose:
            print "Using minidom interface module..."


    def parse (self, file, baseUrl):
        url    = self._convertToUrl(file)
        absUrl = self._convertToAbsUrl (url, baseUrl)
        fp     = urllib.urlopen (absUrl)
        try:
            builder = ExtExpatBuilderNS(file, url, absUrl)
            tree = builder.parseFile(fp)
        finally:
            fp.close()

        return TreeWrapper(self, tree)


    def parseString (self, text):
        builder = ExtExpatBuilderNS("", "", "")
        tree = builder.parseString (text)
        return TreeWrapper (self, tree)


#########################################################
# Wrapper class for minidom.Document class

class TreeWrapper (TreeWrapperBase):

    def getRootNode (self):
        return ElementWrapper (self.xmlIf, self, self.tree.documentElement)

    def insertSubtree (self, nextSiblingWrapper, file, baseUrl):
        subTreeWrapper = self.xmlIf.extParse (file, baseUrl)
        assert self.getRootNode().getLocalName() == subTreeWrapper.getRootNode().getLocalName(),\
               "%s: line %d: root node of include file %s does not match!" %(self.getRootNode().getUrl(), self.getRootNode().getStartLineNumber(), file)

        elementWrapperList = subTreeWrapper.getRootNode().getChildren()
        for elementWrapper in elementWrapperList:
            if nextSiblingWrapper != None:
                self.tree.documentElement.insertBefore(elementWrapper.element, nextSiblingWrapper.element)
            else:
                self.tree.documentElement.appendChild(elementWrapper.element)


#########################################################
# Wrapper class for minidom.Document class

class ElementWrapper (ElementWrapperBase):

    def getTagName (self):
        return self.element.tagName


    def getLocalName (self):
        # base method replaced (optimized method)
        return self.element.localName


    def getNamespaceURI (self):
        # base method replaced (optimized method)
        return self.element.namespaceURI


    def getChildren (self, filterTag=None):
        return map(lambda element: ElementWrapper(self.xmlIf, self.treeWrapper, element), self._getElemNodes(filterTag))


    def getElementsByTagName (self, filterTag=None):
        if filterTag == None:
            filterTag = '*'
        return map(lambda element: ElementWrapper(self.xmlIf, self.treeWrapper, element), self.element.getElementsByTagName(filterTag))


    def removeChild (self, childElementWrapper):
        self.element.removeChild(childElementWrapper.element)


    def getAttributeDict (self):
        """Return dictionary of attributes"""
        attribDict = {}
        for attrName, attrValue in self.element.attributes.items():
            attribDict[attrName] = attrValue
        return attribDict


    def getAttribute (self, attributeName):
        if self.element.attributes.has_key (attributeName):
            return self.element.getAttribute (attributeName)
        else:
            return None


    def hasAttribute (self, attributeName):
        return self.element.attributes.has_key (attributeName)


    def setAttribute (self, attributeName, attributeValue):
        if not self.hasAttribute(attributeName):
            self.element.setAttributeNode (self.treeWrapper.tree.createAttribute (attributeName))
        self.element.setAttribute(attributeName, attributeValue)


    ###############################################################
    # Caution! Currently returns only the first text node!!
    def getElementValue (self):
        textNodes = self._getTextNodes ()
        if textNodes:
            return textNodes[0].data
        else:
            return ""


    ###############################################################
    # Caution! Currently only sets the first text node!!
    def setElementValue (self, value):
        textNodes = self._getTextNodes()
        if textNodes:
            textNodes[0].data = value


    ###############################################################
    # PRIVATE methods
    ###############################################################

    def _getTextNodes (self):
        """Return list of TEXT nodes."""
        return filter (lambda e: (e.nodeType == Node.TEXT_NODE),        # - only TEXT-NODES
                       self.element.childNodes)                         # from element's child nodes


    def _getElemNodes (self, filterTag):
        """Return list of ELEMENT nodes and check for tag name (if given)."""
        return filter (lambda e: (e.nodeType == Node.ELEMENT_NODE) and                          # - only ELEMENTs
                                 (not filterTag or filterTag == '*' or e.tagName == filterTag), # - if tagName given --> check tagName
                       self.element.childNodes)                                                 # from element's nodes



###################################################
# Expat builder class derived from ExpatBuilderNS
# extended to store related line numbers in the node object

class ExtExpatBuilderNS (ExpatBuilderNS):
    def __init__ (self, filePath, url, absUrl):
        self.filePath = filePath
        self.url      = url
        self.absUrl   = absUrl
        ExpatBuilderNS.__init__(self)

    def start_element_handler(self, name, attributes):
        ExpatBuilderNS.start_element_handler(self, name, attributes)
        self.curNode.url      = self.url
        self.curNode.absUrl   = self.absUrl
        self.curNode.filePath = self.filePath
        self.curNode.startLineNumber = self.getParser().ErrorLineNumber

    def end_element_handler(self, name):
        self.curNode.endLineNumber = self.getParser().ErrorLineNumber
        ExpatBuilderNS.end_element_handler(self, name)