source: TI03-DataExtractor/branches/old_stuff/latest_dx/dx/pydxs/DXRMLHandler.py @ 793

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI03-DataExtractor/branches/old_stuff/latest_dx/dx/pydxs/DXRMLHandler.py@793
Revision 793, 7.4 KB checked in by astephen, 13 years ago (diff)

Put all the old code in the old_stuff branch.

Line 
1#   Copyright (C) 2004 CCLRC & NERC( Natural Environment Research Council ).
2#   This software may be distributed under the terms of the
3#   Q Public License, version 1.0 or later. http://ndg.nerc.ac.uk/public_docs/QPublic_license.txt
4
5"""
6DXRMLHandler.py
7===============
8
9Holds the DXRMLHandler class for parsing and writing the
10Data Extractor's Request Markup Language (DXRML).
11
12"""
13
14# Import standard library modules
15from xml.dom import minidom
16from xml.sax import saxutils
17import re
18from StringIO import StringIO
19
20# Import local modules
21from serverConfig import MAX_NUM_DATASETS
22
23# Define global variables
24singleItems=[["request", "numberOfDatasets"],
25         ["request", "outputFormat"],
26         ["request", "useMultipleOutputFiles"], 
27         ["request", "horizontalDomain", "northernExtent"],
28         ["request", "horizontalDomain", "southernExtent"], 
29         ["request", "horizontalDomain", "westernExtent"],
30         ["request", "horizontalDomain", "easternExtent"]]
31         
32perDatasetItems=[["request", "dxDatasets", "dxDataset", "datasetGroup"],
33                 ["request", "dxDatasets", "dxDataset", "dataset"],
34                 ["request", "dxDatasets", "dxDataset", "datasetURI"],           
35                 ["request", "dxDatasets", "dxDataset", "variable"],
36                 ["request", "dxDatasets", "dxDataset", "verticalDomain"],               
37                 ["request", "dxDatasets", "dxDataset", "startDateTime"],
38                 ["request", "dxDatasets", "dxDataset", "endDateTime"],
39                 ["request", "dxDatasets", "dxDataset", "timeIntervalValue"],
40                 ["request", "dxDatasets", "dxDataset", "timeIntervalUnits"]]
41
42
43class DXRMLGenerator:
44    """
45    Class to produce a dxrml output string based on a dx request dictionary.
46    """
47   
48    def __init__(self, requestDict):
49        """
50        Takes in a request dictionary object.
51        """
52        self.request=requestDict
53        self.indent=0
54        self.levels=[]
55        self.xmlString='<?xml version="1.0" encoding="UTF-8"?>'
56        self._constructSingleItemXML()
57        self._constructPerDatasetXML()
58       
59       
60    def _constructSingleItemXML(self):
61        """
62        Parses all the items that should only appear once in the XML
63        output. Any missing or superfluous items are ignored.
64        """
65        lastItemList=None
66        for itemList in singleItems:
67            item=itemList[-1]
68           
69            if len(itemList)>self.indent:
70                for tag in itemList[self.indent:-1]:
71                    indent=self.indent*4*" "
72                    self._addToString(indent+"<"+tag+">")
73                    self.indent=self.indent+1
74            elif len(itemList)<self.indent:
75                revItemList=itemList[:]
76                revItemList.reverse()
77                for tag in revItemList[1:self.indent]:
78                    self.indent=self.indent-1
79                    indent=self.indent*4*" "
80                    self._addToString(indent+"</"+tag+">")
81                 
82            if self.request.has_key(item):
83                indent=self.indent*4*" "               
84                self._addToString("%s<%s>%s</%s>" % (indent, item, self.request[item], item))
85       
86            lastItemList=itemList
87
88        if self.indent>1:
89            revItemList=lastItemList[:]
90            revItemList.reverse()
91            for tag in revItemList[1:self.indent]:
92                self.indent=self.indent-1
93                indent=self.indent*4*" "
94                self._addToString(indent+"</"+tag+">")     
95       
96
97    def _constructPerDatasetXML(self):
98        """
99        Parses all the items that should only appear in the XML
100        output for all datasets. Any missing or superfluous items
101        are ignored.
102        """
103        lastItemList=None
104       
105        for dsetNum in range(1, MAX_NUM_DATASETS+1):
106          for itemList in perDatasetItems:
107            item=itemList[-1]
108           
109            if len(itemList)>self.indent:
110                for tag in itemList[self.indent:-1]:
111                    indent=self.indent*4*" "
112                    self._addToString(indent+"<"+tag+">")
113                    self.indent=self.indent+1
114                   
115            elif len(itemList)<self.indent:
116                revItemList=itemList[:]
117                revItemList.reverse()
118                for tag in revItemList[1:self.indent]:
119                    self.indent=self.indent-1
120                    indent=self.indent*4*" "
121                    self._addToString(indent+"</"+tag+">")
122                 
123            if self.request.has_key("%s_%s" % (item, dsetNum)):
124                indent=self.indent*4*" "               
125                self._addToString("%s<%s>%s</%s>" % (indent, item, self.request["%s_%s" % (item, dsetNum)], item))
126       
127            lastItemList=itemList
128
129        if self.indent>0:
130            revItemList=lastItemList[:]
131            revItemList.reverse()
132
133            for tag in revItemList[1:]:
134                self.indent=self.indent-1
135                indent=self.indent*4*" "
136                self._addToString(indent+"</"+tag+">")     
137       
138
139       
140    def _addToString(self, item):
141        """
142        Adds an item to the current xml string.
143        """
144        self.xmlString=self.xmlString+"\n"+item
145   
146   
147    def writeToFile(self, filename):
148        """
149        Writes the XML file content to an actual output file.
150        """
151        xmlFile=open(filename, 'w')
152        xmlFile.write(self.xmlString+"\n")
153        xmlFile.close() 
154
155
156class DXRMLParser:
157    """
158    Parser class for DXRML files into a python request dictionary.
159    The resulting dictionary has a flat content and can be passed
160    directly into the dx as a request.
161    """
162       
163    def __init__(self, xmlfile):
164        """
165        Method to take in the xml file and call relevant methods
166        to parse the content into a dictionary.
167        """
168        if type(xmlfile) in (type(""), type(u"")):
169            xmlfile=StringIO(xmlfile)
170        self.doc=minidom.parse(xmlfile) 
171        self.internalDict={}
172        self.currentNodes=[]
173        self._parseSingleItems()
174        self._parsePerDatasetItems()   
175       
176
177    def _parseSingleItems(self):
178        """
179        Parses items that only appear once to a dictionary object.
180        """
181        for itemList in singleItems:
182            # Pad one list with None values to get them same length
183            ni=len(itemList)
184            nc=len(self.currentNodes)
185           
186            if ni>nc:
187                self.currentNodes=self.currentNodes+([None]*(ni-nc))
188            elif nc>ni:
189                itemList=itemList+([None]*(nc-ni))
190               
191           
192            for counter in range(ni):
193                tagName=itemList[counter]
194               
195                # If current node is None or not the same as item list then try and get the right item
196                # from the XML file.
197                if self.currentNodes[counter]==None or self.currentNodes[counter].nodeName!=tagName: 
198                    parentNode=self.doc
199                   
200                    if counter>0:
201                        parentNode=self.currentNodes[counter-1]
202                    elementList=parentNode.getElementsByTagName(tagName)
203                   
204                    if len(elementList)>0:
205                        self.currentNodes[counter]=elementList[0]
206                       
207                        # If this is the last item in the itemList then add to dictionary
208                        if counter==ni-1:
209                            self.internalDict[tagName]=self.currentNodes[counter].childNodes[0].nodeValue
210
211       
212    def _parsePerDatasetItems(self):
213        """
214        Parses the items that can be repeated for each dataset.
215        """
216        dxDatasets=self.doc.getElementsByTagName("request")[0].getElementsByTagName("dxDatasets")[0].getElementsByTagName("dxDataset")
217       
218        for dsetNumber in range(len(dxDatasets)):
219            dsetNode=dxDatasets[dsetNumber]
220           
221            for itemList in perDatasetItems:
222                # We only need the last item in each list here as flat format.
223                tagName=itemList[-1] 
224               
225                elementList=dsetNode.getElementsByTagName(tagName)
226               
227                if len(elementList)>0:
228                    dsetNumberPlusOne=dsetNumber+1
229                    self.internalDict["%s_%s" % (tagName, dsetNumberPlusOne)]=elementList[0].childNodes[0].nodeValue   
230
231
232    def getDictionary(self):
233        """
234        Returns the dictionary object created from an XML file.
235        """
236        return self.internalDict
237                   
238       
239    def __getattr__(self, attr):
240        """
241        For dictionary access to the instance object.
242        """
243        if attr in self.internalDict.keys():
244            return self.internalDict[attr]
245
246
247if __name__=="__main__":
248    a=DXRMLParser('testScripts/drxmlTester.xml')
249    print a.getDictionary()
Note: See TracBrowser for help on using the repository browser.