1 /******************************************************************************
2 * $Id$
3 *
4 * Project: MapServer
5 * Purpose: OGC OWS Common Implementation for use by MapServer OGC code
6 * versions:
7 * 1.0.0 (OGC Document 05-008c1)
8 * 1.1.0 (OGC document 06-121r3)
9 *
10 * Author: Tom Kralidis (tomkralidis@gmail.com)
11 *
12 ******************************************************************************
13 * Copyright (c) 2006, Tom Kralidis
14 *
15 * Permission is hereby granted, free of charge, to any person obtaining a
16 * copy of this software and associated documentation files (the "Software"),
17 * to deal in the Software without restriction, including without limitation
18 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
19 * and/or sell copies of the Software, and to permit persons to whom the
20 * Software is furnished to do so, subject to the following conditions:
21 *
22 * The above copyright notice and this permission notice shall be included in
23 * all copies of this Software or works derived from this Software.
24 *
25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
26 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
28 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
30 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
31 * DEALINGS IN THE SOFTWARE.
32 ****************************************************************************/
33
34 #include "mapserver.h"
35 #include "mapows.h"
36
37 #ifdef USE_LIBXML2
38
39 #include<libxml/parser.h>
40 #include<libxml/tree.h>
41
42 #include "mapowscommon.h"
43 #include "maplibxml2.h"
44
45
46
47
48
49 /**
50 * msOWSCommonServiceIdentification()
51 *
52 * returns an object of ServiceIdentification as per:
53 *
54 * 1.0.0 subclause 7.4.3
55 * 1.1.1 subclause 7.4.4
56 *
57 * @param map mapObj used to fetch WEB/METADATA
58 * @param servicetype the OWS type
59 * @param supported_versions the supported version(s) of the OWS
60 *
61 * @return psRootNode xmlNodePtr of XML construct
62 *
63 */
64
msOWSCommonServiceIdentification(xmlNsPtr psNsOws,mapObj * map,const char * servicetype,const char * supported_versions,const char * namespaces,const char * validated_language)65 xmlNodePtr msOWSCommonServiceIdentification(xmlNsPtr psNsOws, mapObj *map,
66 const char *servicetype,
67 const char *supported_versions,
68 const char *namespaces,
69 const char *validated_language)
70 {
71 const char *value = NULL;
72
73 xmlNodePtr psRootNode = NULL;
74 xmlNodePtr psNode = NULL;
75
76 if (_validateNamespace(psNsOws) == MS_FAILURE)
77 psNsOws = xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_OWS_NAMESPACE_URI, BAD_CAST MS_OWSCOMMON_OWS_NAMESPACE_PREFIX);
78
79 /* create element name */
80 psRootNode = xmlNewNode(psNsOws, BAD_CAST "ServiceIdentification");
81
82 /* add child elements */
83
84 value = msOWSLookupMetadataWithLanguage(&(map->web.metadata), namespaces, "title", validated_language);
85
86 psNode = xmlNewTextChild(psRootNode, psNsOws, BAD_CAST "Title", BAD_CAST value);
87
88 if (!value) {
89 xmlAddSibling(psNode, xmlNewComment(BAD_CAST "WARNING: Optional metadata \"ows_title\" missing for ows:Title"));
90 }
91
92 value = msOWSLookupMetadataWithLanguage(&(map->web.metadata), namespaces, "abstract", validated_language);
93
94 psNode = xmlNewTextChild(psRootNode, psNsOws, BAD_CAST "Abstract", BAD_CAST value);
95
96 if (!value) {
97 xmlAddSibling(psNode, xmlNewComment(BAD_CAST "WARNING: Optional metadata \"ows_abstract\" was missing for ows:Abstract"));
98 }
99
100 value = msOWSLookupMetadataWithLanguage(&(map->web.metadata), namespaces, "keywordlist", validated_language);
101
102 if (value) {
103 psNode = xmlNewTextChild(psRootNode, psNsOws, BAD_CAST "Keywords", NULL);
104 msLibXml2GenerateList(psNode, psNsOws, "Keyword", value, ',');
105 }
106
107 else {
108 xmlAddSibling(psNode, xmlNewComment(BAD_CAST "WARNING: Optional metadata \"ows_keywordlist\" was missing for ows:KeywordList"));
109 }
110
111 psNode = xmlNewTextChild(psRootNode, psNsOws, BAD_CAST "ServiceType", BAD_CAST servicetype);
112
113 xmlNewProp(psNode, BAD_CAST "codeSpace", BAD_CAST MS_OWSCOMMON_OGC_CODESPACE);
114
115 msLibXml2GenerateList(psRootNode, psNsOws, "ServiceTypeVersion", supported_versions, ',');
116
117 value = msOWSLookupMetadataWithLanguage(&(map->web.metadata), namespaces, "fees", validated_language);
118
119 psNode = xmlNewTextChild(psRootNode, psNsOws, BAD_CAST "Fees", BAD_CAST value);
120
121 if (!value) {
122 xmlAddSibling(psNode, xmlNewComment(BAD_CAST "WARNING: Optional metadata \"ows_fees\" was missing for ows:Fees"));
123 }
124
125 value = msOWSLookupMetadataWithLanguage(&(map->web.metadata), namespaces, "accessconstraints", validated_language);
126
127 psNode = xmlNewTextChild(psRootNode, psNsOws, BAD_CAST "AccessConstraints", BAD_CAST value);
128
129 if (!value) {
130 xmlAddSibling(psNode, xmlNewComment(BAD_CAST "WARNING: Optional metadata \"ows_accessconstraints\" was missing for ows:AccessConstraints"));
131 }
132
133 return psRootNode;
134 }
135
136 /**
137 * msOWSCommonServiceProvider()
138 *
139 * returns an object of ServiceProvider as per:
140 *
141 *
142 * 1.0.0 subclause 7.4.4
143 * 1.1.0 subclause 7.4.5
144 *
145 * @param map mapObj to fetch MAP/WEB/METADATA
146 *
147 * @return psRootNode xmlNodePtr pointer of XML construct
148 *
149 */
150
msOWSCommonServiceProvider(xmlNsPtr psNsOws,xmlNsPtr psNsXLink,mapObj * map,const char * namespaces,const char * validated_language)151 xmlNodePtr msOWSCommonServiceProvider(xmlNsPtr psNsOws, xmlNsPtr psNsXLink,
152 mapObj *map, const char *namespaces,
153 const char *validated_language)
154 {
155 const char *value = NULL;
156
157 xmlNodePtr psNode = NULL;
158 xmlNodePtr psRootNode = NULL;
159 xmlNodePtr psSubNode = NULL;
160 xmlNodePtr psSubSubNode = NULL;
161 xmlNodePtr psSubSubSubNode = NULL;
162
163 if (_validateNamespace(psNsOws) == MS_FAILURE)
164 psNsOws = xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_OWS_NAMESPACE_URI, BAD_CAST MS_OWSCOMMON_OWS_NAMESPACE_PREFIX);
165
166 psRootNode = xmlNewNode(psNsOws, BAD_CAST "ServiceProvider");
167
168 /* add child elements */
169
170 value = msOWSLookupMetadataWithLanguage(&(map->web.metadata), namespaces, "contactorganization", validated_language);
171
172 psNode = xmlNewTextChild(psRootNode, psNsOws, BAD_CAST "ProviderName", BAD_CAST value);
173
174 if (!value) {
175 xmlAddSibling(psNode, xmlNewComment(BAD_CAST "WARNING: Mandatory metadata \"ows_contactorganization\" was missing for ows:ProviderName"));
176 }
177
178 psNode = xmlNewTextChild(psRootNode, psNsOws, BAD_CAST "ProviderSite", NULL);
179
180 xmlNewNsProp(psNode, psNsXLink, BAD_CAST "type", BAD_CAST "simple");
181
182 value = msOWSLookupMetadataWithLanguage(&(map->web.metadata), namespaces, "service_onlineresource", validated_language);
183
184 xmlNewNsProp(psNode, psNsXLink, BAD_CAST "href", BAD_CAST value);
185
186 if (!value) {
187 xmlAddSibling(psNode, xmlNewComment(BAD_CAST "WARNING: Optional metadata \"ows_service_onlineresource\" was missing for ows:ProviderSite/@xlink:href"));
188 }
189
190 psNode = xmlNewTextChild(psRootNode, psNsOws, BAD_CAST "ServiceContact", NULL);
191
192 value = msOWSLookupMetadataWithLanguage(&(map->web.metadata), namespaces, "contactperson", validated_language);
193
194 psSubNode = xmlNewTextChild(psNode, psNsOws, BAD_CAST "IndividualName", BAD_CAST value);
195
196 if (!value) {
197 xmlAddSibling(psSubNode, xmlNewComment(BAD_CAST "WARNING: Optional metadata \"ows_contactperson\" was missing for ows:IndividualName"));
198 }
199
200 value = msOWSLookupMetadataWithLanguage(&(map->web.metadata), namespaces, "contactposition", validated_language);
201
202 psSubNode = xmlNewTextChild(psNode, psNsOws, BAD_CAST "PositionName", BAD_CAST value);
203
204 if (!value) {
205 xmlAddSibling(psSubNode, xmlNewComment(BAD_CAST "WARNING: Optional metadata \"ows_contactposition\" was missing for ows:PositionName"));
206 }
207
208 psSubNode = xmlNewTextChild(psNode, psNsOws, BAD_CAST "ContactInfo", NULL);
209
210 psSubSubNode = xmlNewTextChild(psSubNode, psNsOws, BAD_CAST "Phone", NULL);
211
212 value = msOWSLookupMetadataWithLanguage(&(map->web.metadata), namespaces, "contactvoicetelephone", validated_language);
213
214 psSubSubSubNode = xmlNewTextChild(psSubSubNode, psNsOws, BAD_CAST "Voice", BAD_CAST value);
215
216 if (!value) {
217 xmlAddSibling(psSubSubSubNode, xmlNewComment(BAD_CAST "WARNING: Optional metadata \"ows_contactvoicetelephone\" was missing for ows:Voice"));
218 }
219
220 value = msOWSLookupMetadataWithLanguage(&(map->web.metadata), namespaces, "contactfacsimiletelephone", validated_language);
221
222 psSubSubSubNode = xmlNewTextChild(psSubSubNode, psNsOws, BAD_CAST "Facsimile", BAD_CAST value);
223
224 if (!value) {
225 xmlAddSibling(psSubSubSubNode, xmlNewComment(BAD_CAST "WARNING: Optional metadata \"ows_contactfacsimiletelephone\" was missing for ows:Facsimile"));
226 }
227
228 psSubSubNode = xmlNewTextChild(psSubNode, psNsOws, BAD_CAST "Address", NULL);
229
230 value = msOWSLookupMetadataWithLanguage(&(map->web.metadata), namespaces, "address", validated_language);
231
232 psSubSubSubNode = xmlNewTextChild(psSubSubNode, psNsOws, BAD_CAST "DeliveryPoint", BAD_CAST value);
233
234 if (!value) {
235 xmlAddSibling(psSubSubSubNode, xmlNewComment(BAD_CAST "WARNING: Optional metadata \"ows_address\" was missing for ows:DeliveryPoint"));
236 }
237
238 value = msOWSLookupMetadataWithLanguage(&(map->web.metadata), namespaces, "city", validated_language);
239
240 psSubSubSubNode = xmlNewTextChild(psSubSubNode, psNsOws, BAD_CAST "City", BAD_CAST value);
241
242 if (!value) {
243 xmlAddSibling(psSubSubSubNode, xmlNewComment(BAD_CAST "WARNING: Optional metadata \"ows_city\" was missing for ows:City"));
244 }
245
246 value = msOWSLookupMetadataWithLanguage(&(map->web.metadata), namespaces, "stateorprovince", validated_language);
247
248 psSubSubSubNode = xmlNewTextChild(psSubSubNode, psNsOws, BAD_CAST "AdministrativeArea", BAD_CAST value);
249
250 if (!value) {
251 xmlAddSibling(psSubSubSubNode, xmlNewComment(BAD_CAST "WARNING: Optional metadata \"ows_stateorprovince\" was missing for ows:AdministrativeArea"));
252 }
253
254 value = msOWSLookupMetadataWithLanguage(&(map->web.metadata), namespaces, "postcode", validated_language);
255
256 psSubSubSubNode = xmlNewTextChild(psSubSubNode, psNsOws, BAD_CAST "PostalCode", BAD_CAST value);
257
258 if (!value) {
259 xmlAddSibling(psSubSubSubNode, xmlNewComment(BAD_CAST "WARNING: Optional metadata \"ows_postcode\" was missing for ows:PostalCode"));
260 }
261
262 value = msOWSLookupMetadataWithLanguage(&(map->web.metadata), namespaces, "country", validated_language);
263
264 psSubSubSubNode = xmlNewTextChild(psSubSubNode, psNsOws, BAD_CAST "Country", BAD_CAST value);
265
266 if (!value) {
267 xmlAddSibling(psSubSubSubNode, xmlNewComment(BAD_CAST "WARNING: Optional metadata \"ows_country\" was missing for ows:Country"));
268 }
269
270 value = msOWSLookupMetadataWithLanguage(&(map->web.metadata), namespaces, "contactelectronicmailaddress", validated_language);
271
272 psSubSubSubNode = xmlNewTextChild(psSubSubNode, psNsOws, BAD_CAST "ElectronicMailAddress", BAD_CAST value);
273
274 if (!value) {
275 xmlAddSibling(psSubSubSubNode, xmlNewComment(BAD_CAST "WARNING: Optional metadata \"ows_contactelectronicmailaddress\" was missing for ows:ElectronicMailAddress"));
276 }
277
278 psSubSubNode = xmlNewTextChild(psSubNode, psNsOws, BAD_CAST "OnlineResource", NULL);
279
280 xmlNewNsProp(psSubSubNode, psNsXLink, BAD_CAST "type", BAD_CAST "simple");
281
282 value = msOWSLookupMetadataWithLanguage(&(map->web.metadata), namespaces, "service_onlineresource", validated_language);
283
284 xmlNewNsProp(psSubSubNode, psNsXLink, BAD_CAST "href", BAD_CAST value);
285
286 if (!value) {
287 xmlAddSibling(psSubSubNode, xmlNewComment(BAD_CAST "WARNING: Optional metadata \"ows_service_onlineresource\" was missing for ows:OnlineResource/@xlink:href"));
288 }
289
290 value = msOWSLookupMetadataWithLanguage(&(map->web.metadata), namespaces, "hoursofservice", validated_language);
291
292 psSubSubNode = xmlNewTextChild(psSubNode, psNsOws, BAD_CAST "HoursOfService", BAD_CAST value);
293
294 if (!value) {
295 xmlAddSibling(psSubSubNode, xmlNewComment(BAD_CAST "WARNING: Optional metadata \"ows_hoursofservice\" was missing for ows:HoursOfService"));
296 }
297
298 value = msOWSLookupMetadataWithLanguage(&(map->web.metadata), namespaces, "contactinstructions", validated_language);
299
300 psSubSubNode = xmlNewTextChild(psSubNode, psNsOws, BAD_CAST "ContactInstructions", BAD_CAST value);
301
302 if (!value) {
303 xmlAddSibling(psSubSubNode, xmlNewComment(BAD_CAST "WARNING: Optional metadata \"ows_contactinstructions\" was missing for ows:ContactInstructions"));
304 }
305
306 value = msOWSLookupMetadataWithLanguage(&(map->web.metadata), namespaces, "role", validated_language);
307
308 psSubNode = xmlNewTextChild(psNode, psNsOws, BAD_CAST "Role", BAD_CAST value);
309
310 if (!value) {
311 xmlAddSibling(psSubNode, xmlNewComment(BAD_CAST "WARNING: Optional metadata \"ows_role\" was missing for ows:Role"));
312 }
313
314 return psRootNode;
315
316 }
317
318 /**
319 * msOWSCommonOperationsMetadata()
320 *
321 * returns the root element of OperationsMetadata as per:
322 *
323 * 1.0.0 subclause 7.4.5
324 * 1.1.0 subclause 7.4.6
325 *
326 * @return psRootNode xmlNodePtr pointer of XML construct
327 *
328 */
329
msOWSCommonOperationsMetadata(xmlNsPtr psNsOws)330 xmlNodePtr msOWSCommonOperationsMetadata(xmlNsPtr psNsOws)
331 {
332 xmlNodePtr psRootNode = NULL;
333
334 if (_validateNamespace(psNsOws) == MS_FAILURE)
335 psNsOws = xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_OWS_NAMESPACE_URI, BAD_CAST MS_OWSCOMMON_OWS_NAMESPACE_PREFIX);
336
337 psRootNode = xmlNewNode(psNsOws, BAD_CAST "OperationsMetadata");
338 return psRootNode;
339 }
340
341 /**
342 * msOWSCommonOperationsMetadataOperation()
343 *
344 * returns an Operation element of OperationsMetadata as per:
345 *
346 * 1.0.0 subclause 7.4.5
347 * 1.1.0 subclause 7.4.6
348 *
349 * @param name name of the Operation
350 * @param method HTTP method: OWS_METHOD_GET, OWS_METHOD_POST or OWS_METHOD_GETPOST)
351 * @param url online resource URL
352 *
353 * @return psRootNode xmlNodePtr pointer of XML construct
354 */
355
msOWSCommonOperationsMetadataOperation(xmlNsPtr psNsOws,xmlNsPtr psXLinkNs,char * name,int method,char * url)356 xmlNodePtr msOWSCommonOperationsMetadataOperation(xmlNsPtr psNsOws, xmlNsPtr psXLinkNs, char *name, int method, char *url)
357 {
358 xmlNodePtr psRootNode = NULL;
359 xmlNodePtr psNode = NULL;
360 xmlNodePtr psSubNode = NULL;
361 xmlNodePtr psSubSubNode = NULL;
362
363 if (_validateNamespace(psNsOws) == MS_FAILURE)
364 psNsOws = xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_OWS_NAMESPACE_URI, BAD_CAST MS_OWSCOMMON_OWS_NAMESPACE_PREFIX);
365
366
367 psRootNode = xmlNewNode(psNsOws, BAD_CAST "Operation");
368
369 xmlNewProp(psRootNode, BAD_CAST "name", BAD_CAST name);
370
371 psNode = xmlNewChild(psRootNode, psNsOws, BAD_CAST "DCP", NULL);
372
373 psSubNode = xmlNewChild(psNode, psNsOws, BAD_CAST "HTTP", NULL);
374
375 if (method == OWS_METHOD_GET || method == OWS_METHOD_GETPOST ) {
376 psSubSubNode = xmlNewChild(psSubNode, psNsOws, BAD_CAST "Get", NULL);
377 xmlNewNsProp(psSubSubNode, psXLinkNs, BAD_CAST "type", BAD_CAST "simple");
378 xmlNewNsProp(psSubSubNode, psXLinkNs, BAD_CAST "href", BAD_CAST url);
379 }
380
381 if (method == OWS_METHOD_POST || method == OWS_METHOD_GETPOST ) {
382 psSubSubNode = xmlNewChild(psSubNode, psNsOws, BAD_CAST "Post", NULL);
383 xmlNewNsProp(psSubSubNode, psXLinkNs, BAD_CAST "type", BAD_CAST "simple");
384 xmlNewNsProp(psSubSubNode, psXLinkNs, BAD_CAST "href", BAD_CAST url);
385 }
386
387 return psRootNode;
388 }
389
390 /**
391 * msOWSCommonOperationsMetadataDomainType()
392 *
393 * returns a Parameter or Constraint element (which are of type ows:DomainType)
394 * of OperationsMetadata as per:
395 *
396 * 1.0.0 subclause 7.4.5
397 * 1.1.0 subclause 7.4.6
398 *
399 * @param version the integerized x.y.z version of OWS Common to use
400 * @param elname name of the element (Parameter | Constraint)
401 * @param name name of the Parameter
402 * @param values list of values (comma separated list) or NULL if none
403 *
404 * @return psRootNode xmlNodePtr pointer of XML construct
405 *
406 */
407
msOWSCommonOperationsMetadataDomainType(int version,xmlNsPtr psNsOws,char * elname,char * name,char * values)408 xmlNodePtr msOWSCommonOperationsMetadataDomainType(int version, xmlNsPtr psNsOws, char *elname, char *name, char *values)
409 {
410 xmlNodePtr psRootNode = NULL;
411 xmlNodePtr psNode = NULL;
412
413 if (_validateNamespace(psNsOws) == MS_FAILURE)
414 psNsOws = xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_OWS_NAMESPACE_URI, BAD_CAST MS_OWSCOMMON_OWS_NAMESPACE_PREFIX);
415
416 psRootNode = xmlNewNode(psNsOws, BAD_CAST elname);
417
418 xmlNewProp(psRootNode, BAD_CAST "name", BAD_CAST name);
419
420 if (version == OWS_1_0_0) {
421 msLibXml2GenerateList(psRootNode, psNsOws, "Value", values, ',');
422 }
423 if (version == OWS_1_1_0 || version == OWS_2_0_0) {
424 psNode = xmlNewChild(psRootNode, psNsOws, BAD_CAST "AllowedValues", NULL);
425 msLibXml2GenerateList(psNode, psNsOws, "Value", values, ',');
426 }
427
428 return psRootNode;
429 }
430
431 /**
432 * msOWSCommonExceptionReport()
433 *
434 * returns an object of ExceptionReport as per clause 8
435 *
436 * @param ows_version the version of OWS Common to use
437 * @param schemas_location URL to OGC Schemas Location base
438 * @param version the version of the calling specification
439 * @param language ISO3166 code of language
440 * @param exceptionCode a code from the calling specification's list of exceptions, or from OWS Common
441 * @param locator where the exception was encountered (i.e. "layers" keyword)
442 * @param ExceptionText the actual error message
443 *
444 * @return psRootNode xmlNodePtr pointer of XML construct
445 *
446 */
447
msOWSCommonExceptionReport(xmlNsPtr psNsOws,int ows_version,const char * schemas_location,const char * version,const char * language,const char * exceptionCode,const char * locator,const char * ExceptionText)448 xmlNodePtr msOWSCommonExceptionReport(xmlNsPtr psNsOws, int ows_version, const char *schemas_location, const char *version, const char *language, const char *exceptionCode, const char *locator, const char *ExceptionText)
449 {
450 char *xsi_schemaLocation = NULL;
451 char szVersionBuf[OWS_VERSION_MAXLEN];
452
453 xmlNsPtr psNsXsi = NULL;
454 xmlNodePtr psRootNode = NULL;
455 xmlNodePtr psMainNode = NULL;
456
457 psRootNode = xmlNewNode(psNsOws, BAD_CAST "ExceptionReport");
458
459 psNsXsi = xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_W3C_XSI_NAMESPACE_URI, BAD_CAST MS_OWSCOMMON_W3C_XSI_NAMESPACE_PREFIX);
460
461 /* add attributes to root element */
462 xmlNewProp(psRootNode, BAD_CAST "version", BAD_CAST version);
463
464 if (ows_version == OWS_1_0_0) {
465 xmlNewProp(psRootNode, BAD_CAST "language", BAD_CAST language);
466 }
467 if (ows_version == OWS_1_1_0) {
468 xmlNewProp(psRootNode, BAD_CAST "xml:lang", BAD_CAST language);
469 }
470
471 xsi_schemaLocation = msStrdup((char *)psNsOws->href);
472 xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, " ");
473 xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, (char *)schemas_location);
474 xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, "/ows/");
475 xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, (char *)msOWSGetVersionString(ows_version, szVersionBuf));
476 xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, "/owsExceptionReport.xsd");
477
478 /* add namespace'd attributes to root element */
479 xmlNewNsProp(psRootNode, psNsXsi, BAD_CAST "schemaLocation", BAD_CAST xsi_schemaLocation);
480
481 /* add child element */
482 psMainNode = xmlNewChild(psRootNode, NULL, BAD_CAST "Exception", NULL);
483
484 /* add attributes to child */
485 xmlNewProp(psMainNode, BAD_CAST "exceptionCode", BAD_CAST exceptionCode);
486
487 if (locator != NULL) {
488 xmlNewProp(psMainNode, BAD_CAST "locator", BAD_CAST locator);
489 }
490
491 if (ExceptionText != NULL) {
492 xmlNewTextChild(psMainNode, NULL, BAD_CAST "ExceptionText", BAD_CAST ExceptionText);
493 }
494
495 free(xsi_schemaLocation);
496 return psRootNode;
497 }
498
499 /**
500 * msOWSCommonBoundingBox()
501 *
502 * returns an object of BoundingBox as per subclause 10.2.1
503 *
504 * If necessary (ie. an EPSG URN GCS such as 4326) the tuple axes will be
505 * reoriented to match the EPSG coordinate system expectations.
506 *
507 * @param psNsOws OWS namespace object
508 * @param crs the CRS / EPSG code
509 * @param dimensions number of dimensions of the coordinates
510 * @param minx minx
511 * @param miny miny
512 * @param maxx maxx
513 * @param maxy maxy
514 *
515 * @return psRootNode xmlNodePtr pointer of XML construct
516 */
517
msOWSCommonBoundingBox(xmlNsPtr psNsOws,const char * crs,int dimensions,double minx,double miny,double maxx,double maxy)518 xmlNodePtr msOWSCommonBoundingBox(xmlNsPtr psNsOws, const char *crs, int dimensions, double minx, double miny, double maxx, double maxy)
519 {
520 char LowerCorner[100];
521 char UpperCorner[100];
522 char dim_string[100];
523 xmlNodePtr psRootNode = NULL;
524
525 /* Do we need to reorient tuple axes? */
526 if(crs && strstr(crs, "imageCRS") == NULL) {
527 projectionObj proj;
528
529 msInitProjection( &proj );
530 if( msLoadProjectionString( &proj, (char *) crs ) == 0 ) {
531 msAxisNormalizePoints( &proj, 1, &minx, &miny );
532 msAxisNormalizePoints( &proj, 1, &maxx, &maxy );
533 }
534 msFreeProjection( &proj );
535 }
536
537
538 if (_validateNamespace(psNsOws) == MS_FAILURE)
539 psNsOws = xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_OWS_NAMESPACE_URI, BAD_CAST MS_OWSCOMMON_OWS_NAMESPACE_PREFIX);
540
541 /* create element name */
542 psRootNode = xmlNewNode(psNsOws, BAD_CAST "BoundingBox");
543
544 /* add attributes to the root element */
545 xmlNewProp(psRootNode, BAD_CAST "crs", BAD_CAST crs);
546
547 snprintf( dim_string, sizeof(dim_string), "%d", dimensions );
548 xmlNewProp(psRootNode, BAD_CAST "dimensions", BAD_CAST dim_string);
549
550 snprintf(LowerCorner, sizeof(LowerCorner), "%.15g %.15g", minx, miny);
551 snprintf(UpperCorner, sizeof(UpperCorner), "%.15g %.15g", maxx, maxy);
552
553 /* add child elements */
554 xmlNewChild(psRootNode, psNsOws,BAD_CAST "LowerCorner",BAD_CAST LowerCorner);
555 xmlNewChild(psRootNode, psNsOws,BAD_CAST "UpperCorner",BAD_CAST UpperCorner);
556
557 return psRootNode;
558 }
559
560 /**
561 * msOWSCommonWGS84BoundingBox()
562 *
563 * returns an object of WGS84BoundingBox as per subclause 10.2.2
564 *
565 * @param psNsOws OWS namespace object
566 * @param dimensions number of dimensions of the coordinates
567 * @param minx minx
568 * @param miny miny
569 * @param maxx maxx
570 * @param maxy maxy
571 *
572 * @return psRootNode xmlNodePtr pointer of XML construct
573 */
574
msOWSCommonWGS84BoundingBox(xmlNsPtr psNsOws,int dimensions,double minx,double miny,double maxx,double maxy)575 xmlNodePtr msOWSCommonWGS84BoundingBox(xmlNsPtr psNsOws, int dimensions, double minx, double miny, double maxx, double maxy)
576 {
577 char LowerCorner[100];
578 char UpperCorner[100];
579 char dim_string[100];
580
581 xmlNodePtr psRootNode = NULL;
582
583 if (_validateNamespace(psNsOws) == MS_FAILURE)
584 psNsOws = xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_OWS_NAMESPACE_URI, BAD_CAST MS_OWSCOMMON_OWS_NAMESPACE_PREFIX);
585
586 /* create element name */
587 psRootNode = xmlNewNode(psNsOws, BAD_CAST "WGS84BoundingBox");
588
589 snprintf( dim_string, sizeof(dim_string), "%d", dimensions );
590 xmlNewProp(psRootNode, BAD_CAST "dimensions", BAD_CAST dim_string);
591
592 snprintf(LowerCorner, sizeof(LowerCorner), "%.15g %.15g", minx, miny);
593 snprintf(UpperCorner, sizeof(UpperCorner), "%.15g %.15g", maxx, maxy);
594
595 /* add child elements */
596 xmlNewChild(psRootNode, psNsOws,BAD_CAST "LowerCorner",BAD_CAST LowerCorner);
597 xmlNewChild(psRootNode, psNsOws,BAD_CAST "UpperCorner",BAD_CAST UpperCorner);
598
599 return psRootNode;
600 }
601
602 /**
603 * _validateNamespace()
604 *
605 * validates the namespace passed to this module's functions
606 *
607 * @param psNsOws namespace object
608 *
609 * @return MS_SUCCESS or MS_FAILURE
610 *
611 */
612
_validateNamespace(xmlNsPtr psNsOws)613 int _validateNamespace(xmlNsPtr psNsOws)
614 {
615 char namespace_prefix[10];
616 snprintf(namespace_prefix, sizeof(namespace_prefix), "%s", psNsOws->prefix);
617 if (strcmp(namespace_prefix, MS_OWSCOMMON_OWS_NAMESPACE_PREFIX) == 0)
618 return MS_SUCCESS;
619 else
620 return MS_FAILURE;
621 }
622
623 /*
624 * Valid an xml string against an XML schema
625 * Inpired from: http://xml.developpez.com/sources/?page=validation#validate_XSD_CppCLI_2
626 * taken from tinyows.org
627 */
msOWSSchemaValidation(const char * xml_schema,const char * xml)628 int msOWSSchemaValidation(const char* xml_schema, const char* xml)
629 {
630 xmlSchemaPtr schema;
631 xmlSchemaParserCtxtPtr ctxt;
632 xmlSchemaValidCtxtPtr validctxt;
633 int ret;
634 xmlDocPtr doc;
635
636 if (!xml_schema || !xml)
637 return MS_FAILURE;
638
639 xmlInitParser();
640 schema = NULL;
641 ret = -1;
642
643 /* To valide WFS 2.0 requests, we might need to explicitely import */
644 /* GML and FES 2.0 */
645 if( strlen(xml_schema) > strlen(MS_OWSCOMMON_WFS_20_SCHEMA_LOCATION) &&
646 strcmp(xml_schema + strlen(xml_schema) -
647 strlen(MS_OWSCOMMON_WFS_20_SCHEMA_LOCATION), MS_OWSCOMMON_WFS_20_SCHEMA_LOCATION) == 0 )
648 {
649 char szInMemSchema[2048];
650 char szBaseLocation[256];
651
652 strncpy(szBaseLocation, xml_schema, strlen(xml_schema) - strlen(MS_OWSCOMMON_WFS_20_SCHEMA_LOCATION));
653 szBaseLocation[strlen(xml_schema) - strlen(MS_OWSCOMMON_WFS_20_SCHEMA_LOCATION)] = '\0';
654
655 strcpy(szInMemSchema, "<schema elementFormDefault=\"qualified\" version=\"1.0.0\" "
656 "xmlns=\"http://www.w3.org/2001/XMLSchema\">\n");
657
658 sprintf(szInMemSchema + strlen(szInMemSchema),
659 "<import namespace=\"%s\" schemaLocation=\"%s\" />\n",
660 MS_OWSCOMMON_WFS_20_NAMESPACE_URI, xml_schema);
661
662 if( strstr(xml, MS_OWSCOMMON_FES_20_NAMESPACE_URI) != NULL )
663 {
664 sprintf(szInMemSchema + strlen(szInMemSchema),
665 "<import namespace=\"%s\" schemaLocation=\"%s%s\" />\n",
666 MS_OWSCOMMON_FES_20_NAMESPACE_URI, szBaseLocation, MS_OWSCOMMON_FES_20_SCHEMA_LOCATION);
667 }
668
669 if( strstr(xml, MS_OWSCOMMON_GML_32_NAMESPACE_URI) != NULL )
670 {
671 sprintf(szInMemSchema + strlen(szInMemSchema),
672 "<import namespace=\"%s\" schemaLocation=\"%s%s\" />\n",
673 MS_OWSCOMMON_GML_32_NAMESPACE_URI, szBaseLocation, MS_OWSCOMMON_GML_321_SCHEMA_LOCATION);
674 }
675 else if( strstr(xml, MS_OWSCOMMON_GML_NAMESPACE_URI) != NULL )
676 {
677 if( strstr(xml, MS_OWSCOMMON_GML_212_SCHEMA_LOCATION) != NULL )
678 {
679 sprintf(szInMemSchema + strlen(szInMemSchema),
680 "<import namespace=\"%s\" schemaLocation=\"%s%s\" />\n",
681 MS_OWSCOMMON_GML_NAMESPACE_URI, szBaseLocation, MS_OWSCOMMON_GML_212_SCHEMA_LOCATION);
682 }
683 else if( strstr(xml, MS_OWSCOMMON_GML_311_SCHEMA_LOCATION) != NULL )
684 {
685 sprintf(szInMemSchema + strlen(szInMemSchema),
686 "<import namespace=\"%s\" schemaLocation=\"%s%s\" />\n",
687 MS_OWSCOMMON_GML_NAMESPACE_URI, szBaseLocation, MS_OWSCOMMON_GML_311_SCHEMA_LOCATION);
688 }
689 }
690
691 strcat(szInMemSchema, "</schema>\n");
692 /*fprintf(stderr, "%s\n", szInMemSchema);*/
693
694 ctxt = xmlSchemaNewMemParserCtxt(szInMemSchema, strlen(szInMemSchema));
695 }
696 else
697 {
698 /* Open XML Schema File */
699 ctxt = xmlSchemaNewParserCtxt(xml_schema);
700 }
701
702 /*
703 xmlSchemaSetParserErrors(ctxt,
704 (xmlSchemaValidityErrorFunc) libxml2_callback,
705 (xmlSchemaValidityWarningFunc) libxml2_callback, stderr);
706 */
707
708 schema = xmlSchemaParse(ctxt);
709 xmlSchemaFreeParserCtxt(ctxt);
710
711 /* If XML Schema hasn't been rightly loaded */
712 if (schema == NULL) {
713 xmlSchemaCleanupTypes();
714 xmlMemoryDump();
715 xmlCleanupParser();
716 return ret;
717 }
718
719 doc = xmlParseDoc((xmlChar *)xml);
720
721 if (doc != NULL) {
722 /* Loading XML Schema content */
723 validctxt = xmlSchemaNewValidCtxt(schema);
724 /*
725 xmlSchemaSetValidErrors(validctxt,
726 (xmlSchemaValidityErrorFunc) libxml2_callback,
727 (xmlSchemaValidityWarningFunc) libxml2_callback, stderr);
728 */
729 /* validation */
730 ret = xmlSchemaValidateDoc(validctxt, doc);
731 xmlSchemaFreeValidCtxt(validctxt);
732 }
733
734 xmlSchemaFree(schema);
735 xmlFreeDoc(doc);
736 xmlCleanupParser();
737
738 return ret;
739 }
740
741 #endif /* defined(USE_LIBXML2) */
742
743
744 /**
745 * msOWSCommonNegotiateVersion()
746 *
747 * returns a supported version as per subclause 7.3.2
748 *
749 * @param requested_version the version passed by the client
750 * @param supported_versions an array of supported versions
751 * @param num_supported_versions size of supported_versions
752 *
753 * @return supported version integer, or -1 on error
754 *
755 */
756
msOWSCommonNegotiateVersion(int requested_version,const int supported_versions[],int num_supported_versions)757 int msOWSCommonNegotiateVersion(int requested_version, const int supported_versions[], int num_supported_versions)
758 {
759 int i;
760
761 /* if version is not set return error */
762 if (! requested_version)
763 return -1;
764
765 /* return the first entry that's equal to the requested version */
766 for (i = 0; i < num_supported_versions; i++) {
767 if (supported_versions[i] == requested_version)
768 return supported_versions[i];
769 }
770
771 /* no match; calling code should throw an exception */
772 return -1;
773 }
774