source: TI02-CSML/trunk/services/3rdParty/pywps-1.0.0/pywps/Wps/describe.py @ 2194

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI02-CSML/trunk/services/3rdParty/pywps-1.0.0/pywps/Wps/describe.py@2194
Revision 2194, 19.9 KB checked in by lawrence, 13 years ago (diff)

Adding various specs and 3rd party code of interest for the CSML
services development.

Line 
1#!/usr/bin/python
2"""
3This module generates XML file with DescribeProcess response of WPS
4"""
5# Author:       Jachym Cepicky
6#               http://les-ejk.cz
7# Lince:
8#
9# Web Processing Service implementation
10# Copyright (C) 2006 Jachym Cepicky
11#
12# This program is free software; you can redistribute it and/or modify
13# it under the terms of the GNU General Public License as published by
14# the Free Software Foundation; either version 2 of the License, or
15# (at your option) any later version.
16#
17# This program is distributed in the hope that it will be useful,
18# but WITHOUT ANY WARRANTY; without even the implied warranty of
19# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20# GNU General Public License for more details.
21#
22# You should have received a copy of the GNU General Public License
23# along with this program; if not, write to the Free Software
24# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
25
26# TODO:
27#   * BoundingBoxData not implemented
28
29
30
31from xml.dom.minidom import Document
32from ogc import processdescription
33import append
34
35class Describe:
36    def __init__(self,serverSettings,processes,formValues):
37        """
38        By initalization creates ProcessDescriptions XML response.
39
40        Inputs:
41            serverSettings      - file with server settings structure (etc/settings.py)
42            describeProcesses   - array of processes, which should be described
43        """
44
45        self.document = Document()
46        self.settings = serverSettings
47        self.WPS = processdescription.WPS()
48        self.pd = self.WPS.pd['response'] # structure, where part of OGC 05-007r4 is hold
49        self.Append = append.Append() # siple appending of some "standard" nodes
50
51        # creattin array for all processes
52        describeProcesses = []
53        for process in formValues['identifier']:
54            describeProcesses.append(eval("processes.%s.Process()" % (process)))
55
56        # ProcessDescriptions
57        self.ProcessDescriptions = self.document.createElementNS(self.WPS.namespaces['ows'],"ProcessDescriptions")
58        self.ProcessDescriptions.setAttribute("xmlns",self.WPS.namespaces['wps'])
59        self.ProcessDescriptions.setAttribute("xmlns:xlink",self.WPS.namespaces['xlink'])
60        self.ProcessDescriptions.setAttribute("xmlns:ows",self.WPS.namespaces['ows'])
61        self.ProcessDescriptions.setAttribute("xmlns:xsi",self.WPS.namespaces['xsi'])
62        self.ProcessDescriptions.setAttribute("xsi:schemaLocation",self.WPS.namespaces['wps']+' '+self.WPS.schemalocation['wps'])
63        self.document.appendChild(self.ProcessDescriptions)
64
65        # for each process, the user wants to describe
66        for process in describeProcesses:
67            ProcessDescription = self.document.createElement("ProcessDescription")
68            self.ProcessDescriptions.appendChild(ProcessDescription)
69
70            # process description attributes
71            for attribute in self.pd['attributes']:
72                self.Append.Attribute(
73                        self.document,
74                        attribute, 
75                        ProcessDescription,
76                        self.pd['attributes'],
77                        process
78                        )
79       
80            # for each element in describeProcess structure
81            for key in self.pd['order']:
82                # For each ProcessInputs
83                if key == "DataInputs":
84                    datainputs = self.document.createElement("%s%s" %\
85                            (self.pd['elements']['DataInputs']['ns'],"DataInputs"))
86                    self.dataInputsNode(process,datainputs)
87                    ProcessDescription.appendChild(datainputs)
88                    # compile each input in process
89
90                elif key == "ProcessOutputs":
91                    processOutputs = self.document.createElement("%s%s" %\
92                            (self.pd['elements']['ProcessOutputs']['ns'],"ProcessOutputs"))
93                    try:
94                        self.processOutputsNode(process,processOutputs)
95                        ProcessDescription.appendChild(processOutputs)
96                    except AttributeError, e:
97                        if e == "Outputs":
98                            processOutputs.appendChild(document.createComment(
99                                "===== This process defined no outputs ====="
100                                ))
101                else: # key != ProcessInputs or != ProcessOutputs -> key is something "normal"
102                    self.Append.Node(
103                            self.document, key, ProcessDescription,
104                            self.pd['elements'], process
105                            )
106        return
107
108    def dataInputsNode(self,process,parent):
109        """
110        Creates DataInputs XML Node
111
112        Inputs:
113            parent  - node to which the DataInputs node should be appended
114            process - process, for which will be the data inputs described
115        """
116
117        inputSett = self.pd['elements']['DataInputs']['Input'] # settings after OGC
118
119        # for each input
120        for input in process.Inputs:
121
122            # default value
123            if input.has_key('value') and \
124                input['value'] != None:
125
126                if input.has_key("Abstract"):
127                    input['Abstract'] += "\n\nDefault value: %s" %\
128                    (str(input['value']))
129                else:
130                    input['Abstract'] = "\n\nDefault value: %s" %\
131                    (str(input['value']))
132
133
134            # create input node
135            dataInput = self.document.createElement("%s%s" %\
136                    (self.pd['elements']['DataInputs']['Input']['ns'],"Input"))
137            parent.appendChild(dataInput)
138           
139            # for each input from conf file
140            dataStructureDefined = 0
141            for inputParam in inputSett['order']:
142                if inputParam in [ "ComplexData", "LiteralData", "BoundingBoxData" ]:
143                    dataStructureDefined = 1
144                    if inputParam == "ComplexData":
145                        inputType = "ComplexValue"
146                        if input.has_key("ComplexValueReference"):
147                            inputType = "ComplexValueReference"
148                    elif inputParam == "LiteralData":
149                        inputType = "LiteralValue"
150                        if input.has_key("LiteralData"):
151                            inputType = "LiteralData"
152                    elif inputParam == "BoundingBoxData":
153                        inputType = "BoundingBoxValue"
154                    try:
155                        # create the InputData Structure
156                        self.inputDataStructure(\
157                                inputStruct = inputSett['elements'][inputParam],\
158                                processInput = input[inputType],\
159                                parent=dataInput,
160                                inputtype=inputType,\
161                                input=input       
162                                )
163                        dataStructureDefined = 1
164                    except KeyError, what:
165                        #print "KeyError: ",what
166                        pass
167                    continue
168
169                # minimum occures/maximum occures
170                if inputParam == "MinimumOccurs":
171                    if input.has_key("MinimumOccurs"):
172                        occursTag=self.document.createElement("MinimumOccurs")
173                        occursTag.appendChild(
174                                self.document.createTextNode(str(input['MinimumOccurs'])))
175                        dataInput.appendChild(occursTag)
176                        continue
177                    elif input.has_key('value') and input['value']:
178                        occursTag=self.document.createElement("MinimumOccurs")
179                        occursTag.appendChild(
180                                self.document.createTextNode("0"))
181                        dataInput.appendChild(occursTag)
182                        continue
183
184                self.Append.Node(
185                        document=self.document, 
186                        childNode=inputParam, 
187                        parentNode=dataInput,
188                        Elements=inputSett['elements'], 
189                        Values=input
190                        )
191
192            # It is not usual, that operation has no input
193            if not dataStructureDefined:
194                dataInput.appendChild(self.document.createComment(\
195                        "===== At least one input should be defined, but none found ===="))
196        return
197
198    def processOutputsNode(self,process,parent):
199        """
200        Creates ProcessOutputs XML Node
201
202        Inputs:
203            parent  - node to which the DataInputs node should be appended
204            process - process, for which will be the data inputs described
205        """
206
207        outputSett = self.pd['elements']['ProcessOutputs']['Output']
208
209        # for each output from output array
210        for output in process.Outputs:
211            outputNode = self.document.createElement("%s%s" % (outputSett['ns'],"Output"))
212            parent.appendChild(outputNode)
213            # for each output parameter
214            for outputParam in outputSett['order']:
215
216                # special handling
217                if outputParam in [ "ComplexOutput", "LiteralOutput", "BoundingBoxOutput" ]:
218
219                    try:
220                        if (output.has_key("LiteralValue") and\
221                            outputParam=="LiteralOutput") or\
222                            \
223                            (output.has_key("ComplexValueReference") and\
224                            outputParam=="ComplexOutput") or\
225                            \
226                            (output.has_key("ComplexValue") and\
227                            outputParam=="ComplexOutput") or \
228                            \
229                            (output.has_key("BoundingBoxValue") and\
230                            outputParam=="BoundingBoxOutput"):
231
232                            if output.has_key("ComplexValue"):
233                                key = "ComplexValue"
234                            elif output.has_key("ComplexValueReference"):
235                                key = "ComplexValueReference"
236                            elif output.has_key("LiteralValue"):
237                                key = "LiteralValue"
238                            elif output.has_key("BoundingBoxValue"):
239                                key = "BoundingBoxValue"
240                            self.outputDataStructure(
241                                    outputSett['elements'][outputParam],
242                                    output[key],
243                                    outputNode,key,
244                                    )
245                    except KeyError, what:
246                        #print "KeyError: ",what
247                        pass
248                else: # append 'normal' node
249                    self.Append.Node(
250                            document=self.document, 
251                            childNode=outputParam, 
252                            parentNode=outputNode,
253                            Elements=outputSett['elements'], 
254                            Values=output
255                            )
256        return 
257
258    def inputDataStructure(self,inputStruct,processInput,parent,inputtype,input):
259        """
260        Creates the "ComplexData" structure - see table 19 in WPS 0.4.0
261
262        inputStruct         one of ProcessInputs structure (LiteralData, BBoxData or ComplexData)
263        processInput        configuration structure
264        parrent             parrent node, to which is everything appended
265        inputtype           one of 'LiteralData', 'BoundingBoxData', 'ComplexData' text string
266        input               the whole intpu structure
267        """
268        # <ComplexData>
269        if inputtype == "ComplexValue" or \
270                inputtype == "ComplexValueReference":
271            complexdata = self.document.createElement("ComplexData")
272
273            # <ComplexData defaultFormat="?" >
274            try:
275                complexdata.setAttribute("%s%s" %\
276                        (inputStruct['ns'],"defaultFormat"), \
277                        processInput['Formats'][0])
278            except IndexError:
279                complexdata.setAttribute("%s%s" %\
280                        (inputStruct['ns'],"defaultFormat",
281                        inputStruct['attributes']['defaultFormat']['default']
282                        ))
283            parent.appendChild(complexdata)
284
285            # compile every format in configuration structure, append
286            for format in processInput['Formats']:
287                supportedComData = self.document.createElement("%s%s" %\
288                        (inputStruct['elements']['SupportedComplexData']['ns'],
289                        "SupportedComplexData"))
290                node = self.document.createElement("%s%s" %\
291                        (inputStruct['elements']['SupportedComplexData']['elements']['Format']['ns'],\
292                        "Format"))
293                text = self.document.createTextNode(format)
294                node.appendChild(text)
295                supportedComData.appendChild(node)
296            complexdata.appendChild(supportedComData)
297
298        # <LiteralData>
299        elif inputtype == "LiteralValue":
300            literaldata = self.document.createElement("%s%s" %\
301                    (inputStruct['ns'],"LiteralData"))
302
303            parent.appendChild(literaldata)
304
305            # for each Node in LiteralData structure
306            for litData in inputStruct['order']:
307                if litData == "LiteralValues":
308
309                    # anyvalue
310                    if not processInput.has_key('values') or "*" in processInput['values']:
311                        valueNode = self.document.createElement("%s%s" %\
312                            (inputStruct['elements']['LiteralValues']['elements']['AnyValue']['ns'],
313                            "AnyValue"))
314                        literaldata.appendChild(valueNode)
315
316                    # allowed values
317                    else:
318                        valueNode = self.document.createElement("%s%s" %\
319                            (inputStruct['elements']['LiteralValues']['elements']['AllowedValues']['ns'],
320                            "AllowedValues"))
321                        literaldata.appendChild(valueNode)
322                        for val in processInput['values']:
323                            value = self.document.createElement("Value")
324                            value.appendChild(self.document.createTextNode(str(val)))
325                            valueNode.appendChild(value)
326                    continue
327
328                # append supported values
329                elif litData == "SupportedUOMs":
330                    self.supportedUOMsElement(literaldata, processInput,
331                                inputStruct)
332                    continue
333
334                # default values
335                if litData == "DefaultValue":
336                    if input.has_key('value') and \
337                            input['value'] != None:
338
339                        defaultValue = self.document.createElement("%s%s" %\
340                            (inputStruct['elements']['DefaultValue']['ns'],
341                            "DefaultValue"))
342                        defaultValue.appendChild(
343                                self.document.createTextNode(str(input['value'])))
344                        literaldata.appendChild(defaultValue)
345                    continue
346
347                else: # other 'normal' node will be appended
348                    self.Append.Node(
349                            document=self.document, 
350                            childNode=litData, 
351                            parentNode=literaldata,
352                            Elements=inputStruct['elements'],
353                            Values=processInput
354                            )
355
356        # <BoundingBoxData> not implemented
357        elif inputtype == "BoundingBoxValue":
358            bboxNode = self.document.createElement("%s%s" %\
359                    (inputStruct['ns'],"BoundingBoxData"))
360            bboxNode.setAttribute("defaultCRS","")
361            crsNode = self.document.createElement("CRS")
362            bboxNode.appendChild(crsNode)
363
364            parent.appendChild(bboxNode)
365
366            pass
367
368        return
369
370    def outputDataStructure(self,outputStructure,processOutput,parent,outputtype):
371        """
372        Creates the "ComplexData" structure - see table 19 in WPS 0.4.0
373       
374        outputStructure     one of ProcessInputs structure (LiteralData, BBoxData or ComplexData)
375        processOutput       structure with process output from conf. file
376        parent              parent node, to which is everything appended
377        outputtype          one of 'LiteralData', 'BoundingBoxData', 'ComplexData' text string
378        """
379
380        # <ComplexData>
381        if outputtype == "ComplexValue" or \
382           outputtype == "ComplexValueReference":
383
384            complexdata = self.document.createElement("%s%s" %\
385                    (outputStructure['ns'],"ComplexOutput"))
386            parent.appendChild(complexdata)
387           
388            # <ComplexData defaultFormat="?" >
389            try:
390                complexdata.setAttribute("%s%s" %\
391                        (outputStructure['ns'],"defaultFormat"), processOutput['Formats'][0])
392            except (IndexError,AttributeError):
393                complexdata.setAttribute("defaultFormat", "text/XML")
394
395            # compile every format in configuration structure, append
396            supportedComData = self.document.createElement("SupportedComplexData")
397            for format in processOutput['Formats']:
398                node = self.document.createElement("Format")
399                text = self.document.createTextNode(format)
400                node.appendChild(text)
401                supportedComData.appendChild(node)
402            complexdata.appendChild(supportedComData)
403
404        ## LiteralData
405        elif outputtype == "LiteralValue":
406            literaldata = self.document.createElement("LiteralOutput")
407            parent.appendChild(literaldata)
408
409            # for each 'LiteralOutput':{'UOMs':["meters","hectars","kilograms"]}
410            self.supportedUOMsElement(literaldata, processOutput,
411                    outputStructure)
412
413 
414        ## BoundingBoxData not implemented
415        elif outputtype == "BoundingBoxValue":
416            bboxNode = self.document.createElement("BoundingBoxOutput")
417            bboxNode.setAttribute("defaultCRS","")
418            crsNode = self.document.createElement("CRS")
419            bboxNode.appendChild(crsNode)
420            parent.appendChild(bboxNode)
421        return
422
423    def supportedUOMsElement(self, parent, litvalue, outputStructure):
424        """
425        Creates <SuppotedUOMs> tag with it's subelements
426       
427        parent  - parent xml tag
428        litvalue - literaloutput process structure
429        outputStructure  - definition of literaloutput structure (from  ogc/describeprocess.py)
430        """
431
432        supportedUOMs = self.document.createElement("%s%s" % \
433                (outputStructure['elements']['SupportedUOMs']['ns'],"SupportedUOMs"))
434       
435        # uoms here?
436        if litvalue.has_key('UOMs'):
437
438            supportedUOMs.setAttribute("%s%s" % \
439                    (outputStructure['elements']['SupportedUOMs']['attributes']['defaultUOM']['ns'],\
440                    "defaultUOM"), litvalue['UOMs'][0])
441
442            # for each UOM, make tag
443            for uom in litvalue['UOMs']:
444                UOM = self.document.createElement("%s%s" % \
445                        (outputStructure['elements']['SupportedUOMs']['elements']['UOM']['ns'],\
446                        "UOM"))
447                supportedUOMs.appendChild(UOM)
448                UOM.appendChild(self.document.createTextNode(uom))
449
450               
451        # no uoms, take the default value
452        else:
453            supportedUOMs.setAttribute("%s%s" % \
454                    (outputStructure['elements']['SupportedUOMs']['attributes']['defaultUOM']['ns'],\
455                    "defaultUOM"),
456                    outputStructure['elements']['SupportedUOMs']['attributes']['defaultUOM']['default'])
457        parent.appendChild(supportedUOMs)
458
Note: See TracBrowser for help on using the repository browser.