1 /**********************************************************************
2  * $Id$
3  *
4  * Project:  MapServer
5  * Purpose:  OGC SOS implementation
6  * Author:   Y. Assefa, DM Solutions Group (assefa@dmsolutions.ca)
7  *
8  **********************************************************************
9  * Copyright (c) 2006, Y. Assefa, DM Solutions Group Inc
10  *
11  * Permission is hereby granted, free of charge, to any person obtaining a
12  * copy of this software and associated documentation files (the "Software"),
13  * to deal in the Software without restriction, including without limitation
14  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15  * and/or sell copies of the Software, and to permit persons to whom the
16  * Software is furnished to do so, subject to the following conditions:
17  *
18  * The above copyright notice and this permission notice shall be included in
19  * all copies of this Software or works derived from this Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
24  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27  * DEALINGS IN THE SOFTWARE.
28  **********************************************************************/
29 
30 #define _GNU_SOURCE
31 
32 #include "mapserver.h"
33 #include "mapows.h"
34 
35 #if defined(USE_SOS_SVR) && defined(USE_LIBXML2)
36 
37 #include "maperror.h"
38 #include "mapthread.h"
39 #include "mapows.h"
40 #include "maptime.h"
41 #include "mapgml.h"
42 #include "mapogcfilter.h"
43 
44 #include "mapowscommon.h"
45 #include "maplibxml2.h"
46 
47 #include "libxml/parser.h"
48 #include "libxml/tree.h"
49 #include "libxml/xpath.h"
50 #include "libxml/xpathInternals.h"
51 
52 const char *pszSOSVersion                = "1.0.0";
53 const char *pszSOSNamespaceUri           = "http://www.opengis.net/sos/1.0";
54 const char *pszSOSNamespacePrefix        = "sos";
55 const char *pszOMNamespaceUri            = "http://www.opengis.net/om/1.0";
56 const char *pszOMNamespacePrefix         = "om";
57 const char *pszSOSDescribeSensorMimeType = "text/xml; subtype=\"sensorML/1.0.0\"";
58 const char *pszSOSGetObservationMimeType = "text/xml; subtype=\"om/1.0.0\"";
59 
60 typedef struct {
61   char *pszProcedure;
62   xmlNodePtr psResultNode;
63 } SOSProcedureNode;
64 
65 int msSOSParseRequest(mapObj *map, cgiRequestObj *request, sosParamsObj *sosparams);
66 void msSOSFreeParamsObj(sosParamsObj *sosparams);
67 
68 /*
69 ** msSOSException()
70 **
71 ** Report current MapServer error in XML exception format.
72 ** Wrapper function around msOWSCommonExceptionReport. Merely
73 ** passes SOS specific info.
74 **
75 */
76 
msSOSException(mapObj * map,char * locator,char * exceptionCode)77 static int msSOSException(mapObj *map, char *locator, char *exceptionCode)
78 {
79   int size = 0;
80   char *errorString     = NULL;
81   char *schemasLocation = NULL;
82 
83   xmlDocPtr  psDoc      = NULL;
84   xmlNodePtr psRootNode = NULL;
85   xmlNsPtr   psNsOws    = NULL;
86   xmlChar *buffer       = NULL;
87 
88   psNsOws = xmlNewNs(NULL, BAD_CAST "http://www.opengis.net/ows/1.1", BAD_CAST "ows");
89 
90   errorString = msGetErrorString("\n");
91   schemasLocation = msEncodeHTMLEntities(msOWSGetSchemasLocation(map));
92 
93   psDoc = xmlNewDoc(BAD_CAST "1.0");
94 
95   psRootNode = msOWSCommonExceptionReport(psNsOws, OWS_1_1_0, schemasLocation, pszSOSVersion, msOWSGetLanguage(map, "exception"), exceptionCode, locator, errorString);
96 
97   xmlDocSetRootElement(psDoc, psRootNode);
98 
99   xmlNewNs(psRootNode, BAD_CAST "http://www.opengis.net/ows/1.1", BAD_CAST "ows");
100 
101   msIO_setHeader("Content-Type","text/xml; charset=UTF-8");
102   msIO_sendHeaders();
103 
104   xmlDocDumpFormatMemoryEnc(psDoc, &buffer, &size, ("UTF-8"), 1);
105 
106   msIO_printf("%s", buffer);
107 
108   /*free buffer and the document */
109   free(errorString);
110   free(schemasLocation);
111   xmlFree(buffer);
112   xmlFreeDoc(psDoc);
113   xmlFreeNs(psNsOws);
114 
115   /*
116   ** The typical pattern is to call msSOSException() right after
117   ** msSetError().  In order to prevent mapserv.c from re-reporting this
118   ** error at a higher level, we mark it as reported here. #3571
119   */
120   {
121     errorObj *err = msGetErrorObj();
122     if( err != NULL && err->code != MS_NOERR )
123       err->isreported = MS_TRUE;
124   }
125 
126   return MS_FAILURE;
127 }
128 
_IsInList(char ** papsProcedures,int nDistinctProcedures,char * pszProcedure)129 static int _IsInList(char **papsProcedures, int nDistinctProcedures, char *pszProcedure)
130 {
131   int i = 0;
132   if (papsProcedures && nDistinctProcedures > 0 && pszProcedure) {
133     for (i=0; i<nDistinctProcedures; i++) {
134       if (papsProcedures[i] && strcmp(papsProcedures[i], pszProcedure) == 0)
135         return 1;
136     }
137   }
138   return 0;
139 }
140 
141 /************************************************************************/
142 /*                           msSOSValidateFilter                        */
143 /*                                                                      */
144 /*      Look if the filter's property names have an equivalent          */
145 /*      layre's attribute.                                              */
146 /************************************************************************/
msSOSValidateFilter(FilterEncodingNode * psFilterNode,layerObj * lp)147 static int msSOSValidateFilter(FilterEncodingNode *psFilterNode,
148                                layerObj *lp)
149 {
150   int i=0, bFound =0;
151   /* assuming here that the layer is opened*/
152   if (psFilterNode && lp) {
153     if (psFilterNode->eType == FILTER_NODE_TYPE_PROPERTYNAME) {
154       for (i=0; i<lp->numitems; i++) {
155         if (strcasecmp(lp->items[i], psFilterNode->pszValue) == 0) {
156           bFound = 1;
157           break;
158         }
159       }
160       if (!bFound)
161         return MS_FALSE;
162     }
163     if (psFilterNode->psLeftNode && psFilterNode->eType != FILTER_NODE_TYPE_SPATIAL) {
164       if (msSOSValidateFilter(psFilterNode->psLeftNode, lp) == MS_FALSE)
165         return MS_FALSE;
166     }
167     if (psFilterNode->psRightNode && psFilterNode->eType != FILTER_NODE_TYPE_SPATIAL) {
168       if (msSOSValidateFilter(psFilterNode->psRightNode, lp) == MS_FALSE)
169         return MS_FALSE;
170     }
171   }
172 
173   return MS_TRUE;
174 }
175 
176 
177 
178 /************************************************************************/
179 /*                        msSOSAddMetadataChildNode                     */
180 /*                                                                      */
181 /*      Utility function to add a metadata node.                        */
182 /************************************************************************/
msSOSAddMetadataChildNode(xmlNodePtr psParent,const char * psNodeName,xmlNsPtr psNs,hashTableObj * metadata,const char * psNamespaces,const char * psMetadataName,const char * psDefaultValue)183 void msSOSAddMetadataChildNode(xmlNodePtr psParent, const char *psNodeName,
184                                xmlNsPtr psNs, hashTableObj *metadata,
185                                const char *psNamespaces,
186                                const char *psMetadataName,
187                                const char *psDefaultValue)
188 {
189   xmlNodePtr psNode = NULL;
190   char *psValue = NULL;
191 
192   if (psParent && psNodeName) {
193     psValue = msOWSGetEncodeMetadata(metadata, psNamespaces, psMetadataName,
194                                      psDefaultValue);
195     if (psValue) {
196       psNode = xmlNewChild(psParent, NULL, BAD_CAST psNodeName, BAD_CAST psValue);
197       if (psNs)
198         xmlSetNs(psNode,  psNs);
199       free(psValue);
200     }
201   }
202 }
203 
204 
205 /************************************************************************/
206 /*                      msSOSGetFirstLayerForOffering                   */
207 /*                                                                      */
208 /*      return the first layer for the offering.                        */
209 /************************************************************************/
msSOSGetFirstLayerForOffering(mapObj * map,const char * pszOffering,const char * pszProperty)210 layerObj *msSOSGetFirstLayerForOffering(mapObj *map, const char *pszOffering,
211                                         const char *pszProperty)
212 {
213   layerObj *lp = NULL;
214   const char *pszTmp = NULL;
215   int i = 0;
216 
217   if (pszOffering && map) {
218     for (i=0; i<map->numlayers; i++) {
219       pszTmp =
220         msOWSLookupMetadata(&(GET_LAYER(map, i)->metadata), "S", "offering_id");
221       if (pszTmp && (strcasecmp(pszTmp, pszOffering) == 0)) {
222         if (pszProperty) {
223           pszTmp =
224             msOWSLookupMetadata(&(GET_LAYER(map, i)->metadata), "S",
225                                 "observedproperty_id");
226           if (pszTmp && (strcasecmp(pszTmp, pszProperty) == 0)) {
227             lp = (GET_LAYER(map, i));
228             break;
229           }
230         } else {
231           lp = (GET_LAYER(map, i));
232           break;
233         }
234       }
235     }
236   }
237   return lp;
238 }
239 
msSOSAddTimeNode(xmlNsPtr psNs,xmlNsPtr psNsGml,char * pszStart,char * pszEnd)240 xmlNodePtr msSOSAddTimeNode(xmlNsPtr psNs, xmlNsPtr psNsGml, char *pszStart, char *pszEnd)
241 {
242   xmlNodePtr psNode=NULL;
243 
244   char *timeel= NULL;
245 
246   if (strcmp((char *)psNs->prefix,"sos") == 0)
247     timeel = "time";
248   if (strcmp((char *)psNs->prefix,"om") == 0)
249     timeel = "samplingTime";
250   else
251     timeel = "time";
252 
253   psNode = xmlNewNode(psNs, BAD_CAST timeel);
254   xmlAddChild(psNode, msGML3TimePeriod(psNsGml, pszStart, pszEnd));
255   return psNode;
256 }
257 
msSOSAddPropertyNode(xmlNsPtr psNsSwe,xmlNsPtr psNsXLink,xmlNodePtr psParent,layerObj * lp,xmlNsPtr psNsGml,char * pszCompositePhenomenonId)258 void msSOSAddPropertyNode(xmlNsPtr psNsSwe, xmlNsPtr psNsXLink, xmlNodePtr psParent, layerObj *lp, xmlNsPtr psNsGml, char *pszCompositePhenomenonId)
259 {
260   const char *pszValue = NULL;
261   char *pszTmpVal = NULL, *pszFullName = NULL;
262   xmlNodePtr psCompNode, psNode;
263   int i, j=0;
264   char szTmp[256];
265   const char *pszComponentBase = "urn:ogc:def:property:";
266 
267   if (psParent && lp) {
268     psNode = xmlNewChild(psParent, NULL, BAD_CAST "observedProperty", NULL);
269     psCompNode = xmlNewChild(psNode, psNsSwe, BAD_CAST "CompositePhenomenon", NULL);
270     pszValue = msOWSLookupMetadata(&(lp->metadata), "S",
271                                    "observedproperty_id");
272     pszTmpVal = msStrdup(pszValue);
273 
274     if (pszCompositePhenomenonId != NULL) { /* unique value needs to be constructed */
275       pszTmpVal = msStringConcatenate(pszTmpVal, "_");
276       pszTmpVal = msStringConcatenate(pszTmpVal, pszCompositePhenomenonId);
277     }
278 
279     if (pszTmpVal) { /*should always be true */
280       xmlNewNsProp(psCompNode, psNsGml, BAD_CAST "id", BAD_CAST pszTmpVal);
281       msFree(pszTmpVal);
282     }
283 
284     pszValue = msOWSLookupMetadata(&(lp->metadata), "S",
285                                    "observedproperty_name");
286     if (pszValue)
287       psNode = xmlNewTextChild(psCompNode, psNsGml,
288                            BAD_CAST "name", BAD_CAST pszValue);
289 
290     /* add components */
291 
292     /*assuming that the layer is opened and msLayerGetItems called*/
293     for(i=0; i<lp->numitems; i++) {
294       pszValue = msOWSLookupMetadata(&(lp->metadata), "S", "observedproperty_authority");
295 
296       if (pszValue)
297         pszTmpVal = msStrdup(pszValue);
298       else
299         pszTmpVal = msStrdup("OGC-SWE");
300 
301       pszFullName = msStrdup(pszComponentBase);
302 
303       pszFullName = msStringConcatenate(pszFullName, pszTmpVal);
304 
305       free(pszTmpVal);
306 
307       pszFullName = msStringConcatenate(pszFullName, ":");
308 
309       pszValue = msOWSLookupMetadata(&(lp->metadata), "S", "observedproperty_version");
310 
311       if (pszValue)
312         pszTmpVal = msStrdup(pszValue);
313       else
314         pszTmpVal = msStrdup("1");
315 
316       pszFullName = msStringConcatenate(pszFullName, pszTmpVal);
317 
318       free(pszTmpVal);
319 
320       pszFullName = msStringConcatenate(pszFullName, ":");
321 
322       snprintf(szTmp, sizeof(szTmp), "%s_alias", lp->items[i]);
323       pszValue = msOWSLookupMetadata(&(lp->metadata), "S", szTmp);
324 
325       if (pszValue)
326         pszTmpVal = msStrdup(pszValue);
327       else
328         pszTmpVal = msStrdup(lp->items[i]);
329 
330       pszFullName = msStringConcatenate(pszFullName, pszTmpVal);
331 
332       psNode = xmlNewChild(psCompNode, psNsSwe, BAD_CAST "component", NULL);
333 
334       xmlNewNsProp(psNode, psNsXLink, BAD_CAST "href", BAD_CAST pszFullName);
335       free(pszFullName);
336       free(pszTmpVal);
337       j++;
338     }
339     pszTmpVal = msIntToString(j);
340     xmlNewNsProp(psCompNode, NULL, BAD_CAST "dimension", BAD_CAST pszTmpVal);
341     free(pszTmpVal);
342   }
343 }
344 
345 /************************************************************************/
346 /*                           msSOSAddGeometryNode                       */
347 /*                                                                      */
348 /*      Outout gml 2 gemptry nodes based on a shape. All logic comes    */
349 /*      from gmlWriteGeometry_GML2. Should be merged at one point if    */
350 /*      possible.                                                       */
351 /************************************************************************/
msSOSAddGeometryNode(xmlNsPtr psNsGml,xmlNsPtr psNsMs,xmlNodePtr psParent,mapObj * map,layerObj * lp,shapeObj * psShape,const char * pszEpsg_in)352 void  msSOSAddGeometryNode(xmlNsPtr psNsGml, xmlNsPtr psNsMs, xmlNodePtr psParent, mapObj *map, layerObj *lp, shapeObj *psShape,
353                            const char *pszEpsg_in)
354 {
355   char *pszTmp = NULL;
356   int i,j = 0;
357   xmlNodePtr psPointNode, psNode, psLineNode, psPolygonNode;
358   int *panOuterList = NULL, *panInnerList = NULL;
359   const char *pszEpsg = pszEpsg_in;
360   char *pszEpsg_buf = NULL;
361 
362 
363   if (psParent && psShape) {
364     if (msProjectionsDiffer(&map->projection, &lp->projection) == MS_TRUE) {
365       if( lp->reprojectorLayerToMap == NULL )
366       {
367         lp->reprojectorLayerToMap = msProjectCreateReprojector(
368             &lp->projection, &map->projection);
369       }
370       if( lp->reprojectorLayerToMap )
371       {
372         msProjectShapeEx(lp->reprojectorLayerToMap, psShape);
373       }
374       msOWSGetEPSGProj(&(map->projection), &(lp->metadata), "SO", MS_TRUE, &pszEpsg_buf);
375       pszEpsg = pszEpsg_buf;
376     }
377     switch(psShape->type) {
378       case(MS_SHAPE_POINT):
379         psNode = xmlNewChild(psParent, NULL, BAD_CAST "msGeometry", NULL);
380         xmlSetNs(psNode, psNsMs);
381         if (psShape->line[0].numpoints > 1) {
382           psPointNode = xmlNewChild(psNode, NULL, BAD_CAST "MultiPoint", NULL);
383           xmlSetNs(psPointNode, psNsGml);
384 
385           if (pszEpsg)
386             xmlNewProp(psPointNode, BAD_CAST "srsName", BAD_CAST pszEpsg);
387         } else
388           psPointNode= psNode;
389 
390         /*add all points */
391         for(i=0; i<psShape->line[0].numpoints; i++) {
392           psNode = xmlAddChild(psPointNode, msGML3Point(psNsGml, pszEpsg, NULL, psShape->line[0].point[i].x, psShape->line[0].point[i].y));
393         }
394         break;
395 
396       case(MS_SHAPE_LINE):
397         psNode = xmlNewChild(psParent, NULL, BAD_CAST "msGeometry", NULL);
398         xmlSetNs(psNode,xmlNewNs(psNode, NULL,  NULL));
399         if (psShape->numlines > 1) {
400           psLineNode = xmlNewChild(psNode, NULL, BAD_CAST "MultiLineString", NULL);
401           xmlSetNs(psLineNode,xmlNewNs(psLineNode,
402                                        BAD_CAST "http://www.opengis.net/gml",
403                                        BAD_CAST "gml"));
404 
405           if (pszEpsg)
406             xmlNewProp(psLineNode, BAD_CAST "srsName", BAD_CAST pszEpsg);
407         } else
408           psLineNode= psNode;
409 
410         for(i=0; i<psShape->numlines; i++) {
411           if (psShape->numlines > 1) {
412             psNode = xmlNewChild(psLineNode, NULL, BAD_CAST "lineStringMember", NULL);
413             xmlSetNs(psNode,xmlNewNs(psNode,
414                                      BAD_CAST "http://www.opengis.net/gml",
415                                      BAD_CAST "gml"));
416             psNode = xmlNewChild(psNode, NULL, BAD_CAST "LineString", NULL);
417             xmlSetNs(psNode,xmlNewNs(psNode,
418                                      BAD_CAST "http://www.opengis.net/gml",
419                                      BAD_CAST "gml"));
420           } else {
421             psNode = xmlNewChild(psLineNode, NULL, BAD_CAST "LineString", NULL);
422             xmlSetNs(psNode,xmlNewNs(psNode,
423                                      BAD_CAST "http://www.opengis.net/gml",
424                                      BAD_CAST "gml"));
425           }
426           if (pszEpsg)
427             xmlNewProp(psNode, BAD_CAST "srsName", BAD_CAST pszEpsg);
428 
429           pszTmp = NULL;
430           for(j=0; j<psShape->line[i].numpoints; j++) {
431             char *doubleTmp = msDoubleToString(psShape->line[i].point[j].x, MS_TRUE);
432             pszTmp = msStringConcatenate(pszTmp, doubleTmp);
433             pszTmp = msStringConcatenate(pszTmp, ",");
434             free(doubleTmp);
435             doubleTmp = msDoubleToString(psShape->line[i].point[j].y, MS_TRUE);
436             pszTmp = msStringConcatenate(pszTmp, doubleTmp);
437             pszTmp = msStringConcatenate(pszTmp, ",");
438             free(doubleTmp);
439           }
440           psNode = xmlNewChild(psNode, NULL, BAD_CAST "coordinates", BAD_CAST pszTmp);
441           xmlSetNs(psNode,xmlNewNs(psNode, BAD_CAST "http://www.opengis.net/gml", BAD_CAST "gml"));
442           free(pszTmp);
443         }
444 
445         break;
446 
447       case(MS_SHAPE_POLYGON):
448         psNode = xmlNewChild(psParent, NULL, BAD_CAST "msGeometry", NULL);
449         xmlSetNs(psNode,xmlNewNs(psNode, NULL,  NULL));
450         if (psShape->numlines > 1) {
451           psPolygonNode = xmlNewChild(psNode, NULL, BAD_CAST "MultiPolygon", NULL);
452           xmlSetNs(psPolygonNode,
453                    xmlNewNs(psPolygonNode, BAD_CAST "http://www.opengis.net/gml",
454                             BAD_CAST "gml"));
455 
456           if (pszEpsg)
457             xmlNewProp(psPolygonNode, BAD_CAST "srsName", BAD_CAST pszEpsg);
458         } else
459           psPolygonNode= psNode;
460 
461         panOuterList = msGetOuterList(psShape);
462 
463         for(i=0; i<psShape->numlines; i++) {
464           if(panOuterList[i] != MS_TRUE)
465             continue;
466 
467           panInnerList = msGetInnerList(psShape, i, panOuterList);
468 
469           if (psShape->numlines > 1) {
470             psNode = xmlNewChild(psPolygonNode, NULL, BAD_CAST "polygonMember", NULL);
471             xmlSetNs(psNode,xmlNewNs(psNode, BAD_CAST "http://www.opengis.net/gml",
472                                      BAD_CAST "gml"));
473             psNode = xmlNewChild(psNode, NULL, BAD_CAST "Polygon", NULL);
474             xmlSetNs(psNode,xmlNewNs(psNode, BAD_CAST "http://www.opengis.net/gml",
475                                      BAD_CAST "gml"));
476           } else {
477             psNode = xmlNewChild(psPolygonNode, NULL, BAD_CAST "Polygon", NULL);
478             xmlSetNs(psNode,xmlNewNs(psNode, BAD_CAST "http://www.opengis.net/gml",
479                                      BAD_CAST "gml"));
480           }
481           if (pszEpsg)
482             xmlNewProp(psNode, BAD_CAST "srsName", BAD_CAST pszEpsg);
483 
484           psNode = xmlNewChild(psNode, NULL, BAD_CAST "outerBoundaryIs", NULL);
485           xmlSetNs(psNode,xmlNewNs(psNode, BAD_CAST "http://www.opengis.net/gml",
486                                    BAD_CAST "gml"));
487           psNode = xmlNewChild(psNode, NULL, BAD_CAST "LinearRing", NULL);
488           xmlSetNs(psNode,xmlNewNs(psNode, BAD_CAST "http://www.opengis.net/gml",
489                                    BAD_CAST "gml"));
490 
491           pszTmp = NULL;
492           for(j=0; j<psShape->line[i].numpoints; j++) {
493             char *doubleTmp;
494             doubleTmp = msDoubleToString(psShape->line[i].point[j].x, MS_TRUE);
495             pszTmp = msStringConcatenate(pszTmp, doubleTmp);
496             pszTmp = msStringConcatenate(pszTmp, ",");
497             free(doubleTmp);
498             doubleTmp = msDoubleToString(psShape->line[i].point[j].y, MS_TRUE);
499             pszTmp = msStringConcatenate(pszTmp, doubleTmp);
500             pszTmp = msStringConcatenate(pszTmp, " ");
501             free(doubleTmp);
502           }
503           psNode = xmlNewChild(psNode, NULL, BAD_CAST "coordinates", BAD_CAST pszTmp);
504           xmlSetNs(psNode,xmlNewNs(psNode,
505                                    BAD_CAST "http://www.opengis.net/gml",
506                                    BAD_CAST "gml"));
507           free(pszTmp);
508 
509           if (panInnerList)
510             free(panInnerList);
511         }
512 
513         if (panOuterList)
514           free(panOuterList);
515 
516         break;
517 
518       default:
519         break;
520     }
521 
522   }
523   msFree(pszEpsg_buf);
524 
525 }
526 
527 /************************************************************************/
528 /*          void msSOSAddDataBlockDefinition(xmlNodePtr psParent,       */
529 /*      layerObj *lp)                                                   */
530 /*                                                                      */
531 /*      Add a databalock used for GetObservation request.               */
532 /************************************************************************/
msSOSAddDataBlockDefinition(xmlNsPtr psNsSwe,xmlNodePtr psParent,layerObj * lp)533 void msSOSAddDataBlockDefinition(xmlNsPtr psNsSwe, xmlNodePtr psParent, layerObj *lp)
534 {
535   xmlNodePtr psNode, psRecordNode, psCompNode, psSubNode, psEncNode;
536   const char *pszDefinition = NULL, *pszUom=NULL, *pszValue=NULL, *pszName=NULL;
537   char szTmp[100];
538   int i=0;
539   char *pszTokenValue = NULL;
540   char *pszBlockValue = NULL;
541   const char *pszBlockSep=NULL, *pszTokenSep=NULL;
542 
543   if (psParent) {
544     psNode = xmlNewChild(psParent, NULL, BAD_CAST "DataBlockDefinition", NULL);
545     xmlSetNs(psNode, psNsSwe);
546 
547     /* -------------------------------------------------------------------- */
548     /*      Add components.                                                 */
549     /* -------------------------------------------------------------------- */
550     psCompNode = xmlNewChild(psNode, NULL, BAD_CAST "components", NULL);
551     psEncNode = xmlNewChild(psNode, NULL, BAD_CAST "encoding", NULL);
552     psRecordNode = xmlNewChild(psCompNode, NULL, BAD_CAST "DataRecord", NULL);
553 
554     /*always add a time field if timeitem is defined*/
555     if (msOWSLookupMetadata(&(lp->metadata), "SO", "timeitem")) {
556       psNode = xmlNewChild(psRecordNode, NULL, BAD_CAST "field", NULL);
557       xmlNewNsProp(psNode, NULL, BAD_CAST "name", BAD_CAST "time");
558       psNode = xmlNewChild(psNode, NULL, BAD_CAST "Time", NULL);
559       xmlNewNsProp(psNode, NULL, BAD_CAST "definition", BAD_CAST "urn:ogc:phenomenon:time:iso8601");
560     }
561     /*add all other fields*/
562     /*assuming that the layer is open */
563     for(i=0; i<lp->numitems; i++) {
564       snprintf(szTmp, sizeof(szTmp), "%s_alias", lp->items[i]);
565       pszValue = msOWSLookupMetadata(&(lp->metadata), "S", szTmp);
566       if (pszValue) {
567         psNode = xmlNewChild(psRecordNode, NULL, BAD_CAST "field", NULL);
568 
569         /* check if there is an alias/full name used */
570         snprintf(szTmp, sizeof(szTmp), "%s_alias", lp->items[i]);
571         pszName = msOWSLookupMetadata(&(lp->metadata), "S", szTmp);
572         if (!pszName)
573           pszName = lp->items[i];
574 
575         xmlNewNsProp(psNode, NULL, BAD_CAST "name", BAD_CAST pszName);
576 
577         psNode = xmlNewChild(psNode, NULL, BAD_CAST "Quantity", NULL);
578 
579         /* get definition and uom */
580         snprintf(szTmp, sizeof(szTmp), "%s_definition", lp->items[i]);
581         pszDefinition =  msOWSLookupMetadata(&(lp->metadata), "S", szTmp);
582 
583         if (pszDefinition == NULL)
584           pszDefinition = "urn:ogc:object:definition";
585 
586         xmlNewNsProp(psNode, NULL, BAD_CAST "definition", BAD_CAST pszDefinition);
587 
588         snprintf(szTmp, sizeof(szTmp), "%s_uom", lp->items[i]);
589         pszUom =  msOWSLookupMetadata(&(lp->metadata), "S", szTmp);
590 
591         if (pszUom == NULL)
592           pszUom = "urn:ogc:object:uom";
593 
594         psNode = xmlNewChild(psNode, NULL, BAD_CAST "uom", NULL);
595         xmlNewNsProp(psNode, NULL, BAD_CAST "code", BAD_CAST pszUom);
596 
597       }
598     }
599 
600     /* -------------------------------------------------------------------- */
601     /*      Add encoding block.                                             */
602     /* -------------------------------------------------------------------- */
603     pszBlockSep = msOWSLookupMetadata(&(lp->map->web.metadata), "S",
604                                       "encoding_blockSeparator");
605     pszTokenSep = msOWSLookupMetadata(&(lp->map->web.metadata), "S",
606                                       "encoding_tokenSeparator");
607 
608     psSubNode = xmlNewChild(psEncNode, NULL, BAD_CAST "TextBlock", NULL);
609 
610     if (pszTokenSep)
611       pszTokenValue = msStringConcatenate(pszTokenValue, (char *)pszTokenSep);
612     else
613       pszTokenValue = msStringConcatenate(pszTokenValue, ",");
614 
615     xmlNewNsProp(psSubNode, NULL, BAD_CAST "tokenSeparator", BAD_CAST pszTokenValue);
616 
617     if (pszBlockSep)
618       pszBlockValue = msStringConcatenate(pszBlockValue, (char *)pszBlockSep);
619     else
620       pszBlockValue = msStringConcatenate(pszBlockValue, "\n");
621 
622     xmlNewNsProp(psSubNode, NULL, BAD_CAST "blockSeparator", BAD_CAST pszBlockValue);
623 
624     xmlNewNsProp(psSubNode, NULL, BAD_CAST "decimalSeparator", BAD_CAST ".");
625 
626     msFree(pszTokenValue);
627     msFree(pszBlockValue);
628   }
629 }
630 
631 /************************************************************************/
632 /*                            msSOSAddMemberNode                        */
633 /*                                                                      */
634 /*      Add a memeber node corresponding to a feature.                  */
635 /*      Assuming that the layer is opened and msLayerGetItems is        */
636 /*      called on it.                                                   */
637 /************************************************************************/
msSOSAddMemberNode(xmlNsPtr psNsGml,xmlNsPtr psNsOm,xmlNsPtr psNsSwe,xmlNsPtr psNsXLink,xmlNsPtr psNsMs,xmlNodePtr psParent,mapObj * map,layerObj * lp,int iFeatureId,const char * script_url,const char * opLayerName)638 void msSOSAddMemberNode(xmlNsPtr psNsGml, xmlNsPtr psNsOm, xmlNsPtr psNsSwe, xmlNsPtr psNsXLink, xmlNsPtr psNsMs, xmlNodePtr psParent, mapObj *map, layerObj *lp,
639                         int iFeatureId, const char *script_url, const char *opLayerName)
640 {
641   xmlNodePtr psObsNode, psNode, psLayerNode = NULL;
642   const char *pszValue = NULL;
643   char *pszEpsg = NULL;
644   int status,i,j;
645   shapeObj sShape;
646   char szTmp[256];
647   layerObj *lpfirst = NULL;
648   const char *pszTimeField = NULL;
649   char *pszTmp = NULL;
650   char *pszOid = NULL;
651   char *pszTime = NULL;
652   char *pszValueShape = NULL;
653   const char *pszFeatureId  = NULL;
654 
655   if (psParent) {
656     msInitShape(&sShape);
657 
658     status = msLayerGetShape(lp, &sShape, &(lp->resultcache->results[iFeatureId]));
659     if(status != MS_SUCCESS) {
660       xmlFreeNs(psNsOm);
661       return;
662     }
663 
664     psNode = xmlNewChild(psParent, NULL, BAD_CAST "member", NULL);
665 
666     psObsNode = xmlNewChild(psNode, NULL, BAD_CAST "Observation", BAD_CAST pszValue);
667 
668     pszFeatureId = msOWSLookupMetadata(&(lp->metadata), "OSG", "featureid");
669 
670     if(pszFeatureId && msLayerGetItems(lp) == MS_SUCCESS) {
671       /* find the featureid amongst the items for this layer */
672       for(j=0; j<lp->numitems; j++) {
673         if(strcasecmp(lp->items[j], pszFeatureId) == 0) { /* found it  */
674           break;
675         }
676       }
677       if (j<lp->numitems) {
678         pszOid = msStringConcatenate(pszOid, "o_");
679         pszOid = msStringConcatenate(pszOid, sShape.values[j]);
680         xmlNewNsProp(psObsNode, psNsGml, BAD_CAST "id", BAD_CAST pszOid);
681       }
682     }
683 
684     /* order of elements is time, location, procedure, observedproperty
685      featureofinterest, result */
686 
687     /* time*/
688     pszTimeField =  msOWSLookupMetadata(&(lp->metadata), "SO",
689                                         "timeitem");
690     if (pszTimeField && sShape.values) {
691       for(i=0; i<lp->numitems; i++) {
692         if (strcasecmp(lp->items[i], pszTimeField) == 0) {
693           if (sShape.values[i] && strlen(sShape.values[i]) > 0) {
694             pszTime = msStringConcatenate(pszTime, sShape.values[i]);
695             psNode = xmlNewChild(psObsNode, psNsOm, BAD_CAST "samplingTime", NULL);
696             xmlAddChild(psNode, msGML3TimeInstant(psNsGml, pszTime));
697             msFree(pszTime);
698           }
699           break;
700         }
701       }
702     }
703     /*TODO add location*/
704 
705     /*procedure*/
706     /* if a procedure_item is defined, we should extract the value for the
707        attributes. If not dump what is found in the procedure metadata bug 2054*/
708     if ((pszValue =  msOWSLookupMetadata(&(lp->metadata), "S", "procedure_item"))) {
709       lpfirst = msSOSGetFirstLayerForOffering(map,
710                                               msOWSLookupMetadata(&(lp->metadata), "S",
711                                                   "offering_id"),
712                                               msOWSLookupMetadata(&(lp->metadata), "S",
713                                                   "observedproperty_id"));
714 
715       if (lp != lpfirst)
716         status = msLayerOpen(lpfirst);
717       if (status == MS_SUCCESS && msLayerGetItems(lpfirst) == MS_SUCCESS) {
718         for(i=0; i<lpfirst->numitems; i++) {
719           if (strcasecmp(lpfirst->items[i], pszValue) == 0) {
720             break;
721           }
722         }
723         if (i < lpfirst->numitems) {
724           snprintf(szTmp, sizeof(szTmp), "%s", "urn:ogc:def:procedure:");
725           pszTmp = msStringConcatenate(pszTmp, szTmp);
726           pszValueShape = msEncodeHTMLEntities(sShape.values[i]);
727           pszTmp = msStringConcatenate(pszTmp, pszValueShape);
728 
729           psNode =  xmlNewChild(psObsNode, NULL, BAD_CAST "procedure", NULL);
730           xmlNewNsProp(psNode, psNsXLink, BAD_CAST "href", BAD_CAST pszTmp);
731           msFree(pszTmp);
732           pszTmp = NULL;
733           msFree(pszValueShape);
734         }
735         /*else should we generate a warning !*/
736         if (lp != lpfirst)
737           msLayerClose(lpfirst);
738       }
739 
740     } else if ((pszValue = msOWSLookupMetadata(&(lp->metadata), "S", "procedure"))) {
741       if (! msOWSLookupMetadata(&(lp->metadata), "S", "procedure_item"))
742         xmlAddSibling(psNode, xmlNewComment(BAD_CAST "WARNING: Optional metadata \"sos_procedure_item\" missing for sos:procedure.  If you have more than 1 procedures, sos:procedure will output them incorrectly."));
743 
744       snprintf(szTmp, sizeof(szTmp), "%s", "urn:ogc:def:procedure:");
745       pszTmp = msStringConcatenate(pszTmp, szTmp);
746       pszTmp = msStringConcatenate(pszTmp, (char *)pszValue);
747 
748       psNode =  xmlNewChild(psObsNode, NULL, BAD_CAST "procedure", NULL);
749       xmlNewNsProp(psNode, psNsXLink, BAD_CAST "href", BAD_CAST pszTmp);
750       msFree(pszTmp);
751       pszTmp = NULL;
752     }
753 
754     /*observed property*/
755     pszValue = msOWSLookupMetadata(&(lp->metadata), "S",
756                                    "observedproperty_id");
757     if (pszValue)
758       msSOSAddPropertyNode(psNsSwe, psNsXLink, psObsNode, lp, psNsGml, pszOid);
759     msFree(pszOid);
760     pszOid = NULL;
761 
762     /*TODO add featureofinterest*/
763 
764     pszTmp = msStringConcatenate(pszTmp, (char *) script_url);
765     pszTmp = msStringConcatenate(pszTmp, "service=WFS&version=1.1.0&request=DescribeFeatureType&typename=");
766     pszTmp = msStringConcatenate(pszTmp, (char *) opLayerName);
767 
768     psNode =  xmlNewChild(psObsNode, psNsOm, BAD_CAST "featureOfInterest", NULL);
769     xmlNewNsProp(psNode, psNsXLink, BAD_CAST "href", BAD_CAST pszTmp);
770 
771     msFree(pszTmp);
772     pszTmp=NULL;
773 
774     /* add result : gml:featureMember of all selected elements */
775     psNode = xmlNewChild(psObsNode, NULL, BAD_CAST "result", NULL);
776 
777     /*TODO should we add soemwhere the units of the value :
778       <om:result uom="units.xml#cm">29.00</om:result> */
779 
780 
781     if(msProjectionsDiffer(&(lp->projection), &(map->projection)))
782     {
783       if( lp->reprojectorLayerToMap == NULL )
784       {
785         lp->reprojectorLayerToMap = msProjectCreateReprojector(
786             &lp->projection, &map->projection);
787       }
788       if( lp->reprojectorLayerToMap )
789       {
790         msProjectShapeEx(lp->reprojectorLayerToMap, &sShape);
791       }
792     }
793 
794     psNode = xmlNewChild(psNode, psNsGml, BAD_CAST "featureMember", NULL);
795     /* xmlSetNs(psNode,xmlNewNs(psNode, BAD_CAST "http://www.opengis.net/gml", BAD_CAST "gml")); */
796 
797     /*TODO : add namespaces like wfs " ms and a url to mapserve ? */
798     psLayerNode = xmlNewChild(psNode, psNsMs, BAD_CAST lp->name, NULL);
799 
800     /* fetch gml:id */
801 
802     pszFeatureId = msOWSLookupMetadata(&(lp->metadata), "OSG", "featureid");
803 
804     if(pszFeatureId && msLayerOpen(lp) == MS_SUCCESS && msLayerGetItems(lp) == MS_SUCCESS)
805 
806       xmlSetNs(psLayerNode,psNsMs);
807 
808     /*bbox*/
809 
810     msOWSGetEPSGProj(&(map->projection), &(lp->metadata), "SO", MS_TRUE, &pszEpsg);
811     if (!pszEpsg)
812       msOWSGetEPSGProj(&(lp->projection), &(lp->metadata), "SO", MS_TRUE, &pszEpsg);
813 
814     if (msProjectionsDiffer(&map->projection, &lp->projection) == MS_TRUE)
815       msProjectRect(&lp->projection, &map->projection, &sShape.bounds);
816 
817     psNode = xmlAddChild(psLayerNode, msGML3BoundedBy(psNsGml, sShape.bounds.minx, sShape.bounds.miny, sShape.bounds.maxx, sShape.bounds.maxy, pszEpsg));
818 
819     /*geometry*/
820     msSOSAddGeometryNode(psNsGml, psNsMs, psLayerNode, map, lp, &sShape, pszEpsg);
821     msFree(pszEpsg);
822 
823     /*attributes */
824     /* TODO only output attributes where there is a sos_%s_alias (to be discussed)*/
825     /* the first layer is the one that has to have all the metadata defined */
826     lpfirst = msSOSGetFirstLayerForOffering(map,
827                                             msOWSLookupMetadata(&(lp->metadata), "S",
828                                                 "offering_id"),
829                                             msOWSLookupMetadata(&(lp->metadata), "S",
830                                                 "observedproperty_id"));
831 
832     if (lpfirst && msLayerOpen(lpfirst) == MS_SUCCESS &&
833         msLayerGetItems(lpfirst) == MS_SUCCESS) {
834       for(i=0; i<lpfirst->numitems; i++) {
835         snprintf(szTmp, sizeof(szTmp), "%s_alias", lpfirst->items[i]);
836         pszValue = msOWSLookupMetadata(&(lpfirst->metadata), "S", szTmp);
837         if (pszValue) {
838           for (j=0; j<lp->numitems; j++) {
839             if (strcasecmp(lpfirst->items[i],  lpfirst->items[j]) == 0) {
840               /*if there is an alias used, use it to output the
841                 parameter name : eg "sos_AMMON_DIS_alias" "Amonia"  */
842               snprintf(szTmp, sizeof(szTmp), "%s_alias", lpfirst->items[i]);
843               pszValue = msOWSLookupMetadata(&(lpfirst->metadata), "S", szTmp);
844               pszValueShape = msEncodeHTMLEntities(sShape.values[j]);
845 
846               if (pszValue) {
847                 pszTmp = msEncodeHTMLEntities(pszValue);
848                 psNode = xmlNewChild(psLayerNode, psNsMs, BAD_CAST pszValue,
849                                      BAD_CAST pszValueShape);
850                 free(pszTmp);
851               } else {
852                 pszTmp = msEncodeHTMLEntities(lpfirst->items[i]);
853                 psNode = xmlNewChild(psLayerNode, psNsMs,
854                                      BAD_CAST lpfirst->items[i],
855                                      BAD_CAST pszValueShape);
856                 free(pszTmp);
857               }
858 
859               free(pszValueShape);
860               xmlSetNs(psNode,psNsMs);
861               break;
862             }
863           }
864         }
865       }
866       if (lp->index != lpfirst->index)
867         msLayerClose(lpfirst);
868     }
869     msFreeShape(&sShape);
870   }
871 }
872 
873 /************************************************************************/
874 /*                           msSOSReturnMemberResult                    */
875 /*                                                                      */
876 /*      Add a result string to the result node (used for                */
877 /*      GetObservation using "observation" as the response output.      */
878 /*      Assuming here that the layer is already opened.                 */
879 /************************************************************************/
msSOSReturnMemberResult(layerObj * lp,int iFeatureId,char ** ppszProcedure)880 char* msSOSReturnMemberResult(layerObj *lp, int iFeatureId, char **ppszProcedure)
881 {
882   char *pszFinalValue = NULL;
883   shapeObj sShape;
884   int i, j, status;
885   layerObj *lpfirst;
886   const char *pszTimeField = NULL, *pszValue=NULL, *pszProcedureField=NULL;
887   char *pszValueShape = NULL;
888   char szTmp[100];
889   const char *pszSep=NULL;
890 
891   msInitShape(&sShape);
892   status = msLayerGetShape(lp, &sShape, &(lp->resultcache->results[iFeatureId]));
893   if(status != MS_SUCCESS)
894     return NULL;
895 
896   pszTimeField =  msOWSLookupMetadata(&(lp->metadata), "SO", "timeitem");
897   if (pszTimeField && sShape.values) {
898     for(i=0; i<lp->numitems; i++) {
899       if (strcasecmp(lp->items[i], pszTimeField) == 0) {
900         pszFinalValue = msStringConcatenate(pszFinalValue,  sShape.values[i]);
901         break;
902       }
903     }
904   }
905   if (ppszProcedure) {
906     pszProcedureField = msOWSLookupMetadata(&(lp->metadata), "S", "procedure_item");
907     for(i=0; i<lp->numitems; i++) {
908       if (strcasecmp(lp->items[i], pszProcedureField) == 0) {
909         (*ppszProcedure) = msStrdup( sShape.values[i]);
910         break;
911       }
912     }
913   }
914 
915   /* the first layer is the one that has to have all the metadata defined */
916   lpfirst = msSOSGetFirstLayerForOffering(lp->map,
917                                           msOWSLookupMetadata(&(lp->metadata), "S",
918                                               "offering_id"),
919                                           msOWSLookupMetadata(&(lp->metadata), "S",
920                                               "observedproperty_id"));
921 
922 
923   if (lp == lpfirst || (lpfirst && msLayerOpen(lpfirst) == MS_SUCCESS &&
924                         msLayerGetItems(lpfirst) == MS_SUCCESS)) {
925     pszSep = msOWSLookupMetadata(&(lp->map->web.metadata), "S",
926                                  "encoding_tokenSeparator");
927     for(i=0; i<lpfirst->numitems; i++) {
928       snprintf(szTmp, sizeof(szTmp), "%s_alias", lpfirst->items[i]);
929       pszValue = msOWSLookupMetadata(&(lpfirst->metadata), "S", szTmp);
930       if (pszValue) {
931         for (j=0; j<lp->numitems; j++) {
932           if (strcasecmp(lpfirst->items[i],  lpfirst->items[j]) == 0) {
933             pszValueShape = msEncodeHTMLEntities(sShape.values[j]);
934 
935 
936             if (pszFinalValue) {
937               if (pszSep)
938                 pszFinalValue = msStringConcatenate(pszFinalValue, (char *)pszSep);
939               else
940                 pszFinalValue = msStringConcatenate(pszFinalValue, ",");
941             }
942             pszFinalValue = msStringConcatenate(pszFinalValue,  pszValueShape);
943 
944             msFree(pszValueShape);
945           }
946         }
947       }
948     }
949   }
950   msFreeShape(&sShape);
951   return pszFinalValue;
952 }
953 
954 /************************************************************************/
955 /*                      msSOSAddMemberNodeObservation                   */
956 /*                                                                      */
957 /*      Add a member node used for getObservation request using         */
958 /*      Observation as the result format.                               */
959 /************************************************************************/
msSOSAddMemberNodeObservation(xmlNsPtr psNsGml,xmlNsPtr psNsSos,xmlNsPtr psNsOm,xmlNsPtr psNsSwe,xmlNsPtr psNsXLink,xmlNodePtr psParent,mapObj * map,layerObj * lp,const char * pszProcedure)960 xmlNodePtr msSOSAddMemberNodeObservation(xmlNsPtr psNsGml, xmlNsPtr psNsSos, xmlNsPtr psNsOm, xmlNsPtr psNsSwe, xmlNsPtr psNsXLink, xmlNodePtr psParent, mapObj *map, layerObj *lp, const char *pszProcedure)
961 {
962   char *pszTmp = NULL;
963   xmlNodePtr psNode=NULL, psObsNode=NULL, psMemberNode=NULL;
964   layerObj *lpfirst;
965   const char *value = NULL;
966 
967   /*always featch the first layer that has the same offering id and observered propery.
968    This allows to only define all the attributes and components on the first layer if the user
969   wants to present several mapserver layers as the same offering.*/
970   lpfirst = msSOSGetFirstLayerForOffering(map,
971                                           msOWSLookupMetadata(&(lp->metadata), "S",
972                                               "offering_id"),
973                                           msOWSLookupMetadata(&(lp->metadata), "S",
974                                               "observedproperty_id"));
975   if (psParent) {
976     psMemberNode = xmlNewChild(psParent, NULL, BAD_CAST "member", NULL);
977     psObsNode = xmlNewChild(psMemberNode, NULL, BAD_CAST "Observation", NULL);
978 
979     /*time*/
980     /* ??TODO : sampling time is a manadatory element but uses a non mandatory metadata sos_offering_timeextent */
981     value = msOWSLookupMetadata(&(lp->metadata), "S", "offering_timeextent");
982     if (value) {
983       char **tokens;
984       int n;
985       char *pszEndTime = NULL;
986       tokens = msStringSplit(value, '/', &n);
987       if (tokens==NULL || (n != 1 && n!=2)) {
988         msSetError(MS_SOSERR, "Wrong number of arguments for sos_offering_timeextent.",
989                    "msSOSGetObservation()");
990         msSOSException(map, "sos_offering_timeextent", "InvalidParameterValue");
991         return NULL;
992       }
993 
994       if (n == 2) /* end time is empty. It is going to be set as "now*/
995         pszEndTime = tokens[1];
996 
997       psNode = xmlAddChild(psObsNode, msSOSAddTimeNode(psNsOm, psNsGml, tokens[0], pszEndTime));
998       msFreeCharArray(tokens, n);
999 
1000     }
1001 
1002     /* procedure */
1003     if (pszProcedure) { /*this should always be true since procedure is a manadtory element*/
1004       if (! msOWSLookupMetadata(&(lp->metadata), "S", "procedure_item") && msOWSLookupMetadata(&(lp->metadata), "S", "procedure"))
1005         xmlAddSibling(psNode, xmlNewComment(BAD_CAST "WARNING: Optional metadata \"sos_procedure_item\" missing for sos:procedure.  If you have more than 1 procedures, sos:procedure will output them incorrectly."));
1006 
1007       pszTmp = msStringConcatenate(pszTmp, "urn:ogc:def:procedure:");
1008       pszTmp = msStringConcatenate(pszTmp, (char *)pszProcedure);
1009       psNode =  xmlNewChild(psObsNode, NULL, BAD_CAST "procedure", NULL);
1010       /* xmlNewNsProp(psNode, xmlNewNs(NULL, BAD_CAST "http://www.w3.org/1999/xlink", BAD_CAST "xlink"), BAD_CAST "href", BAD_CAST pszTmp); */
1011       xmlNewNsProp(psNode, psNsXLink, BAD_CAST "href", BAD_CAST pszTmp);
1012       msFree(pszTmp);
1013       pszTmp = NULL;
1014     }
1015 
1016     /*observed propery and components*/
1017     if (lp != lpfirst &&
1018         msLayerOpen(lpfirst) == MS_SUCCESS && msLayerGetItems(lpfirst) == MS_SUCCESS) {
1019       msSOSAddPropertyNode(psNsSwe, psNsXLink, psObsNode, lpfirst, psNsGml, NULL);
1020       msLayerClose(lpfirst);
1021     } else
1022       msSOSAddPropertyNode(psNsSwe, psNsXLink, psObsNode, lpfirst, psNsGml, NULL);
1023 
1024     /* result definition*/
1025     psNode = xmlNewChild(psObsNode, NULL, BAD_CAST "resultDefinition", NULL);
1026     msSOSAddDataBlockDefinition(psNsSwe, psNode, lpfirst);
1027 
1028   }
1029 
1030   return psObsNode;
1031 }
1032 
1033 /************************************************************************/
1034 /*                            msSOSParseTimeGML                         */
1035 /*                                                                      */
1036 /*      Utility function to convert a gml time value to a               */
1037 /*      string. Supported gml times are :                               */
1038 /*                                                                      */
1039 /*       -  <gml:TimePeriod>                                            */
1040 /*           <gml:beginPosition>2005-09-01T11:54:32</gml:beginPosition> */
1041 /*            <gml:endPosition>2005-09-02T14:54:32</gml:endPosition>    */
1042 /*          </gml:TimePeriod>                                           */
1043 /*        This will be converted to startime/endtime                    */
1044 /*                                                                      */
1045 /*       - <gml:TimeInstant>                                            */
1046 /*           <gml:timePosition>2003-02-13T12:28-08:00</gml:timePosition>*/
1047 /*           </gml:TimeInstant>                                         */
1048 /*       This will retunr the timevalue as a string.                    */
1049 /*                                                                      */
1050 /*       The caller of the function should free the return value.       */
1051 /************************************************************************/
msSOSParseTimeGML(char * pszGmlTime)1052 char *msSOSParseTimeGML(char *pszGmlTime)
1053 {
1054   char *pszReturn = NULL, *pszBegin = NULL, *pszEnd = NULL;
1055   CPLXMLNode *psRoot=NULL, *psChild=NULL;
1056   CPLXMLNode *psTime=NULL, *psBegin=NULL, *psEnd=NULL;
1057   struct tm tm_struct;
1058 
1059   if (pszGmlTime) {
1060     psRoot = CPLParseXMLString(pszGmlTime);
1061     if(!psRoot)
1062       return NULL;
1063     CPLStripXMLNamespace(psRoot, "gml", 1);
1064 
1065     if (psRoot->eType == CXT_Element &&
1066         (EQUAL(psRoot->pszValue,"TimePeriod") ||
1067          EQUAL(psRoot->pszValue,"TimeInstant"))) {
1068       if (EQUAL(psRoot->pszValue,"TimeInstant")) {
1069         psChild = psRoot->psChild;
1070         if (psChild && EQUAL(psChild->pszValue,"timePosition")) {
1071           psTime = psChild->psNext;
1072           if (psTime && psTime->pszValue && psTime->eType == CXT_Text) {
1073             if (msParseTime(psTime->pszValue, &tm_struct) == MS_TRUE)
1074               pszReturn = msStrdup(psTime->pszValue);
1075           }
1076         }
1077       } else {
1078         psBegin = psRoot->psChild;
1079         if (psBegin)
1080           psEnd = psBegin->psNext;
1081 
1082         if (psBegin && EQUAL(psBegin->pszValue, "beginPosition") &&
1083             psEnd && EQUAL(psEnd->pszValue, "endPosition")) {
1084           if (psBegin->psChild && psBegin->psChild->pszValue &&
1085               psBegin->psChild->eType == CXT_Text)
1086             pszBegin = msStrdup( psBegin->psChild->pszValue);
1087 
1088           if (psEnd->psChild && psEnd->psChild->pszValue &&
1089               psEnd->psChild->eType == CXT_Text)
1090             pszEnd = msStrdup(psEnd->psChild->pszValue);
1091 
1092           if (pszBegin && pszEnd) {
1093             if (msParseTime(pszBegin, &tm_struct) == MS_TRUE &&
1094                 msParseTime(pszEnd, &tm_struct) == MS_TRUE) {
1095               pszReturn = msStrdup(pszBegin);
1096               pszReturn = msStringConcatenate(pszReturn, "/");
1097               pszReturn = msStringConcatenate(pszReturn, pszEnd);
1098             }
1099           }
1100           msFree(pszBegin);
1101           msFree(pszEnd);
1102         }
1103       }
1104     }
1105   }
1106   CPLDestroyXMLNode(psRoot);
1107   return pszReturn;
1108 }
1109 
1110 
1111 /************************************************************************/
1112 /*                           msSOSGetCapabilities                       */
1113 /*                                                                      */
1114 /*      getCapabilities request handler.                                */
1115 /************************************************************************/
msSOSGetCapabilities(mapObj * map,sosParamsObj * sosparams,cgiRequestObj * req,owsRequestObj * ows_request)1116 int msSOSGetCapabilities(mapObj *map, sosParamsObj *sosparams, cgiRequestObj *req, owsRequestObj *ows_request)
1117 {
1118   xmlDocPtr psDoc = NULL;       /* document pointer */
1119   xmlNodePtr psRootNode, psMainNode, psNode;
1120   xmlNodePtr psOfferingNode;
1121 
1122   char *schemalocation = NULL;
1123   char *xsi_schemaLocation = NULL;
1124   char *script_url=NULL;
1125   const char *updatesequence=NULL;
1126 
1127   int i,j,k;
1128   layerObj *lp = NULL, *lpTmp = NULL;
1129   const char *value = NULL;
1130   char *pszTmp = NULL;
1131   char *pszProcedure = NULL;
1132   char szTmp[256];
1133 
1134   /* array of offering */
1135   char **papsOfferings = NULL;
1136   int nOfferings  =0, nCurrentOff = -1;
1137   int nProperties = 0;
1138   char **papszProperties = NULL;
1139 
1140   int iItemPosition = -1;
1141   shapeObj sShape;
1142   int status;
1143 
1144   /* for each layer it indicates the indice to be used in papsOfferings
1145      (to associate it with the offering) */
1146   int *panOfferingLayers = NULL;
1147 
1148   char **papsProcedures = NULL;
1149   int nDistinctProcedures =0;
1150 
1151   xmlNsPtr psNsGml = NULL;
1152   xmlNsPtr psNsSos = NULL;
1153   xmlNsPtr psNsOws = NULL;
1154   xmlNsPtr psNsOgc = NULL;
1155   xmlNsPtr psNsXLink = NULL;
1156   xmlNsPtr psNsSwe = NULL;
1157 
1158   xmlChar *buffer = NULL;
1159   int size = 0;
1160   msIOContext *context = NULL;
1161 
1162   int ows_version = OWS_1_1_0;
1163 
1164   int sosSupportedVersions[] = {OWS_1_0_0};
1165   int sosNumSupportedVersions = 1;
1166 
1167   /* acceptversions: do OWS Common style of version negotiation */
1168   if (sosparams->pszAcceptVersions) {
1169     char **tokens;
1170     int i, j, k=-1;
1171 
1172     tokens = msStringSplit(sosparams->pszAcceptVersions, ',', &j);
1173 
1174     for (i=0; i<j; i++) {
1175       int iVersion = 0;
1176 
1177       iVersion = msOWSParseVersionString(tokens[i]);
1178 
1179       if (iVersion == -1) {
1180         msSetError(MS_SOSERR, "Invalid version format : %s.", "msSOSGetCapabilities()", tokens[i]);
1181         msFreeCharArray(tokens, j);
1182         return msSOSException(map, "acceptversions", "VersionNegotiationFailed");
1183       }
1184 
1185       /* negotiate version */
1186       k = msOWSCommonNegotiateVersion(iVersion, sosSupportedVersions, sosNumSupportedVersions);
1187 
1188       if (k != -1)
1189         break;
1190     }
1191     msFreeCharArray(tokens, j);
1192 
1193     if(k == -1) {
1194       msSetError(MS_SOSERR, "ACCEPTVERSIONS list (%s) does not match supported versions (%s)", "msSOSGetCapabilities()", sosparams->pszAcceptVersions, pszSOSVersion);
1195       return msSOSException(map, "acceptversions", "VersionNegotiationFailed");
1196     }
1197   }
1198 
1199   /* updateSequence */
1200   updatesequence = msOWSLookupMetadata(&(map->web.metadata), "SO", "updatesequence");
1201 
1202   if (sosparams->pszUpdateSequence != NULL) {
1203     i = msOWSNegotiateUpdateSequence(sosparams->pszUpdateSequence, updatesequence);
1204     if (i == 0) { /* current */
1205       msSetError(MS_SOSERR, "UPDATESEQUENCE parameter (%s) is equal to server (%s)", "msSOSGetCapabilities()", sosparams->pszUpdateSequence, updatesequence);
1206       return msSOSException(map, "updatesequence", "CurrentUpdateSequence");
1207     }
1208     if (i > 0) { /* invalid */
1209       msSetError(MS_SOSERR, "UPDATESEQUENCE parameter (%s) is higher than server (%s)", "msSOSGetCapabilities()", sosparams->pszUpdateSequence, updatesequence);
1210       return msSOSException(map, "updatesequence", "InvalidUpdateSequence");
1211     }
1212   }
1213 
1214   psDoc = xmlNewDoc(BAD_CAST "1.0");
1215 
1216   psRootNode = xmlNewNode(NULL, BAD_CAST "Capabilities");
1217 
1218   xmlDocSetRootElement(psDoc, psRootNode);
1219 
1220   psNsGml = xmlNewNs(NULL, BAD_CAST "http://www.opengis.net/gml", BAD_CAST "gml");
1221   psNsSos = xmlNewNs(NULL, BAD_CAST pszSOSNamespaceUri, BAD_CAST pszSOSNamespacePrefix);
1222   psNsOgc = xmlNewNs(NULL, BAD_CAST MS_OWSCOMMON_OGC_NAMESPACE_URI, BAD_CAST MS_OWSCOMMON_OGC_NAMESPACE_PREFIX);
1223   psNsSwe = xmlNewNs(NULL, BAD_CAST "http://www.opengis.net/swe/1.0.1", BAD_CAST "swe");
1224 
1225   /* name spaces */
1226   xmlSetNs(psRootNode,  xmlNewNs(psRootNode, BAD_CAST "http://www.opengis.net/gml", BAD_CAST "gml"));
1227   xmlSetNs(psRootNode,  xmlNewNs(psRootNode, BAD_CAST "http://www.opengis.net/om/1.0", BAD_CAST "om"));
1228 
1229   psNsOws = xmlNewNs(psRootNode, BAD_CAST "http://www.opengis.net/ows/1.1", BAD_CAST "ows");
1230   xmlSetNs(psRootNode, psNsOws );
1231 
1232   xmlSetNs(psRootNode,xmlNewNs(psRootNode, BAD_CAST "http://www.opengis.net/swe/1.0.1", BAD_CAST "swe"));
1233 
1234   psNsXLink = xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_W3C_XLINK_NAMESPACE_URI, BAD_CAST MS_OWSCOMMON_W3C_XLINK_NAMESPACE_PREFIX);
1235   xmlSetNs(psRootNode, psNsXLink );
1236 
1237   xmlSetNs(psRootNode,xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_W3C_XSI_NAMESPACE_URI, BAD_CAST MS_OWSCOMMON_W3C_XSI_NAMESPACE_PREFIX));
1238   xmlSetNs(psRootNode, xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_OGC_NAMESPACE_URI, BAD_CAST MS_OWSCOMMON_OGC_NAMESPACE_PREFIX));
1239   xmlSetNs(psRootNode, xmlNewNs(psRootNode, BAD_CAST pszSOSNamespaceUri, BAD_CAST pszSOSNamespacePrefix));
1240 
1241   /*version fixed for now*/
1242   xmlNewProp(psRootNode, BAD_CAST "version", BAD_CAST pszSOSVersion);
1243 
1244   value = msOWSLookupMetadata(&(map->web.metadata), "SO", "updatesequence");
1245 
1246   if (value)
1247     xmlNewProp(psRootNode, BAD_CAST "updateSequence", BAD_CAST value);
1248 
1249   /*schema fixed*/
1250   schemalocation = msEncodeHTMLEntities( msOWSGetSchemasLocation(map) );
1251   xsi_schemaLocation = msStrdup(pszSOSNamespaceUri);
1252   xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, " ");
1253   xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, schemalocation);
1254   xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, "/sos/");
1255   xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, (char *)pszSOSVersion);
1256   xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, "/sosGetCapabilities.xsd");
1257   xmlNewNsProp(psRootNode, NULL, BAD_CAST "xsi:schemaLocation", BAD_CAST xsi_schemaLocation);
1258 
1259   xmlAddChild(psRootNode, xmlNewComment(BAD_CAST msGetVersion()));
1260 
1261   /*service identification*/
1262   xmlAddChild(psRootNode, msOWSCommonServiceIdentification(psNsOws, map, "SOS", pszSOSVersion, "SO", NULL));
1263 
1264   /*service provider*/
1265   xmlAddChild(psRootNode, msOWSCommonServiceProvider(psNsOws, psNsXLink, map, "SO", NULL));
1266 
1267   /*operation metadata */
1268 
1269   if ((script_url=msOWSGetOnlineResource(map, "SO", "onlineresource", req)) == NULL)
1270     return msSOSException(map, "NoApplicableCode", "NoApplicableCode");
1271 
1272   psMainNode = xmlAddChild(psRootNode, msOWSCommonOperationsMetadata(psNsOws));
1273 
1274   psNode     = xmlAddChild(psMainNode, msOWSCommonOperationsMetadataOperation(psNsOws,psNsXLink,"GetCapabilities", OWS_METHOD_GETPOST, (char *) script_url));
1275   xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType(ows_version, psNsOws,"Parameter", "service", "SOS"));
1276   xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType(ows_version, psNsOws,"Parameter", "version", (char *)pszSOSVersion));
1277 
1278   if (msOWSRequestIsEnabled(map, NULL, "S", "DescribeSensor", MS_TRUE)) {
1279     psNode     = xmlAddChild(psMainNode, msOWSCommonOperationsMetadataOperation(psNsOws,psNsXLink,"DescribeSensor", OWS_METHOD_GETPOST, (char *) script_url));
1280     xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType(ows_version, psNsOws,"Parameter", "service", "SOS"));
1281     xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType(ows_version, psNsOws,"Parameter", "version", (char *)pszSOSVersion));
1282     xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType(ows_version, psNsOws,"Parameter", "sensorid", "urn:ogc:object:procedure"));
1283     xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType(ows_version, psNsOws,"Parameter", "outputFormat", (char *)pszSOSDescribeSensorMimeType));
1284   }
1285 
1286   if (msOWSRequestIsEnabled(map, NULL, "S", "DescribeObservationType", MS_TRUE)) {
1287     psNode     = xmlAddChild(psMainNode, msOWSCommonOperationsMetadataOperation(psNsOws,psNsXLink,"DescribeObservationType", OWS_METHOD_GETPOST, (char *) script_url));
1288     xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType(ows_version, psNsOws,"Parameter", "service", "SOS"));
1289     xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType(ows_version, psNsOws,"Parameter", "version", (char *)pszSOSVersion));
1290     xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType(ows_version, psNsOws,"Parameter", "observedproperty", "urn:ogc:object:observedproperty"));
1291   }
1292 
1293   if (msOWSRequestIsEnabled(map, NULL, "S", "GetObservation", MS_TRUE)) {
1294     psNode     = xmlAddChild(psMainNode, msOWSCommonOperationsMetadataOperation(psNsOws,psNsXLink,"GetObservation", OWS_METHOD_GETPOST, (char *) script_url));
1295     xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType(ows_version, psNsOws,"Parameter", "service", "SOS"));
1296     xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType(ows_version, psNsOws,"Parameter", "version", (char *)pszSOSVersion));
1297     xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType(ows_version, psNsOws,"Parameter", "offering", "urn:ogc:object:offering"));
1298     xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType(ows_version, psNsOws,"Parameter", "observedproperty", "urn:ogc:object:observedproperty"));
1299     xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType(ows_version, psNsOws,"Parameter", "eventtime", "sos:time"));
1300     xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType(ows_version, psNsOws,"Parameter", "procedure", "urn:ogc:object:sensor"));
1301     xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType(ows_version, psNsOws,"Parameter", "featureofinterest", "gml:location"));
1302     xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType(ows_version, psNsOws,"Parameter", "result", "ogc:Filter"));
1303     xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType(ows_version, psNsOws,"Parameter", "responseFormat", (char *)pszSOSGetObservationMimeType));
1304     xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType(ows_version, psNsOws,"Parameter", "resultModel", "Observation,Measurement"));
1305   }
1306 
1307   value = msOWSLookupMetadata(&(map->web.metadata), "SO", "maxfeatures");
1308 
1309   if (value) {
1310     psNode  = xmlAddChild(psMainNode, msOWSCommonOperationsMetadataDomainType(ows_version, psNsOws,"Constraint", "DefaultMaxFeatures", (char *)value));
1311   }
1312 
1313   /*<ogc:Filter_Capabilities> */
1314   xmlAddChild(psRootNode, FLTGetCapabilities(psNsSos, psNsOgc, MS_TRUE));
1315 
1316   /*Offerings */
1317   psNode = xmlNewChild(psRootNode, NULL, BAD_CAST "Contents", NULL);
1318   psMainNode = xmlNewChild(psNode, NULL, BAD_CAST "ObservationOfferingList", NULL);
1319 
1320   /*go through the layers and check for metadata sos_offering_id.
1321     One or more layers could have the same offering id. In that case they
1322     are adverized as the same offering. The first layer that has*/
1323 
1324   if (map->numlayers) {
1325     papsOfferings = (char **)malloc(sizeof(char *)*map->numlayers);
1326     panOfferingLayers = (int *)malloc(sizeof(int)*map->numlayers);
1327     for (i=0; i<map->numlayers; i++)
1328       panOfferingLayers[i] = -1;
1329 
1330     for (i=0; i<map->numlayers; i++) {
1331       lp = (GET_LAYER(map, i));
1332 
1333       if (lp->status == MS_DELETE)
1334         continue;
1335 
1336       value = msOWSLookupMetadata(&(lp->metadata), "S", "offering_id");
1337       if (value && (msIntegerInArray(lp->index, ows_request->enabled_layers, ows_request->numlayers))) {
1338         nCurrentOff = -1;
1339         for (j=0; j<nOfferings; j++) {
1340           if (strcasecmp(value, papsOfferings[j]) == 0) {
1341             nCurrentOff = j;
1342             break;
1343           }
1344         }
1345         if (nCurrentOff >= 0) /* existing offering */
1346           panOfferingLayers[i] = nCurrentOff;
1347         else { /*new offering */
1348           papsOfferings[nOfferings] = msStrdup(value);
1349           panOfferingLayers[i] = nOfferings;
1350           nOfferings++;
1351         }
1352       }
1353     }
1354 
1355     if (nOfferings > 0) {
1356       for (i=0; i<nOfferings; i++) {
1357         psOfferingNode =
1358           xmlNewChild(psMainNode, NULL,BAD_CAST "ObservationOffering", NULL);
1359         xmlNewNsProp(psOfferingNode, psNsGml,
1360                      BAD_CAST "id", BAD_CAST papsOfferings[i]);
1361         for (j=0; j<map->numlayers; j++) {
1362           if (panOfferingLayers[j] == i) /*first layer of the offering */
1363             break;
1364         }
1365 
1366         lp = (GET_LAYER(map, j));
1367 
1368         /*description*/
1369         value = msOWSLookupMetadata(&(lp->metadata), "S",
1370                                     "offering_description");
1371         if (value)
1372           psNode = xmlNewChild(psOfferingNode, psNsGml, BAD_CAST "description", BAD_CAST value);
1373         else
1374           xmlAddSibling(psNode, xmlNewComment(BAD_CAST "WARNING: Optional metadata \"sos_offering_description\" missing for gml:description"));
1375 
1376         /*name*/
1377         value = msOWSLookupMetadata(&(lp->metadata), "S", "offering_name");
1378         if (value)
1379           psNode = xmlNewChild(psOfferingNode, psNsGml, BAD_CAST "name", BAD_CAST value);
1380         else
1381           xmlAddSibling(psNode, xmlNewComment(BAD_CAST "WARNING: Optional metadata \"sos_offering_name\" missing for gml:name"));
1382 
1383         /* srsName */
1384         value = msOWSLookupMetadata(&(map->web.metadata), "SO", "srs");
1385 
1386         if (value)
1387           msLibXml2GenerateList(psOfferingNode, psNsGml, "srsName", value, ' ');
1388         else
1389           xmlAddSibling(psNode, xmlNewComment(BAD_CAST "WARNING: Required metadata \"sos_srs\" missing for gml:srsName"));
1390 
1391         /*bounding box */
1392         /*TODO : if sos_offering_extent does not exist compute extents
1393                  Check also what happen if epsg not present */
1394         value = msOWSLookupMetadata(&(lp->metadata), "S", "offering_extent");
1395         if (value) {
1396           char **tokens,*pszLayerEPSG;
1397           int n;
1398           tokens = msStringSplit(value, ',', &n);
1399           if (tokens==NULL || n != 4) {
1400             msSetError(MS_SOSERR, "Wrong number of arguments for sos_offering_extent.",
1401                        "msSOSGetCapabilities()");
1402             return msSOSException(map, "sos_offering_extent", "InvalidParameterValue");
1403           }
1404           msOWSGetEPSGProj(&(lp->projection),&(lp->metadata), "SO", MS_TRUE,&pszLayerEPSG);
1405           if (pszLayerEPSG) {
1406             psNode = xmlAddChild(psOfferingNode, msGML3BoundedBy(psNsGml, atof(tokens[0]), atof(tokens[1]), atof(tokens[2]), atof(tokens[3]), pszLayerEPSG));
1407             msFree(pszLayerEPSG);
1408           }
1409           msFreeCharArray(tokens, n);
1410 
1411         }
1412 
1413         /* intended application */
1414 
1415         value = msOWSLookupMetadata(&(lp->metadata), "S", "offering_intendedapplication");
1416 
1417         if (value)
1418           psNode = xmlNewChild(psOfferingNode, psNsSos, BAD_CAST "intendedApplication", BAD_CAST value);
1419         else
1420           xmlAddSibling(psNode, xmlNewComment(BAD_CAST "WARNING: Optional metadata \"sos_offering_intendedapplication\" missing for sos:intendedApplication"));
1421 
1422         /*time*/
1423         value = msOWSLookupMetadata(&(lp->metadata), "S",
1424                                     "offering_timeextent");
1425         if (value) {
1426           char **tokens;
1427           int n;
1428           char *pszEndTime = NULL;
1429           tokens = msStringSplit(value, '/', &n);
1430           if (tokens==NULL || (n != 1 && n!=2)) {
1431             msSetError(MS_SOSERR, "Wrong number of arguments for sos_offering_timeextent.",
1432                        "msSOSGetCapabilities()");
1433             return msSOSException(map, "sos_offering_timeextent", "InvalidParameterValue");
1434           }
1435 
1436           if (n == 2) /* end time is empty. It is going to be set as "now*/
1437             pszEndTime = tokens[1];
1438 
1439           psNode = xmlAddChild(psOfferingNode, msSOSAddTimeNode(psNsSos, psNsGml, tokens[0], pszEndTime));
1440           msFreeCharArray(tokens, n);
1441 
1442         }
1443 
1444         /*procedure : output all procedure links for the offering */
1445         for (j=0; j<map->numlayers; j++) {
1446           if (panOfferingLayers[j] == i) {
1447             value = msOWSLookupMetadata(&(GET_LAYER(map, j)->metadata), "S",
1448                                         "procedure");
1449             if (value && strlen(value) > 0) {
1450               /*value could be a list of procedure*/
1451               char **tokens;
1452               int n = 0;
1453               tokens = msStringSplit(value, ' ', &n);
1454               for (k=0; k<n; k++) {
1455                 /*TODO review the urn output */
1456                 snprintf(szTmp, sizeof(szTmp), "%s", "urn:ogc:def:procedure:");
1457                 pszTmp = msStringConcatenate(pszTmp, szTmp);
1458                 pszTmp = msStringConcatenate(pszTmp, tokens[k]);
1459 
1460                 psNode =
1461                   xmlNewChild(psOfferingNode, NULL, BAD_CAST "procedure", NULL);
1462                 /* xmlNewNsProp(psNode, xmlNewNs(NULL, BAD_CAST "http://www.w3.org/1999/xlink", BAD_CAST "xlink"), BAD_CAST "href", BAD_CAST pszTmp); */
1463                 xmlNewNsProp(psNode, psNsXLink, BAD_CAST "href", BAD_CAST pszTmp);
1464                 msFree(pszTmp);
1465                 pszTmp = NULL;
1466               }
1467               msFreeCharArray(tokens, n);
1468             } else if ((value = msOWSLookupMetadata(&(GET_LAYER(map,j)->metadata), "S",
1469                                                     "procedure_item"))) {
1470               /* if a procedure_item is used, it means that the procedure
1471                  (or sensor) need to be extracted from the data. Thus we need to
1472                  query the layer and get the values from each feature */
1473 
1474 
1475               lpTmp = GET_LAYER(map,j);
1476               if (lpTmp->template == NULL)
1477                 lpTmp->template = msStrdup("ttt");
1478 
1479               map->query.type = MS_QUERY_BY_RECT;
1480               map->query.mode = MS_QUERY_MULTIPLE;
1481               map->query.layer = j;
1482               map->query.rect = map->extent;
1483               msQueryByRect(map);
1484 
1485               /*check if the attribute specified in the procedure_item is available
1486                 on the layer*/
1487               iItemPosition = -1;
1488               if (msLayerGetItems(lpTmp) == MS_SUCCESS &&
1489                   lpTmp->resultcache && lpTmp->resultcache->numresults > 0) {
1490                 for(k=0; k<lpTmp->numitems; k++) {
1491                   if (strcasecmp(lpTmp->items[k], value) == 0) {
1492                     iItemPosition = k;
1493                     break;
1494                   }
1495                 }
1496                 if (iItemPosition == -1) {
1497                   msSetError(MS_SOSERR, "procedure_item %s could not be found on the layer %s",
1498                              "msSOSGetCapabilities()", value, lpTmp->name);
1499                   return msSOSException(map, "mapserv", "NoApplicableCode");
1500                 }
1501 
1502                 /*for each selected feature, grab the value of the prodedire_item*/
1503                 /* do not duplicate sensor ids if they are the same */
1504 
1505                 /*keep list of distinct procedures*/
1506                 papsProcedures =
1507                   (char **)malloc(sizeof(char *) * lpTmp->resultcache->numresults);
1508                 nDistinctProcedures = 0;
1509                 for(k=0; k<lpTmp->resultcache->numresults; k++)
1510                   papsProcedures[k] = NULL;
1511 
1512 
1513                 for(k=0; k<lpTmp->resultcache->numresults; k++) {
1514                   msInitShape(&sShape);
1515                   status = msLayerGetShape(lp, &sShape, &(lpTmp->resultcache->results[k]));
1516                   if(status != MS_SUCCESS)
1517                     continue;
1518 
1519                   if (sShape.values[iItemPosition]) {
1520                     pszProcedure = msStringConcatenate(pszProcedure, sShape.values[iItemPosition]);
1521                     if (!_IsInList(papsProcedures, nDistinctProcedures, pszProcedure)) {
1522                       papsProcedures[nDistinctProcedures] = msStrdup(pszProcedure);
1523                       nDistinctProcedures++;
1524                       snprintf(szTmp, sizeof(szTmp), "%s", "urn:ogc:def:procedure:");
1525                       pszTmp = msStringConcatenate(pszTmp, szTmp);
1526                       pszTmp = msStringConcatenate(pszTmp, pszProcedure);
1527 
1528                       psNode =
1529                         xmlNewChild(psOfferingNode, NULL, BAD_CAST "procedure", NULL);
1530                       xmlNewNsProp(psNode,
1531                                    xmlNewNs(NULL, BAD_CAST "http://www.w3.org/1999/xlink",
1532                                             BAD_CAST "xlink"), BAD_CAST "href", BAD_CAST pszTmp);
1533                       msFree(pszTmp);
1534                       pszTmp = NULL;
1535 
1536                     }
1537                     msFree(pszProcedure);
1538                     pszProcedure = NULL;
1539                   }
1540                 }
1541                 for(k=0; k<lpTmp->resultcache->numresults; k++)
1542                   if (papsProcedures[k] != NULL)
1543                     msFree(papsProcedures[k]);
1544                 msFree(papsProcedures);
1545 
1546               } else {
1547                 msSetError(MS_SOSERR, "Invalid procedure %s", "msSOSGetCapabilities()", value);
1548                 return msSOSException(map, "procedure", "InvalidParameterValue");
1549               }
1550             } else {
1551               msSetError(MS_SOSERR, "Mandatory metadata procedure_item could not be found on the layer %s",
1552                          "msSOSGetCapabilities()", GET_LAYER(map,j)->name);
1553               return msSOSException(map, "mapserv", "NoApplicableCode");
1554             }
1555 
1556           }
1557         }
1558         /*observed property */
1559         /* observed property are equivalent to layers. We can group
1560            sevaral layers using the same sos_observedproperty_id. The
1561            components are the attributes. Components are exposed
1562            using the metadata sos_%s_aliasl */
1563 
1564         nProperties = 0;
1565         papszProperties =
1566           (char **)malloc(sizeof(char *)*map->numlayers);
1567 
1568         for (j=0; j<map->numlayers; j++) {
1569           if (panOfferingLayers[j] == i) {
1570             if ((value =
1571                    msOWSLookupMetadata(&(GET_LAYER(map, j)->metadata), "S",
1572                                        "observedproperty_id"))) {
1573               for (k=0; k<nProperties; k++) {
1574                 if (strcasecmp(value, papszProperties[k]) == 0)
1575                   break;
1576               }
1577               if (k == nProperties) { /*not found*/
1578                 papszProperties[nProperties] = msStrdup(value);
1579                 nProperties++;
1580                 lpTmp = GET_LAYER(map, j);
1581                 if (msLayerOpen(lpTmp) == MS_SUCCESS && msLayerGetItems(lpTmp) == MS_SUCCESS) {
1582                   msSOSAddPropertyNode(psNsSwe, psNsXLink, psOfferingNode,
1583                                        lpTmp, psNsGml, NULL);
1584                   msLayerClose(lpTmp);
1585                 }
1586               }
1587             }
1588           }
1589         }
1590         for (j=0; j<nProperties; j++)
1591           free(papszProperties[j]);
1592         free(papszProperties);
1593 
1594         psNode = xmlNewChild(psOfferingNode, NULL, BAD_CAST "featureOfInterest", NULL);
1595         xmlNewNsProp(psNode, psNsXLink, BAD_CAST "href", BAD_CAST "urn:ogc:def:feature:OGC-SWE:3:transient");
1596 
1597         psNode = xmlNewChild(psOfferingNode, NULL, BAD_CAST "responseFormat",
1598                              BAD_CAST pszSOSGetObservationMimeType);
1599         psNode = xmlNewChild(psOfferingNode, NULL, BAD_CAST "resultModel",
1600                              BAD_CAST "om:Observation");
1601         psNode = xmlNewChild(psOfferingNode, NULL, BAD_CAST "resultModel",
1602                              BAD_CAST "om:Measurement");
1603         psNode = xmlNewChild(psOfferingNode, NULL, BAD_CAST "responseMode",
1604                              BAD_CAST "inline");
1605 
1606       }/*end of offerings*/
1607     }
1608 
1609     if (papsOfferings && nOfferings > 0) {
1610       for (i=0; i<nOfferings; i++)
1611         msFree(papsOfferings[i]);
1612     }
1613     msFree(papsOfferings);
1614     if(panOfferingLayers)
1615       msFree(panOfferingLayers);
1616 
1617   }/* end of offerings */
1618 
1619   if ( msIO_needBinaryStdout() == MS_FAILURE )
1620     return MS_FAILURE;
1621 
1622   msIO_setHeader("Content-Type","text/xml; charset=UTF-8");
1623   msIO_sendHeaders();
1624 
1625   /*TODO* : check the encoding validity. Internally libxml2 uses UTF-8
1626   msOWSPrintEncodeMetadata(stdout, &(map->web.metadata),
1627                            "SO", "encoding", OWS_NOERR,
1628                            "<?xml version='1.0' encoding=\"%s\" standalone=\"no\" ?>\n",
1629                            "ISO-8859-1");
1630   */
1631   /*xmlDocDumpFormatMemoryEnc(psDoc, &buffer, &size, (encoding ? encoding : "ISO-8859-1"), 1);*/
1632 
1633   /* xmlDocDump crashs withe the prebuild windows binaries distibutes at the libxml site???.
1634    It works with locally build binaries*/
1635 
1636   context = msIO_getHandler(stdout);
1637 
1638   xmlDocDumpFormatMemoryEnc(psDoc, &buffer, &size, ("UTF-8"), 1);
1639   msIO_contextWrite(context, buffer, size);
1640   xmlFree(buffer);
1641 
1642   /*free buffer and the document */
1643   /*xmlFree(buffer);*/
1644   xmlFreeDoc(psDoc);
1645   xmlFreeNs(psNsGml);
1646   xmlFreeNs(psNsSos);
1647   xmlFreeNs(psNsOgc);
1648   xmlFreeNs(psNsSwe);
1649 
1650   free(xsi_schemaLocation);
1651   free(schemalocation);
1652   msFree(script_url);
1653 
1654   /*
1655    *Free the global variables that may
1656    *have been allocated by the parser.
1657    */
1658   xmlCleanupParser();
1659 
1660 
1661   return(MS_SUCCESS);
1662 
1663 
1664   /*
1665   nSize = sizeof(workbuffer);
1666   nSize = nSize-1;*/ /* the last character for the '\0' */
1667 
1668   /*
1669   if (size > nSize)
1670   {
1671        iIndice = 0;
1672        while ((iIndice + nSize) <= size)
1673        {
1674            snprintf(workbuffer, (sizeof(workbuffer)-1), "%s", buffer+iIndice );
1675            workbuffer[sizeof(workbuffer)-1] = '\0';
1676            msIO_printf("%s", workbuffer);
1677 
1678            iIndice +=nSize;
1679        }
1680        if (iIndice < size)
1681        {
1682             sprintf(workbuffer, "%s", buffer+iIndice );
1683             msIO_printf("%s", workbuffer);
1684        }
1685    }
1686   else
1687   {
1688       msIO_printf("%s", buffer);
1689   }
1690   */
1691 }
1692 
1693 /************************************************************************/
1694 /*                           msSOSGetObservation                        */
1695 /*                                                                      */
1696 /*      GetObservation request handler                                  */
1697 /************************************************************************/
msSOSGetObservation(mapObj * map,sosParamsObj * sosparams,cgiRequestObj * req,owsRequestObj * ows_request)1698 int msSOSGetObservation(mapObj *map, sosParamsObj *sosparams, cgiRequestObj *req, owsRequestObj *ows_request)
1699 {
1700   char *schemalocation = NULL;
1701   char *xsi_schemaLocation = NULL;
1702   const char *pszTmp = NULL, *pszTmp2 = NULL;
1703   const char *user_namespace_uri = "http://mapserver.gis.umn.edu/mapserver";
1704   const char *user_namespace_prefix = "ms";
1705   char *script_url=NULL;
1706   int i, j, k, bLayerFound = 0;
1707   layerObj *lp = NULL, *lpfirst = NULL;
1708   const char *pszTimeExtent=NULL, *pszTimeField=NULL, *pszValue=NULL;
1709   FilterEncodingNode *psFilterNode = NULL;
1710   rectObj sBbox;
1711 
1712   xmlDocPtr psDoc = NULL;
1713   xmlNodePtr psRootNode,  psNode;
1714   char **tokens=NULL, **tokens1;
1715   int n=0, n1=0;
1716   xmlNsPtr psNsGml = NULL;
1717   xmlNsPtr psNsOm = NULL;
1718   xmlNsPtr psNsSwe = NULL;
1719   xmlNsPtr psNsXLink = NULL;
1720   xmlNsPtr psNsSos = NULL;
1721   xmlNsPtr psNsMs = NULL;
1722   const char *opLayerName = NULL;
1723   char *pszBuffer = NULL;
1724   const char *pszProcedureItem = NULL;
1725   int bSpatialDB = 0;
1726   xmlChar *buffer = NULL;
1727   int size = 0;
1728   msIOContext *context = NULL;
1729   xmlNodePtr psObservationNode = NULL, psResultNode=NULL;
1730   const char *pszProcedure = NULL;
1731   const char *pszBlockSep=NULL;
1732   int nDiffrentProc = 0;
1733   SOSProcedureNode *paDiffrentProc = NULL;
1734   int iItemPosition, status;
1735   shapeObj sShape;
1736   char* pszEscapedStr = NULL;
1737 
1738   sBbox = map->extent;
1739 
1740   /* establish local namespace */
1741   pszTmp = msOWSLookupMetadata(&(map->web.metadata), "SFO", "namespace_uri");
1742 
1743   if(pszTmp) user_namespace_uri = pszTmp;
1744 
1745   pszTmp = msOWSLookupMetadata(&(map->web.metadata), "SFO", "namespace_prefix");
1746   if(pszTmp) user_namespace_prefix = pszTmp;
1747 
1748   /* validates mandatory request elements */
1749   if (!sosparams->pszOffering) {
1750     msSetError(MS_SOSERR, "Missing OFFERING parameter.", "msSOSGetObservation()");
1751     return msSOSException(map, "offering", "MissingParameterValue");
1752   }
1753 
1754   if (!sosparams->pszObservedProperty) {
1755     msSetError(MS_SOSERR, "Missing OBSERVEDPROPERTY parameter.", "msSOSGetObservation()");
1756     return msSOSException(map, "observedproperty", "MissingParameterValue");
1757   }
1758 
1759   if (!sosparams->pszResponseFormat) {
1760     msSetError(MS_SOSERR, "Missing RESPONSEFORMAT parameter.", "msSOSGetObservation()");
1761     return msSOSException(map, "responseformat", "MissingParameterValue");
1762   }
1763 
1764   if (strcasecmp(sosparams->pszResponseFormat, pszSOSGetObservationMimeType) != 0) {
1765     msSetError(MS_SOSERR, "Invalid RESPONSEFORMAT parameter %s.  Allowable values are: %s", "msSOSGetObservation()", sosparams->pszResponseFormat, pszSOSGetObservationMimeType);
1766     return msSOSException(map, "responseformat", "InvalidParameterValue");
1767   }
1768 
1769   if (sosparams->pszResponseMode && strcasecmp(sosparams->pszResponseMode, "inline") != 0) {
1770     msSetError(MS_SOSERR, "Invalid RESPONSEMODE parameter %s.  Allowable values are: \"inline\"", "msSOSGetObservation()", sosparams->pszResponseMode);
1771     return msSOSException(map, "responsemode", "InvalidParameterValue");
1772   }
1773 
1774   /*validate if offering exists*/
1775   for (i=0; i<map->numlayers; i++) {
1776     pszTmp = msOWSLookupMetadata(&(GET_LAYER(map, i)->metadata), "S", "offering_id");
1777     if (pszTmp && (strcasecmp(pszTmp, sosparams->pszOffering) == 0) &&
1778         (msIntegerInArray(GET_LAYER(map, i)->index, ows_request->enabled_layers, ows_request->numlayers)))
1779       break;
1780   }
1781 
1782   if (i==map->numlayers) {
1783     msSetError(MS_SOSERR, "Offering %s not found. A layer might be disabled for \
1784 this request. Check sos/ows_enable_request settings.", "msSOSGetObservation()", sosparams->pszOffering);
1785     return msSOSException(map, "offering", "InvalidParameterValue");
1786   }
1787 
1788   /*validate if observed property exist*/
1789   /* Allow more the 1 oberved property comma separated (specs is unclear on it). If we
1790      do it, we need to see if other parameters like result (filter encoding)
1791      should be given for each property too) */
1792 
1793   bLayerFound = 0;
1794   tokens = msStringSplit(sosparams->pszObservedProperty, ',', &n);
1795 
1796   for (i=0; i<map->numlayers; i++) {
1797     pszTmp = msOWSLookupMetadata(&(GET_LAYER(map, i)->metadata), "S", "offering_id");
1798     pszTmp2 = msOWSLookupMetadata(&(GET_LAYER(map, i)->metadata), "S", "observedproperty_id");
1799 
1800     GET_LAYER(map, i)->status = MS_OFF;
1801 
1802     if (pszTmp && pszTmp2) {
1803       if (strcasecmp(pszTmp, sosparams->pszOffering) == 0) {
1804         if (tokens && n > 0) {
1805           for (j=0; j<n; j++) {
1806             if(strcasecmp(pszTmp2, tokens[j]) == 0) {
1807               GET_LAYER(map, i)->status = MS_ON;
1808               /* opLayerName = msStrdup(GET_LAYER(map, i)->name); */
1809               opLayerName = GET_LAYER(map, i)->name;
1810               /* Force setting a template to enable query. */
1811               if (!GET_LAYER(map, i)->template)
1812                 GET_LAYER(map, i)->template = msStrdup("ttt.html");
1813               bLayerFound = 1;
1814               break;
1815             }
1816           }
1817         }
1818       }
1819     }
1820   }
1821   if (tokens && n > 0)
1822     msFreeCharArray(tokens, n);
1823 
1824   if (bLayerFound == 0) {
1825     msSetError(MS_SOSERR, "ObservedProperty %s not found.", "msSOSGetObservation()", sosparams->pszObservedProperty);
1826     return msSOSException(map, "observedproperty", "InvalidParameterValue");
1827   }
1828 
1829   /* apply procedure : could be a comma separated list.
1830      set status to on those layers that have the sos_procedure metadata
1831      equals to this parameter. Note that the layer should already have it's status at ON
1832      by the  offering,observedproperty filter done above */
1833 
1834   if (sosparams->pszProcedure) {
1835     bLayerFound = 0;
1836     tokens = msStringSplit(sosparams->pszProcedure, ',', &n);
1837 
1838     if (tokens && n > 0) {
1839       for (i=0; i<map->numlayers; i++) {
1840         if(GET_LAYER(map, i)->status == MS_ON) {
1841           pszValue =  msOWSLookupMetadata(&(GET_LAYER(map, i)->metadata), "S", "procedure");
1842 
1843           if (pszValue) {
1844             /* the procedure metadata can be a list "sensor1 sensor2..."*/
1845             tokens1 = msStringSplit(pszValue, ' ', &n1);
1846 
1847             for (j=0; j<n; j++) {
1848               for (k=0; k<n1; k++) {
1849                 if (strcasecmp(tokens1[k], tokens[j]) == 0) { /* found */
1850                   bLayerFound = 1;
1851                   break;
1852                 }
1853               }
1854               if (k<n1)
1855                 break;
1856             }
1857             if (j == n) /*not found*/
1858               GET_LAYER(map, i)->status = MS_OFF;
1859 
1860             if (tokens1)
1861               msFreeCharArray(tokens1, n1);
1862 
1863             if (bLayerFound == 0) {
1864               msSetError(MS_SOSERR, "Procedure %s not found.", "msSOSGetObservation()", sosparams->pszProcedure);
1865               msFreeCharArray(tokens, n);
1866               return msSOSException(map, "procedure", "InvalidParameterValue");
1867             }
1868           }
1869 
1870           /* if there is a procedure_item defined on the layer, we will */
1871           /* use it to set the filter parameter of the layer */
1872 
1873           if ((GET_LAYER(map, i)->status == MS_ON) && (pszProcedureItem =  msOWSLookupMetadata(&(GET_LAYER(map, i)->metadata), "S", "procedure_item"))) {
1874 
1875             lp = GET_LAYER(map, i);
1876 
1877             /* HACK BEGIN */
1878 
1879             if (msOWSLookupMetadata(&(GET_LAYER(map,i)->metadata), "S", "procedure") == NULL) {
1880               /* if sos_procedure_item is used, and sos_procedure is not, it means that */
1881               /* the procedure or sensor) need to be extracted from the data. Thus we */
1882               /* need to query the layer and get the values from each feature */
1883 
1884               if (lp->template == NULL)
1885                 lp->template = msStrdup("ttt");
1886 
1887               map->query.type = MS_QUERY_BY_RECT;
1888               map->query.mode = MS_QUERY_MULTIPLE;
1889               map->query.layer = i;
1890               map->query.rect = map->extent;
1891               msQueryByRect(map);
1892 
1893               /*check if the attribute specified in the procedure_item is available */
1894               /*on the layer*/
1895               iItemPosition = -1;
1896               if (msLayerGetItems(lp) == MS_SUCCESS && lp->resultcache && lp->resultcache->numresults > 0) {
1897                 for(k=0; k<lp->numitems; k++) {
1898                   if (strcasecmp(lp->items[k], pszProcedureItem) == 0) {
1899                     iItemPosition = k;
1900                     break;
1901                   }
1902                 }
1903                 if (iItemPosition == -1) {
1904                   msSetError(MS_SOSERR, "sos_procedure_item %s could not be found on the layer %s",
1905                              "msSOSGetCapabilities()", pszProcedureItem, lp->name);
1906                   return msSOSException(map, "mapserv", "NoApplicableCode");
1907                 }
1908 
1909                 /*for each selected feature, grab the value of the procedure_item*/
1910                 bLayerFound = 0;
1911 
1912                 for(k=0; k<lp->resultcache->numresults; k++) {
1913                   msInitShape(&sShape);
1914                   status = msLayerGetShape(lp, &sShape, &(lp->resultcache->results[k]));
1915                   if(status != MS_SUCCESS)
1916                     continue;
1917 
1918                   if (sShape.values[iItemPosition]) {
1919                     tokens = msStringSplit(sosparams->pszProcedure, ',', &n);
1920                     for (j=0; j<n; j++) {
1921                       if (strcasecmp(sShape.values[iItemPosition], tokens[j]) == 0) { /* found */
1922                         bLayerFound = 1;
1923                         break;
1924                       }
1925                     }
1926                   }
1927 
1928                   if (bLayerFound)
1929                     break;
1930                 }
1931 
1932                 if (bLayerFound == 0) {
1933                   msSetError(MS_SOSERR, "Invalid procedure value %s", "msSOSGetCapabilities()", sosparams->pszProcedure);
1934                   return msSOSException(map, "procedure", "InvalidParameterValue");
1935                 }
1936               }
1937             }
1938             /* HACK END */
1939 
1940             pszBuffer = NULL;
1941             if (lp->filter.string && strlen(lp->filter.string) > 0)
1942               msFreeExpression(&lp->filter);
1943 
1944             /*The filter should reflect the underlying db*/
1945             /*for ogr add a where clause */
1946             bSpatialDB = 0;
1947             if (lp->connectiontype == MS_POSTGIS ||  lp->connectiontype == MS_ORACLESPATIAL || lp->connectiontype == MS_OGR)
1948               bSpatialDB = 1;
1949 
1950 
1951             if (bSpatialDB) {
1952               if (lp->connectiontype != MS_OGR)
1953                 pszBuffer = msStringConcatenate(pszBuffer, "(");
1954               else
1955                 pszBuffer = msStringConcatenate(pszBuffer, "WHERE ");
1956             } else
1957               pszBuffer = msStringConcatenate(pszBuffer, "(");
1958 
1959             for (j=0; j<n; j++) {
1960               if (j > 0)
1961                 pszBuffer = msStringConcatenate(pszBuffer, " OR ");
1962 
1963               pszBuffer = msStringConcatenate(pszBuffer, "(");
1964 
1965               if (!bSpatialDB) {
1966                 pszBuffer = msStringConcatenate(pszBuffer, "'[");
1967                 pszBuffer = msStringConcatenate(pszBuffer, (char *)pszProcedureItem);
1968               } else {
1969                 pszEscapedStr = msLayerEscapePropertyName(lp, (char *)pszProcedureItem);
1970                 pszBuffer = msStringConcatenate(pszBuffer, pszEscapedStr);
1971                 msFree(pszEscapedStr);
1972                 pszEscapedStr = NULL;
1973               }
1974 
1975               if (!bSpatialDB)
1976                 pszBuffer = msStringConcatenate(pszBuffer, "]'");
1977 
1978               pszBuffer = msStringConcatenate(pszBuffer, " = '");
1979               pszEscapedStr = msLayerEscapeSQLParam(lp, tokens[j]);
1980               pszBuffer = msStringConcatenate(pszBuffer,  pszEscapedStr);
1981               msFree(pszEscapedStr);
1982               pszBuffer = msStringConcatenate(pszBuffer,  "')");
1983             }
1984 
1985             if (!bSpatialDB || lp->connectiontype != MS_OGR)
1986               pszBuffer = msStringConcatenate(pszBuffer, ")");
1987 
1988             msLoadExpressionString(&lp->filter, pszBuffer);
1989             if (pszBuffer)
1990               msFree(pszBuffer);
1991           }
1992         }
1993       }
1994       msFreeCharArray(tokens, n);
1995     }
1996   }
1997 
1998   /* -------------------------------------------------------------------- */
1999   /*      supports 2 types of gml:Time : TimePeriod and TimeInstant :     */
2000   /*      - <gml:TimePeriod>                                              */
2001   /*          <gml:beginPosition>2005-09-01T11:54:32</gml:beginPosition>  */
2002   /*         <gml:endPosition>2005-09-02T14:54:32</gml:endPosition>       */
2003   /*       </gml:TimePeriod>                                              */
2004   /*                                                                      */
2005   /*      - <gml:TimeInstant>                                             */
2006   /*           <gml:timePosition>2003-02-13T12:28-08:00</gml:timePosition>*/
2007   /*         </gml:TimeInstant>                                           */
2008   /*                                                                      */
2009   /*       The user can specify mutilple times separated by commas.       */
2010   /*                                                                      */
2011   /*       The gml will be parsed and trasformed into a sting tah         */
2012   /*      looks like timestart/timeend,...                                */
2013   /* -------------------------------------------------------------------- */
2014 
2015   /*apply time filter if available */
2016   if (sosparams->pszEventTime) {
2017     char **apszTimes = NULL;
2018     int numtimes = 0;
2019     char *pszTimeString = NULL, *pszTmp = NULL;
2020 
2021     /* Because SOS has specific TemporalOperator which extends FES 1.1, the time filter  */
2022     /* passed is different than what mapogcfilter (per 1.0.0) supports.                  */
2023     /*                                                                                   */
2024     /* Because, in XML POST mode, we traverse directly to gml:TimePeriod|gml:TimeInstant */
2025     /* this is passed directly to mapogcfilter.                                          */
2026     /* for GET requests, we strip the parent element before passing                      */
2027 
2028     pszTmp = msStrdup(sosparams->pszEventTime);
2029 
2030     pszTmp = msCaseReplaceSubstring(pszTmp, "<ogc:TM_Equals>", "");
2031     pszTmp = msCaseReplaceSubstring(pszTmp, "<TM_Equals>", "");
2032     pszTmp = msCaseReplaceSubstring(pszTmp, "</ogc:TM_Equals>", "");
2033     pszTmp = msCaseReplaceSubstring(pszTmp, "</TM_Equals>", "");
2034 
2035     apszTimes = msStringSplit (pszTmp, ',', &numtimes);
2036     msFree(pszTmp);
2037 
2038     if (numtimes >=1) {
2039       for (i=0; i<numtimes; i++) {
2040         pszTmp = msSOSParseTimeGML(apszTimes[i]);
2041         if (pszTmp) {
2042           if (pszTimeString)
2043             pszTimeString = msStringConcatenate(pszTimeString, ",");
2044           pszTimeString = msStringConcatenate(pszTimeString, pszTmp);
2045           msFree(pszTmp);
2046         }
2047       }
2048       msFreeCharArray(apszTimes, numtimes);
2049     }
2050     if (!pszTimeString) {
2051       msSetError(MS_SOSERR, "Invalid time value given for the eventTime parameter %s", "msSOSGetObservation()", sosparams->pszEventTime);
2052       return msSOSException(map, "eventtime", "InvalidParameterValue");
2053     }
2054     for (i=0; i<map->numlayers; i++) {
2055       if (GET_LAYER(map, i)->status == MS_ON) {
2056         /* the sos_offering_timeextent should be used for time validation*/
2057         /*TODO : too documented  ?*/
2058         lpfirst = msSOSGetFirstLayerForOffering(map, msOWSLookupMetadata(&(GET_LAYER(map, i)->metadata), "S", "offering_id"), NULL);
2059         if (lpfirst)
2060           pszTimeExtent = msOWSLookupMetadata(&lpfirst->metadata, "S", "offering_timeextent");
2061 
2062         pszTimeField =  msOWSLookupMetadata(&(GET_LAYER(map, i)->metadata), "SO", "timeitem");
2063 
2064         if (pszTimeField) {
2065           /*validate only if time extent is set.*/
2066           if (pszTimeExtent) {
2067             if (msValidateTimeValue(pszTimeString, pszTimeExtent) == MS_TRUE)
2068               msLayerSetTimeFilter((GET_LAYER(map, i)), pszTimeString, pszTimeField);
2069             else {
2070               /*we should turn the layer off since the eventTime is not in the time extent*/
2071               GET_LAYER(map, i)->status = MS_OFF;
2072             }
2073           } else
2074             msLayerSetTimeFilter((GET_LAYER(map, i)), pszTimeString, pszTimeField);
2075         }
2076       }
2077     }
2078     if (pszTimeString)
2079       msFree(pszTimeString);
2080   }
2081 
2082   /*bbox*/
2083   /* this is a gml feature
2084   <gml:Envelope xmlns:gml="http://www.opengis.net/gml">
2085   <gml:lowerCorner srsName="EPSG:4326">-66 43</gml:lowerCorner>
2086   <upperCorner srsName="EPSG:4326">-62 45</upperCorner>
2087   </gml:Envelope>
2088   */
2089 
2090   if (sosparams->pszFeatureOfInterest) {
2091     int bValid = 0;
2092     CPLXMLNode *psRoot=NULL;
2093     char *pszSRS = NULL;
2094 
2095     psRoot = CPLParseXMLString(sosparams->pszFeatureOfInterest);
2096     if(!psRoot) {
2097       msSetError(MS_SOSERR, "Invalid gml:Envelope value given for featureOfInterest.", "msSOSGetObservation()");
2098       return msSOSException(map, "featureofinterest", "InvalidParameterValue");
2099     }
2100 
2101     CPLStripXMLNamespace(psRoot, "gml", 1);
2102     bValid = FLTParseGMLEnvelope(psRoot, &sBbox, &pszSRS);
2103 
2104     /* TODO we should reproject the bbox to the map projection if there is an srs defined */
2105     if (!bValid) {
2106       msSetError(MS_SOSERR, "Invalid gml:Envelope value given for featureOfInterest %s.", "msSOSGetObservation()", sosparams->pszEventTime);
2107       return msSOSException(map, "featureofinterest", "InvalidParameterValue");
2108     }
2109     map->extent.minx = sBbox.minx;
2110     map->extent.miny = sBbox.miny;
2111     map->extent.maxx = sBbox.maxx;
2112     map->extent.maxy = sBbox.maxy;
2113 
2114     CPLDestroyXMLNode(psRoot);
2115     msFree(pszSRS);
2116   }
2117 
2118   if (sosparams->pszSrsName) { /* validate against MAP.WEB.METADATA.sos_srs */
2119     int iUnits = -1;
2120     char **tokens = NULL;
2121     const char *pszSRSList = NULL;
2122     int n = 0;
2123     int bFound = 0;
2124     int k;
2125     char srsbuffer[100];
2126     projectionObj po;
2127 
2128     pszSRSList = msOWSLookupMetadata(&(map->web.metadata), "SO", "srs");
2129 
2130     if (pszSRSList) {
2131       tokens = msStringSplit(pszSRSList, ' ', &n);
2132 
2133       if (tokens && n > 0) {
2134         for (k=0; k<n; k++) {
2135           if (strncasecmp(tokens[k], "EPSG:", strlen("EPSG:")) == 0 &&
2136               strcasecmp(sosparams->pszSrsName, tokens[k]) == 0) { /* match */
2137             bFound = 1;
2138 
2139             /* project MAP.EXTENT to this SRS */
2140             msInitProjection(&po);
2141             msProjectionInheritContextFrom(&po, &map->projection);
2142 
2143             snprintf(srsbuffer, sizeof(srsbuffer), "+init=epsg:%.20s", sosparams->pszSrsName+strlen("EPSG:"));
2144 
2145             if (msLoadProjectionString(&po, srsbuffer) != 0) {
2146               msSetError(MS_SOSERR, "Could not set output projection to \"%s\"", "msSOSGetObservation()", sosparams->pszSrsName);
2147               return msSOSException(map, "mapserv", "NoApplicableCode");
2148             }
2149 
2150             if (msProjectionsDiffer(&map->projection, &po) == MS_TRUE) {
2151               msProjectRect(&map->projection, &po, &map->extent);
2152               sBbox = map->extent;
2153             }
2154 
2155             /* set map->projection to this SRS */
2156             if (msLoadProjectionString(&(map->projection), srsbuffer) != 0) {
2157               msSetError(MS_SOSERR, "Could not set output projection to \"%s\"", "msSOSGetObservation()", sosparams->pszSrsName);
2158               return msSOSException(map, "mapserv", "NoApplicableCode");
2159             }
2160 
2161             iUnits = GetMapserverUnitUsingProj(&(map->projection));
2162             if (iUnits != -1)
2163               map->units = iUnits;
2164 
2165             msFreeProjection(&po);
2166             break;
2167           }
2168         }
2169         msFreeCharArray(tokens, n);
2170       }
2171       if (bFound == 0) {
2172         msSetError(MS_SOSERR, "srsName value \"%s\" unsupported / invalid", "msSOSGetObservation()", sosparams->pszSrsName);
2173         return msSOSException(map, "srsName", "InvalidParameterValue");
2174       }
2175     } else {
2176       msSetError(MS_SOSERR, "MAP.WEB.METADATA.sos_srs not set", "msSOSGetObservation()");
2177       return msSOSException(map, "mapserv", "NoApplicableCode");
2178     }
2179   }
2180 
2181   /* apply filter */
2182   if (sosparams->pszResult) {
2183     psFilterNode = FLTParseFilterEncoding(sosparams->pszResult);
2184 
2185     if (!psFilterNode) {
2186       msSetError(MS_SOSERR, "Invalid or Unsupported RESULT in GetObservation: %s", "msSOSGetObservation()", sosparams->pszResult);
2187       return msSOSException(map, "result", "InvalidParameterValue");
2188     }
2189     /* apply the filter to all layers that are on */
2190     for (i=0; i<map->numlayers; i++) {
2191       lp = GET_LAYER(map, i);
2192       if (lp->status == MS_ON) {
2193         /* preparse parser so that alias for fields can be used */
2194         FLTPreParseFilterForAliasAndGroup(psFilterNode, map, i, "S");
2195         /* validate that the property names used are valid
2196           (there is a corresponding layer attribute) */
2197         if (msLayerOpen(lp) == MS_SUCCESS && msLayerGetItems(lp) == MS_SUCCESS) {
2198           if (msSOSValidateFilter(psFilterNode, lp)== MS_FALSE) {
2199             msSetError(MS_SOSERR, "Invalid component name in RESULT statement", "msSOSGetObservation()");
2200             return msSOSException(map, "result", "InvalidParameterValue");
2201           }
2202           msLayerClose(lp);
2203         }
2204         FLTApplyFilterToLayer(psFilterNode, map, i);
2205       }
2206     }
2207 
2208     FLTFreeFilterEncodingNode(psFilterNode);
2209   }
2210 
2211 
2212 
2213   /* this is just a fall back if bbox is enetered. The bbox parameter is not supported
2214      by the sos specs */
2215   if (sosparams->pszBBox && !sosparams->pszFeatureOfInterest) {
2216     char **tokens;
2217     int n;
2218 
2219     tokens = msStringSplit(sosparams->pszBBox, ',', &n);
2220     if (tokens==NULL || n != 4) {
2221       msSetError(MS_SOSERR, "Wrong number of arguments for bounding box.", "msSOSGetObservation()");
2222       return msSOSException(map, "bbox", "InvalidParameterValue");
2223     }
2224     sBbox.minx = atof(tokens[0]);
2225     sBbox.miny = atof(tokens[1]);
2226     sBbox.maxx = atof(tokens[2]);
2227     sBbox.maxy = atof(tokens[3]);
2228     msFreeCharArray(tokens, n);
2229   }
2230 
2231   /* do the query if the filter encoding (pszResult) is not part of the request.
2232      If pszResult is available, the query on the layers will be done when the filter
2233      is parsed*/
2234   if (!sosparams->pszResult) {
2235     map->query.type = MS_QUERY_BY_RECT;
2236     map->query.mode = MS_QUERY_MULTIPLE;
2237     map->query.layer = -1;
2238     map->query.rect = sBbox;
2239     msQueryByRect(map);
2240   }
2241 
2242   /*get the first layers of the offering*/
2243   for (i=0; i<map->numlayers; i++) {
2244     pszTmp = msOWSLookupMetadata(&(GET_LAYER(map, i)->metadata), "S", "offering_id");
2245     if (pszTmp && (strcasecmp(pszTmp, sosparams->pszOffering) == 0)) {
2246       lp = (GET_LAYER(map, i));
2247       break;
2248     }
2249   }
2250 
2251   /* build xml return tree*/
2252 
2253   psNsSos = xmlNewNs(NULL, BAD_CAST "http://www.opengis.net/sos/1.0", BAD_CAST "sos");
2254   psNsGml = xmlNewNs(NULL, BAD_CAST "http://www.opengis.net/gml", BAD_CAST "gml");
2255   psNsOm = xmlNewNs(NULL, BAD_CAST pszOMNamespaceUri, BAD_CAST pszOMNamespacePrefix);
2256   psNsSwe = xmlNewNs(NULL, BAD_CAST "http://www.opengis.net/swe/1.0.1", BAD_CAST "swe");
2257   psNsXLink = xmlNewNs(NULL, BAD_CAST MS_OWSCOMMON_W3C_XLINK_NAMESPACE_URI, BAD_CAST MS_OWSCOMMON_W3C_XLINK_NAMESPACE_PREFIX);
2258   psNsMs = xmlNewNs(NULL, BAD_CAST user_namespace_uri, BAD_CAST user_namespace_prefix);
2259 
2260   psDoc = xmlNewDoc(BAD_CAST "1.0");
2261   psRootNode = xmlNewNode(NULL, BAD_CAST "ObservationCollection");
2262   xmlDocSetRootElement(psDoc, psRootNode);
2263 
2264   xmlSetNs(psRootNode,  xmlNewNs(psRootNode, BAD_CAST "http://www.opengis.net/gml", BAD_CAST "gml"));
2265   xmlSetNs(psRootNode,  xmlNewNs(psRootNode, BAD_CAST "http://www.opengis.net/ows/1.1", BAD_CAST "ows"));
2266   xmlSetNs(psRootNode,  xmlNewNs(psRootNode, BAD_CAST "http://www.opengis.net/swe/1.0.1", BAD_CAST "swe"));
2267   xmlSetNs(psRootNode,  xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_W3C_XLINK_NAMESPACE_URI, BAD_CAST MS_OWSCOMMON_W3C_XLINK_NAMESPACE_PREFIX));
2268   xmlSetNs(psRootNode,  xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_W3C_XSI_NAMESPACE_URI, BAD_CAST MS_OWSCOMMON_W3C_XSI_NAMESPACE_PREFIX));
2269   xmlSetNs(psRootNode,  xmlNewNs(psRootNode, BAD_CAST pszSOSNamespaceUri, BAD_CAST pszSOSNamespacePrefix));
2270   xmlSetNs(psRootNode,  xmlNewNs(psRootNode, BAD_CAST user_namespace_uri, BAD_CAST user_namespace_prefix));
2271   xmlSetNs(psRootNode,  xmlNewNs(psRootNode, BAD_CAST "http://www.opengis.net/om/1.0", BAD_CAST "om"));
2272 
2273   xmlNewNsProp(psRootNode, psNsGml, BAD_CAST "id", BAD_CAST sosparams->pszOffering);
2274 
2275   schemalocation = msEncodeHTMLEntities(msOWSGetSchemasLocation(map));
2276 
2277   if ((script_url=msOWSGetOnlineResource(map, "SO", "onlineresource", req)) == NULL)
2278     return msSOSException(map, "NoApplicableCode", "NoApplicableCode");
2279 
2280   xsi_schemaLocation = msStrdup("http://www.opengis.net/om/1.0 ");
2281   xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, schemalocation);
2282   xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, "/om/1.0.0/om.xsd ");
2283   xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, (char *) user_namespace_uri);
2284   xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, " ");
2285   xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, (char *) script_url);
2286   xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, "service=WFS&version=1.1.0&request=DescribeFeatureType&typename=");
2287   xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, (char *) opLayerName);
2288   xmlNewNsProp(psRootNode, NULL, BAD_CAST "xsi:schemaLocation", BAD_CAST xsi_schemaLocation);
2289 
2290   /* description */
2291   pszTmp = msOWSLookupMetadata(&(lp->metadata), "S", "offering_description");
2292   if (pszTmp) {
2293     psNode = xmlNewChild(psRootNode, NULL, BAD_CAST "description", BAD_CAST pszTmp);
2294     xmlSetNs(psNode, xmlNewNs(psNode, BAD_CAST "http://www.opengis.net/gml", BAD_CAST "gml"));
2295   }
2296 
2297   /* name */
2298   pszTmp = msOWSLookupMetadata(&(lp->metadata), "S", "offering_name");
2299   if (pszTmp) {
2300     psNode = xmlNewChild(psRootNode, NULL, BAD_CAST "name", BAD_CAST pszTmp);
2301     xmlSetNs(psNode, xmlNewNs(psNode, BAD_CAST "http://www.opengis.net/gml", BAD_CAST "gml"));
2302   }
2303 
2304   /* extent */
2305   pszTmp = msOWSLookupMetadata(&(lp->metadata), "S", "offering_extent");
2306 
2307   if (pszTmp) {
2308     char **tokens;
2309     char *pszMapEpsg;
2310     int n;
2311     rectObj envelope;
2312 
2313     msOWSGetEPSGProj(&(map->projection), &(lp->metadata), "SO", MS_TRUE, &pszMapEpsg);
2314 
2315     tokens = msStringSplit(pszTmp, ',', &n);
2316     if (tokens==NULL || n != 4) {
2317       msSetError(MS_SOSERR, "Wrong number of arguments for sos_offering_extent.",
2318                  "msSOSGetCapabilities()");
2319       msFree(script_url);
2320       return msSOSException(map, "sos_offering_extent", "InvalidParameterValue");
2321     }
2322 
2323     envelope.minx = atof(tokens[0]);
2324     envelope.miny = atof(tokens[1]);
2325     envelope.maxx = atof(tokens[2]);
2326     envelope.maxy = atof(tokens[3]);
2327 
2328     if (map && msProjectionsDiffer(&map->projection, &lp->projection) == MS_TRUE) {
2329       if (msProjectRect(&lp->projection, &map->projection, &envelope) == MS_FAILURE) {
2330         msSetError(MS_SOSERR, "Coordinates transformation failed.  Raised in msProjectRect() of file %s line %d", "msSOSGetCapabilities()", __FILE__, __LINE__);
2331         msFree(script_url);
2332         return msSOSException(map, "sos_offering_extent", "InvalidParameterValue");
2333       }
2334     }
2335 
2336     psNode = xmlAddChild(psRootNode, msGML3BoundedBy(psNsGml, envelope.minx, envelope.miny, envelope.maxx, envelope.maxy, pszMapEpsg));
2337     msFreeCharArray(tokens, n);
2338     msFree(pszMapEpsg);
2339   }
2340 
2341   /* time
2342   pszTmp = msOWSLookupMetadata(&(lp->metadata), "S","offering_timeextent");
2343   if (pszTmp)
2344   {
2345       char **tokens;
2346       int n;
2347       char *pszEndTime = NULL;
2348       tokens = msStringSplit(pszTmp, '/', &n);
2349       if (tokens==NULL || (n != 1 && n!=2)) {
2350           msSetError(MS_SOSERR, "Wrong number of arguments for sos_offering_timeextent.",
2351                      "msSOSGetCapabilities()");
2352           return msSOSException(map, "sos_offering_timeextent", "InvalidParameterValue");
2353       }
2354   */
2355   /*    if (n == 2) */ /* end time is empty. It is going to be set as "now" */
2356   /*      pszEndTime = tokens[1];
2357 
2358         psNode = xmlAddChild(psRootNode, msSOSAddTimeNode(xmlNewNs(NULL, BAD_CAST pszOMNamespaceUri, BAD_CAST pszOMNamespacePrefix), tokens[0], pszEndTime));
2359       psNode = xmlAddChild(psRootNode, msSOSAddTimeNode(psNsOm, psNsGml, tokens[0], pszEndTime));
2360       msFreeCharArray(tokens, n);
2361 
2362   }
2363   */
2364 
2365   if (sosparams->pszResultModel && strcasecmp(sosparams->pszResultModel, "om:Measurement") != 0 &&
2366       strcasecmp(sosparams->pszResultModel, "om:Observation") != 0) {
2367     msSetError(MS_SOSERR, "resultModel should be om:Measurement or om:Observation", "msSOSGetObservation()");
2368     free(xsi_schemaLocation);
2369     free(schemalocation);
2370     msFree(script_url);
2371     xmlFreeNs(psNsSos);
2372     xmlFreeNs(psNsGml);
2373     xmlFreeNs(psNsOm);
2374     xmlFreeNs(psNsSwe);
2375     xmlFreeNs(psNsXLink);
2376     xmlFreeNs(psNsMs);
2377     xmlFreeDoc(psDoc);
2378     return msSOSException(map, "resultModel", "InvalidParameterValue");
2379   }
2380 
2381   else {
2382     /* output result members */
2383     for (i=0; i<map->numlayers; i++) {
2384       if (GET_LAYER(map, i)->resultcache && GET_LAYER(map, i)->resultcache->numresults > 0) {
2385         msLayerGetItems((GET_LAYER(map, i)));
2386         pszTmp = msOWSLookupMetadata(&(map->web.metadata), "SO", "maxfeatures");
2387         if (pszTmp != NULL)
2388           n1 = atoi(pszTmp);
2389         else
2390           n1 = 0;
2391 
2392         if (sosparams->pszResultModel == NULL || strcasecmp(sosparams->pszResultModel, "om:Measurement") == 0) {
2393           for(j=0; j<GET_LAYER(map, i)->resultcache->numresults; j++) {
2394             msSOSAddMemberNode(psNsGml, psNsOm, psNsSwe, psNsXLink, psNsMs, psRootNode, map, (GET_LAYER(map, i)), j, script_url, opLayerName);
2395             if (j == n1-1)
2396               break;
2397           }
2398         } else { /*assuming here that pszResultModel = observation */
2399           /*layer does not define a procedure_item: this means one procedure per
2400             layer defined using sos_procedure)*/
2401           if (msOWSLookupMetadata(&(GET_LAYER(map, i)->metadata), "S", "procedure_item") == NULL) {
2402             pszProcedure = msOWSLookupMetadata(&(lp->metadata), "S", "procedure");
2403             psObservationNode = msSOSAddMemberNodeObservation(psNsGml, psNsSos, psNsOm, psNsSwe, psNsXLink, psRootNode, map, (GET_LAYER(map, i)),
2404                                 pszProcedure);
2405             /*add a result node*/
2406             psResultNode = xmlNewChild(psObservationNode, NULL, BAD_CAST "result", NULL);
2407             for(j=0; j<GET_LAYER(map, i)->resultcache->numresults; j++) {
2408               /*add a block separator*/
2409               if (j > 0) {
2410                 pszBlockSep = msOWSLookupMetadata(&(map->web.metadata), "S",
2411                                                   "encoding_blockSeparator");
2412                 if (pszBlockSep)
2413                   xmlNodeAddContent(psResultNode, BAD_CAST pszBlockSep);
2414                 else
2415                   xmlNodeAddContent(psResultNode, BAD_CAST "\n");
2416               }
2417               {
2418                 char* pszResult = msSOSReturnMemberResult((GET_LAYER(map, i)), j, NULL);
2419                 if (pszResult) {
2420                   xmlNodeAddContent(psResultNode, BAD_CAST pszResult);
2421                   msFree(pszResult);
2422                 }
2423               }
2424             }
2425           }
2426           /*this is the case where procedure_item is used. Needs more management since
2427             the same data on a layer contains different procedures (procedures are
2428             one of the fields of the record)*/
2429           else {
2430 
2431             for(j=0; j<GET_LAYER(map, i)->resultcache->numresults; j++) {
2432               char* pszProcedureValue = NULL;
2433               char* pszResult = msSOSReturnMemberResult((GET_LAYER(map, i)), j, &pszProcedureValue);
2434               if (!pszProcedureValue || !pszResult)
2435               {
2436                 msFree(pszProcedureValue);
2437                 msFree(pszResult);
2438                 continue;
2439               }
2440               for (k=0; k<nDiffrentProc; k++) {
2441                 if (strcasecmp(paDiffrentProc[k].pszProcedure, pszProcedureValue) == 0) {
2442                   pszBlockSep = msOWSLookupMetadata(&(map->web.metadata), "S",
2443                                                     "encoding_blockSeparator");
2444                   if (pszBlockSep)
2445                     xmlNodeAddContent(paDiffrentProc[k].psResultNode, BAD_CAST pszBlockSep);
2446                   else
2447                     xmlNodeAddContent(paDiffrentProc[k].psResultNode, BAD_CAST "\n");
2448                   xmlNodeAddContent(paDiffrentProc[k].psResultNode, BAD_CAST pszResult);
2449                   break;
2450                 }
2451               }
2452               if (k == nDiffrentProc) { /*a new procedure*/
2453                 nDiffrentProc++;
2454                 if (paDiffrentProc == NULL)
2455                   paDiffrentProc = (SOSProcedureNode *)malloc(sizeof(SOSProcedureNode));
2456                 else
2457                   paDiffrentProc = (SOSProcedureNode *)realloc(paDiffrentProc,
2458                                    sizeof(SOSProcedureNode)
2459                                    *nDiffrentProc);
2460 
2461                 paDiffrentProc[nDiffrentProc-1].pszProcedure = msStrdup(pszProcedureValue);
2462                 psObservationNode = msSOSAddMemberNodeObservation(psNsGml, psNsSos, psNsOm, psNsSwe, psNsXLink, psRootNode, map,
2463                                     (GET_LAYER(map, i)),
2464                                     pszProcedureValue);
2465 
2466                 paDiffrentProc[nDiffrentProc-1].psResultNode =
2467                   xmlNewChild(psObservationNode, NULL, BAD_CAST "result", NULL);
2468 
2469                 xmlNodeAddContent(paDiffrentProc[nDiffrentProc-1].psResultNode, BAD_CAST pszResult);
2470               }
2471               msFree(pszProcedureValue);
2472               msFree(pszResult);
2473             }
2474             if (paDiffrentProc) {
2475               for (k=0; k<nDiffrentProc; k++)
2476                 msFree(paDiffrentProc[k].pszProcedure);
2477               free(paDiffrentProc);
2478             }
2479           }
2480         }
2481       }
2482     }
2483   }
2484 
2485   /* output results */
2486   msIO_setHeader("Content-Type","text/xml; charset=UTF-8");
2487   msIO_sendHeaders();
2488 
2489   context = msIO_getHandler(stdout);
2490   xmlDocDumpFormatMemoryEnc(psDoc, &buffer, &size, ("UTF-8"), 1);
2491   msIO_contextWrite(context, buffer, size);
2492   free(schemalocation);
2493   free(xsi_schemaLocation);
2494   xmlFreeNs(psNsSos);
2495   xmlFreeNs(psNsGml);
2496   xmlFreeNs(psNsOm);
2497   xmlFreeNs(psNsSwe);
2498   xmlFreeNs(psNsXLink);
2499   xmlFreeNs(psNsMs);
2500   xmlFree(buffer);
2501   msFree(script_url);
2502 
2503   /*free  document */
2504   xmlFreeDoc(psDoc);
2505   /*
2506   *Free the global variables that may
2507   *have been allocated by the parser.
2508   */
2509   xmlCleanupParser();
2510 
2511 
2512   return(MS_SUCCESS);
2513 }
2514 
2515 
2516 
2517 /************************************************************************/
2518 /*                           msSOSDescribeSensor                        */
2519 /*                                                                      */
2520 /*      Describe sensor request handler.                               */
2521 /************************************************************************/
msSOSDescribeSensor(mapObj * map,sosParamsObj * sosparams,owsRequestObj * ows_request)2522 int msSOSDescribeSensor(mapObj *map, sosParamsObj *sosparams, owsRequestObj *ows_request)
2523 {
2524   char *pszEncodedUrl = NULL;
2525   const char *pszId = NULL, *pszUrl = NULL;
2526   int i = 0, j=0, k=0;
2527   layerObj *lp = NULL;
2528   int iItemPosition = -1;
2529   shapeObj sShape;
2530   int status;
2531   char *tmpstr = NULL, *pszTmp = NULL, *pszProcedureURI = NULL, *pszProcedureId = NULL;
2532 
2533   if (!sosparams->pszOutputFormat) {
2534     msSetError(MS_SOSERR, "Missing mandatory parameter outputFormat.", "msSOSDescribeSensor()");
2535     return msSOSException(map, "outputformat", "MissingParameterValue");
2536   }
2537 
2538   if (strcasecmp(sosparams->pszOutputFormat, pszSOSDescribeSensorMimeType) != 0) {
2539     msSetError(MS_SOSERR, "Invalid outputformat parameter %s.  Allowable values are: %s", "msSOSDescribeSensor()", sosparams->pszOutputFormat, pszSOSDescribeSensorMimeType);
2540     return msSOSException(map, "outputformat", "InvalidParameterValue");
2541   }
2542 
2543   if (!sosparams->pszProcedure) {
2544     msSetError(MS_SOSERR, "Missing mandatory parameter procedure", "msSOSDescribeSensor()");
2545     return msSOSException(map, "procedure", "MissingParameterValue");
2546   }
2547 
2548   for (i=0; i<map->numlayers; i++) {
2549     lp = GET_LAYER(map, i);
2550     pszId = msOWSLookupMetadata(&(lp->metadata), "S", "procedure");
2551     if (pszId && strlen(pszId) > 0) {
2552       /*procedure could be a list*/
2553       char **tokens = NULL;
2554       int n=0;
2555       int bFound = 0;
2556       tokens = msStringSplit(pszId, ' ', &n);
2557       for (k=0; k<n; k++) {
2558         if (tokens[k] && strlen(tokens[k]) > 0) {
2559           pszProcedureURI = msStrdup("urn:ogc:def:procedure:");
2560           pszProcedureURI = msStringConcatenate(pszProcedureURI, tokens[k]);
2561           if ( (pszProcedureURI && strcasecmp(pszProcedureURI, sosparams->pszProcedure) == 0) &&
2562                (msIntegerInArray(lp->index, ows_request->enabled_layers, ows_request->numlayers)) ) {
2563             bFound = 1;
2564             pszProcedureId = msStrdup(tokens[k]);
2565             msFree(pszProcedureURI);
2566             break;
2567           }
2568           msFree(pszProcedureURI);
2569         }
2570       }
2571       msFreeCharArray(tokens, n);
2572       if (bFound) {
2573         pszUrl = msOWSLookupMetadata(&(lp->metadata), "S", "describesensor_url");
2574         if (pszUrl) {
2575           pszTmp = msStrdup(pszUrl);
2576 
2577           /* %procedure% is the hardcoded variable name to use
2578              within sos_describesensor_url */
2579           tmpstr = (char *)malloc(sizeof(char)*strlen("procedure") + 3);
2580           sprintf(tmpstr,"%%%s%%", "procedure");
2581           if (strcasestr(pszUrl, tmpstr) != NULL)
2582             pszTmp = msCaseReplaceSubstring(pszTmp, tmpstr, pszProcedureId);
2583           msFree(tmpstr);
2584 
2585           pszEncodedUrl = msEncodeHTMLEntities(pszTmp);
2586           msIO_printf("Location: %s\n\n", pszEncodedUrl);
2587           msFree(pszTmp);
2588           msFree(pszEncodedUrl);
2589           msFree(pszProcedureId);
2590           return(MS_SUCCESS);
2591         } else {
2592           msSetError(MS_SOSERR, "Missing mandatory metadata sos_describesensor_url on layer %s", "msSOSDescribeSensor()", lp->name);
2593           return msSOSException(map, "sos_describesensor_url", "MissingParameterValue");
2594         }
2595       }
2596     } else if ((pszId = msOWSLookupMetadata(&(lp->metadata), "S", "procedure_item"))) {
2597       iItemPosition = -1;
2598       if (msLayerOpen(lp) == MS_SUCCESS && msLayerGetItems(lp) == MS_SUCCESS) {
2599         for(j=0; j<lp->numitems; j++) {
2600           if (strcasecmp(lp->items[j], pszId) == 0) {
2601             iItemPosition = j;
2602             break;
2603           }
2604         }
2605         msLayerClose(lp);
2606       }
2607       if (iItemPosition >=0) {
2608         if (lp->template == NULL)
2609           lp->template = msStrdup("ttt");
2610 
2611         map->query.type = MS_QUERY_BY_RECT;
2612         map->query.mode = MS_QUERY_MULTIPLE;
2613         map->query.layer = i;
2614         map->query.rect = map->extent;
2615         msQueryByRect(map);
2616 
2617         msLayerGetItems(lp);
2618 
2619         if (lp->resultcache && lp->resultcache->numresults > 0) {
2620           for(j=0; j<lp->resultcache->numresults; j++) {
2621             msInitShape(&sShape);
2622             status = msLayerGetShape(lp, &sShape, &(lp->resultcache->results[j]));
2623             if(status != MS_SUCCESS)
2624               continue;
2625 
2626             if (sShape.values[iItemPosition]) {
2627               pszProcedureURI = msStrdup("urn:ogc:def:procedure:");
2628               pszProcedureURI = msStringConcatenate(pszProcedureURI, sShape.values[iItemPosition]);
2629               if (strcasecmp(pszProcedureURI, sosparams->pszProcedure) == 0) {
2630                 pszUrl = msOWSLookupMetadata(&(lp->metadata), "S", "describesensor_url");
2631                 pszProcedureId = msStrdup(sShape.values[iItemPosition]);
2632                 if (pszUrl) {
2633                   pszTmp = msStrdup(pszUrl);
2634 
2635                   /* %procedure% is the hardcoded variable names to use
2636                      within sos_describesensor_url */
2637                   tmpstr = (char *)malloc(sizeof(char)*strlen("procedure") + 3);
2638                   sprintf(tmpstr,"%%%s%%", "procedure");
2639                   if (strcasestr(pszUrl, tmpstr) != NULL)
2640                     pszTmp = msCaseReplaceSubstring(pszTmp, tmpstr, pszProcedureId);
2641                   msFree(tmpstr);
2642 
2643                   pszEncodedUrl = msEncodeHTMLEntities(pszTmp);
2644                   msIO_printf("Location: %s\n\n", pszEncodedUrl);
2645                   msFree(pszTmp);
2646                   return(MS_SUCCESS);
2647                 } else {
2648                   msSetError(MS_SOSERR, "Missing mandatory metadata sos_describesensor_url on layer %s", "msSOSDescribeSensor()", lp->name);
2649                   return msSOSException(map, "mapserv", "NoApplicableCode");
2650                 }
2651               }
2652             }
2653           }
2654         }
2655       }
2656     }
2657   }
2658   msSetError(MS_SOSERR, "procedure %s not found.", "msSOSDescribeSensor()", sosparams->pszProcedure);
2659   return msSOSException(map, "procedure", "InvalidParameterValue");
2660 }
2661 
2662 /************************************************************************/
2663 /*                           msSOSDescribeObservationType               */
2664 /*                                                                      */
2665 /*      DescribeObserrvationType request handler                        */
2666 /************************************************************************/
msSOSDescribeObservationType(mapObj * map,sosParamsObj * sosparams,cgiRequestObj * req,owsRequestObj * ows_request)2667 int msSOSDescribeObservationType(mapObj *map, sosParamsObj *sosparams, cgiRequestObj *req, owsRequestObj *ows_request)
2668 {
2669   int i, j, n = 0, bLayerFound = 0;
2670   char **tokens = NULL;
2671   char *script_url=NULL;
2672   const char *pszTmp = NULL;
2673   char *pszTmp2=NULL;
2674   const char *opLayerName = NULL;
2675 
2676   if (!sosparams->pszObservedProperty) {
2677     msSetError(MS_SOSERR, "Missing mandatory parameter observedproperty", "msSOSDescribeObservationType()");
2678     return msSOSException(map, "observedproperty", "MissingParameterValue");
2679   }
2680 
2681   tokens = msStringSplit(sosparams->pszObservedProperty, ',', &n);
2682 
2683   for (i=0; i<map->numlayers; i++) {
2684     if (!msIntegerInArray(GET_LAYER(map, i)->index, ows_request->enabled_layers, ows_request->numlayers))
2685       continue;
2686     pszTmp = msOWSLookupMetadata(&(GET_LAYER(map, i)->metadata), "S", "observedproperty_id");
2687     if (pszTmp) {
2688       if (strcasecmp(pszTmp, sosparams->pszObservedProperty) == 0) {
2689         if (tokens && n > 0) {
2690           for (j=0; j<n; j++) {
2691             if(strcasecmp(pszTmp, tokens[j]) == 0) {
2692               opLayerName = GET_LAYER(map, i)->name;
2693               bLayerFound = 1;
2694               break;
2695             }
2696           }
2697         }
2698       }
2699     }
2700   }
2701   if (tokens && n > 0)
2702     msFreeCharArray(tokens, n);
2703 
2704   if (bLayerFound == 0) {
2705     msSetError(MS_SOSERR, "ObservedProperty %s not found.", "msSOSGetObservation()", sosparams->pszObservedProperty);
2706     return msSOSException(map, "observedproperty", "InvalidParameterValue");
2707   }
2708 
2709   if ((script_url=msOWSGetOnlineResource(map, "SO", "onlineresource", req)) == NULL)
2710     return msSOSException(map, "NoApplicableCode", "NoApplicableCode");
2711 
2712   pszTmp2 = msStringConcatenate(pszTmp2, (char *) script_url);
2713   pszTmp2 = msStringConcatenate(pszTmp2, "service=WFS&version=1.1.0&request=DescribeFeatureType&typename=");
2714   pszTmp2 = msStringConcatenate(pszTmp2, (char *) opLayerName);
2715 
2716   msIO_printf("Location: %s\n\n", pszTmp2);
2717   msFree(pszTmp2);
2718   msFree(script_url);
2719   return(MS_SUCCESS);
2720 }
2721 
2722 
2723 #endif /* defined(USE_WCS_SVR) && defined(USE_LIBXML2) */
2724 
2725 /*
2726 ** msSOSDispatch() is the entry point for SOS requests.
2727 ** - If this is a valid request then it is processed and MS_SUCCESS is returned
2728 **   on success, or MS_FAILURE on failure.
2729 */
msSOSDispatch(mapObj * map,cgiRequestObj * req,owsRequestObj * ows_request)2730 int msSOSDispatch(mapObj *map, cgiRequestObj *req, owsRequestObj *ows_request)
2731 {
2732 #if defined(USE_SOS_SVR) && defined(USE_LIBXML2)
2733   int returnvalue = MS_DONE;
2734   sosParamsObj *paramsObj = (sosParamsObj *)calloc(1, sizeof(sosParamsObj));
2735 
2736   if (msSOSParseRequest(map, req, paramsObj) == MS_FAILURE) {
2737     msSOSFreeParamsObj(paramsObj);
2738     free(paramsObj);
2739     return MS_FAILURE;
2740   }
2741 
2742   /* SERVICE must be specified and be SOS */
2743   if (paramsObj->pszService && strcasecmp(paramsObj->pszService, "SOS") == 0) { /* this is an SOS request */
2744     if (!paramsObj->pszRequest) {
2745       msSetError(MS_SOSERR, "Missing REQUEST Parameter", "msSOSDispatch()");
2746       msSOSFreeParamsObj(paramsObj);
2747       free(paramsObj);
2748       paramsObj = NULL;
2749       return msSOSException(map, "request", "MissingParameterValue");
2750     }
2751 
2752     msOWSRequestLayersEnabled(map, "S", paramsObj->pszRequest, ows_request);
2753     if (ows_request->numlayers == 0) {
2754       msSetError(MS_SOSERR, "SOS request not enabled. Check sos/ows_enable_request settings.", "msSOSDispatch()");
2755       msSOSFreeParamsObj(paramsObj);
2756       free(paramsObj);
2757       paramsObj = NULL;
2758       return msSOSException(map, "request", "InvalidParameterValue");
2759     }
2760 
2761     if (strcasecmp(paramsObj->pszRequest, "GetCapabilities") == 0) {
2762       returnvalue = msSOSGetCapabilities(map, paramsObj, req, ows_request);
2763       msSOSFreeParamsObj(paramsObj);
2764       free(paramsObj);
2765       paramsObj = NULL;
2766       return returnvalue;
2767     }
2768 
2769     else if (strcasecmp(paramsObj->pszRequest, "DescribeSensor") == 0 ||
2770              strcasecmp(paramsObj->pszRequest, "GetObservation") == 0 ||
2771              strcasecmp(paramsObj->pszRequest, "DescribeObservationType") == 0
2772             ) {
2773       /* check version */
2774       if (!paramsObj->pszVersion) {
2775         msSetError(MS_SOSERR, "Missing VERSION parameter", "msSOSDispatch()");
2776         msSOSFreeParamsObj(paramsObj);
2777         free(paramsObj);
2778         paramsObj = NULL;
2779         return msSOSException(map, "version", "MissingParameterValue");
2780       }
2781 
2782       if (msOWSParseVersionString(paramsObj->pszVersion) != OWS_1_0_0) {
2783         msSetError(MS_SOSERR, "VERSION %s not supported.  Supported versions are: %s.", "msSOSDispatch()", paramsObj->pszVersion, pszSOSVersion);
2784         msSOSFreeParamsObj(paramsObj);
2785         free(paramsObj);
2786         paramsObj = NULL;
2787         return msSOSException(map, "version", "InvalidParameterValue");
2788       }
2789 
2790       if (strcasecmp(paramsObj->pszRequest, "DescribeSensor") == 0)
2791         returnvalue = msSOSDescribeSensor(map, paramsObj, ows_request);
2792 
2793       else if (strcasecmp(paramsObj->pszRequest, "GetObservation") == 0)
2794         returnvalue = msSOSGetObservation(map, paramsObj, req, ows_request);
2795 
2796       else if (strcasecmp(paramsObj->pszRequest, "DescribeObservationType") == 0)
2797         returnvalue = msSOSDescribeObservationType(map, paramsObj, req, ows_request);
2798 
2799       msSOSFreeParamsObj(paramsObj);
2800       free(paramsObj);
2801       paramsObj = NULL;
2802       return returnvalue;
2803     } else {
2804       msSetError(MS_SOSERR, "Invalid REQUEST parameter: %s", "msSOSDispatch()", paramsObj->pszRequest);
2805       msSOSFreeParamsObj(paramsObj);
2806       free(paramsObj);
2807       paramsObj = NULL;
2808       return msSOSException(map, "request", "InvalidParameterValue");
2809     }
2810   } else {
2811     msSOSFreeParamsObj(paramsObj);
2812     free(paramsObj);
2813     return MS_DONE;  /* Not an SOS request */
2814   }
2815 #else
2816   msSetError(MS_SOSERR, "SOS support is not available.", "msSOSDispatch()");
2817   return(MS_FAILURE);
2818 #endif
2819 }
2820 
2821 #if defined(USE_SOS_SVR) && defined(USE_LIBXML2)
2822 
msSOSParseRequest(mapObj * map,cgiRequestObj * request,sosParamsObj * sosparams)2823 int msSOSParseRequest(mapObj *map, cgiRequestObj *request, sosParamsObj *sosparams)
2824 {
2825   int i;
2826   xmlDocPtr doc;
2827   xmlXPathContextPtr context;
2828   xmlNodeSetPtr nodeset;
2829   xmlXPathObjectPtr psXPathTmp;
2830   char *pszTmp = NULL;
2831 
2832   if (request->NumParams) { /* this is a GET request */
2833     for(i=0; i<request->NumParams; i++) {
2834       if (strcasecmp(request->ParamNames[i], "SERVICE") == 0)
2835         sosparams->pszService = msStrdup(request->ParamValues[i]);
2836       else if (strcasecmp(request->ParamNames[i], "VERSION") == 0)
2837         sosparams->pszVersion = msStrdup(request->ParamValues[i]);
2838       else if (strcasecmp(request->ParamNames[i], "ACCEPTVERSIONS") == 0)
2839         sosparams->pszAcceptVersions = msStrdup(request->ParamValues[i]);
2840       else if (strcasecmp(request->ParamNames[i], "REQUEST") == 0)
2841         sosparams->pszRequest = msStrdup(request->ParamValues[i]);
2842       else if (strcasecmp(request->ParamNames[i], "UPDATESEQUENCE") == 0)
2843         sosparams->pszUpdateSequence = msStrdup(request->ParamValues[i]);
2844       else  if (strcasecmp(request->ParamNames[i], "SENSORID") == 0)
2845         sosparams->pszSensorId = msStrdup(request->ParamValues[i]);
2846       else  if (strcasecmp(request->ParamNames[i], "PROCEDURE") == 0)
2847         sosparams->pszProcedure = msStrdup(request->ParamValues[i]);
2848       else if (strcasecmp(request->ParamNames[i], "OUTPUTFORMAT") == 0)
2849         sosparams->pszOutputFormat = msStrdup(request->ParamValues[i]);
2850       else if (strcasecmp(request->ParamNames[i], "OFFERING") == 0)
2851         sosparams->pszOffering = msStrdup(request->ParamValues[i]);
2852       else if (strcasecmp(request->ParamNames[i], "OBSERVEDPROPERTY") == 0)
2853         sosparams->pszObservedProperty = msStrdup(request->ParamValues[i]);
2854       else if (strcasecmp(request->ParamNames[i], "EVENTTIME") == 0)
2855         sosparams->pszEventTime = msStrdup(request->ParamValues[i]);
2856       else if (strcasecmp(request->ParamNames[i], "RESULT") == 0)
2857         sosparams->pszResult = msStrdup(request->ParamValues[i]);
2858       else if (strcasecmp(request->ParamNames[i], "RESULTMODEL") == 0)
2859         sosparams->pszResultModel = msStrdup(request->ParamValues[i]);
2860       else if (strcasecmp(request->ParamNames[i], "RESPONSEFORMAT") == 0)
2861         sosparams->pszResponseFormat = msStrdup(request->ParamValues[i]);
2862       else if (strcasecmp(request->ParamNames[i], "RESPONSEMODE") == 0)
2863         sosparams->pszResponseMode = msStrdup(request->ParamValues[i]);
2864       else if (strcasecmp(request->ParamNames[i], "BBOX") == 0)
2865         sosparams->pszBBox = msStrdup(request->ParamValues[i]);
2866       else if (strcasecmp(request->ParamNames[i], "SRSNAME") == 0)
2867         sosparams->pszSrsName = msStrdup(request->ParamValues[i]);
2868       else if (strcasecmp(request->ParamNames[i], "FEATUREOFINTEREST") == 0)
2869         sosparams->pszFeatureOfInterest = msStrdup(request->ParamValues[i]);
2870     }
2871   }
2872 
2873   if (request->postrequest) { /* this a POST request */
2874     /* load document */
2875     doc = xmlParseDoc((xmlChar *)request->postrequest);
2876     if (doc == NULL ) {
2877       msSetError(MS_SOSERR, "Invalid POST request.  XML is not well-formed", "msSOSParseRequest()");
2878       return msSOSException(map, "request", "InvalidRequest");
2879     }
2880 
2881     /* load context */
2882     context = xmlXPathNewContext(doc);
2883     if (context == NULL) {
2884       msSetError(MS_SOSERR, "Could not create context (xmlXPathNewContext)", "msSOSParseRequest()");
2885       return msSOSException(map, "request", "NoApplicableCode");
2886     }
2887 
2888     /* register namespaces */
2889     if(xmlXPathRegisterNs(context, (xmlChar *)"sos", (xmlChar *)"http://www.opengis.net/sos/1.0") != 0 ||
2890         xmlXPathRegisterNs(context, (xmlChar *)"ows", (xmlChar *)"http://www.opengis.net/ows/1.1") != 0 ||
2891         xmlXPathRegisterNs(context, (xmlChar *)"ogc", (xmlChar *)"http://www.opengis.net/ogc") != 0 ||
2892         xmlXPathRegisterNs(context, (xmlChar *)"gml", (xmlChar *)"http://www.opengis.net/gml") != 0) {
2893       msSetError(MS_SOSERR, "Could not register namespaces (xmlXPathRegisterNs)", "msSOSParseRequest()");
2894       return msSOSException(map, "request", "NoApplicableCode");
2895     }
2896 
2897     /* check for service */
2898     psXPathTmp = msLibXml2GetXPath(doc, context, (xmlChar *)"/*/@service");
2899 
2900     if (psXPathTmp) {
2901       nodeset = psXPathTmp->nodesetval;
2902       sosparams->pszService = (char *)xmlNodeListGetString(doc, nodeset->nodeTab[0]->xmlChildrenNode, 1);
2903     }
2904 
2905     xmlXPathFreeObject(psXPathTmp);
2906 
2907     /* check for updateSequence*/
2908     psXPathTmp = msLibXml2GetXPath(doc, context, (xmlChar *)"/*/@updateSequence");
2909 
2910     if (psXPathTmp) {
2911       nodeset = psXPathTmp->nodesetval;
2912       sosparams->pszUpdateSequence = (char *)xmlNodeListGetString(doc, nodeset->nodeTab[0]->xmlChildrenNode, 1);
2913     }
2914 
2915     xmlXPathFreeObject(psXPathTmp);
2916 
2917     /* check for version */
2918     psXPathTmp = msLibXml2GetXPath(doc, context, (xmlChar *)"/*/ows:AcceptVersions/ows:Version|/*/@version");
2919 
2920     if (psXPathTmp) {
2921       nodeset = psXPathTmp->nodesetval;
2922       sosparams->pszVersion = (char *)xmlNodeListGetString(doc, nodeset->nodeTab[0]->xmlChildrenNode, 1);
2923     }
2924 
2925     xmlXPathFreeObject(psXPathTmp);
2926 
2927     /* check for request */
2928 
2929     psXPathTmp = msLibXml2GetXPath(doc, context, (xmlChar *)"/sos:GetCapabilities");
2930 
2931     if (psXPathTmp)
2932       sosparams->pszRequest = msStrdup("GetCapabilities");
2933 
2934     xmlXPathFreeObject(psXPathTmp);
2935 
2936     psXPathTmp = msLibXml2GetXPath(doc, context, (xmlChar *)"/sos:DescribeSensor");
2937 
2938     if (psXPathTmp)
2939       sosparams->pszRequest = msStrdup("DescribeSensor");
2940 
2941     xmlXPathFreeObject(psXPathTmp);
2942 
2943     psXPathTmp = msLibXml2GetXPath(doc, context, (xmlChar *)"/sos:GetObservation");
2944 
2945     if (psXPathTmp)
2946       sosparams->pszRequest = msStrdup("GetObservation");
2947 
2948     xmlXPathFreeObject(psXPathTmp);
2949 
2950     psXPathTmp = msLibXml2GetXPath(doc, context, (xmlChar *)"/sos:DescribeObservationType");
2951 
2952     if (psXPathTmp)
2953       sosparams->pszRequest = msStrdup("DescribeObservationType");
2954 
2955     xmlXPathFreeObject(psXPathTmp);
2956 
2957     /* check for outputformat */
2958     psXPathTmp = msLibXml2GetXPath(doc, context, (xmlChar *)"/sos:DescribeSensor/@outputFormat");
2959 
2960     if (psXPathTmp) {
2961       nodeset = psXPathTmp->nodesetval;
2962       sosparams->pszOutputFormat = (char *)xmlNodeListGetString(doc, nodeset->nodeTab[0]->xmlChildrenNode, 1);
2963     }
2964 
2965     xmlXPathFreeObject(psXPathTmp);
2966 
2967     /* check for Procedure */
2968     psXPathTmp = msLibXml2GetXPath(doc, context, (xmlChar *)"/sos:DescribeSensor/sos:procedure");
2969 
2970     if (psXPathTmp) {
2971       nodeset = psXPathTmp->nodesetval;
2972       sosparams->pszProcedure = (char *)xmlNodeListGetString(doc, nodeset->nodeTab[0]->xmlChildrenNode, 1);
2973     }
2974 
2975     xmlXPathFreeObject(psXPathTmp);
2976 
2977     /* check for offering */
2978     psXPathTmp = msLibXml2GetXPath(doc, context, (xmlChar *)"/sos:GetObservation/sos:offering");
2979 
2980     if (psXPathTmp) {
2981       nodeset = psXPathTmp->nodesetval;
2982       sosparams->pszOffering = (char *)xmlNodeListGetString(doc, nodeset->nodeTab[0]->xmlChildrenNode, 1);
2983     }
2984 
2985     xmlXPathFreeObject(psXPathTmp);
2986 
2987     /* check for observedproperty */
2988     psXPathTmp = msLibXml2GetXPath(doc, context, (xmlChar *)"/sos:GetObservation/sos:observedProperty");
2989 
2990     if (psXPathTmp) {
2991       nodeset = psXPathTmp->nodesetval;
2992       sosparams->pszObservedProperty = (char *)xmlNodeListGetString(doc, nodeset->nodeTab[0]->xmlChildrenNode, 1);
2993     }
2994 
2995     xmlXPathFreeObject(psXPathTmp);
2996 
2997     /* check for procedure */
2998     psXPathTmp = msLibXml2GetXPath(doc, context, (xmlChar *)"/sos:GetObservation/sos:procedure");
2999 
3000     if (psXPathTmp) {
3001       nodeset = psXPathTmp->nodesetval;
3002       sosparams->pszProcedure = (char *)xmlNodeListGetString(doc, nodeset->nodeTab[0]->xmlChildrenNode, 1);
3003     }
3004 
3005     xmlXPathFreeObject(psXPathTmp);
3006 
3007     /* check for responseFormat */
3008     psXPathTmp = msLibXml2GetXPath(doc, context, (xmlChar *)"/sos:GetObservation/sos:responseFormat");
3009 
3010     if (psXPathTmp) {
3011       nodeset = psXPathTmp->nodesetval;
3012       sosparams->pszResponseFormat = (char *)xmlNodeListGetString(doc, nodeset->nodeTab[0]->xmlChildrenNode, 1);
3013     }
3014 
3015     xmlXPathFreeObject(psXPathTmp);
3016 
3017     /* check for resultModel */
3018     psXPathTmp = msLibXml2GetXPath(doc, context, (xmlChar *)"/sos:GetObservation/sos:resultModel");
3019 
3020     if (psXPathTmp) {
3021       nodeset = psXPathTmp->nodesetval;
3022       sosparams->pszResultModel = (char *)xmlNodeListGetString(doc, nodeset->nodeTab[0]->xmlChildrenNode, 1);
3023     }
3024 
3025     xmlXPathFreeObject(psXPathTmp);
3026 
3027     /* check for responseMode */
3028     psXPathTmp = msLibXml2GetXPath(doc, context, (xmlChar *)"/sos:GetObservation/sos:responseMode");
3029 
3030     if (psXPathTmp) {
3031       nodeset = psXPathTmp->nodesetval;
3032       sosparams->pszResponseMode = (char *)xmlNodeListGetString(doc, nodeset->nodeTab[0]->xmlChildrenNode, 1);
3033     }
3034 
3035     xmlXPathFreeObject(psXPathTmp);
3036 
3037     /* check for srsName */
3038     psXPathTmp = msLibXml2GetXPath(doc, context, (xmlChar *)"/sos:GetObservation/@srsName");
3039 
3040     if (psXPathTmp) {
3041       nodeset = psXPathTmp->nodesetval;
3042       sosparams->pszSrsName = (char *)xmlNodeListGetString(doc, nodeset->nodeTab[0]->xmlChildrenNode, 1);
3043     }
3044 
3045     xmlXPathFreeObject(psXPathTmp);
3046 
3047     /* check for result (chunk of XML) */
3048     psXPathTmp = msLibXml2GetXPath(doc, context, (xmlChar *)"/sos:GetObservation/sos:result/child::*");
3049 
3050     if (psXPathTmp) {
3051       sosparams->pszResult = msLibXml2GetXPathTree(doc, psXPathTmp);
3052       pszTmp = msStringConcatenate(pszTmp, "<ogc:Filter>");
3053       pszTmp = msStringConcatenate(pszTmp, sosparams->pszResult);
3054       pszTmp = msStringConcatenate(pszTmp, "</ogc:Filter>");
3055       msFree(sosparams->pszResult);
3056       sosparams->pszResult = msStrdup(pszTmp);
3057       msFree(pszTmp);
3058     }
3059 
3060     xmlXPathFreeObject(psXPathTmp);
3061 
3062     /* check for featureOfInterest (chunk of XML) */
3063     psXPathTmp = msLibXml2GetXPath(doc, context, (xmlChar *)"/sos:GetObservation/sos:featureOfInterest/ogc:BBOX/gml:Envelope");
3064 
3065     if (psXPathTmp) {
3066       sosparams->pszFeatureOfInterest = (char *)msLibXml2GetXPathTree(doc, psXPathTmp);
3067     }
3068 
3069     xmlXPathFreeObject(psXPathTmp);
3070 
3071     /* check for eventTime (chunk of XML) */
3072     psXPathTmp = msLibXml2GetXPath(doc, context, (xmlChar *)"/sos:GetObservation/sos:eventTime/*/gml:TimeInstant|/sos:GetObservation/sos:eventTime/*/gml:TimePeriod");
3073 
3074     if (psXPathTmp) {
3075       sosparams->pszEventTime = (char *)msLibXml2GetXPathTree(doc, psXPathTmp);
3076     }
3077 
3078     xmlXPathFreeObject(psXPathTmp);
3079     xmlXPathFreeContext(context);
3080     xmlFreeDoc(doc);
3081     xmlCleanupParser();
3082   }
3083   return MS_SUCCESS;
3084 }
3085 
msSOSFreeParamsObj(sosParamsObj * sosparams)3086 void msSOSFreeParamsObj(sosParamsObj *sosparams)
3087 {
3088   if (sosparams) {
3089     if (sosparams->pszService)
3090       free(sosparams->pszService);
3091     if (sosparams->pszVersion)
3092       free(sosparams->pszVersion);
3093     if (sosparams->pszAcceptVersions)
3094       free(sosparams->pszAcceptVersions);
3095     if (sosparams->pszUpdateSequence)
3096       free(sosparams->pszUpdateSequence);
3097     if (sosparams->pszRequest)
3098       free(sosparams->pszRequest);
3099     if (sosparams->pszOutputFormat)
3100       free(sosparams->pszOutputFormat);
3101     if (sosparams->pszSensorId)
3102       free(sosparams->pszSensorId);
3103     if (sosparams->pszProcedure)
3104       free(sosparams->pszProcedure);
3105     if (sosparams->pszOffering)
3106       free(sosparams->pszOffering);
3107     if (sosparams->pszObservedProperty)
3108       free(sosparams->pszObservedProperty);
3109     if (sosparams->pszEventTime)
3110       free(sosparams->pszEventTime);
3111     if (sosparams->pszResult)
3112       free(sosparams->pszResult);
3113     if (sosparams->pszResponseFormat)
3114       free(sosparams->pszResponseFormat);
3115     if (sosparams->pszResultModel)
3116       free(sosparams->pszResultModel);
3117     if (sosparams->pszResponseMode)
3118       free(sosparams->pszResponseMode);
3119     if (sosparams->pszSrsName)
3120       free(sosparams->pszSrsName);
3121     if (sosparams->pszFeatureOfInterest)
3122       free(sosparams->pszFeatureOfInterest);
3123   }
3124 }
3125 #endif /* defined(USE_SOS_SVR) && defined(USE_LIBXML2) */
3126