Recursive. Much smaller. Also uses namespace URL.
[sfa.git] / rspec / rspecvalidate.py
1 #!/usr/bin/python
2
3 # $HeadURL$
4 # $Id$
5
6 #
7 # Validate RSPEC hiearchy, values, types, and names using supplied xsd.
8 #
9 # Faiyaz Ahmed <faiyaza at cs dot princeton dot edu>
10 #
11 # Copyright 2009 Princeton University
12 # http://www.planet-lab.org
13 #
14
15 import sys
16 import pprint
17 import os
18 from xml.dom import minidom
19 import logging 
20 import httplib
21
22 logging.basicConfig(level=logging.DEBUG)
23
24
25 class Schema():
26     '''Manipulates Rspec xsd into python dict'''
27     def __init__(self):
28         self.NSURL = "www.planet-lab.org"
29         self.xsd = "planetlab.xsd"
30         self.schemaDom = None # parsed schema file's DOM
31         self.schemaDict = self.nodeDict()
32        
33     def _getSchema(self):
34         '''If the schema doesn't exist at the NameSpace's URL, then use the 
35            local file.'''
36         conn = httplib.HTTPConnection(self.NSURL)
37         conn.request("GET", "/" + self.xsd)
38         r1 = conn.getresponse()
39         if r1.status != 200:
40             logging.debug("http://%s/%s: file not found" %(self.NSURL,self.xsd))
41             if os.path.exists(self.xsd):
42                 logging.debug("using local copy.")
43                 self.schemaDom = minidom.parse(self.xsd)
44         else:
45             self.schemaDom = minidom.parseString(r1.read())
46         # XML begings with a '#document'.  Just check to be safe.
47         if self.schemaDom.nodeName == "#document": 
48             self.schemaDom = self.schemaDom.childNodes[0]
49  
50
51     def _getText(self, nodelist):
52         rc = ""
53         for node in nodelist:
54             if node.nodeType == node.TEXT_NODE:
55                 rc = rc + node.data
56         return rc
57     
58     # The rspec is comprised of 2 parts, and 1 reference:
59     # attributes/elements describe individual resources
60     # complexTypes are used to describe a set of attributes/elements
61     # complexTypes can include a reference to other complexTypes.
62     
63     
64     def _getName(self, node):
65         '''Gets name of node. If tag has no name, then return tag's localName'''
66         if not node.nodeName.startswith("#"):
67             if node.attributes.has_key("name"):
68                 name = node.attributes.get("name").value
69             else: 
70                 name = node.localName
71         return name
72
73     def nodeDict(self, nodeDom = None):
74         '''Traverse complex node.  Create a dict 
75         {name : [{attributename : {name: value,}, sequence]}'''
76         children = [] # array of dicts.  1 for each element/attribute.
77         node = {}
78         if not nodeDom: 
79             self._getSchema()
80             nodeDom = self.schemaDom
81         if nodeDom.nodeName and not nodeDom.nodeName.startswith("#"):
82             # attributes have tags and values.  get {tag: value}, else {type: value} 
83             children.append(self._attributeDict(nodeDom))
84             # resolve the child nodes.
85             if nodeDom.hasChildNodes():
86                 for child in nodeDom.childNodes:
87                         childelems = self.nodeDict(child)
88                         if len(childelems): children.append(childelems)
89             node = { self._getName(nodeDom) : children}
90         return node
91     
92     
93     # Attribute.  {name : nameofattribute, {items: values})
94     def _attributeDict(self, attributeDom):
95         '''Traverse single attribute node.  Create a dict {attributename : {name: value,}]}'''
96         node = {} # parsed dict
97         for attr in attributeDom.attributes.keys():
98             node[attr] = attributeDom.attributes.get(attr).value
99         return node
100
101    
102 def main(fname):
103     pp = pprint.PrettyPrinter(indent=4)
104     dom = minidom.parse(fname)
105     s = Schema()
106     print "Testing Complex Type:"
107     pp.pprint(s.nodeDict(dom.childNodes[0].childNodes[21]))
108
109     print "Testing Whole Doc:"
110     pp.pprint(s.nodeDict(dom.childNodes[0]))
111
112     print "Testing URL ofWhole doc:"
113     pp.pprint(s.schemaDict)
114
115 if __name__ == '__main__':  
116     main(fname="planetlab.xsd")