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