diff --git a/tools/generator/lib/genxmlif/README.txt b/tools/generator/lib/genxmlif/README.txt new file mode 100644 index 0000000..e1c31cc --- /dev/null +++ b/tools/generator/lib/genxmlif/README.txt @@ -0,0 +1,82 @@ +Release Notes for genxmlif, Release 0.9.0 + +genxmlif is a generic XML interface package +which currently uses minidom, elementtree or 4DOM as XML parser +Other parsers can be adapted by implementing an appropriate interface class + +-------------------------------------------------------------------- + The genxmlif generic XML interface package is + + Copyright (c) 2005-2008 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. +--------------------------------------------------------------------- + +Contents +======== + +README.txt +__init__.py +xmlif4Dom.py +xmlifApi.py +xmlifBase.py +xmlifDom.py +xmlifElementTree.py +xmlifMinidom.py +xmlifODict.py +xmlifUtils.py +xmliftest.py + + +--------------------------------------------------------------------- + +HISTORY: +======= + +Changes for Release 0.9.0 +========================= + +- Caution, interface changed! + API changes: + * TreeWrapper and ElementWrapper classes re-designed and renamed + (Now derivation from these classes is possible) + * insertSubtree method moved from TreeWrapper class to ElementWrapper class + * some new public methods added (e.g. removeAttribute) + * print functionality improved + * GenXmlIfError exception introduced (parser and XInclude errors are mapped to this exception class) + * pydoc comments for all API methods added + * caching introduced (for performance optimization) + + +Changes for Release 0.8 +======================= + +- Caution, interface changed! Method getXPathList returns now 3 parameters instead of 1 in release 0.7! +- performance optimization (caching, mainly for elementtree interface) +- some bugs fixed + + +Changes for Release 0.7 +======================= + +- some special methods for XML schema validation support added diff --git a/tools/generator/lib/genxmlif/__init__.py b/tools/generator/lib/genxmlif/__init__.py new file mode 100644 index 0000000..e4832d6 --- /dev/null +++ b/tools/generator/lib/genxmlif/__init__.py @@ -0,0 +1,92 @@ +# +# genxmlif, Release 0.9.0 +# file: __init__.py +# +# genxmlif package file +# +# history: +# 2005-04-25 rl created +# +# Copyright (c) 2005-2008 by Roland Leuthe. All rights reserved. +# +# -------------------------------------------------------------------- +# The generic XML interface is +# +# Copyright (c) 2005-2008 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. +# -------------------------------------------------------------------- + + +###################################################################### +# PUBLIC DEFINITIONS +###################################################################### + + +# supported XML interfaces + +XMLIF_MINIDOM = "XMLIF_MINIDOM" +XMLIF_4DOM = "XMLIF_4DOM" +XMLIF_ELEMENTTREE = "XMLIF_ELEMENTTREE" + +# namespace definitions + +XINC_NAMESPACE = "http://www.w3.org/2001/XInclude" + + +# definition of genxmlif path + +import os +GENXMLIF_DIR = os.path.dirname(__file__) + + +######################################## +# central function to choose the XML interface to be used +# + +def chooseXmlIf (xmlIf, verbose=0, useCaching=1, processXInclude=1): + if xmlIf == XMLIF_MINIDOM: + import xmlifMinidom + return xmlifMinidom.XmlInterfaceMinidom(verbose, useCaching, processXInclude) + + elif xmlIf == XMLIF_4DOM: + import xmlif4Dom + return xmlif4Dom.XmlInterface4Dom(verbose, useCaching, processXInclude) + + elif xmlIf == XMLIF_ELEMENTTREE: + import xmlifElementTree + return xmlifElementTree.XmlInterfaceElementTree(verbose, useCaching, processXInclude) + + else: + raise AttributeError, "Unknown XML interface: %s" %(xmlIf) + + +######################################## +# define own exception for GenXmlIf errors +# The following errors/exceptions are mapped to a GenxmlIf exception: +# - Expat errors +# - XInclude errors +# +class GenXmlIfError (StandardError): + pass + diff --git a/tools/generator/lib/genxmlif/xmlif4Dom.py b/tools/generator/lib/genxmlif/xmlif4Dom.py new file mode 100644 index 0000000..ded171e --- /dev/null +++ b/tools/generator/lib/genxmlif/xmlif4Dom.py @@ -0,0 +1,139 @@ +# +# genxmlif, Release 0.9.0 +# file: xmlif4Dom.py +# +# XML interface class to the 4DOM library +# +# history: +# 2005-04-25 rl created +# 2008-07-01 rl Limited support of XInclude added +# +# Copyright (c) 2005-2008 by Roland Leuthe. All rights reserved. +# +# -------------------------------------------------------------------- +# The generix XML interface is +# +# Copyright (c) 2005-2008 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 xml.dom.ext.reader.Sax2 import Reader, XmlDomGenerator +from xml.sax._exceptions import SAXParseException +from ..genxmlif import XMLIF_4DOM, GenXmlIfError +from xmlifUtils import convertToAbsUrl +from xmlifDom import XmlInterfaceDom, XmlIfBuilderExtensionDom, InternalDomTreeWrapper, InternalDomElementWrapper + + +class XmlInterface4Dom (XmlInterfaceDom): + ##################################################### + # for description of the interface methods see xmlifbase.py + ##################################################### + + def __init__ (self, verbose, useCaching, processXInclude): + XmlInterfaceDom.__init__ (self, verbose, useCaching, processXInclude) + self.xmlIfType = XMLIF_4DOM + if self.verbose: + print "Using 4Dom interface module..." + + + def parse (self, file, baseUrl="", internalOwnerDoc=None): + absUrl = convertToAbsUrl (file, baseUrl) + fp = urllib.urlopen (absUrl) + return self._parseStream (fp, file, absUrl, internalOwnerDoc) + + + def parseString (self, text, baseUrl="", internalOwnerDoc=None): + import cStringIO + fp = cStringIO.StringIO(text) + absUrl = convertToAbsUrl ("", baseUrl) + return self._parseStream (fp, "", absUrl, internalOwnerDoc) + + + def _parseStream (self, fp, file, absUrl, internalOwnerDoc): + reader = Reader(validate=0, keepAllWs=0, catName=None, + saxHandlerClass=ExtXmlDomGenerator, parser=None) + reader.handler.extinit(file, absUrl, reader.parser, self) + if internalOwnerDoc != None: + ownerDoc = internalOwnerDoc.document + else: + ownerDoc = None + try: + tree = reader.fromStream(fp, ownerDoc) + fp.close() + except SAXParseException, errInst: + fp.close() + raise GenXmlIfError, "%s: SAXParseException: %s" %(file, str(errInst)) + + treeWrapper = reader.handler.treeWrapper + + # XInclude support + if self.processXInclude: + if internalOwnerDoc == None: + internalOwnerDoc = treeWrapper.getTree() + self.xInclude (treeWrapper.getRootNode(), absUrl, internalOwnerDoc) + + return treeWrapper + + +################################################### +# Extended DOM generator class derived from XmlDomGenerator +# extended to store related line numbers, file/URL names and +# defined namespaces in the node object + +class ExtXmlDomGenerator(XmlDomGenerator, XmlIfBuilderExtensionDom): + def __init__(self, keepAllWs=0): + XmlDomGenerator.__init__(self, keepAllWs) + self.treeWrapper = None + + + def extinit (self, filePath, absUrl, parser, xmlIf): + self.filePath = filePath + self.absUrl = absUrl + self.parser = parser + self.xmlIf = xmlIf + + + def startElement(self, name, attribs): + XmlDomGenerator.startElement(self, name, attribs) + + if not self.treeWrapper: + self.treeWrapper = self.xmlIf.treeWrapperClass(self, InternalDomTreeWrapper(self._rootNode), self.xmlIf.useCaching) + XmlIfBuilderExtensionDom.__init__(self, self.filePath, self.absUrl, self.treeWrapper, self.xmlIf.elementWrapperClass) + + curNode = self._nodeStack[-1] + internal4DomElementWrapper = InternalDomElementWrapper(curNode, self.treeWrapper.getTree()) + curNs = self._namespaces.items() + try: + curNs.remove( (None,None) ) + except: + pass + + XmlIfBuilderExtensionDom.startElementHandler (self, internal4DomElementWrapper, self.parser.getLineNumber(), curNs) + + + def endElement(self, name): + curNode = self._nodeStack[-1] + XmlIfBuilderExtensionDom.endElementHandler (self, curNode.xmlIfExtInternalWrapper, self.parser.getLineNumber()) + XmlDomGenerator.endElement(self, name) diff --git a/tools/generator/lib/genxmlif/xmlifApi.py b/tools/generator/lib/genxmlif/xmlifApi.py new file mode 100644 index 0000000..6d7e478 --- /dev/null +++ b/tools/generator/lib/genxmlif/xmlifApi.py @@ -0,0 +1,1291 @@ +# +# genxmlif, Release 0.9.0 +# file: xmlifapi.py +# +# API (interface) classes for generic interface package +# +# history: +# 2007-06-29 rl created, classes extracted from xmlifbase.py +# +# Copyright (c) 2005-2008 by Roland Leuthe. All rights reserved. +# +# -------------------------------------------------------------------- +# The generic XML interface is +# +# Copyright (c) 2005-2008 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. +# -------------------------------------------------------------------- + +__author__ = "Roland Leuthe " +__date__ = "08. August 2008" +__version__ = "0.9.0" + +import string +import os +import re +import copy +from types import TupleType, StringTypes +from xml.dom import EMPTY_PREFIX, EMPTY_NAMESPACE +from xmlifUtils import processWhitespaceAction, NsNameTupleFactory, splitQName, nsNameToQName, escapeCdata, escapeAttribute + + +######################################## +# XML interface base class +# All not implemented methods have to be overloaded by the derived class!! +# + +class XmlInterfaceBase: + """XML interface base class. + + All not implemented methods have to be overloaded by the derived class!! + """ + + def __init__(self, verbose, useCaching, processXInclude): + """Constructor of class XmlInterfaceBase. + + Input parameter: + 'verbose': 0 or 1: controls verbose print output for module genxmlif + 'useCaching': 0 or 1: controls usage of caching for module genxmlif + 'processXInclude': 0 or 1: controls XInclude processing during parsing + """ + + self.verbose = verbose + self.useCaching = useCaching + self.processXInclude = processXInclude + + # set default wrapper classes + self.setTreeWrapperClass (XmlTreeWrapper) + self.setElementWrapperClass (XmlElementWrapper) + + + def createXmlTree (self, namespace, xmlRootTagName, attributeDict={}, publicId=None, systemId=None): + """Create a new XML TreeWrapper object (wrapper for DOM document or elementtree). + + Input parameter: + 'namespace': not yet handled (for future use) + 'xmlRootTagName': specifies the tag name of the root element + 'attributeDict': contains the attributes of the root node (optional) + 'publicId': forwarded to contained DOM tree (unused for elementtree) + 'systemId': forwarded to contained DOM tree (unused for elementtree) + Returns the created XML tree wrapper object. + Method has to be implemented by derived classes! + """ + + raise NotImplementedError + + + def parse (self, filePath, baseUrl="", ownerDoc=None): + """Call the XML parser for 'file'. + + Input parameter: + 'filePath': a file path or an URI + 'baseUrl': if specified, it is used e.g. as base path for schema files referenced inside the XML file. + 'ownerDoc': only used in case of 4DOM (forwarded to 4DOM parser). + Returns the respective XML tree wrapper object for the parsed XML file. + Method has to be implemented by derived classes! + """ + + raise NotImplementedError + + + def parseString (self, text, baseUrl="", ownerDoc=None): + """Call the XML parser for 'text'. + + Input parameter: + 'text': contains the XML string to be parsed + 'baseUrl': if specified, it is used e.g. as base path for schema files referenced inside the XML string. + 'ownerDoc': only used in case of 4DOM (forwarded to 4DOM parser). + Returns the respective XML tree wrapper object for the parsed XML 'text' string. + Method has to be implemented by derived classes! + """ + raise NotImplementedError + + + def setTreeWrapperClass (self, treeWrapperClass): + """Set the tree wrapper class which shall be used by this interface. + + Input parameter: + treeWrapperClass: tree wrapper class + """ + self.treeWrapperClass = treeWrapperClass + + + def setElementWrapperClass (self, elementWrapperClass): + """Set the element wrapper classes which shall be used by this interface. + + Input parameter: + elementWrapperClass: element wrapper class + """ + self.elementWrapperClass = elementWrapperClass + + + def getXmlIfType (self): + """Retrieve the type of the XML interface.""" + return self.xmlIfType + + +######################################## +# Tree wrapper API (interface class) +# + +class XmlTreeWrapper: + """XML tree wrapper API. + + Contains a DOM tree or an elementtree (depending on used XML parser) + """ + + def __init__(self, xmlIf, tree, useCaching): + """Constructor of wrapper class XmlTreeWrapper. + + Input parameter: + 'xmlIf': used XML interface class + 'tree': DOM tree or elementtree which is wrapped by this object + 'useCaching': 1 if caching shall be used inside genxmlif, otherwise 0 + """ + self.xmlIf = xmlIf + self.__tree = tree + self.__useCaching = useCaching + + + def createElement (self, tupleOrLocalName, attributeDict=None, curNs=[]): + """Create an ElementWrapper object. + + Input parameter: + tupleOrLocalName: tag name of element node to be created + (tuple of namespace and localName or only localName if no namespace is used) + attributeDict: attributes for this elements + curNs: namespaces for scope of this element + Returns an ElementWrapper object containing the created element node. + """ + nsName = NsNameTupleFactory(tupleOrLocalName) + elementNode = self.__tree.xmlIfExtCreateElement(nsName, attributeDict, curNs) + return self.xmlIf.elementWrapperClass(elementNode, self, curNs) + + + def cloneTree (self): + """Creates a copy of a whole XML DOM tree.""" + rootElementWrapperCopy = self.getRootNode().cloneNode(deep=1) + treeWrapperCopy = self.__class__(self.xmlIf, + self.__tree.xmlIfExtCloneTree(rootElementWrapperCopy.element), + self.__useCaching) + for elementWrapper in rootElementWrapperCopy.getIterator(): + elementWrapper.treeWrapper = treeWrapperCopy + return treeWrapperCopy + + + def getRootNode (self): + """Retrieve the wrapper object of the root element of the contained XML tree. + + Returns the ElementWrapper object of the root element. + """ + return self.__tree.xmlIfExtGetRootNode().xmlIfExtElementWrapper + + + def getTree (self): + """Retrieve the contained XML tree. + + Returns the contained XML tree object (internal DOM tree wrapper or elementtree). + """ + return self.__tree + + + def printTree (self, prettyPrint=0, printElementValue=1, encoding=None): + """Return the string representation of the contained XML tree. + + Input parameter: + 'prettyPrint': aligns the columns of the attributes of childNodes + 'printElementValue': controls if the lement values are printed or not. + Returns a string with the string representation of the whole XML tree. + """ + if not encoding: + encoding = "utf-8" + if encoding != "utf-8" and encoding != "us-ascii": + text = "\n" % encoding + else: + text = "" + return text + self.getRootNode().printNode(deep=1, prettyPrint=prettyPrint, printElementValue=printElementValue, encoding=encoding) + + + def useCaching (self): + """Return 1 if caching should be used for the contained XML tree.""" + return self.__useCaching + + + def setExternalCacheUsage (self, used): + """Set external cache usage for the whole tree + unlink commands are ignored if used by an external cache + + Input parameter: + used: 0 or 1 (used by external cache) + """ + self.getRootNode().setExternalCacheUsage (used, deep=1) + + + def unlink (self): + """Break circular references of the complete XML tree. + + To be called if the XML tree is not longer used => garbage collection! + """ + self.getRootNode().unlink() + + + def __str__ (self): + """Return the string representation of the contained XML tree.""" + return self.printTree() + + + +######################################## +# Element wrapper API (interface class) +# + +class XmlElementWrapper: + """XML element wrapper API. + + Contains a XML element node + All not implemented methods have to be overloaded by the derived class!! + """ + + def __init__(self, element, treeWrapper, curNs=[], initAttrSeq=1): + """Constructor of wrapper class XmlElementWrapper. + + Input parameter: + element: XML element node which is wrapped by this object + treeWrapper: XML tree wrapper class the current element belongs to + curNs: namespaces for scope of this element + """ + self.element = element + self.element.xmlIfExtElementWrapper = self + self.treeWrapper = treeWrapper + self.nodeUsedByExternalCache = 0 + + if self.__useCaching(): + self.__childrenCache = {} + self.__firstChildCache = {} + self.__qNameAttrCache = {} + + self.baseUrl = None + self.absUrl = None + self.filePath = None + self.startLineNumber = None + self.endLineNumber = None + self.curNs = curNs[:] + self.attributeSequence = [] + + if initAttrSeq: + self.attributeSequence = self.getAttributeDict().keys() + + + def unlink (self): + """Break circular references of this element and its children.""" + for childWrapper in self.getChildren(): + childWrapper.unlink() + if not self.isUsedByExternalCache(): + self.element.xmlIfExtUnlink() + + + def cloneNode (self, deep, cloneCallback=None): + """Create a copy of the current element wrapper. + The reference to the parent node is set to None!""" + elementCopy = self.element.xmlIfExtCloneNode() + elementWrapperCopy = self.__class__(elementCopy, self.treeWrapper, initAttrSeq=0) + elementWrapperCopy.treeWrapper = None + elementWrapperCopy.baseUrl = self.baseUrl + elementWrapperCopy.absUrl = self.absUrl + elementWrapperCopy.filePath = self.filePath + elementWrapperCopy.startLineNumber = self.startLineNumber + elementWrapperCopy.endLineNumber = self.endLineNumber + elementWrapperCopy.curNs = self.curNs[:] + elementWrapperCopy.attributeSequence = self.attributeSequence[:] + if cloneCallback: cloneCallback(elementWrapperCopy) + if deep: + for childElement in self.element.xmlIfExtGetChildren(): + childWrapperElementCopy = childElement.xmlIfExtElementWrapper.cloneNode(deep, cloneCallback) + childWrapperElementCopy.element.xmlIfExtSetParentNode(elementWrapperCopy.element) + elementWrapperCopy.element.xmlIfExtAppendChild(childWrapperElementCopy.element) + return elementWrapperCopy + + + def clearNodeCache (self): + """Clear all caches used by this element wrapper which contains element wrapper references.""" + self.__clearChildrenCache() + + + def isUsedByExternalCache (self): + """Check if this node is used by an external cache. + unlink commands are ignored if used by an external cache""" + return self.nodeUsedByExternalCache + + + def setExternalCacheUsage (self, used, deep=1): + """Set external cache usage for this node and its children + unlink commands are ignored if used by an external cache + + Input parameter: + used: 0 or 1 (used by external cache) + deep: 0 or 1: controls if the child elements are also marked as used by external cache + """ + self.nodeUsedByExternalCache = used + if deep: + for childWrapper in self.getChildren(): + childWrapper.setExternalCacheUsage (used, deep) + + + + ########################################################## + # attributes of the current node can be accessed via key operator + + def __getitem__(self, tupleOrAttrName): + """Attributes of the contained element node can be accessed via key operator. + + Input parameter: + tupleOrAttrName: name of the attribute (tuple of namespace and attributeName or only attributeName) + Returns the attribute value. + """ + attrValue = self.getAttribute (tupleOrAttrName) + if attrValue != None: + return attrValue + else: + raise AttributeError, "Attribute %s not found!" %(repr(tupleOrAttrName)) + + + def __setitem__(self, tupleOrAttrName, attributeValue): + """Attributes of the contained element node can be accessed via key operator. + + Input parameter: + tupleOrAttrName: name of the attribute (tuple of namespace and attributeName or only attributeName) + attributeValue: attribute value to be set + """ + self.setAttribute (tupleOrAttrName, attributeValue) + + +#++++++++++++ methods concerning the tag name ++++++++++++++++++++++++ + + def getTagName (self): + """Retrieve the (complete) tag name of the contained element node + + Returns the (complete) tag name of the contained element node + """ + return self.element.xmlIfExtGetTagName() + + + def getLocalName (self): + """Retrieve the local name (without namespace) of the contained element node + + Returns the local name (without namespace) of the contained element node + """ + + try: + return self.__localNameCache + except: + prefix, localName = splitQName (self.getTagName()) + if self.__useCaching(): + self.__localNameCache = localName + return localName + + + def getNamespaceURI (self): + """Retrieve the namespace URI of the contained element node + + Returns the namespace URI of the contained element node (None if no namespace is used). + """ + try: + return self.__nsUriCache + except: + prefix = self.element.xmlIfExtGetNamespaceURI() + if self.__useCaching(): + self.__nsUriCache = prefix + return prefix + + + def getNsName (self): + """Retrieve a tuple (namespace, localName) of the contained element node + + Returns a tuple (namespace, localName) of the contained element node (namespace is None if no namespace is used). + """ + try: + return self.__nsNameCache + except: + nsName = NsNameTupleFactory( (self.getNamespaceURI(), self.getLocalName()) ) + if self.__useCaching(): + self.__nsNameCache = nsName + return nsName + + + def getQName (self): + """Retrieve a string prefix and localName of the contained element node + + Returns a string "prefix:localName" of the contained element node + """ + return self.nsName2QName(self.getNsName()) + + + def getPrefix (self): + """Retrieve the namespace prefix of the contained element node + + Returns the namespace prefix of the contained element node (None if no namespace is used). + """ + return self.getNsPrefix(self.getNsName()) + + +#++++++++++++ methods concerning print support ++++++++++++++++++++++++ + + def __str__ (self): + """Retrieve the textual representation of the contained element node.""" + return self.printNode() + + + def printNode (self, indent="", deep=0, prettyPrint=0, attrMaxLengthDict={}, printElementValue=1, encoding=None): + """Retrieve the textual representation of the contained element node. + + Input parameter: + indent: indentation to be used for string representation + deep: 0 or 1: controls if the child element nodes are also printed + prettyPrint: aligns the columns of the attributes of childNodes + attrMaxLengthDict: dictionary containing the length of the attribute values (used for prettyprint) + printElementValue: 0 or 1: controls if the element value is printed + Returns the string representation + """ + patternXmlTagShort = '''\ +%(indent)s<%(qName)s%(attributeString)s/>%(tailText)s%(lf)s''' + + patternXmlTagLong = '''\ +%(indent)s<%(qName)s%(attributeString)s>%(elementValueString)s\ +%(lf)s%(subTreeString)s\ +%(indent)s%(tailText)s%(lf)s''' + + subTreeStringList = [] + tailText = "" + addIndent = "" + lf = "" + if deep: + childAttrMaxLengthDict = {} + if prettyPrint: + for childNode in self.getChildren(): + childNode.__updateAttrMaxLengthDict(childAttrMaxLengthDict) + lf = "\n" + addIndent = " " + for childNode in self.getChildren(): + subTreeStringList.append (childNode.printNode(indent + addIndent, deep, prettyPrint, childAttrMaxLengthDict, printElementValue)) + tailText = escapeCdata(self.element.xmlIfExtGetElementTailText(), encoding) + + attributeStringList = [] + for attrName in self.getAttributeList(): + attrValue = escapeAttribute(self.getAttribute(attrName), encoding) + if prettyPrint: + try: + align = attrMaxLengthDict[attrName] + except: + align = len(attrValue) + else: + align = len(attrValue) + qName = self.nsName2QName(attrName) + attributeStringList.append (' %s="%s"%*s' %(qName, attrValue, align - len(attrValue), "")) + attributeString = string.join (attributeStringList, "") + + qName = self.getQName() + if printElementValue: + if deep: + elementValueString = escapeCdata(self.element.xmlIfExtGetElementText(), encoding) + else: + elementValueString = escapeCdata(self.getElementValue(ignoreEmtpyStringFragments=1), encoding) + else: + elementValueString = "" + + if subTreeStringList == [] and elementValueString == "": + printPattern = patternXmlTagShort + else: + if subTreeStringList != []: + subTreeString = string.join (subTreeStringList, "") + else: + subTreeString = "" + printPattern = patternXmlTagLong + return printPattern % vars() + + +#++++++++++++ methods concerning the parent of the current node ++++++++++++++++++++++++ + + def getParentNode (self): + """Retrieve the ElementWrapper object of the parent element node. + + Returns the ElementWrapper object of the parent element node. + """ + parent = self.element.xmlIfExtGetParentNode() + if parent != None: + return parent.xmlIfExtElementWrapper + else: + return None + + +#++++++++++++ methods concerning the children of the current node ++++++++++++++++++++++++ + + + def getChildren (self, tagFilter=None): + """Retrieve the ElementWrapper objects of the children element nodes. + + Input parameter: + tagFilter: retrieve only the children with this tag name ('*' or None returns all children) + Returns all children of this element node which match 'tagFilter' (list) + """ + if tagFilter in (None, '*', (None, '*')): + children = self.element.xmlIfExtGetChildren() + elif tagFilter[1] == '*': + # handle (namespace, '*') + children = filter(lambda child:child.xmlIfExtElementWrapper.getNamespaceURI() == tagFilter[0], + self.element.xmlIfExtGetChildren()) + else: + nsNameFilter = NsNameTupleFactory(tagFilter) + try: + children = self.__childrenCache[nsNameFilter] + except: + children = self.element.xmlIfExtGetChildren(nsNameFilter) + if self.__useCaching(): + self.__childrenCache[nsNameFilter] = children + + return map(lambda child: child.xmlIfExtElementWrapper, children) + + + def getChildrenNS (self, namespaceURI, tagFilter=None): + """Retrieve the ElementWrapper objects of the children element nodes using a namespace. + + Input parameter: + namespaceURI: the namespace URI of the children or None + tagFilter: retrieve only the children with this localName ('*' or None returns all children) + Returns all children of this element node which match 'namespaceURI' and 'tagFilter' (list) + """ + return self.getChildren((namespaceURI, tagFilter)) + + + def getChildrenWithKey (self, tagFilter=None, keyAttr=None, keyValue=None): + """Retrieve the ElementWrapper objects of the children element nodes. + + Input parameter: + tagFilter: retrieve only the children with this tag name ('*' or None returns all children) + keyAttr: name of the key attribute + keyValue: value of the key + Returns all children of this element node which match 'tagFilter' (list) + """ + children = self.getChildren(tagFilter) + return filter(lambda child:child[keyAttr]==keyValue, children) + + + def getFirstChild (self, tagFilter=None): + """Retrieve the ElementWrapper objects of the first child element node. + + Input parameter: + tagFilter: retrieve only the first child with this tag name ('*' or None: no filter) + Returns the first child of this element node which match 'tagFilter' + or None if no suitable child element was found + """ + if tagFilter in (None, '*', (None, '*')): + element = self.element.xmlIfExtGetFirstChild() + elif tagFilter[1] == '*': + # handle (namespace, '*') + children = filter(lambda child:child.xmlIfExtElementWrapper.getNamespaceURI() == tagFilter[0], + self.element.xmlIfExtGetChildren()) + try: + element = children[0] + except: + element = None + else: + nsNameFilter = NsNameTupleFactory(tagFilter) + try: + element = self.__firstChildCache[nsNameFilter] + except: + element = self.element.xmlIfExtGetFirstChild(nsNameFilter) + if self.__useCaching(): + self.__firstChildCache[nsNameFilter] = element + + if element != None: + return element.xmlIfExtElementWrapper + else: + return None + + + def getFirstChildNS (self, namespaceURI, tagFilter=None): + """Retrieve the ElementWrapper objects of the first child element node using a namespace. + + Input parameter: + namespaceURI: the namespace URI of the children or None + tagFilter: retrieve only the first child with this localName ('*' or None: no filter) + Returns the first child of this element node which match 'namespaceURI' and 'tagFilter' + or None if no suitable child element was found + """ + return self.getFirstChild ((namespaceURI, tagFilter)) + + + def getFirstChildWithKey (self, tagFilter=None, keyAttr=None, keyValue=None): + """Retrieve the ElementWrapper objects of the children element nodes. + + Input parameter: + tagFilter: retrieve only the children with this tag name ('*' or None returns all children) + keyAttr: name of the key attribute + keyValue: value of the key + Returns all children of this element node which match 'tagFilter' (list) + """ + children = self.getChildren(tagFilter) + childrenWithKey = filter(lambda child:child[keyAttr]==keyValue, children) + if childrenWithKey != []: + return childrenWithKey[0] + else: + return None + + + def getElementsByTagName (self, tagFilter=None): + """Retrieve all descendant ElementWrapper object of current node whose tag name match 'tagFilter'. + + Input parameter: + tagFilter: retrieve only the children with this tag name ('*' or None returns all descendants) + Returns all descendants of this element node which match 'tagFilter' (list) + """ + if tagFilter in (None, '*', (None, '*'), (None, None)): + descendants = self.element.xmlIfExtGetElementsByTagName() + + elif tagFilter[1] == '*': + # handle (namespace, '*') + descendants = filter(lambda desc:desc.xmlIfExtElementWrapper.getNamespaceURI() == tagFilter[0], + self.element.xmlIfExtGetElementsByTagName()) + else: + nsNameFilter = NsNameTupleFactory(tagFilter) + descendants = self.element.xmlIfExtGetElementsByTagName(nsNameFilter) + + return map(lambda descendant: descendant.xmlIfExtElementWrapper, descendants) + + + def getElementsByTagNameNS (self, namespaceURI, tagFilter=None): + """Retrieve all descendant ElementWrapper object of current node whose tag name match 'namespaceURI' and 'tagFilter'. + + Input parameter: + namespaceURI: the namespace URI of the descendants or None + tagFilter: retrieve only the descendants with this localName ('*' or None returns all descendants) + Returns all descendants of this element node which match 'namespaceURI' and 'tagFilter' (list) + """ + return self.getElementsByTagName((namespaceURI, tagFilter)) + + + def getIterator (self, tagFilter=None): + """Creates a tree iterator. The iterator loops over this element + and all subelements, in document order, and returns all elements + whose tag name match 'tagFilter'. + + Input parameter: + tagFilter: retrieve only the children with this tag name ('*' or None returns all descendants) + Returns all element nodes which match 'tagFilter' (list) + """ + if tagFilter in (None, '*', (None, '*'), (None, None)): + matchingElements = self.element.xmlIfExtGetIterator() + elif tagFilter[1] == '*': + # handle (namespace, '*') + matchingElements = filter(lambda desc:desc.xmlIfExtElementWrapper.getNamespaceURI() == tagFilter[0], + self.element.xmlIfExtGetIterator()) + else: + nsNameFilter = NsNameTupleFactory(tagFilter) + matchingElements = self.element.xmlIfExtGetIterator(nsNameFilter) + + return map(lambda e: e.xmlIfExtElementWrapper, matchingElements) + + + def appendChild (self, tupleOrLocalNameOrElement, attributeDict={}): + """Append an element node to the children of the current node. + + Input parameter: + tupleOrLocalNameOrElement: (namespace, localName) or tagName or ElementWrapper object of the new child + attributeDict: attribute dictionary containing the attributes of the new child (optional) + If not an ElementWrapper object is given, a new ElementWrapper object is created with tupleOrLocalName + Returns the ElementWrapper object of the new child. + """ + if not isinstance(tupleOrLocalNameOrElement, self.__class__): + childElementWrapper = self.__createElement (tupleOrLocalNameOrElement, attributeDict) + else: + childElementWrapper = tupleOrLocalNameOrElement + self.element.xmlIfExtAppendChild (childElementWrapper.element) + self.__clearChildrenCache(childElementWrapper.getNsName()) + return childElementWrapper + + + def insertBefore (self, tupleOrLocalNameOrElement, refChild, attributeDict={}): + """Insert an child element node before the given reference child of the current node. + + Input parameter: + tupleOrLocalNameOrElement: (namespace, localName) or tagName or ElementWrapper object of the new child + refChild: reference child ElementWrapper object + attributeDict: attribute dictionary containing the attributes of the new child (optional) + If not an ElementWrapper object is given, a new ElementWrapper object is created with tupleOrLocalName + Returns the ElementWrapper object of the new child. + """ + if not isinstance(tupleOrLocalNameOrElement, self.__class__): + childElementWrapper = self.__createElement (tupleOrLocalNameOrElement, attributeDict) + else: + childElementWrapper = tupleOrLocalNameOrElement + if refChild == None: + self.appendChild (childElementWrapper) + else: + self.element.xmlIfExtInsertBefore(childElementWrapper.element, refChild.element) + self.__clearChildrenCache(childElementWrapper.getNsName()) + return childElementWrapper + + + def removeChild (self, childElementWrapper): + """Remove the given child element node from the children of the current node. + + Input parameter: + childElementWrapper: ElementWrapper object to be removed + """ + self.element.xmlIfExtRemoveChild(childElementWrapper.element) + self.__clearChildrenCache(childElementWrapper.getNsName()) + + + def insertSubtree (self, refChildWrapper, subTreeWrapper, insertSubTreeRootNode=1): + """Insert the given subtree before 'refChildWrapper' ('refChildWrapper' is not removed!) + + Input parameter: + refChildWrapper: reference child ElementWrapper object + subTreeWrapper: subtree wrapper object which contains the subtree to be inserted + insertSubTreeRootNode: if 1, root node of subtree is inserted into parent tree, otherwise not + """ + if refChildWrapper != None: + self.element.xmlIfExtInsertSubtree (refChildWrapper.element, subTreeWrapper.getTree(), insertSubTreeRootNode) + else: + self.element.xmlIfExtInsertSubtree (None, subTreeWrapper.getTree(), insertSubTreeRootNode) + self.__clearChildrenCache() + + + + def replaceChildBySubtree (self, childElementWrapper, subTreeWrapper, insertSubTreeRootNode=1): + """Replace child element node by XML subtree (e.g. expanding included XML files) + + Input parameter: + childElementWrapper: ElementWrapper object to be replaced + subTreeWrapper: XML subtree wrapper object to be inserted + insertSubTreeRootNode: if 1, root node of subtree is inserted into parent tree, otherwise not + """ + self.insertSubtree (childElementWrapper, subTreeWrapper, insertSubTreeRootNode) + self.removeChild(childElementWrapper) + + +#++++++++++++ methods concerning the attributes of the current node ++++++++++++++++++++++++ + + def getAttributeDict (self): + """Retrieve a dictionary containing all attributes of the current element node. + + Returns a dictionary (copy) containing all attributes of the current element node. + """ + return self.element.xmlIfExtGetAttributeDict() + + + def getAttributeList (self): + """Retrieve a list containing all attributes of the current element node + in the sequence specified in the input XML file. + + Returns a list (copy) containing all attributes of the current element node + in the sequence specified in the input XML file (TODO: does currently not work for 4DOM/pyXML interface). + """ + attrList = map(lambda a: NsNameTupleFactory(a), self.attributeSequence) + return attrList + + + def getAttribute (self, tupleOrAttrName): + """Retrieve an attribute value of the current element node. + + Input parameter: + tupleOrAttrName: tuple '(namespace, attributeName)' or 'attributeName' if no namespace is used + Returns the value of the specified attribute. + """ + nsName = NsNameTupleFactory(tupleOrAttrName) + return self.element.xmlIfExtGetAttribute(nsName) + + + def getAttributeOrDefault (self, tupleOrAttrName, defaultValue): + """Retrieve an attribute value of the current element node or the given default value if the attribute doesn't exist. + + Input parameter: + tupleOrAttrName: tuple '(namespace, attributeName)' or 'attributeName' if no namespace is used + Returns the value of the specified attribute or the given default value if the attribute doesn't exist. + """ + attributeValue = self.getAttribute (tupleOrAttrName) + if attributeValue == None: + attributeValue = defaultValue + return attributeValue + + + def getQNameAttribute (self, tupleOrAttrName): + """Retrieve a QName attribute value of the current element node. + + Input parameter: + tupleOrAttrName: tuple '(namespace, attributeName)' or 'attributeName' if no namespace is used + Returns the value of the specified QName attribute as tuple (namespace, localName), + i.e. the prefix is converted into the corresponding namespace value. + """ + nsNameAttrName = NsNameTupleFactory(tupleOrAttrName) + try: + return self.__qNameAttrCache[nsNameAttrName] + except: + qNameValue = self.getAttribute (nsNameAttrName) + nsNameValue = self.qName2NsName(qNameValue, useDefaultNs=1) + if self.__useCaching(): + self.__qNameAttrCache[nsNameAttrName] = nsNameValue + return nsNameValue + + + def hasAttribute (self, tupleOrAttrName): + """Checks if the requested attribute exist for the current element node. + + Returns 1 if the attribute exists, otherwise 0. + """ + nsName = NsNameTupleFactory(tupleOrAttrName) + attrValue = self.element.xmlIfExtGetAttribute(nsName) + if attrValue != None: + return 1 + else: + return 0 + + + def setAttribute (self, tupleOrAttrName, attributeValue): + """Sets an attribute value of the current element node. + If the attribute does not yet exist, it will be created. + + Input parameter: + tupleOrAttrName: tuple '(namespace, attributeName)' or 'attributeName' if no namespace is used + attributeValue: attribute value to be set + """ + if not isinstance(attributeValue, StringTypes): + raise TypeError, "%s (attribute %s) must be a string!" %(repr(attributeValue), repr(tupleOrAttrName)) + + nsNameAttrName = NsNameTupleFactory(tupleOrAttrName) + if nsNameAttrName not in self.attributeSequence: + self.attributeSequence.append(nsNameAttrName) + + if self.__useCaching(): + if self.__qNameAttrCache.has_key(nsNameAttrName): + del self.__qNameAttrCache[nsNameAttrName] + + self.element.xmlIfExtSetAttribute(nsNameAttrName, attributeValue, self.getCurrentNamespaces()) + + + def setAttributeDefault (self, tupleOrAttrName, defaultValue): + """Create attribute and set value to default if it does not yet exist for the current element node. + If the attribute is already existing nothing is done. + + Input parameter: + tupleOrAttrName: tuple '(namespace, attributeName)' or 'attributeName' if no namespace is used + defaultValue: default attribute value to be set + """ + if not self.hasAttribute(tupleOrAttrName): + self.setAttribute(tupleOrAttrName, defaultValue) + + + def removeAttribute (self, tupleOrAttrName): + """Removes an attribute from the current element node. + No exception is raised if there is no matching attribute. + + Input parameter: + tupleOrAttrName: tuple '(namespace, attributeName)' or 'attributeName' if no namespace is used + """ + nsNameAttrName = NsNameTupleFactory(tupleOrAttrName) + + if self.__useCaching(): + if self.__qNameAttrCache.has_key(nsNameAttrName): + del self.__qNameAttrCache[nsNameAttrName] + + self.element.xmlIfExtRemoveAttribute(nsNameAttrName) + + + def processWsAttribute (self, tupleOrAttrName, wsAction): + """Process white space action for the specified attribute according to requested 'wsAction'. + + Input parameter: + tupleOrAttrName: tuple '(namespace, attributeName)' or 'attributeName' if no namespace is used + wsAction: 'collapse': substitute multiple whitespace characters by a single ' ' + 'replace': substitute each whitespace characters by a single ' ' + """ + attributeValue = self.getAttribute(tupleOrAttrName) + newValue = processWhitespaceAction (attributeValue, wsAction) + if newValue != attributeValue: + self.setAttribute(tupleOrAttrName, newValue) + return newValue + + +#++++++++++++ methods concerning the content of the current node ++++++++++++++++++++++++ + + def getElementValue (self, ignoreEmtpyStringFragments=0): + """Retrieve the content of the current element node. + + Returns the content of the current element node as string. + The content of multiple text nodes / CDATA nodes are concatenated to one string. + + Input parameter: + ignoreEmtpyStringFragments: if 1, text nodes containing only whitespaces are ignored + """ + return "".join (self.getElementValueFragments(ignoreEmtpyStringFragments)) + + + def getElementValueFragments (self, ignoreEmtpyStringFragments=0): + """Retrieve the content of the current element node as value fragment list. + + Returns the content of the current element node as list of string fragments. + Each list element represents one text nodes / CDATA node. + + Input parameter: + ignoreEmtpyStringFragments: if 1, text nodes containing only whitespaces are ignored + + Method has to be implemented by derived classes! + """ + return self.element.xmlIfExtGetElementValueFragments (ignoreEmtpyStringFragments) + + + def setElementValue (self, elementValue): + """Set the content of the current element node. + + Input parameter: + elementValue: string containing the new element value + If multiple text nodes / CDATA nodes are existing, 'elementValue' is set + for the first text node / CDATA node. All other text nodes /CDATA nodes are set to ''. + """ + self.element.xmlIfExtSetElementValue(elementValue) + + + def processWsElementValue (self, wsAction): + """Process white space action for the content of the current element node according to requested 'wsAction'. + + Input parameter: + wsAction: 'collapse': substitute multiple whitespace characters by a single ' ' + 'replace': substitute each whitespace characters by a single ' ' + """ + self.element.xmlIfExtProcessWsElementValue(wsAction) + return self.getElementValue() + + +#++++++++++++ methods concerning the info about the current node in the XML file ++++++++++++++++++++ + + + def getStartLineNumber (self): + """Retrieve the start line number of the current element node. + + Returns the start line number of the current element node in the XML file + """ + return self.startLineNumber + + + def getEndLineNumber (self): + """Retrieve the end line number of the current element node. + + Returns the end line number of the current element node in the XML file + """ + return self.endLineNumber + + + def getAbsUrl (self): + """Retrieve the absolute URL of the XML file the current element node belongs to. + + Returns the absolute URL of the XML file the current element node belongs to. + """ + return self.absUrl + + + def getBaseUrl (self): + """Retrieve the base URL of the XML file the current element node belongs to. + + Returns the base URL of the XML file the current element node belongs to. + """ + return self.baseUrl + + + def getFilePath (self): + """Retrieve the file path of the XML file the current element node belongs to. + + Returns the file path of the XML file the current element node belongs to. + """ + return self.filePath + + + def getLocation (self, end=0, fullpath=0): + """Retrieve a string containing file name and line number of the current element node. + + Input parameter: + end: 1 if end line number shall be shown, 0 for start line number + fullpath: 1 if the full path of the XML file shall be shown, 0 for only the file name + Returns a string containing file name and line number of the current element node. + (e.g. to be used for traces or error messages) + """ + lineMethod = (self.getStartLineNumber, self.getEndLineNumber) + pathFunc = (os.path.basename, os.path.abspath) + return "%s, %d" % (pathFunc[fullpath](self.getFilePath()), lineMethod[end]()) + + +#++++++++++++ miscellaneous methods concerning namespaces ++++++++++++++++++++ + + + def getCurrentNamespaces (self): + """Retrieve the namespace prefixes visible for the current element node + + Returns a list of the namespace prefixes visible for the current node. + """ + return self.curNs + + + def qName2NsName (self, qName, useDefaultNs): + """Convert a qName 'prefix:localName' to a tuple '(namespace, localName)'. + + Input parameter: + qName: qName to be converted + useDefaultNs: 1 if default namespace shall be used + Returns the corresponding tuple '(namespace, localName)' for 'qName'. + """ + if qName != None: + qNamePrefix, qNameLocalName = splitQName (qName) + for prefix, namespaceURI in self.getCurrentNamespaces(): + if qNamePrefix == prefix: + if prefix != EMPTY_PREFIX or useDefaultNs: + nsName = (namespaceURI, qNameLocalName) + break + else: + if qNamePrefix == None: + nsName = (EMPTY_NAMESPACE, qNameLocalName) + else: + raise ValueError, "Namespace prefix '%s' not bound to a namespace!" % (qNamePrefix) + else: + nsName = (None, None) + return NsNameTupleFactory(nsName) + + + def nsName2QName (self, nsLocalName): + """Convert a tuple '(namespace, localName)' to a string 'prefix:localName' + + Input parameter: + nsLocalName: tuple '(namespace, localName)' to be converted + Returns the corresponding string 'prefix:localName' for 'nsLocalName'. + """ + qName = nsNameToQName (nsLocalName, self.getCurrentNamespaces()) + if qName == "xmlns:None": qName = "xmlns" + return qName + + + def getNamespace (self, qName): + """Retrieve namespace for a qName 'prefix:localName'. + + Input parameter: + qName: qName 'prefix:localName' + Returns the corresponding namespace for the prefix of 'qName'. + """ + if qName != None: + qNamePrefix, qNameLocalName = splitQName (qName) + for prefix, namespaceURI in self.getCurrentNamespaces(): + if qNamePrefix == prefix: + namespace = namespaceURI + break + else: + if qNamePrefix == None: + namespace = EMPTY_NAMESPACE + else: + raise LookupError, "Namespace for QName '%s' not found!" % (qName) + else: + namespace = EMPTY_NAMESPACE + return namespace + + + def getNsPrefix (self, nsLocalName): + """Retrieve prefix for a tuple '(namespace, localName)'. + + Input parameter: + nsLocalName: tuple '(namespace, localName)' + Returns the corresponding prefix for the namespace of 'nsLocalName'. + """ + ns = nsLocalName[0] + for prefix, namespace in self.getCurrentNamespaces(): + if ns == namespace: + return prefix + else: + if ns == None: + return None + else: + raise LookupError, "Prefix for namespaceURI '%s' not found!" % (ns) + + +#++++++++++++ limited XPath support ++++++++++++++++++++ + + def getXPath (self, xPath, namespaceRef=None, useDefaultNs=1, attrIgnoreList=[]): + """Retrieve node list or attribute list for specified XPath + + Input parameter: + xPath: string containing xPath specification + namespaceRef: scope for namespaces (default is own element node) + useDefaultNs: 1, if default namespace shall be used if no prefix is available + attrIgnoreList: list of attributes to be ignored if wildcard is specified for attributes + + Returns all nodes which match xPath specification or + list of attribute values if xPath specifies an attribute + """ + return self.getXPathList(xPath, namespaceRef, useDefaultNs, attrIgnoreList)[0] + + + def getXPathList (self, xPath, namespaceRef=None, useDefaultNs=1, attrIgnoreList=[]): + """Retrieve node list or attribute list for specified XPath + + Input parameter: + xPath: string containing xPath specification + namespaceRef: scope for namespaces (default is own element node) + useDefaultNs: 1, if default namespace shall be used if no prefix is available + attrIgnoreList: list of attributes to be ignored if wildcard is specified for attributes + + Returns tuple (completeChildList, attrNodeList, attrNsNameFirst). + completeChildList: contains all child node which match xPath specification or + list of attribute values if xPath specifies an attribute + attrNodeList: contains all child nodes where the specified attribute was found + attrNsNameFirst: contains the name of the first attribute which was found + TODO: Re-design namespace and attribute handling of this method + """ + reChild = re.compile('child *::') + reAttribute = re.compile('attribute *::') + if namespaceRef == None: namespaceRef = self + xPath = reChild.sub('./', xPath) + xPath = reAttribute.sub('@', xPath) + xPathList = string.split (xPath, "|") + completeChildDict = {} + completeChildList = [] + attrNodeList = [] + attrNsNameFirst = None + for xRelPath in xPathList: + xRelPath = string.strip(xRelPath) + descendantOrSelf = 0 + if xRelPath[:3] == ".//": + descendantOrSelf = 1 + xRelPath = xRelPath[3:] + xPathLocalStepList = string.split (xRelPath, "/") + childList = [self, ] + for localStep in xPathLocalStepList: + localStep = string.strip(localStep) + stepChildList = [] + if localStep == "": + raise IOError ("Invalid xPath '%s'!" %(xRelPath)) + elif localStep == ".": + continue + elif localStep[0] == '@': + if len(localStep) == 1: + raise ValueError ("Attribute name is missing in xPath!") + if descendantOrSelf: + childList = self.getElementsByTagName() + attrName = localStep[1:] + for childNode in childList: + if attrName == '*': + attrNodeList.append (childNode) + attrDict = childNode.getAttributeDict() + for attrIgnore in attrIgnoreList: + if attrDict.has_key(attrIgnore): + del attrDict[attrIgnore] + stepChildList.extend(attrDict.values()) + try: + attrNsNameFirst = attrDict.keys()[0] + except: + pass + else: + attrNsName = namespaceRef.qName2NsName (attrName, useDefaultNs=0) + if attrNsName[1] == '*': + for attr in childNode.getAttributeDict().keys(): + if attr[0] == attrNsName[0]: + if attrNodeList == []: + attrNsNameFirst = attrNsName + attrNodeList.append (childNode) + stepChildList.append (childNode.getAttribute(attr)) + elif childNode.hasAttribute(attrNsName): + if attrNodeList == []: + attrNsNameFirst = attrNsName + attrNodeList.append (childNode) + stepChildList.append (childNode.getAttribute(attrNsName)) + childList = stepChildList + else: + nsLocalName = namespaceRef.qName2NsName (localStep, useDefaultNs=useDefaultNs) + if descendantOrSelf: + descendantOrSelf = 0 + if localStep == "*": + stepChildList = self.getElementsByTagName() + else: + stepChildList = self.getElementsByTagName(nsLocalName) + else: + for childNode in childList: + if localStep == "*": + stepChildList.extend (childNode.getChildren()) + else: + stepChildList.extend (childNode.getChildrenNS(nsLocalName[0], nsLocalName[1])) + childList = stepChildList + # filter duplicated childs + for child in childList: + try: + childKey = child.element + except: + childKey = child + if not completeChildDict.has_key(childKey): + completeChildList.append(child) + completeChildDict[childKey] = 1 + return completeChildList, attrNodeList, attrNsNameFirst + + + ############################################################### + # PRIVATE methods + ############################################################### + + def __createElement (self, tupleOrLocalName, attributeDict): + """Create a new ElementWrapper object. + + Input parameter: + tupleOrLocalName: tuple '(namespace, localName)' or 'localName' if no namespace is used + attributeDict: dictionary which contains the attributes and their values of the element node to be created + Returns the created ElementWrapper object + """ + childElementWrapper = self.treeWrapper.createElement (tupleOrLocalName, attributeDict, self.curNs[:]) # TODO: when to be adapted???) + childElementWrapper.element.xmlIfExtSetParentNode(self.element) + return childElementWrapper + + + def __updateAttrMaxLengthDict (self, attrMaxLengthDict): + """Update dictionary which contains the maximum length of node attributes. + + Used for pretty print to align the attributes of child nodes. + attrMaxLengthDict is in/out parameter. + """ + for attrName, attrValue in self.getAttributeDict().items(): + attrLength = len(attrValue) + if not attrMaxLengthDict.has_key(attrName): + attrMaxLengthDict[attrName] = attrLength + else: + attrMaxLengthDict[attrName] = max(attrMaxLengthDict[attrName], attrLength) + + + def __clearChildrenCache (self, childNsName=None): + """Clear children cache. + """ + if self.__useCaching(): + if childNsName != None: + if self.__childrenCache.has_key(childNsName): + del self.__childrenCache[childNsName] + if self.__firstChildCache.has_key(childNsName): + del self.__firstChildCache[childNsName] + else: + self.__childrenCache.clear() + self.__firstChildCache.clear() + + + def __useCaching(self): + return self.treeWrapper.useCaching() + + diff --git a/tools/generator/lib/genxmlif/xmlifBase.py b/tools/generator/lib/genxmlif/xmlifBase.py new file mode 100644 index 0000000..a66e23a --- /dev/null +++ b/tools/generator/lib/genxmlif/xmlifBase.py @@ -0,0 +1,130 @@ +# +# genxmlif, Release 0.9.0 +# file: xmlifbase.py +# +# XML interface base classes +# +# history: +# 2005-04-25 rl created +# 2006-08-18 rl some methods for XML schema validation support added +# 2007-05-25 rl performance optimization (caching) added, bugfixes for XPath handling +# 2007-07-04 rl complete re-design, API classes moved to xmlifApi.py +# +# Copyright (c) 2005-2008 by Roland Leuthe. All rights reserved. +# +# -------------------------------------------------------------------- +# The generic XML interface is +# +# Copyright (c) 2005-2008 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. +# -------------------------------------------------------------------- + +__author__ = "Roland Leuthe " +__date__ = "28 July 2008" +__version__ = "0.9" + +from xml.dom import XML_NAMESPACE, XMLNS_NAMESPACE +from xmlifUtils import NsNameTupleFactory, convertToAbsUrl + + + +######################################## +# XmlIf builder extension base class +# All not implemented methods have to be overloaded by the derived class!! +# + +class XmlIfBuilderExtensionBase: + """XmlIf builder extension base class. + + This class provides additional data (e.g. line numbers or caches) + for an element node which are stored in the element node object during parsing. + """ + + def __init__ (self, filePath, absUrl, treeWrapper, elementWrapperClass): + """Constructor for this class + + Input parameter: + filePath: contains the file path of the corresponding XML file + absUrl: contains the absolute URL of the corresponding XML file + """ + self.filePath = filePath + self.absUrl = absUrl + self.baseUrlStack = [absUrl, ] + self.treeWrapper = treeWrapper + self.elementWrapperClass = elementWrapperClass + + + def startElementHandler (self, curNode, startLineNumber, curNs, attributes=[]): + """Called by the XML parser at creation of an element node. + + Input parameter: + curNode: current element node + startLineNumber: first line number of the element tag in XML file + curNs: namespaces visible for this element node + attributes: list of attributes and their values for this element node + (same sequence as int he XML file) + """ + + elementWrapper = self.elementWrapperClass(curNode, self.treeWrapper, curNs, initAttrSeq=0) + + elementWrapper.baseUrl = self.__getBaseUrl(elementWrapper) + elementWrapper.absUrl = self.absUrl + elementWrapper.filePath = self.filePath + elementWrapper.startLineNumber = startLineNumber + elementWrapper.curNs.extend ([("xml", XML_NAMESPACE), ("xmlns", XMLNS_NAMESPACE)]) + + if attributes != []: + for i in range (0, len(attributes), 2): + elementWrapper.attributeSequence.append(attributes[i]) + else: + attrList = elementWrapper.getAttributeDict().keys() + attrList.sort() + elementWrapper.attributeSequence.extend (attrList) + + self.baseUrlStack.insert (0, elementWrapper.baseUrl) + + + def endElementHandler (self, curNode, endLineNumber): + """Called by the XML parser after creation of an element node. + + Input parameter: + curNode: current element node + endLineNumber: last line number of the element tag in XML file + """ + curNode.xmlIfExtElementWrapper.endLineNumber = endLineNumber + self.baseUrlStack.pop (0) + + + def __getBaseUrl (self, elementWrapper): + """Retrieve base URL for the given element node. + + Input parameter: + elementWrapper: wrapper of current element node + """ + nsNameBaseAttr = NsNameTupleFactory ((XML_NAMESPACE, "base")) + if elementWrapper.hasAttribute(nsNameBaseAttr): + return convertToAbsUrl (elementWrapper.getAttribute(nsNameBaseAttr), self.baseUrlStack[0]) + else: + return self.baseUrlStack[0] + diff --git a/tools/generator/lib/genxmlif/xmlifDom.py b/tools/generator/lib/genxmlif/xmlifDom.py new file mode 100644 index 0000000..01a0115 --- /dev/null +++ b/tools/generator/lib/genxmlif/xmlifDom.py @@ -0,0 +1,352 @@ +# +# genxmlif, Release 0.9.0 +# file: xmlifDom.py +# +# XML interface base class for Python DOM implementations +# +# history: +# 2005-04-25 rl created +# 2007-07-02 rl complete re-design, internal wrapper +# for DOM trees and elements introduced +# 2008-07-01 rl Limited support of XInclude added +# +# Copyright (c) 2005-2008 by Roland Leuthe. All rights reserved. +# +# -------------------------------------------------------------------- +# The generic XML interface is +# +# Copyright (c) 2005-2008 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 string +import copy +import urllib +from types import TupleType +from xml.dom import Node, getDOMImplementation, XMLNS_NAMESPACE +from ..genxmlif import XINC_NAMESPACE, GenXmlIfError +from xmlifUtils import nsNameToQName, processWhitespaceAction, collapseString, NsNameTupleFactory, convertToAbsUrl +from xmlifBase import XmlIfBuilderExtensionBase +from xmlifApi import XmlInterfaceBase + + +class XmlInterfaceDom (XmlInterfaceBase): + """Derived interface class for handling of DOM parsers. + + For description of the interface methods see xmlifbase.py. + """ + + def xInclude (self, elementWrapper, baseUrl, ownerDoc): + filePath = elementWrapper.getFilePath() + for childElementWrapper in elementWrapper.getChildren(): + line = childElementWrapper.getStartLineNumber() + if childElementWrapper.getNsName() == (XINC_NAMESPACE, "include"): + href = childElementWrapper["href"] + parse = childElementWrapper.getAttributeOrDefault ("parse", "xml") + encoding = childElementWrapper.getAttribute ("encoding") + if self.verbose: + print "Xinclude: %s" %href + try: + if parse == "xml": + subTreeWrapper = self.parse (href, baseUrl, ownerDoc) + elementWrapper.replaceChildBySubtree (childElementWrapper, subTreeWrapper) + elif parse == "text": + absUrl = convertToAbsUrl (href, baseUrl) + fp = urllib.urlopen (absUrl) + data = fp.read() + if encoding: + data = data.decode(encoding) + newTextNode = ownerDoc.xmlIfExtCreateTextNode(data) + elementWrapper.element.element.insertBefore (newTextNode, childElementWrapper.element.element) + elementWrapper.removeChild (childElementWrapper) + fp.close() + else: + raise GenXmlIfError, "%s: line %s: XIncludeError: Invalid 'parse' Attribut: '%s'" %(filePath, line, parse) + except IOError, errInst: + raise GenXmlIfError, "%s: line %s: IOError: %s" %(filePath, line, str(errInst)) + elif childElementWrapper.getNsName() == (XINC_NAMESPACE, "fallback"): + raise GenXmlIfError, "%s: line %s: XIncludeError: xi:fallback tag must be child of xi:include" %(filePath, line) + else: + self.xInclude(childElementWrapper, baseUrl, ownerDoc) + + + +class InternalDomTreeWrapper: + """Internal wrapper for a DOM Document class. + """ + def __init__ (self, document): + self.document = document + + def xmlIfExtGetRootNode (self): + domNode = self.document + if domNode.nodeType == Node.DOCUMENT_NODE: + return domNode.documentElement.xmlIfExtInternalWrapper + elif domNode.nodeType == Node.DOCUMENT_FRAGMENT_NODE: + for node in domNode.childNodes: + if node.nodeType == Node.ELEMENT_NODE: + return node.xmlIfExtInternalWrapper + else: + return None + else: + return None + + + def xmlIfExtCreateElement (self, nsName, attributeDict, curNs): + elementNode = self.document.createElementNS (nsName[0], nsName[1]) + intElementWrapper = self.internalElementWrapperClass(elementNode, self) + for attrName, attrValue in attributeDict.items(): + intElementWrapper.xmlIfExtSetAttribute (NsNameTupleFactory(attrName), attrValue, curNs) + return intElementWrapper + + + def xmlIfExtCreateTextNode (self, data): + return self.document.createTextNode(data) + + + def xmlIfExtImportNode (self, node): + return self.document.importNode (node, 0) + + + def xmlIfExtCloneTree (self, rootElementCopy): + domImpl = getDOMImplementation() +# documentCopy = domImpl.createDocument(rootElementCopy.xmlIfExtGetNamespaceURI(), rootElementCopy.xmlIfExtGetTagName(), None) + documentCopy = domImpl.createDocument(None, None, None) +# documentCopy = copy.copy(self.document) + documentCopy.documentElement = rootElementCopy.element + return self.__class__(documentCopy) + + + +######################################################### +# Internal Wrapper class for a Dom Element class + +class InternalDomElementWrapper: + """Internal Wrapper for a Dom Element class. + """ + + def __init__ (self, element, internalDomTreeWrapper): + self.element = element + element.xmlIfExtInternalWrapper = self + self.internalDomTreeWrapper = internalDomTreeWrapper + + + def xmlIfExtUnlink (self): + self.xmlIfExtElementWrapper = None + + + def xmlIfExtCloneNode (self): + nodeCopy = self.__class__(self.element.cloneNode(deep=0), self.internalDomTreeWrapper) + for childTextNode in self.__xmlIfExtGetChildTextNodes(): + childTextNodeCopy = childTextNode.cloneNode(0) + nodeCopy.element.appendChild (childTextNodeCopy) +# for nsAttrName, attrValue in self.xmlIfExtGetAttributeDict().items(): +# nodeCopy.xmlIfExtSetAttribute(nsAttrName, attrValue, self.xmlIfExtElementWrapper.getCurrentNamespaces()) + return nodeCopy + + + def xmlIfExtGetTagName (self): + return self.element.tagName + + + def xmlIfExtGetNamespaceURI (self): + return self.element.namespaceURI + + + def xmlIfExtGetParentNode (self): + parentNode = self.element.parentNode + if parentNode.nodeType == Node.ELEMENT_NODE: + return self.element.parentNode.xmlIfExtInternalWrapper + else: + return None + + + def xmlIfExtSetParentNode (self, parentElement): + pass # nothing to do since parent is provided by DOM interface + + + def xmlIfExtGetChildren (self, tagFilter=None): + # TODO: Handle also wildcard tagFilter = (namespace, None) + children = filter (lambda e: (e.nodeType == Node.ELEMENT_NODE) and # - only ELEMENTs + (tagFilter == None or + (e.namespaceURI == tagFilter[0] and e.localName == tagFilter[1])), # - if tagFilter given --> check + self.element.childNodes ) # from element's nodes + + return map(lambda element: element.xmlIfExtInternalWrapper, children) + + + def xmlIfExtGetFirstChild (self, tagFilter=None): + children = self.xmlIfExtGetChildren (tagFilter) + if children != []: + return children[0] + else: + None + + + def xmlIfExtGetElementsByTagName (self, tagFilter=('*','*')): + elementList = self.element.getElementsByTagNameNS( tagFilter[0], tagFilter[1] ) + return map( lambda element: element.xmlIfExtInternalWrapper, elementList ) + + + def xmlIfExtGetIterator (self, tagFilter=('*','*')): + elementList = [] + if tagFilter in (('*','*'), (self.element.namespaceURI, self.element.localName)): + elementList.append(self.element) + elementList.extend(self.element.getElementsByTagNameNS( tagFilter[0], tagFilter[1] )) + return map( lambda element: element.xmlIfExtInternalWrapper, elementList ) + + + def xmlIfExtAppendChild (self, childElement): + self.element.appendChild (childElement.element) + + + def xmlIfExtInsertBefore (self, childElement, refChildElement): + self.element.insertBefore (childElement.element, refChildElement.element) + + + def xmlIfExtRemoveChild (self, childElement): + self.element.removeChild (childElement.element) + + + def xmlIfExtInsertSubtree (self, refChildElement, subTree, insertSubTreeRootNode): + if insertSubTreeRootNode: + childElementList = [subTree.xmlIfExtGetRootNode(),] + else: + childElementList = subTree.xmlIfExtGetRootNode().xmlIfExtGetChildren() + + for childElement in childElementList: + if refChildElement != None: + self.element.insertBefore(childElement.element, refChildElement.element) + else: + self.element.appendChild(childElement.element) + + + def xmlIfExtGetAttributeDict (self): + attribDict = {} + for nsAttrName, attrNodeOrValue in self.element.attributes.items(): + attribDict[NsNameTupleFactory(nsAttrName)] = attrNodeOrValue.nodeValue + return attribDict + + + def xmlIfExtGetAttribute (self, nsAttrName): + if self.element.attributes.has_key (nsAttrName): + return self.element.getAttributeNS (nsAttrName[0], nsAttrName[1]) + elif nsAttrName[1] == "xmlns" and self.element.attributes.has_key(nsAttrName[1]): + # workaround for minidom for correct access of xmlns attribute + return self.element.getAttribute (nsAttrName[1]) + else: + return None + + + def xmlIfExtSetAttribute (self, nsAttrName, attributeValue, curNs): + if nsAttrName[0] != None: + qName = nsNameToQName (nsAttrName, curNs) + else: + qName = nsAttrName[1] + + self.element.setAttributeNS (nsAttrName[0], qName, attributeValue) + + + def xmlIfExtRemoveAttribute (self, nsAttrName): + self.element.removeAttributeNS (nsAttrName[0], nsAttrName[1]) + + + def xmlIfExtGetElementValueFragments (self, ignoreEmtpyStringFragments): + elementValueList = [] + for childTextNode in self.__xmlIfExtGetChildTextNodes(): + elementValueList.append(childTextNode.data) + if ignoreEmtpyStringFragments: + elementValueList = filter (lambda s: collapseString(s) != "", elementValueList) + if elementValueList == []: + elementValueList = ["",] + return elementValueList + + + def xmlIfExtGetElementText (self): + elementTextList = ["",] + if self.element.childNodes != []: + for childNode in self.element.childNodes: + if childNode.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE): + elementTextList.append (childNode.data) + else: + break + return "".join(elementTextList) + + + def xmlIfExtGetElementTailText (self): + tailTextList = ["",] + nextSib = self.element.nextSibling + while nextSib: + if nextSib.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE): + tailTextList.append (nextSib.data) + nextSib = nextSib.nextSibling + else: + break + return "".join(tailTextList) + + + def xmlIfExtSetElementValue (self, elementValue): + if self.__xmlIfExtGetChildTextNodes() == []: + textNode = self.internalDomTreeWrapper.xmlIfExtCreateTextNode (elementValue) + self.element.appendChild (textNode) + else: + self.__xmlIfExtGetChildTextNodes()[0].data = elementValue + if len (self.__xmlIfExtGetChildTextNodes()) > 1: + for textNode in self.__xmlIfExtGetChildTextNodes()[1:]: + textNode.data = "" + + + def xmlIfExtProcessWsElementValue (self, wsAction): + textNodes = self.__xmlIfExtGetChildTextNodes() + + if len(textNodes) == 1: + textNodes[0].data = processWhitespaceAction (textNodes[0].data, wsAction) + elif len(textNodes) > 1: + textNodes[0].data = processWhitespaceAction (textNodes[0].data, wsAction, rstrip=0) + lstrip = 0 + if len(textNodes[0].data) > 0 and textNodes[0].data[-1] == " ": + lstrip = 1 + for textNode in textNodes[1:-1]: + textNode.data = processWhitespaceAction (textNode.data, wsAction, lstrip, rstrip=0) + if len(textNode.data) > 0 and textNode.data[-1] == " ": + lstrip = 1 + else: + lstrip = 0 + textNodes[-1].data = processWhitespaceAction (textNodes[-1].data, wsAction, lstrip) + + + ############################################################### + # PRIVATE methods + ############################################################### + + def __xmlIfExtGetChildTextNodes ( self ): + """Return list of TEXT nodes.""" + return filter (lambda e: ( e.nodeType in (Node.TEXT_NODE, Node.CDATA_SECTION_NODE) ), # - only TEXT-NODES + self.element.childNodes) # from element's child nodes + + + +class XmlIfBuilderExtensionDom (XmlIfBuilderExtensionBase): + """XmlIf builder extension class for DOM parsers.""" + + pass diff --git a/tools/generator/lib/genxmlif/xmlifElementTree.py b/tools/generator/lib/genxmlif/xmlifElementTree.py new file mode 100644 index 0000000..d7a2b37 --- /dev/null +++ b/tools/generator/lib/genxmlif/xmlifElementTree.py @@ -0,0 +1,407 @@ +# +# genxmlif, Release 0.9.0 +# file: xmlifElementTree.py +# +# XML interface class to elementtree toolkit by Fredrik Lundh +# +# history: +# 2005-04-25 rl created +# 2007-05-25 rl performance optimization (caching) added, some bugfixes +# 2007-06-29 rl complete re-design, ElementExtension class introduced +# 2008-07-01 rl Limited support of XInclude added +# +# Copyright (c) 2005-2008 by Roland Leuthe. All rights reserved. +# +# -------------------------------------------------------------------- +# The generic XML interface is +# +# Copyright (c) 2005-2008 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 sys +import string +import urllib +from xml.dom import EMPTY_NAMESPACE, XMLNS_NAMESPACE +from xml.parsers.expat import ExpatError +# from version 2.5 on the elementtree module is part of the standard python distribution +if sys.version_info[:2] >= (2,5): + from xml.etree.ElementTree import ElementTree, _ElementInterface, XMLTreeBuilder, TreeBuilder + from xml.etree import ElementInclude +else: + from elementtree.ElementTree import ElementTree, _ElementInterface, XMLTreeBuilder, TreeBuilder + from elementtree import ElementInclude +from ..genxmlif import XMLIF_ELEMENTTREE, GenXmlIfError +from xmlifUtils import convertToAbsUrl, processWhitespaceAction, collapseString, toClarkQName, splitQName +from xmlifBase import XmlIfBuilderExtensionBase +from xmlifApi import XmlInterfaceBase + +######################################################### +# Derived interface class for elementtree toolkit + +class XmlInterfaceElementTree (XmlInterfaceBase): + ##################################################### + # for description of the interface methods see xmlifbase.py + ##################################################### + + def __init__ (self, verbose, useCaching, processXInclude): + XmlInterfaceBase.__init__ (self, verbose, useCaching, processXInclude) + self.xmlIfType = XMLIF_ELEMENTTREE + if self.verbose: + print "Using elementtree interface module..." + + + def createXmlTree (self, namespace, xmlRootTagName, attributeDict={}, publicId=None, systemId=None): + rootNode = ElementExtension(toClarkQName(xmlRootTagName), attributeDict) + rootNode.xmlIfExtSetParentNode(None) + treeWrapper = self.treeWrapperClass(self, ElementTreeExtension(rootNode), self.useCaching) + rootNodeWrapper = self.elementWrapperClass (rootNode, treeWrapper, []) # TODO: namespace handling + return treeWrapper + + + def parse (self, file, baseUrl="", ownerDoc=None): + absUrl = convertToAbsUrl (file, baseUrl) + fp = urllib.urlopen (absUrl) + try: + tree = ElementTreeExtension() + treeWrapper = self.treeWrapperClass(self, tree, self.useCaching) + parser = ExtXMLTreeBuilder(file, absUrl, self, treeWrapper) + treeWrapper.getTree().parse(fp, parser) + fp.close() + + # XInclude support + if self.processXInclude: + loaderInst = ExtXIncludeLoader (self.parse, absUrl, ownerDoc) + try: + ElementInclude.include(treeWrapper.getTree().getroot(), loaderInst.loader) + except IOError, errInst: + raise GenXmlIfError, "%s: IOError: %s" %(file, str(errInst)) + + except ExpatError, errstr: + fp.close() + raise GenXmlIfError, "%s: ExpatError: %s" %(file, str(errstr)) + except ElementInclude.FatalIncludeError, errInst: + fp.close() + raise GenXmlIfError, "%s: XIncludeError: %s" %(file, str(errInst)) + + return treeWrapper + + + def parseString (self, text, baseUrl="", ownerDoc=None): + absUrl = convertToAbsUrl ("", baseUrl) + tree = ElementTreeExtension() + treeWrapper = self.treeWrapperClass(self, tree, self.useCaching) + parser = ExtXMLTreeBuilder("", absUrl, self, treeWrapper) + parser.feed(text) + treeWrapper.getTree()._setroot(parser.close()) + + # XInclude support + if self.processXInclude: + loaderInst = ExtXIncludeLoader (self.parse, absUrl, ownerDoc) + ElementInclude.include(treeWrapper.getTree().getroot(), loaderInst.loader) + + return treeWrapper + + +######################################################### +# Extension (derived) class for ElementTree class + +class ElementTreeExtension (ElementTree): + + def xmlIfExtGetRootNode (self): + return self.getroot() + + + def xmlIfExtCreateElement (self, nsName, attributeDict, curNs): + clarkQName = toClarkQName(nsName) + return ElementExtension (clarkQName, attributeDict) + + + def xmlIfExtCloneTree (self, rootElementCopy): + return self.__class__(element=rootElementCopy) + + +######################################################### +# Wrapper class for Element class + +class ElementExtension (_ElementInterface): + + def __init__ (self, xmlRootTagName, attributeDict): + _ElementInterface.__init__(self, xmlRootTagName, attributeDict) + + + def xmlIfExtUnlink (self): + self.xmlIfExtElementWrapper = None + self.__xmlIfExtParentElement = None + + + def xmlIfExtCloneNode (self): + nodeCopy = self.__class__(self.tag, self.attrib.copy()) + nodeCopy.text = self.text + nodeCopy.tail = self.tail + return nodeCopy + + + def xmlIfExtGetTagName (self): + return self.tag + + + def xmlIfExtGetNamespaceURI (self): + prefix, localName = splitQName(self.tag) + return prefix + + + def xmlIfExtGetParentNode (self): + return self.__xmlIfExtParentElement + + + def xmlIfExtSetParentNode (self, parentElement): + self.__xmlIfExtParentElement = parentElement + + + def xmlIfExtGetChildren (self, filterTag=None): + if filterTag == None: + return self.getchildren() + else: + clarkFilterTag = toClarkQName(filterTag) + return self.findall(clarkFilterTag) + + + def xmlIfExtGetFirstChild (self, filterTag=None): + # replace base method (performance optimized) + if filterTag == None: + children = self.getchildren() + if children != []: + element = children[0] + else: + element = None + else: + clarkFilterTag = toClarkQName(filterTag) + element = self.find(clarkFilterTag) + + return element + + + def xmlIfExtGetElementsByTagName (self, filterTag=(None,None)): + clarkFilterTag = toClarkQName(filterTag) + descendants = [] + for node in self.xmlIfExtGetChildren(): + descendants.extend(node.getiterator(clarkFilterTag)) + return descendants + + + def xmlIfExtGetIterator (self, filterTag=(None,None)): + clarkFilterTag = toClarkQName(filterTag) + return self.getiterator (clarkFilterTag) + + + def xmlIfExtAppendChild (self, childElement): + self.append (childElement) + childElement.xmlIfExtSetParentNode(self) + + + def xmlIfExtInsertBefore (self, childElement, refChildElement): + self.insert (self.getchildren().index(refChildElement), childElement) + childElement.xmlIfExtSetParentNode(self) + + + def xmlIfExtRemoveChild (self, childElement): + self.remove (childElement) + + + def xmlIfExtInsertSubtree (self, refChildElement, subTree, insertSubTreeRootNode): + if refChildElement != None: + insertIndex = self.getchildren().index (refChildElement) + else: + insertIndex = 0 + if insertSubTreeRootNode: + elementList = [subTree.xmlIfExtGetRootNode(),] + else: + elementList = subTree.xmlIfExtGetRootNode().xmlIfExtGetChildren() + elementList.reverse() + for element in elementList: + self.insert (insertIndex, element) + element.xmlIfExtSetParentNode(self) + + + def xmlIfExtGetAttributeDict (self): + attrDict = {} + for attrName, attrValue in self.attrib.items(): + namespaceEndIndex = string.find (attrName, '}') + if namespaceEndIndex != -1: + attrName = (attrName[1:namespaceEndIndex], attrName[namespaceEndIndex+1:]) + else: + attrName = (EMPTY_NAMESPACE, attrName) + attrDict[attrName] = attrValue + return attrDict + + + def xmlIfExtGetAttribute (self, tupleOrAttrName): + clarkQName = toClarkQName(tupleOrAttrName) + if self.attrib.has_key(clarkQName): + return self.attrib[clarkQName] + else: + return None + + + def xmlIfExtSetAttribute (self, tupleOrAttrName, attributeValue, curNs): + self.attrib[toClarkQName(tupleOrAttrName)] = attributeValue + + + def xmlIfExtRemoveAttribute (self, tupleOrAttrName): + clarkQName = toClarkQName(tupleOrAttrName) + if self.attrib.has_key(clarkQName): + del self.attrib[clarkQName] + + + def xmlIfExtGetElementValueFragments (self, ignoreEmtpyStringFragments): + elementValueList = [] + if self.text != None: + elementValueList.append(self.text) + for child in self.getchildren(): + if child.tail != None: + elementValueList.append(child.tail) + if ignoreEmtpyStringFragments: + elementValueList = filter (lambda s: collapseString(s) != "", elementValueList) + if elementValueList == []: + elementValueList = ["",] + return elementValueList + + + def xmlIfExtGetElementText (self): + if self.text != None: + return self.text + else: + return "" + + + def xmlIfExtGetElementTailText (self): + if self.tail != None: + return self.tail + else: + return "" + + + def xmlIfExtSetElementValue (self, elementValue): + self.text = elementValue + for child in self.getchildren(): + child.tail = None + + + def xmlIfExtProcessWsElementValue (self, wsAction): + noOfTextFragments = reduce(lambda sum, child: sum + (child.tail != None), self.getchildren(), 0) + noOfTextFragments += (self.text != None) + + rstrip = 0 + lstrip = 1 + if self.text != None: + if noOfTextFragments == 1: + rstrip = 1 + self.text = processWhitespaceAction (self.text, wsAction, lstrip, rstrip) + noOfTextFragments -= 1 + lstrip = 0 + for child in self.getchildren(): + if child.tail != None: + if noOfTextFragments == 1: + rstrip = 1 + child.tail = processWhitespaceAction (child.tail, wsAction, lstrip, rstrip) + noOfTextFragments -= 1 + lstrip = 0 + + +################################################### +# Element tree builder class derived from XMLTreeBuilder +# extended to store related line numbers in the Element object + +class ExtXMLTreeBuilder (XMLTreeBuilder, XmlIfBuilderExtensionBase): + def __init__(self, filePath, absUrl, xmlIf, treeWrapper): + XMLTreeBuilder.__init__(self, target=TreeBuilder(element_factory=ElementExtension)) + self._parser.StartNamespaceDeclHandler = self._start_ns + self._parser.EndNamespaceDeclHandler = self._end_ns + self.namespaces = [] + XmlIfBuilderExtensionBase.__init__(self, filePath, absUrl, treeWrapper, xmlIf.elementWrapperClass) + + def _start(self, tag, attrib_in): + elem = XMLTreeBuilder._start(self, tag, attrib_in) + self.start(elem) + + def _start_list(self, tag, attrib_in): + elem = XMLTreeBuilder._start_list(self, tag, attrib_in) + self.start(elem, attrib_in) + + def _end(self, tag): + elem = XMLTreeBuilder._end(self, tag) + self.end(elem) + + def _start_ns(self, prefix, value): + self.namespaces.insert(0, (prefix, value)) + + def _end_ns(self, prefix): + assert self.namespaces.pop(0)[0] == prefix, "implementation confused" + + + def start(self, element, attributes): + # bugfix for missing start '{' + for i in range (0, len(attributes), 2): + attrName = attributes[i] + namespaceEndIndex = string.find (attrName, '}') + if namespaceEndIndex != -1 and attrName[0] != "{": + attributes[i] = '{' + attributes[i] + # bugfix end + + XmlIfBuilderExtensionBase.startElementHandler (self, element, self._parser.ErrorLineNumber, self.namespaces[:], attributes) + if len(self._target._elem) > 1: + element.xmlIfExtSetParentNode (self._target._elem[-2]) + else: + for namespace in self.namespaces: + if namespace[1] != None: + element.xmlIfExtElementWrapper.setAttribute((XMLNS_NAMESPACE, namespace[0]), namespace[1]) + + + def end(self, element): + XmlIfBuilderExtensionBase.endElementHandler (self, element, self._parser.ErrorLineNumber) + + +################################################### +# XInclude loader +# + +class ExtXIncludeLoader: + + def __init__(self, parser, baseUrl, ownerDoc): + self.parser = parser + self.baseUrl = baseUrl + self.ownerDoc = ownerDoc + + def loader(self, href, parse, encoding=None): + if parse == "xml": + data = self.parser(href, self.baseUrl, self.ownerDoc).getTree().getroot() + else: + absUrl = convertToAbsUrl (href, self.baseUrl) + fp = urllib.urlopen (absUrl) + data = fp.read() + if encoding: + data = data.decode(encoding) + fp.close() + return data diff --git a/tools/generator/lib/genxmlif/xmlifMinidom.py b/tools/generator/lib/genxmlif/xmlifMinidom.py new file mode 100644 index 0000000..c2f9847 --- /dev/null +++ b/tools/generator/lib/genxmlif/xmlifMinidom.py @@ -0,0 +1,198 @@ +# +# genxmlif, Release 0.9.0 +# file: xmlifMinidom.py +# +# XML interface class to Python standard minidom +# +# history: +# 2005-04-25 rl created +# 2007-07-02 rl complete re-design, internal wrapper +# for DOM trees and elements introduced +# 2008-07-01 rl Limited support of XInclude added +# +# Copyright (c) 2005-2008 by Roland Leuthe. All rights reserved. +# +# -------------------------------------------------------------------- +# The generix XML interface is +# +# Copyright (c) 2005-2008 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 string +import urllib +from xml.dom import Node, XMLNS_NAMESPACE +from xml.dom.expatbuilder import ExpatBuilderNS +from xml.parsers.expat import ExpatError +from ..genxmlif import XMLIF_MINIDOM, GenXmlIfError +from xmlifUtils import convertToAbsUrl, NsNameTupleFactory +from xmlifDom import XmlInterfaceDom, InternalDomTreeWrapper, InternalDomElementWrapper, XmlIfBuilderExtensionDom + + +class XmlInterfaceMinidom (XmlInterfaceDom): + """Derived interface class for handling of minidom parser. + + For description of the interface methods see xmlifbase.py. + """ + + def __init__ (self, verbose, useCaching, processXInclude): + XmlInterfaceDom.__init__ (self, verbose, useCaching, processXInclude) + self.xmlIfType = XMLIF_MINIDOM + if self.verbose: + print "Using minidom interface module..." + + + def createXmlTree (self, namespace, xmlRootTagName, attributeDict={}, publicId=None, systemId=None): + from xml.dom.minidom import getDOMImplementation + domImpl = getDOMImplementation() + doctype = domImpl.createDocumentType(xmlRootTagName, publicId, systemId) + domTree = domImpl.createDocument(namespace, xmlRootTagName, doctype) + treeWrapper = self.treeWrapperClass(self, InternalMinidomTreeWrapper(domTree), self.useCaching) + + intRootNodeWrapper = InternalMinidomElementWrapper(domTree.documentElement, treeWrapper.getTree()) + rootNodeWrapper = self.elementWrapperClass (intRootNodeWrapper, treeWrapper, []) # TODO: namespace handling + for attrName, attrValue in attributeDict.items(): + rootNodeWrapper.setAttribute (attrName, attrValue) + + return treeWrapper + + + def parse (self, file, baseUrl="", internalOwnerDoc=None): + absUrl = convertToAbsUrl(file, baseUrl) + fp = urllib.urlopen (absUrl) + try: + builder = ExtExpatBuilderNS(file, absUrl, self) + tree = builder.parseFile(fp) + + # XInclude support + if self.processXInclude: + if internalOwnerDoc == None: + internalOwnerDoc = builder.treeWrapper.getTree() + self.xInclude (builder.treeWrapper.getRootNode(), absUrl, internalOwnerDoc) + + fp.close() + except ExpatError, errInst: + fp.close() + raise GenXmlIfError, "%s: ExpatError: %s" %(file, str(errInst)) + + return builder.treeWrapper + + + def parseString (self, text, baseUrl="", internalOwnerDoc=None): + absUrl = convertToAbsUrl ("", baseUrl) + try: + builder = ExtExpatBuilderNS("", absUrl, self) + builder.parseString (text) + + # XInclude support + if self.processXInclude: + if internalOwnerDoc == None: + internalOwnerDoc = builder.treeWrapper.getTree() + self.xInclude (builder.treeWrapper.getRootNode(), absUrl, internalOwnerDoc) + except ExpatError, errInst: + raise GenXmlIfError, "%s: ExpatError: %s" %(baseUrl, str(errInst)) + + return builder.treeWrapper + + + +class InternalMinidomTreeWrapper (InternalDomTreeWrapper): + """Internal wrapper for a minidom Document class. + """ + + def __init__ (self, document): + InternalDomTreeWrapper.__init__(self, document) + self.internalElementWrapperClass = InternalMinidomElementWrapper + + + +class InternalMinidomElementWrapper (InternalDomElementWrapper): + """Internal Wrapper for a Dom Element class. + """ + + def xmlIfExtGetAttributeDict (self): + """Return a dictionary with all attributes of this element.""" + attribDict = {} + for attrNameNS, attrNodeOrValue in self.element.attributes.itemsNS(): + attribDict[NsNameTupleFactory(attrNameNS)] = attrNodeOrValue + + return attribDict + + + +class ExtExpatBuilderNS (ExpatBuilderNS, XmlIfBuilderExtensionDom): + """Extended Expat Builder class derived from ExpatBuilderNS. + + Extended to store related line numbers, file/URL names and + defined namespaces in the node object. + """ + + def __init__ (self, filePath, absUrl, xmlIf): + ExpatBuilderNS.__init__(self) + internalMinidomTreeWrapper = InternalMinidomTreeWrapper(self.document) + self.treeWrapper = xmlIf.treeWrapperClass(self, internalMinidomTreeWrapper, xmlIf.useCaching) + XmlIfBuilderExtensionDom.__init__(self, filePath, absUrl, self.treeWrapper, xmlIf.elementWrapperClass) + + # set EndNamespaceDeclHandler, currently not used by minidom + self.getParser().EndNamespaceDeclHandler = self.end_namespace_decl_handler + self.curNamespaces = [] + + + def start_element_handler(self, name, attributes): + ExpatBuilderNS.start_element_handler(self, name, attributes) + + # use attribute format {namespace}localName + attrList = [] + for i in range (0, len(attributes), 2): + attrName = attributes[i] + attrNameSplit = string.split(attrName, " ") + if len(attrNameSplit) > 1: + attrName = (attrNameSplit[0], attrNameSplit[1]) + attrList.extend([attrName, attributes[i+1]]) + + internalMinidomElementWrapper = InternalMinidomElementWrapper(self.curNode, self.treeWrapper.getTree()) + XmlIfBuilderExtensionDom.startElementHandler (self, internalMinidomElementWrapper, self.getParser().ErrorLineNumber, self.curNamespaces[:], attrList) + + if self.curNode.parentNode.nodeType == Node.DOCUMENT_NODE: + for namespace in self.curNamespaces: + if namespace[0] != None: + internalMinidomElementWrapper.xmlIfExtElementWrapper.attributeSequence.append((XMLNS_NAMESPACE, namespace[0])) + else: + internalMinidomElementWrapper.xmlIfExtElementWrapper.attributeSequence.append("xmlns") +# internalMinidomElementWrapper.xmlIfExtElementWrapper.setAttribute((XMLNS_NAMESPACE, namespace[0]), namespace[1]) + + + def end_element_handler(self, name): + XmlIfBuilderExtensionDom.endElementHandler (self, self.curNode.xmlIfExtInternalWrapper, self.getParser().ErrorLineNumber) + ExpatBuilderNS.end_element_handler(self, name) + + + def start_namespace_decl_handler(self, prefix, uri): + ExpatBuilderNS.start_namespace_decl_handler(self, prefix, uri) + self.curNamespaces.insert(0, (prefix, uri)) + + + def end_namespace_decl_handler(self, prefix): + assert self.curNamespaces.pop(0)[0] == prefix, "implementation confused" + diff --git a/tools/generator/lib/genxmlif/xmlifODict.py b/tools/generator/lib/genxmlif/xmlifODict.py new file mode 100644 index 0000000..12521f7 --- /dev/null +++ b/tools/generator/lib/genxmlif/xmlifODict.py @@ -0,0 +1,57 @@ +from types import DictType +from UserDict import UserDict + +class odict(UserDict): + def __init__(self, dictOrTuple = None): + self._keys = [] + UserDict.__init__(self, dictOrTuple) + + def __delitem__(self, key): + UserDict.__delitem__(self, key) + self._keys.remove(key) + + def __setitem__(self, key, item): + UserDict.__setitem__(self, key, item) + if key not in self._keys: self._keys.append(key) + + def clear(self): + UserDict.clear(self) + self._keys = [] + + def copy(self): + newInstance = odict() + newInstance.update(self) + return newInstance + + def items(self): + return zip(self._keys, self.values()) + + def keys(self): + return self._keys[:] + + def popitem(self): + try: + key = self._keys[-1] + except IndexError: + raise KeyError('dictionary is empty') + + val = self[key] + del self[key] + + return (key, val) + + def setdefault(self, key, failobj = None): + if key not in self._keys: + self._keys.append(key) + return UserDict.setdefault(self, key, failobj) + + def update(self, dictOrTuple): + if isinstance(dictOrTuple, DictType): + itemList = dictOrTuple.items() + else: + itemList = dictOrTuple + for key, val in itemList: + self.__setitem__(key,val) + + def values(self): + return map(self.get, self._keys) \ No newline at end of file diff --git a/tools/generator/lib/genxmlif/xmlifUtils.py b/tools/generator/lib/genxmlif/xmlifUtils.py new file mode 100644 index 0000000..bce3242 --- /dev/null +++ b/tools/generator/lib/genxmlif/xmlifUtils.py @@ -0,0 +1,374 @@ +# +# genxmlif, Release 0.9.0 +# file: xmlifUtils.py +# +# utility module for genxmlif +# +# history: +# 2005-04-25 rl created +# 2008-08-01 rl encoding support added +# +# Copyright (c) 2005-2008 by Roland Leuthe. All rights reserved. +# +# -------------------------------------------------------------------- +# The generic XML interface is +# +# Copyright (c) 2005-2008 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 string +import re +import os +import urllib +import urlparse +from types import StringTypes, TupleType +from xml.dom import EMPTY_PREFIX, EMPTY_NAMESPACE + +###################################################################### +# DEFINITIONS +###################################################################### + +###################################################################### +# REGULAR EXPRESSION OBJECTS +###################################################################### + +_reWhitespace = re.compile('\s') +_reWhitespaces = re.compile('\s+') + +_reSplitUrlApplication = re.compile (r"(file|http|ftp|gopher):(.+)") # "file:///d:\test.xml" => "file" + "///d:\test.xml" + + +###################################################################### +# FUNCTIONS +###################################################################### + + +######################################## +# remove all whitespaces from a string +# +def removeWhitespaces (strValue): + return _reWhitespaces.sub('', strValue) + + +######################################## +# substitute multiple whitespace characters by a single ' ' +# +def collapseString (strValue, lstrip=1, rstrip=1): + collStr = _reWhitespaces.sub(' ', strValue) + if lstrip and rstrip: + return collStr.strip() + elif lstrip: + return collStr.lstrip() + elif rstrip: + return collStr.rstrip() + else: + return collStr + + + +######################################## +# substitute each whitespace characters by a single ' ' +# +def normalizeString (strValue): + return _reWhitespace.sub(' ', strValue) + + +######################################## +# process whitespace action +# +def processWhitespaceAction (strValue, wsAction, lstrip=1, rstrip=1): + if wsAction == "collapse": + return collapseString(strValue, lstrip, rstrip) + elif wsAction == "replace": + return normalizeString(strValue) + else: + return strValue + + +########################################################## +# convert input parameter 'fileOrUrl' into a valid URL + +def convertToUrl (fileOrUrl): + matchObject = _reSplitUrlApplication.match(fileOrUrl) + if matchObject: + # given fileOrUrl is an absolute URL + if matchObject.group(1) == 'file': + path = re.sub(':', '|', matchObject.group(2)) # replace ':' by '|' in the path string + url = "file:" + path + else: + url = fileOrUrl + elif not os.path.isfile(fileOrUrl): + # given fileOrUrl is treated as a relative URL + url = fileOrUrl + else: + # local filename +# url = "file:" + urllib.pathname2url (fileOrUrl) + url = urllib.pathname2url (fileOrUrl) + + return url + + +########################################################## +# convert input parameter 'fileOrUrl' into a valid absolute URL + +def convertToAbsUrl (fileOrUrl, baseUrl): + if fileOrUrl == "" and baseUrl != "": + absUrl = "file:" + urllib.pathname2url (os.path.join(os.getcwd(), baseUrl, "__NO_FILE__")) + elif os.path.isfile(fileOrUrl): + absUrl = "file:" + urllib.pathname2url (os.path.join(os.getcwd(), fileOrUrl)) + else: + matchObject = _reSplitUrlApplication.match(fileOrUrl) + if matchObject: + # given fileOrUrl is an absolute URL + if matchObject.group(1) == 'file': + path = re.sub(':', '|', matchObject.group(2)) # replace ':' by '|' in the path string + absUrl = "file:" + path + else: + absUrl = fileOrUrl + else: + # given fileOrUrl is treated as a relative URL + if baseUrl != "": + absUrl = urlparse.urljoin (baseUrl, fileOrUrl) + else: + absUrl = fileOrUrl +# raise IOError, "File %s not found!" %(fileOrUrl) + return absUrl + + +########################################################## +# normalize filter +def normalizeFilter (filterVar): + if filterVar == None or filterVar == '*': + filterVar = ("*",) + elif not isinstance(filterVar, TupleType): + filterVar = (filterVar,) + return filterVar + + +###################################################################### +# Namespace handling +###################################################################### + +def nsNameToQName (nsLocalName, curNs): + """Convert a tuple '(namespace, localName)' to a string 'prefix:localName' + + Input parameter: + nsLocalName: tuple '(namespace, localName)' to be converted + curNs: list of current namespaces + Returns the corresponding string 'prefix:localName' for 'nsLocalName'. + """ + ns = nsLocalName[0] + for prefix, namespace in curNs: + if ns == namespace: + if prefix != None: + return "%s:%s" %(prefix, nsLocalName[1]) + else: + return "%s" %nsLocalName[1] + else: + if ns == None: + return nsLocalName[1] + else: + raise LookupError, "Prefix for namespaceURI '%s' not found!" % (ns) + + +def splitQName (qName): + """Split the given 'qName' into prefix/namespace and local name. + + Input parameter: + 'qName': contains a string 'prefix:localName' or '{namespace}localName' + Returns a tuple (prefixOrNamespace, localName) + """ + namespaceEndIndex = string.find (qName, '}') + if namespaceEndIndex != -1: + prefix = qName[1:namespaceEndIndex] + localName = qName[namespaceEndIndex+1:] + else: + namespaceEndIndex = string.find (qName, ':') + if namespaceEndIndex != -1: + prefix = qName[:namespaceEndIndex] + localName = qName[namespaceEndIndex+1:] + else: + prefix = None + localName = qName + return prefix, localName + + +def toClarkQName (tupleOrLocalName): + """converts a tuple (namespace, localName) into clark notation {namespace}localName + qNames without namespace remain unchanged + + Input parameter: + 'tupleOrLocalName': tuple '(namespace, localName)' to be converted + Returns a string {namespace}localName + """ + if isinstance(tupleOrLocalName, TupleType): + if tupleOrLocalName[0] != EMPTY_NAMESPACE: + return "{%s}%s" %(tupleOrLocalName[0], tupleOrLocalName[1]) + else: + return tupleOrLocalName[1] + else: + return tupleOrLocalName + + +def splitClarkQName (qName): + """converts clark notation {namespace}localName into a tuple (namespace, localName) + + Input parameter: + 'qName': {namespace}localName to be converted + Returns prefix and localName as separate strings + """ + namespaceEndIndex = string.find (qName, '}') + if namespaceEndIndex != -1: + prefix = qName[1:namespaceEndIndex] + localName = qName[namespaceEndIndex+1:] + else: + prefix = None + localName = qName + return prefix, localName + + +################################################################## +# XML serialization of text +# the following functions assume an ascii-compatible encoding +# (or "utf-16") + +_escape = re.compile(eval(r'u"[&<>\"\u0080-\uffff]+"')) + +_escapeDict = { + "&": "&", + "<": "<", + ">": ">", + '"': """, +} + + +def _raiseSerializationError(text): + raise TypeError("cannot serialize %r (type %s)" % (text, type(text).__name__)) + + +def _encode(text, encoding): + try: + return text.encode(encoding) + except AttributeError: + return text # assume the string uses the right encoding + + +def _encodeEntity(text, pattern=_escape): + # map reserved and non-ascii characters to numerical entities + def escapeEntities(m, map=_escapeDict): + out = [] + append = out.append + for char in m.group(): + text = map.get(char) + if text is None: + text = "&#%d;" % ord(char) + append(text) + return string.join(out, "") + try: + return _encode(pattern.sub(escapeEntities, text), "ascii") + except TypeError: + _raise_serialization_error(text) + + +def escapeCdata(text, encoding=None, replace=string.replace): + # escape character data + try: + if encoding: + try: + text = _encode(text, encoding) + except UnicodeError: + return _encodeEntity(text) + text = replace(text, "&", "&") + text = replace(text, "<", "<") + text = replace(text, ">", ">") + return text + except (TypeError, AttributeError): + _raiseSerializationError(text) + + +def escapeAttribute(text, encoding=None, replace=string.replace): + # escape attribute value + try: + if encoding: + try: + text = _encode(text, encoding) + except UnicodeError: + return _encodeEntity(text) + text = replace(text, "&", "&") + text = replace(text, "'", "'") # FIXME: overkill + text = replace(text, "\"", """) + text = replace(text, "<", "<") + text = replace(text, ">", ">") + return text + except (TypeError, AttributeError): + _raiseSerializationError(text) + + +###################################################################### +# CLASSES +###################################################################### + +###################################################################### +# class containing a tuple of namespace prefix and localName +# +class QNameTuple(tuple): + def __str__(self): + if self[0] != EMPTY_PREFIX: + return "%s:%s" %(self[0],self[1]) + else: + return self[1] + + +def QNameTupleFactory(initValue): + if isinstance(initValue, StringTypes): + separatorIndex = string.find (initValue, ':') + if separatorIndex != -1: + initValue = (initValue[:separatorIndex], initValue[separatorIndex+1:]) + else: + initValue = (EMPTY_PREFIX, initValue) + return QNameTuple(initValue) + + +###################################################################### +# class containing a tuple of namespace and localName +# +class NsNameTuple(tuple): + def __str__(self): + if self[0] != EMPTY_NAMESPACE: + return "{%s}%s" %(self[0],self[1]) + elif self[1] != None: + return self[1] + else: + return "None" + + +def NsNameTupleFactory(initValue): + if isinstance(initValue, StringTypes): + initValue = splitClarkQName(initValue) + elif initValue == None: + initValue = (EMPTY_NAMESPACE, initValue) + return NsNameTuple(initValue) + + diff --git a/tools/generator/lib/genxmlif/xmliftest.py b/tools/generator/lib/genxmlif/xmliftest.py new file mode 100644 index 0000000..92388e9 --- /dev/null +++ b/tools/generator/lib/genxmlif/xmliftest.py @@ -0,0 +1,14 @@ +from .. import genxmlif +from ..genxmlif.xmlifODict import odict + +xmlIf = genxmlif.chooseXmlIf(genxmlif.XMLIF_ELEMENTTREE) +xmlTree = xmlIf.createXmlTree(None, "testTree", {"rootAttr1":"RootAttr1"}) +xmlRootNode = xmlTree.getRootNode() +myDict = odict( (("childTag1","123"), ("childTag2","123")) ) +xmlRootNode.appendChild("childTag", myDict) +xmlRootNode.appendChild("childTag", {"childTag1":"123456", "childTag2":"123456"}) +xmlRootNode.appendChild("childTag", {"childTag1":"123456789", "childTag3":"1234", "childTag2":"123456789"}) +xmlRootNode.appendChild("childTag", {"childTag1":"1", "childTag2":"1"}) +print xmlTree.printTree(prettyPrint=1) +print xmlTree +print xmlTree.getRootNode()