ported XML parsing from libxml2 to Python's builtin xml.dom.minidom to reduce dependenies
[OpenSRF.git] / src / python / osrf / utils.py
1 import xml.dom.minidom, re
2
3 def osrfXMLFileToObject(filename):
4     """Turns the contents of an XML file into a Python object"""
5     doc = xml.dom.minidom.parse(filename)
6     obj = osrfXMLNodeToObject(doc.childNodes[0])
7     doc.unlink()
8     return obj
9
10 def osrfXMLStringToObject(string):
11     """Turns an XML string into a Python object"""
12     doc = xml.dom.minidom.parseString(string)
13     obj = osrfXMLNodeToObject(doc.childNodes[0])
14     doc.unlink()
15     return obj
16
17 def osrfXMLNodeToObject(xmlNode):
18     """Turns an XML node into a Python object"""
19     obj = {}
20
21     if xmlNode.nodeType != xmlNode.ELEMENT_NODE:
22         return obj
23
24     done = False
25     nodeName = xmlNode.nodeName
26
27     for nodeChild in xmlNode.childNodes:
28         if nodeChild.nodeType == xmlNode.ELEMENT_NODE:
29
30             # If a node has element children, create a new sub-object 
31             # for this node, attach an array for each type of child
32             # and recursively collect the children data into the array(s)
33
34             if not obj.has_key(nodeName):
35                 obj[nodeName] = {}
36
37             sub_obj = osrfXMLNodeToObject(nodeChild);
38
39             if not obj[nodeName].has_key(nodeChild.nodeName):
40                 # we've encountered 1 sub-node with nodeChild's name
41                 obj[nodeName][nodeChild.nodeName] = sub_obj[nodeChild.nodeName]
42
43             else:
44                 if isinstance(obj[nodeName][nodeChild.nodeName], list):
45                     # we already have multiple sub-nodes with nodeChild's name
46                     obj[nodeName][nodeChild.nodeName].append(sub_obj[nodeChild.nodeName])
47
48                 else:
49                     # we already have 1 sub-node with nodeChild's name, make 
50                     # it a list and append the current node
51                     val = obj[nodeName][nodeChild.nodeName]
52                     obj[nodeName][nodeChild.nodeName] = [ val, sub_obj[nodeChild.nodeName] ]
53
54             done = True
55
56     if not done:
57         # If the node has no element children, clean up the text content 
58         # and use that as the data
59         xmlNode = xmlNode.childNodes[0] # extract the text node
60         data = re.compile('^\s*').sub('', str(xmlNode.nodeValue))
61         data = re.compile('\s*$').sub('', data)
62
63         obj[nodeName] = data
64
65     return obj
66
67
68 def osrfObjectFindPath(obj, path, idx=None):
69     """Searches an object along the given path for a value to return.
70
71     Path separaters can be '/' or '.', '/' is tried first."""
72
73     parts = []
74
75     if re.compile('/').search(path):
76         parts = path.split('/')
77     else:
78         parts = path.split('.')
79
80     for part in parts:
81         try:
82             o = obj[part]
83         except Exception:
84             return None
85         if isinstance(o,str): 
86             return o
87         if isinstance(o,list):
88             if( idx != None ):
89                 return o[idx]
90             return o
91         if isinstance(o,dict):
92             obj = o
93         else:
94             return o
95
96     return obj
97
98
99             
100