* tried to put some sense in the way things get logged, at least on server-side for now
[sfa.git] / sfa / util / rspec.py
index 2b1fe85..aab5592 100644 (file)
@@ -1,15 +1,18 @@
 ### $Id$
 ### $URL$
 
 ### $Id$
 ### $URL$
 
-import pdb
 import sys
 import pprint
 import os
 import httplib
 from xml.dom import minidom
 from types import StringTypes, ListType
 import sys
 import pprint
 import os
 import httplib
 from xml.dom import minidom
 from types import StringTypes, ListType
+from lxml import etree
+from StringIO import StringIO
 
 
-class Rspec:
+from sfa.util.sfalogging import sfa_logger
+
+class RSpec:
 
     def __init__(self, xml = None, xsd = None, NSURL = None):
         '''
 
     def __init__(self, xml = None, xsd = None, NSURL = None):
         '''
@@ -28,10 +31,10 @@ class Rspec:
         self.dict = {}
         self.schemaDict = {}
         self.NSURL = NSURL 
         self.dict = {}
         self.schemaDict = {}
         self.NSURL = NSURL 
-        if xml: 
+        if xml:
             if type(xml) == file:
                 self.parseFile(xml)
             if type(xml) == file:
                 self.parseFile(xml)
-            if type(xml) == str:
+            if type(xml) in StringTypes:
                 self.parseString(xml)
             self.dict = self.toDict() 
         if xsd:
                 self.parseString(xml)
             self.dict = self.toDict() 
         if xsd:
@@ -92,6 +95,8 @@ class Rspec:
 
         if (nodeDom.hasChildNodes()):
             childdict={}
 
         if (nodeDom.hasChildNodes()):
             childdict={}
+            for attribute in nodeDom.attributes.keys():
+                childdict = self.appendToDictOrCreate(childdict, attribute, nodeDom.getAttribute(attribute))
             for child in nodeDom.childNodes[:-1]:
                 if (child.nodeValue):
                     siblingdict = self.appendToDictOrCreate(siblingdict, curNodeName, child.nodeValue)
             for child in nodeDom.childNodes[:-1]:
                 if (child.nodeValue):
                     siblingdict = self.appendToDictOrCreate(siblingdict, curNodeName, child.nodeValue)
@@ -101,17 +106,16 @@ class Rspec:
             child = nodeDom.childNodes[-1]
             if (child.nodeValue):
                 siblingdict = self.appendToDictOrCreate(siblingdict, curNodeName, child.nodeValue)
             child = nodeDom.childNodes[-1]
             if (child.nodeValue):
                 siblingdict = self.appendToDictOrCreate(siblingdict, curNodeName, child.nodeValue)
+                if (childdict):
+                    siblingdict = self.appendToDictOrCreate(siblingdict, curNodeName, childdict)
             else:
                 siblingdict = self.toGenDict(child, siblingdict, childdict, curNodeName)
             else:
                 siblingdict = self.toGenDict(child, siblingdict, childdict, curNodeName)
-
-            # Keep the attributes separate from text nodes
-            attrdict={}
-            for attribute in nodeDom.attributes.keys():
-                attrdict = self.appendToDictOrCreate(attrdict, attribute, nodeDom.getAttribute(attribute))
-            if (attrdict):
-                self.appendToDictOrCreate(siblingdict, curNodeName, attrdict)
         else:
         else:
-            self.appendToDictOrCreate(siblingdict, curNodeName, [])
+            childdict={}
+            for attribute in nodeDom.attributes.keys():
+                childdict = self.appendToDictOrCreate(childdict, attribute, nodeDom.getAttribute(attribute))
+
+            self.appendToDictOrCreate(siblingdict, curNodeName, childdict)
             
         if (parentdict is not None):
             parentdict = self.appendToDictOrCreate(parentdict, parent, siblingdict)
             
         if (parentdict is not None):
             parentdict = self.appendToDictOrCreate(parentdict, parent, siblingdict)
@@ -137,23 +141,25 @@ class Rspec:
             if nodeDom.hasChildNodes():
                 for child in nodeDom.childNodes:
                     childName = self._getName(child)
             if nodeDom.hasChildNodes():
                 for child in nodeDom.childNodes:
                     childName = self._getName(child)
-                    # skip null children 
-                    if not childName:
-                        continue
-                    # initialize the possible array of children        
-                    if not node[elementName].has_key(childName):
-                        node[elementName][childName] = []
-                    # if child node has text child nodes
-                    # append the children to the array as strings
-                    if child.hasChildNodes() and isinstance(child.childNodes[0], minidom.Text):
-                        for nextchild in child.childNodes:
+                    
+                    # skip null children
+                    if not childName: continue
+
+                    # initialize the possible array of children
+                    if not node[elementName].has_key(childName): node[elementName][childName] = []
+
+                    if isinstance(child, minidom.Text):
+                        # add if data is not empty
+                        if child.data.strip():
+                            node[elementName][childName].append(nextchild.data)
+                    elif child.hasChildNodes() and isinstance(child.childNodes[0], minidom.Text):
+                        for nextchild in child.childNodes:  
                             node[elementName][childName].append(nextchild.data)
                             node[elementName][childName].append(nextchild.data)
-                    # convert element child node to dict
-                    else:       
+                    else:
                         childdict = self.toDict(child)
                         for value in childdict.values():
                             node[elementName][childName].append(value)
                         childdict = self.toDict(child)
                         for value in childdict.values():
                             node[elementName][childName].append(value)
-                    #node[childName].append(self.toDict(child))
+
         return node
 
   
         return node
 
   
@@ -171,11 +177,19 @@ class Rspec:
         return self.rootNode.toprettyxml()
 
   
         return self.rootNode.toprettyxml()
 
   
+    def __removeWhitespaceNodes(self, parent):
+        for child in list(parent.childNodes):
+            if child.nodeType == minidom.Node.TEXT_NODE and child.data.strip() == '':
+                parent.removeChild(child)
+            else:
+                self.__removeWhitespaceNodes(child)
+
     def parseFile(self, filename):
         """
         read a local xml file and store it as a dom object.
         """
         dom = minidom.parse(filename)
     def parseFile(self, filename):
         """
         read a local xml file and store it as a dom object.
         """
         dom = minidom.parse(filename)
+        self.__removeWhitespaceNodes(dom)
         self.rootNode = dom.childNodes[0]
 
 
         self.rootNode = dom.childNodes[0]
 
 
@@ -183,8 +197,8 @@ class Rspec:
         """
         read an xml string and store it as a dom object.
         """
         """
         read an xml string and store it as a dom object.
         """
-        xml = xml.replace('\n', '').replace('\t', '').strip()
         dom = minidom.parseString(xml)
         dom = minidom.parseString(xml)
+        self.__removeWhitespaceNodes(dom)
         self.rootNode = dom.childNodes[0]
 
  
         self.rootNode = dom.childNodes[0]
 
  
@@ -207,11 +221,13 @@ class Rspec:
 
     def _parseXSD(self, xsdURI):
         """
 
     def _parseXSD(self, xsdURI):
         """
-        Download XSD from URL, or if file, read local xsd file and set schemaDict
+        Download XSD from URL, or if file, read local xsd file and set
+        schemaDict.
+        
+        Since the schema definiton is a global namespace shared by and
+        agreed upon by others, this should probably be a URL.  Check
+        for URL, download xsd, parse, or if local file, use that.
         """
         """
-        # Since the schema definiton is a global namespace shared by and agreed upon by
-        # others, this should probably be a URL.  Check for URL, download xsd, parse, or 
-        # if local file, use local file.
         schemaDom = None
         if xsdURI.startswith("http"):
             try: 
         schemaDom = None
         if xsdURI.startswith("http"):
             try: 
@@ -219,15 +235,14 @@ class Rspec:
             except Exception, e:
                 # logging.debug("%s: web file not found" % xsdURI)
                 # logging.debug("Using local file %s" % self.xsd")
             except Exception, e:
                 # logging.debug("%s: web file not found" % xsdURI)
                 # logging.debug("Using local file %s" % self.xsd")
-                print e
-                print "Can't find %s on the web. Continuing." % xsdURI
+                sfa_logger.log_exc("rspec.parseXSD: can't find %s on the web. Continuing." % xsdURI)
         if not schemaDom:
             if os.path.exists(xsdURI):
                 # logging.debug("using local copy.")
         if not schemaDom:
             if os.path.exists(xsdURI):
                 # logging.debug("using local copy.")
-                print "Using local %s" % xsdURI
+                sfa_logger.debug("rspec.parseXSD: Using local %s" % xsdURI)
                 schemaDom = minidom.parse(xsdURI)
             else:
                 schemaDom = minidom.parse(xsdURI)
             else:
-                raise Exception("Can't find xsd locally")
+                raise Exception("rspec.parseXSD: can't find xsd locally")
         self.schemaDict = self.toDict(schemaDom.childNodes[0])
 
 
         self.schemaDict = self.toDict(schemaDom.childNodes[0])
 
 
@@ -274,7 +289,7 @@ class Rspec:
         """
         Convert a dictionary into a dom object and store it.
         """
         """
         Convert a dictionary into a dom object and store it.
         """
-        self.rootNode = self.dict2dom(rdict, include_doc)
+        self.rootNode = self.dict2dom(rdict, include_doc).childNodes[0]
  
  
     def getDictsByTagName(self, tagname, dom = None):
  
  
     def getDictsByTagName(self, tagname, dom = None):
@@ -332,6 +347,28 @@ class Rspec:
                 self.filter(tagname, attribute, blacklist, whitelist, child) 
 
 
                 self.filter(tagname, attribute, blacklist, whitelist, child) 
 
 
+    def merge(self, rspecs, tagname, dom=None):
+        """
+        Merge this rspec with the requested rspec based on the specified 
+        starting tag name. The start tag (and all of its children) will be merged  
+        """
+        tempdict = {}
+        if not dom:
+            dom = self.rootNode
+
+        whitelist = []
+        blacklist = []
+            
+        if dom.localName in [tagname] and dom.attributes.has_key(attribute):
+            if whitelist and dom.attributes.get(attribute).value not in whitelist:
+                dom.parentNode.removeChild(dom)
+            if blacklist and dom.attributes.get(attribute).value in blacklist:
+                dom.parentNode.removeChild(dom)
+
+        if dom.hasChildNodes():
+            for child in dom.childNodes:
+                self.filter(tagname, attribute, blacklist, whitelist, child) 
+
     def validateDicts(self):
         types = {
             'EInt' : int,
     def validateDicts(self):
         types = {
             'EInt' : int,
@@ -363,7 +400,7 @@ class Rspec:
     
 
 
     
 
 
-class RecordSpec(Rspec):
+class RecordSpec(RSpec):
 
     root_tag = 'record'
     def parseDict(self, rdict, include_doc = False):
 
     root_tag = 'record'
     def parseDict(self, rdict, include_doc = False):
@@ -376,7 +413,7 @@ class RecordSpec(Rspec):
         record_dict = rdict
         if not len(rdict.keys()) == 1:
             record_dict = {self.root_tag : rdict}
         record_dict = rdict
         if not len(rdict.keys()) == 1:
             record_dict = {self.root_tag : rdict}
-        return Rspec.dict2dom(self, record_dict, include_doc)
+        return RSpec.dict2dom(self, record_dict, include_doc)
 
         
 # vim:ts=4:expandtab
 
         
 # vim:ts=4:expandtab