Coverage Report

Created: 2025-08-28 06:57

/src/MapServer/src/mapwfs20.c
Line
Count
Source (jump to first uncovered line)
1
/**********************************************************************
2
 * $Id$
3
 *
4
 * Project:  MapServer
5
 * Purpose:  OGC WFS 2.0.0 implementation. This file holds some WFS 2.0.0
6
 *           specific functions but other parts are still implemented in
7
 *mapwfs.c. Author:   Even Rouault
8
 *
9
 **********************************************************************
10
 * Copyright (c) 2013, Even Rouault
11
 *
12
 * Permission is hereby granted, free of charge, to any person obtaining a
13
 * copy of this software and associated documentation files (the "Software"),
14
 * to deal in the Software without restriction, including without limitation
15
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16
 * and/or sell copies of the Software, and to permit persons to whom the
17
 * Software is furnished to do so, subject to the following conditions:
18
 *
19
 * The above copyright notice and this permission notice shall be included in
20
 * all copies of this Software or works derived from this Software.
21
 *
22
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
25
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28
 ****************************************************************************/
29
30
#include "mapserver.h"
31
#include "mapows.h"
32
33
#if defined(USE_WFS_SVR) && defined(USE_LIBXML2)
34
#include "maplibxml2.h"
35
#include "mapowscommon.h"
36
#include "mapogcfilter.h"
37
38
0
#define MS_OWS_11_NAMESPACE_PREFIX MS_OWSCOMMON_OWS_NAMESPACE_PREFIX
39
0
#define MS_OWS_11_NAMESPACE_URI MS_OWSCOMMON_OWS_110_NAMESPACE_URI
40
41
0
#define URN_GET_FEATURE_BY_ID "urn:ogc:def:query:OGC-WFS::GetFeatureById"
42
43
#define GET_FEATURE_BY_ID                                                      \
44
0
  "<StoredQueryDescription id=\"" URN_GET_FEATURE_BY_ID "\">"                  \
45
0
  "<Title>Get feature by identifier</Title>"                                   \
46
0
  "<Abstract>Returns the single feature whose value is equal to the "          \
47
0
  "specified value of the ID argument</Abstract>"                              \
48
0
  "<Parameter name=\"ID\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" "      \
49
0
  "type=\"xs:string\"/>"                                                       \
50
0
  "<QueryExpressionText isPrivate=\"true\" "                                   \
51
0
  "language=\"urn:ogc:def:queryLanguage:OGC-WFS::WFS_QueryExpression\" "       \
52
0
  "returnFeatureTypes=\"\">"                                                   \
53
0
  "<Query xmlns:fes=\"http://www.opengis.net/fes/2.0\" typeNames=\"?\">"       \
54
0
  "<fes:Filter><fes:ResourceId rid=\"${ID}\"/></fes:Filter>"                   \
55
0
  "</Query>"                                                                   \
56
0
  "</QueryExpressionText>"                                                     \
57
0
  "</StoredQueryDescription>"
58
59
/************************************************************************/
60
/*                          msWFSException20()                          */
61
/************************************************************************/
62
63
int msWFSException20(mapObj *map, const char *locator,
64
0
                     const char *exceptionCode) {
65
0
  int size = 0;
66
0
  char *errorString = NULL;
67
68
0
  xmlDocPtr psDoc = NULL;
69
0
  xmlNodePtr psRootNode = NULL;
70
0
  xmlNsPtr psNsOws = NULL;
71
0
  xmlChar *buffer = NULL;
72
0
  const char *status = NULL;
73
74
0
  psNsOws = xmlNewNs(NULL, BAD_CAST MS_OWS_11_NAMESPACE_URI,
75
0
                     BAD_CAST MS_OWS_11_NAMESPACE_PREFIX);
76
77
0
  errorString = msGetErrorString("\n");
78
79
0
  psDoc = xmlNewDoc(BAD_CAST "1.0");
80
81
0
  psRootNode = msOWSCommonExceptionReport(
82
0
      psNsOws, OWS_1_1_0, msOWSGetSchemasLocation(map), "2.0.0",
83
0
      msOWSGetLanguage(map, "exception"), exceptionCode, locator, errorString);
84
85
0
  xmlDocSetRootElement(psDoc, psRootNode);
86
87
0
  xmlNewNs(psRootNode, BAD_CAST MS_OWS_11_NAMESPACE_URI,
88
0
           BAD_CAST MS_OWS_11_NAMESPACE_PREFIX);
89
90
  /* Table D.2 OGC 09-025r1 - For CITE compliance */
91
0
  if (EQUAL(exceptionCode, MS_OWS_ERROR_OPERATION_NOT_SUPPORTED) ||
92
0
      EQUAL(exceptionCode, MS_OWS_ERROR_OPTION_NOT_SUPPORTED)) {
93
0
    status = "400 Not Implemented";
94
0
  } else if (EQUAL(exceptionCode, MS_OWS_ERROR_MISSING_PARAMETER_VALUE) ||
95
0
             EQUAL(exceptionCode, MS_OWS_ERROR_INVALID_PARAMETER_VALUE) ||
96
0
             EQUAL(exceptionCode, MS_OWS_ERROR_VERSION_NEGOTIATION_FAILED) ||
97
0
             EQUAL(exceptionCode, MS_OWS_ERROR_INVALID_UPDATE_SEQUENCE)) {
98
0
    status = "400 Bad request";
99
0
  } else if (EQUAL(exceptionCode, MS_WFS_ERROR_OPERATION_PROCESSING_FAILED)) {
100
0
    status = "403 Server processing failed";
101
0
  } else if (EQUAL(exceptionCode, MS_OWS_ERROR_NOT_FOUND)) {
102
0
    status = "404 Not Found";
103
0
  } else if (EQUAL(exceptionCode, MS_OWS_ERROR_NO_APPLICABLE_CODE)) {
104
0
    status = "400 Internal Server Error";
105
0
  }
106
107
0
  if (status != NULL) {
108
0
    msIO_setHeader("Status", "%s", status);
109
0
  }
110
0
  msIO_setHeader("Content-Type", "text/xml; charset=UTF-8");
111
0
  msIO_sendHeaders();
112
113
0
  xmlDocDumpFormatMemoryEnc(psDoc, &buffer, &size, "UTF-8", 1);
114
115
0
  msIO_printf("%s", buffer);
116
117
  /*free buffer and the document */
118
0
  free(errorString);
119
0
  xmlFree(buffer);
120
0
  xmlFreeDoc(psDoc);
121
0
  xmlFreeNs(psNsOws);
122
123
  /* clear error since we have already reported it */
124
0
  msResetErrorList();
125
126
0
  return MS_FAILURE;
127
0
}
128
129
/************************************************************************/
130
/*                          msWFSIncludeSection                         */
131
/************************************************************************/
132
0
static int msWFSIncludeSection(wfsParamsObj *params, const char *pszSection) {
133
0
  int i;
134
0
  if (params->pszSections == NULL)
135
0
    return TRUE;
136
0
  for (i = 0; params->pszSections[i] != '\0'; i++) {
137
0
    if (strncasecmp(params->pszSections + i, "All", strlen("All")) == 0)
138
0
      return TRUE;
139
0
    if (strncasecmp(params->pszSections + i, pszSection, strlen(pszSection)) ==
140
0
        0)
141
0
      return TRUE;
142
0
  }
143
0
  return FALSE;
144
0
}
145
146
/************************************************************************/
147
/*                       msWFSConstraintDefaultValue                    */
148
/************************************************************************/
149
150
static xmlNodePtr msWFSConstraintDefaultValue(xmlNsPtr psNs, xmlNsPtr psNsOws,
151
                                              const char *name,
152
0
                                              const char *value) {
153
0
  xmlNodePtr psRootNode = NULL;
154
155
0
  psRootNode = xmlNewNode(psNs, BAD_CAST "Constraint");
156
157
0
  xmlNewProp(psRootNode, BAD_CAST "name", BAD_CAST name);
158
159
0
  xmlNewChild(psRootNode, psNsOws, BAD_CAST "NoValues", NULL);
160
0
  xmlNewTextChild(psRootNode, psNsOws, BAD_CAST "DefaultValue", BAD_CAST value);
161
162
0
  return psRootNode;
163
0
}
164
165
/************************************************************************/
166
/*                              msWFSOperator                           */
167
/************************************************************************/
168
169
static xmlNodePtr msWFSOperator(xmlNsPtr psNsFES, const char *pszOperatorType,
170
0
                                const char *pszOperator) {
171
0
  xmlNodePtr psNode = xmlNewNode(psNsFES, BAD_CAST pszOperatorType);
172
0
  xmlNewProp(psNode, BAD_CAST "name", BAD_CAST pszOperator);
173
0
  return psNode;
174
0
}
175
176
/************************************************************************/
177
/*                       msWFS20FilterCapabilities                      */
178
/************************************************************************/
179
180
static xmlNodePtr msWFS20FilterCapabilities(xmlNsPtr psNsFES, xmlNsPtr psNsOws,
181
0
                                            int bImplementsSorting) {
182
0
  xmlNodePtr psRootNode = NULL, psNode = NULL, psSubNode = NULL;
183
184
0
  psRootNode = xmlNewNode(psNsFES, BAD_CAST "Filter_Capabilities");
185
186
0
  psNode = xmlNewChild(psRootNode, psNsFES, BAD_CAST "Conformance", NULL);
187
188
0
  xmlAddChild(psNode, msWFSConstraintDefaultValue(psNsFES, psNsOws,
189
0
                                                  "ImplementsQuery", "TRUE"));
190
0
  xmlAddChild(psNode, msWFSConstraintDefaultValue(
191
0
                          psNsFES, psNsOws, "ImplementsAdHocQuery", "TRUE"));
192
0
  xmlAddChild(psNode, msWFSConstraintDefaultValue(
193
0
                          psNsFES, psNsOws, "ImplementsFunctions", "FALSE"));
194
0
  xmlAddChild(psNode, msWFSConstraintDefaultValue(
195
0
                          psNsFES, psNsOws, "ImplementsResourceId", "TRUE"));
196
0
  xmlAddChild(psNode, msWFSConstraintDefaultValue(psNsFES, psNsOws,
197
0
                                                  "ImplementsMinStandardFilter",
198
0
                                                  "TRUE"));
199
0
  xmlAddChild(psNode,
200
0
              msWFSConstraintDefaultValue(psNsFES, psNsOws,
201
0
                                          "ImplementsStandardFilter", "TRUE"));
202
0
  xmlAddChild(psNode, msWFSConstraintDefaultValue(psNsFES, psNsOws,
203
0
                                                  "ImplementsMinSpatialFilter",
204
0
                                                  "TRUE"));
205
0
  xmlAddChild(psNode,
206
0
              msWFSConstraintDefaultValue(psNsFES, psNsOws,
207
0
                                          "ImplementsSpatialFilter", "FALSE"));
208
0
  xmlAddChild(psNode, msWFSConstraintDefaultValue(psNsFES, psNsOws,
209
0
                                                  "ImplementsMinTemporalFilter",
210
0
                                                  "TRUE"));
211
0
  xmlAddChild(psNode,
212
0
              msWFSConstraintDefaultValue(psNsFES, psNsOws,
213
0
                                          "ImplementsTemporalFilter", "FALSE"));
214
0
  xmlAddChild(psNode, msWFSConstraintDefaultValue(
215
0
                          psNsFES, psNsOws, "ImplementsVersionNav", "FALSE"));
216
0
  xmlAddChild(psNode, msWFSConstraintDefaultValue(
217
0
                          psNsFES, psNsOws, "ImplementsSorting",
218
0
                          (bImplementsSorting) ? "TRUE" : "FALSE"));
219
0
  xmlAddChild(psNode, msWFSConstraintDefaultValue(psNsFES, psNsOws,
220
0
                                                  "ImplementsExtendedOperators",
221
0
                                                  "FALSE"));
222
0
  xmlAddChild(psNode, msWFSConstraintDefaultValue(
223
0
                          psNsFES, psNsOws, "ImplementsMinimumXPath", "TRUE"));
224
0
  xmlAddChild(psNode, msWFSConstraintDefaultValue(psNsFES, psNsOws,
225
0
                                                  "ImplementsSchemaElementFunc",
226
0
                                                  "FALSE"));
227
228
0
  psNode = xmlNewChild(psRootNode, psNsFES, BAD_CAST "Id_Capabilities", NULL);
229
0
  psSubNode = xmlNewChild(psNode, psNsFES, BAD_CAST "ResourceIdentifier", NULL);
230
0
  xmlNewProp(psSubNode, BAD_CAST "name", BAD_CAST "fes:ResourceId");
231
232
0
  psNode =
233
0
      xmlNewChild(psRootNode, psNsFES, BAD_CAST "Scalar_Capabilities", NULL);
234
0
  xmlNewChild(psNode, psNsFES, BAD_CAST "LogicalOperators", NULL);
235
0
  psNode = xmlNewChild(psNode, psNsFES, BAD_CAST "ComparisonOperators", NULL);
236
0
  xmlAddChild(psNode, msWFSOperator(psNsFES, "ComparisonOperator",
237
0
                                    "PropertyIsEqualTo"));
238
0
  xmlAddChild(psNode, msWFSOperator(psNsFES, "ComparisonOperator",
239
0
                                    "PropertyIsNotEqualTo"));
240
0
  xmlAddChild(psNode, msWFSOperator(psNsFES, "ComparisonOperator",
241
0
                                    "PropertyIsLessThan"));
242
0
  xmlAddChild(psNode, msWFSOperator(psNsFES, "ComparisonOperator",
243
0
                                    "PropertyIsGreaterThan"));
244
0
  xmlAddChild(psNode, msWFSOperator(psNsFES, "ComparisonOperator",
245
0
                                    "PropertyIsLessThanOrEqualTo"));
246
0
  xmlAddChild(psNode, msWFSOperator(psNsFES, "ComparisonOperator",
247
0
                                    "PropertyIsGreaterThanOrEqualTo"));
248
0
  xmlAddChild(psNode,
249
0
              msWFSOperator(psNsFES, "ComparisonOperator", "PropertyIsLike"));
250
0
  xmlAddChild(psNode, msWFSOperator(psNsFES, "ComparisonOperator",
251
0
                                    "PropertyIsBetween"));
252
  /* Missing: PropertyIsNull, PropertyIsNil */
253
254
0
  psNode =
255
0
      xmlNewChild(psRootNode, psNsFES, BAD_CAST "Spatial_Capabilities", NULL);
256
257
0
  psSubNode = xmlNewChild(psNode, psNsFES, BAD_CAST "GeometryOperands", NULL);
258
0
  xmlAddChild(psSubNode,
259
0
              msWFSOperator(psNsFES, "GeometryOperand", "gml:Point"));
260
0
  xmlAddChild(psSubNode,
261
0
              msWFSOperator(psNsFES, "GeometryOperand", "gml:MultiPoint"));
262
0
  xmlAddChild(psSubNode,
263
0
              msWFSOperator(psNsFES, "GeometryOperand", "gml:LineString"));
264
0
  xmlAddChild(psSubNode,
265
0
              msWFSOperator(psNsFES, "GeometryOperand", "gml:MultiLineString"));
266
0
  xmlAddChild(psSubNode,
267
0
              msWFSOperator(psNsFES, "GeometryOperand", "gml:Curve"));
268
0
  xmlAddChild(psSubNode,
269
0
              msWFSOperator(psNsFES, "GeometryOperand", "gml:MultiCurve"));
270
0
  xmlAddChild(psSubNode,
271
0
              msWFSOperator(psNsFES, "GeometryOperand", "gml:Polygon"));
272
0
  xmlAddChild(psSubNode,
273
0
              msWFSOperator(psNsFES, "GeometryOperand", "gml:MultiPolygon"));
274
0
  xmlAddChild(psSubNode,
275
0
              msWFSOperator(psNsFES, "GeometryOperand", "gml:Surface"));
276
0
  xmlAddChild(psSubNode,
277
0
              msWFSOperator(psNsFES, "GeometryOperand", "gml:MultiSurface"));
278
  /* xmlAddChild(psSubNode, msWFSOperator(psNsFES, "GeometryOperand",
279
   * "gml:MultiGeometry")); */
280
0
  xmlAddChild(psSubNode, msWFSOperator(psNsFES, "GeometryOperand", "gml:Box"));
281
0
  xmlAddChild(psSubNode,
282
0
              msWFSOperator(psNsFES, "GeometryOperand", "gml:Envelope"));
283
284
0
  psSubNode = xmlNewChild(psNode, psNsFES, BAD_CAST "SpatialOperators", NULL);
285
#ifdef USE_GEOS
286
  xmlAddChild(psSubNode, msWFSOperator(psNsFES, "SpatialOperator", "Equals"));
287
  xmlAddChild(psSubNode, msWFSOperator(psNsFES, "SpatialOperator", "Disjoint"));
288
  xmlAddChild(psSubNode, msWFSOperator(psNsFES, "SpatialOperator", "Touches"));
289
  xmlAddChild(psSubNode, msWFSOperator(psNsFES, "SpatialOperator", "Within"));
290
  xmlAddChild(psSubNode, msWFSOperator(psNsFES, "SpatialOperator", "Overlaps"));
291
  xmlAddChild(psSubNode, msWFSOperator(psNsFES, "SpatialOperator", "Crosses"));
292
  xmlAddChild(psSubNode,
293
              msWFSOperator(psNsFES, "SpatialOperator", "Intersects"));
294
  xmlAddChild(psSubNode, msWFSOperator(psNsFES, "SpatialOperator", "Contains"));
295
  xmlAddChild(psSubNode, msWFSOperator(psNsFES, "SpatialOperator", "DWithin"));
296
  xmlAddChild(psSubNode, msWFSOperator(psNsFES, "SpatialOperator", "Beyond"));
297
#endif
298
0
  xmlAddChild(psSubNode, msWFSOperator(psNsFES, "SpatialOperator", "BBOX"));
299
300
0
  psNode =
301
0
      xmlNewChild(psRootNode, psNsFES, BAD_CAST "Temporal_Capabilities", NULL);
302
0
  psSubNode = xmlNewChild(psNode, psNsFES, BAD_CAST "TemporalOperands", NULL);
303
0
  xmlAddChild(psSubNode,
304
0
              msWFSOperator(psNsFES, "TemporalOperand", "gml:TimePeriod"));
305
0
  xmlAddChild(psSubNode,
306
0
              msWFSOperator(psNsFES, "TemporalOperand", "gml:TimeInstant"));
307
308
0
  psSubNode = xmlNewChild(psNode, psNsFES, BAD_CAST "TemporalOperators", NULL);
309
0
  xmlAddChild(psSubNode, msWFSOperator(psNsFES, "TemporalOperator", "During"));
310
311
0
  return psRootNode;
312
0
}
313
314
/************************************************************************/
315
/*                          msXMLStripIndentation                       */
316
/************************************************************************/
317
318
0
static void msXMLStripIndentation(char *ptr) {
319
  /* Remove spaces between > and < to get properly indented result */
320
0
  char *afterLastClosingBracket = NULL;
321
0
  if (*ptr == ' ')
322
0
    afterLastClosingBracket = ptr;
323
0
  while (*ptr != '\0') {
324
0
    if (*ptr == '<' && afterLastClosingBracket != NULL) {
325
0
      memmove(afterLastClosingBracket, ptr, strlen(ptr) + 1);
326
0
      ptr = afterLastClosingBracket;
327
0
    } else if (*ptr == '>') {
328
0
      afterLastClosingBracket = ptr + 1;
329
0
    } else if (*ptr != ' ' && *ptr != '\n')
330
0
      afterLastClosingBracket = NULL;
331
0
    ptr++;
332
0
  }
333
0
}
334
335
/************************************************************************/
336
/*                          msWFSAddInspireDSID                         */
337
/************************************************************************/
338
339
static void msWFSAddInspireDSID(mapObj *map, xmlNsPtr psNsInspireDls,
340
                                xmlNsPtr psNsInspireCommon,
341
0
                                xmlNodePtr pDlsExtendedCapabilities) {
342
0
  const char *dsid_code =
343
0
      msOWSLookupMetadata(&(map->web.metadata), "FO", "inspire_dsid_code");
344
0
  const char *dsid_ns =
345
0
      msOWSLookupMetadata(&(map->web.metadata), "FO", "inspire_dsid_ns");
346
0
  if (dsid_code == NULL) {
347
0
    xmlAddChild(
348
0
        pDlsExtendedCapabilities,
349
0
        xmlNewComment(
350
0
            BAD_CAST
351
0
            "WARNING: Required metadata \"inspire_dsid_code\" missing"));
352
0
  } else {
353
0
    int ntokensCode = 0, ntokensNS = 0;
354
0
    char **tokensCode;
355
0
    char **tokensNS = NULL;
356
0
    int i;
357
358
0
    tokensCode = msStringSplit(dsid_code, ',', &ntokensCode);
359
0
    if (dsid_ns != NULL)
360
0
      tokensNS =
361
0
          msStringSplitComplex(dsid_ns, ",", &ntokensNS, MS_ALLOWEMPTYTOKENS);
362
0
    if (ntokensNS > 0 && ntokensNS != ntokensCode) {
363
0
      xmlAddChild(
364
0
          pDlsExtendedCapabilities,
365
0
          xmlNewComment(
366
0
              BAD_CAST
367
0
              "WARNING: \"inspire_dsid_code\" and \"inspire_dsid_ns\" have not "
368
0
              "the same number of elements. Ignoring inspire_dsid_ns"));
369
0
      msFreeCharArray(tokensNS, ntokensNS);
370
0
      tokensNS = NULL;
371
0
      ntokensNS = 0;
372
0
    }
373
0
    for (i = 0; i < ntokensCode; i++) {
374
0
      xmlNodePtr pSDSI =
375
0
          xmlNewNode(psNsInspireDls, BAD_CAST "SpatialDataSetIdentifier");
376
0
      xmlAddChild(pDlsExtendedCapabilities, pSDSI);
377
0
      xmlNewTextChild(pSDSI, psNsInspireCommon, BAD_CAST "Code",
378
0
                      BAD_CAST tokensCode[i]);
379
0
      if (ntokensNS > 0 && tokensNS[i][0] != '\0')
380
0
        xmlNewTextChild(pSDSI, psNsInspireCommon, BAD_CAST "Namespace",
381
0
                        BAD_CAST tokensNS[i]);
382
0
    }
383
0
    msFreeCharArray(tokensCode, ntokensCode);
384
0
    if (tokensNS)
385
0
      msFreeCharArray(tokensNS, ntokensNS);
386
0
  }
387
0
}
388
389
/************************************************************************/
390
/*                          msWFSGetCapabilities20                      */
391
/*                                                                      */
392
/*      Return the capabilities document for WFS 2.0.0                  */
393
/************************************************************************/
394
int msWFSGetCapabilities20(mapObj *map, wfsParamsObj *params,
395
0
                           cgiRequestObj *req, owsRequestObj *ows_request) {
396
0
  xmlDocPtr psDoc = NULL; /* document pointer */
397
0
  xmlNodePtr psRootNode, psMainNode, psNode, psFtNode = NULL;
398
0
  const char *updatesequence = NULL;
399
0
  xmlNsPtr psNsOws, psNsXLink;
400
0
  xmlNsPtr psNsFES = NULL;
401
0
  xmlNsPtr psNsInspireCommon = NULL;
402
0
  xmlNsPtr psNsInspireDls = NULL;
403
0
  xmlDocPtr pInspireTmpDoc = NULL;
404
0
  char *xsi_schemaLocation = NULL;
405
0
  const char *user_namespace_prefix = NULL;
406
0
  const char *user_namespace_uri = NULL;
407
0
  gmlNamespaceListObj *namespaceList =
408
0
      NULL; /* for external application schema support */
409
410
0
  char *script_url = NULL, *formats_list;
411
0
  const char *value = NULL;
412
413
0
  xmlChar *buffer = NULL;
414
0
  int size = 0, i;
415
0
  msIOContext *context = NULL;
416
417
0
  int ows_version = OWS_1_1_0;
418
0
  int ret;
419
420
0
  char *validated_language;
421
0
  int bImplementsSorting = MS_FALSE;
422
423
  /* -------------------------------------------------------------------- */
424
  /*      Handle updatesequence                                           */
425
  /* -------------------------------------------------------------------- */
426
0
  ret = msWFSHandleUpdateSequence(map, params, "msWFSGetCapabilities20()");
427
0
  if (ret != MS_SUCCESS)
428
0
    return ret;
429
430
0
  validated_language = msOWSGetLanguageFromList(map, "FO", params->pszLanguage);
431
432
  /* -------------------------------------------------------------------- */
433
  /*      Create document.                                                */
434
  /* -------------------------------------------------------------------- */
435
0
  psDoc = xmlNewDoc(BAD_CAST "1.0");
436
437
0
  psRootNode = xmlNewNode(NULL, BAD_CAST "WFS_Capabilities");
438
439
0
  xmlDocSetRootElement(psDoc, psRootNode);
440
441
  /* -------------------------------------------------------------------- */
442
  /*      Name spaces                                                     */
443
  /* -------------------------------------------------------------------- */
444
445
  /*default name space*/
446
0
  xmlNewProp(psRootNode, BAD_CAST "xmlns",
447
0
             BAD_CAST MS_OWSCOMMON_WFS_20_NAMESPACE_URI);
448
449
0
  xmlSetNs(psRootNode,
450
0
           xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_GML_32_NAMESPACE_URI,
451
0
                    BAD_CAST MS_OWSCOMMON_GML_NAMESPACE_PREFIX));
452
0
  xmlSetNs(psRootNode,
453
0
           xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_WFS_20_NAMESPACE_URI,
454
0
                    BAD_CAST MS_OWSCOMMON_WFS_NAMESPACE_PREFIX));
455
456
0
  psNsOws = xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_OWS_110_NAMESPACE_URI,
457
0
                     BAD_CAST MS_OWSCOMMON_OWS_NAMESPACE_PREFIX);
458
0
  psNsXLink =
459
0
      xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_W3C_XLINK_NAMESPACE_URI,
460
0
               BAD_CAST MS_OWSCOMMON_W3C_XLINK_NAMESPACE_PREFIX);
461
0
  xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_W3C_XSI_NAMESPACE_URI,
462
0
           BAD_CAST MS_OWSCOMMON_W3C_XSI_NAMESPACE_PREFIX);
463
0
  xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_FES_20_NAMESPACE_URI,
464
0
           BAD_CAST MS_OWSCOMMON_FES_20_NAMESPACE_PREFIX);
465
466
0
  value = msOWSLookupMetadata(&(map->web.metadata), "FO", "namespace_uri");
467
0
  if (value)
468
0
    user_namespace_uri = value;
469
0
  else
470
0
    user_namespace_uri = MS_DEFAULT_NAMESPACE_URI;
471
472
0
  value = msOWSLookupMetadata(&(map->web.metadata), "FO", "namespace_prefix");
473
0
  if (value)
474
0
    user_namespace_prefix = value;
475
0
  else
476
0
    user_namespace_prefix = MS_DEFAULT_NAMESPACE_PREFIX;
477
478
0
  if (user_namespace_prefix != NULL &&
479
0
      msIsXMLTagValid(user_namespace_prefix) == MS_FALSE)
480
0
    msIO_printf(
481
0
        "<!-- WARNING: The value '%s' is not valid XML namespace. -->\n",
482
0
        user_namespace_prefix);
483
0
  else
484
0
    xmlNewNs(psRootNode, BAD_CAST user_namespace_uri,
485
0
             BAD_CAST user_namespace_prefix);
486
487
  /* any additional namespaces */
488
0
  namespaceList = msGMLGetNamespaces(&(map->web), "G");
489
0
  for (i = 0; i < namespaceList->numnamespaces; i++) {
490
0
    if (namespaceList->namespaces[i].uri) {
491
0
      xmlNewNs(psRootNode, BAD_CAST namespaceList->namespaces[i].uri,
492
0
               BAD_CAST namespaceList->namespaces[i].prefix);
493
0
    }
494
0
  }
495
0
  msGMLFreeNamespaces(namespaceList);
496
497
0
  if (msOWSLookupMetadata(&(map->web.metadata), "FO", "inspire_capabilities")) {
498
0
    psNsInspireCommon =
499
0
        xmlNewNs(psRootNode, BAD_CAST MS_INSPIRE_COMMON_NAMESPACE_URI,
500
0
                 BAD_CAST MS_INSPIRE_COMMON_NAMESPACE_PREFIX);
501
0
    psNsInspireDls = xmlNewNs(psRootNode, BAD_CAST MS_INSPIRE_DLS_NAMESPACE_URI,
502
0
                              BAD_CAST MS_INSPIRE_DLS_NAMESPACE_PREFIX);
503
0
  }
504
505
0
  xmlNewProp(psRootNode, BAD_CAST "version", BAD_CAST params->pszVersion);
506
507
0
  updatesequence =
508
0
      msOWSLookupMetadata(&(map->web.metadata), "FO", "updatesequence");
509
510
0
  if (updatesequence)
511
0
    xmlNewProp(psRootNode, BAD_CAST "updateSequence", BAD_CAST updatesequence);
512
513
  /*schema*/
514
0
  xsi_schemaLocation = msStrdup(MS_OWSCOMMON_WFS_20_NAMESPACE_URI);
515
0
  xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, " ");
516
0
  xsi_schemaLocation =
517
0
      msStringConcatenate(xsi_schemaLocation, msOWSGetSchemasLocation(map));
518
0
  xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation,
519
0
                                           MS_OWSCOMMON_WFS_20_SCHEMA_LOCATION);
520
521
0
  if (psNsInspireDls != NULL) {
522
0
    xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, " ");
523
0
    xsi_schemaLocation =
524
0
        msStringConcatenate(xsi_schemaLocation, MS_INSPIRE_DLS_NAMESPACE_URI);
525
0
    xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, " ");
526
0
    xsi_schemaLocation = msStringConcatenate(
527
0
        xsi_schemaLocation, msOWSGetInspireSchemasLocation(map));
528
0
    xsi_schemaLocation =
529
0
        msStringConcatenate(xsi_schemaLocation, MS_INSPIRE_DLS_SCHEMA_LOCATION);
530
0
    xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, " ");
531
0
    xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation,
532
0
                                             MS_INSPIRE_COMMON_NAMESPACE_URI);
533
0
    xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, " ");
534
0
    xsi_schemaLocation = msStringConcatenate(
535
0
        xsi_schemaLocation, msOWSGetInspireSchemasLocation(map));
536
0
    xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation,
537
0
                                             MS_INSPIRE_COMMON_SCHEMA_LOCATION);
538
0
  }
539
540
0
  xmlNewNsProp(psRootNode, NULL, BAD_CAST "xsi:schemaLocation",
541
0
               BAD_CAST xsi_schemaLocation);
542
0
  free(xsi_schemaLocation);
543
544
  /* -------------------------------------------------------------------- */
545
  /*      Service metadata.                                               */
546
  /* -------------------------------------------------------------------- */
547
548
  /* TODO? : also add 1.1.0 and 1.0.0 as extra <ows:ServiceTypeVersion>. The OWS
549
   */
550
  /* schema would suggest to do so, and also the example */
551
  /* http://schemas.opengis.net/wfs/2.0/examples/GetCapabilities/GetCapabilities_Res_01.xml
552
   */
553
  /* and Deegree too, but GeoServer also only lists the current version. */
554
0
  if (msWFSIncludeSection(params, "ServiceIdentification")) {
555
0
    xmlAddChild(psRootNode, msOWSCommonServiceIdentification(
556
0
                                psNsOws, map, "WFS", params->pszVersion, "FO",
557
0
                                validated_language));
558
0
  }
559
560
  /*service provider*/
561
0
  if (msWFSIncludeSection(params, "ServiceProvider")) {
562
0
    xmlAddChild(psRootNode,
563
0
                msOWSCommonServiceProvider(psNsOws, psNsXLink, map, "FO",
564
0
                                           validated_language));
565
0
  }
566
567
  /*operation metadata */
568
0
  if (msWFSIncludeSection(params, "OperationsMetadata")) {
569
0
    if ((script_url = msOWSGetOnlineResource2(map, "FO", "onlineresource", req,
570
0
                                              validated_language)) == NULL) {
571
0
      msSetError(MS_WFSERR, "Server URL not found", "msWFSGetCapabilities20()");
572
0
      return msWFSException11(map, "mapserv", MS_OWS_ERROR_NO_APPLICABLE_CODE,
573
0
                              params->pszVersion);
574
0
    }
575
576
    /* -------------------------------------------------------------------- */
577
    /*      Operations metadata.                                            */
578
    /* -------------------------------------------------------------------- */
579
0
    psMainNode =
580
0
        xmlAddChild(psRootNode, msOWSCommonOperationsMetadata(psNsOws));
581
582
    /* -------------------------------------------------------------------- */
583
    /*      GetCapabilities                                                 */
584
    /* -------------------------------------------------------------------- */
585
0
    psNode = xmlAddChild(psMainNode, msOWSCommonOperationsMetadataOperation(
586
0
                                         psNsOws, psNsXLink, "GetCapabilities",
587
0
                                         OWS_METHOD_GETPOST, script_url));
588
589
0
    xmlAddChild(psMainNode, psNode);
590
591
    /*accept version*/
592
0
    xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType(
593
0
                            ows_version, psNsOws, "Parameter", "AcceptVersions",
594
0
                            "2.0.0,1.1.0,1.0.0"));
595
    /*format*/
596
0
    xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType(
597
0
                            ows_version, psNsOws, "Parameter", "AcceptFormats",
598
0
                            "text/xml"));
599
    /*sections*/
600
0
    xmlAddChild(psNode,
601
0
                msOWSCommonOperationsMetadataDomainType(
602
0
                    ows_version, psNsOws, "Parameter", "Sections",
603
0
                    "ServiceIdentification,ServiceProvider,OperationsMetadata,"
604
0
                    "FeatureTypeList,Filter_Capabilities"));
605
606
    /* -------------------------------------------------------------------- */
607
    /*      DescribeFeatureType                                             */
608
    /* -------------------------------------------------------------------- */
609
0
    if (msOWSRequestIsEnabled(map, NULL, "F", "DescribeFeatureType", MS_TRUE)) {
610
0
      psNode =
611
0
          xmlAddChild(psMainNode, msOWSCommonOperationsMetadataOperation(
612
0
                                      psNsOws, psNsXLink, "DescribeFeatureType",
613
0
                                      OWS_METHOD_GETPOST, script_url));
614
0
      xmlAddChild(psMainNode, psNode);
615
616
      /*output format*/
617
0
      xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType(
618
0
                              ows_version, psNsOws, "Parameter", "outputFormat",
619
0
                              "application/gml+xml; version=3.2,"
620
0
                              "text/xml; subtype=gml/3.2.1,"
621
0
                              "text/xml; subtype=gml/3.1.1,"
622
0
                              "text/xml; subtype=gml/2.1.2"));
623
0
    }
624
625
    /* -------------------------------------------------------------------- */
626
    /*      GetFeature                                                      */
627
    /* -------------------------------------------------------------------- */
628
0
    if (msOWSRequestIsEnabled(map, NULL, "F", "GetFeature", MS_TRUE)) {
629
630
0
      psNode = xmlAddChild(psMainNode, msOWSCommonOperationsMetadataOperation(
631
0
                                           psNsOws, psNsXLink, "GetFeature",
632
0
                                           OWS_METHOD_GETPOST, script_url));
633
0
      xmlAddChild(psMainNode, psNode);
634
635
0
      formats_list = msWFSGetOutputFormatList(map, NULL, OWS_2_0_0);
636
0
      xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType(
637
0
                              ows_version, psNsOws, "Parameter", "outputFormat",
638
0
                              formats_list));
639
0
      msFree(formats_list);
640
0
    }
641
642
    /* -------------------------------------------------------------------- */
643
    /*      GetPropertyValue                                                */
644
    /* -------------------------------------------------------------------- */
645
0
    if (msOWSRequestIsEnabled(map, NULL, "F", "GetPropertyValue", MS_TRUE)) {
646
647
0
      psNode =
648
0
          xmlAddChild(psMainNode, msOWSCommonOperationsMetadataOperation(
649
0
                                      psNsOws, psNsXLink, "GetPropertyValue",
650
0
                                      OWS_METHOD_GETPOST, script_url));
651
0
      xmlAddChild(psMainNode, psNode);
652
653
      /* Only advertise built-in GML formats for GetPropertyValue. Not sure */
654
      /* it makes sense to advertise OGR formats. */
655
0
      xmlAddChild(psNode, msOWSCommonOperationsMetadataDomainType(
656
0
                              ows_version, psNsOws, "Parameter", "outputFormat",
657
0
                              "application/gml+xml; version=3.2,"
658
0
                              "text/xml; subtype=gml/3.2.1,"
659
0
                              "text/xml; subtype=gml/3.1.1,"
660
0
                              "text/xml; subtype=gml/2.1.2"));
661
0
    }
662
663
    /* -------------------------------------------------------------------- */
664
    /*      ListStoredQueries                                               */
665
    /* -------------------------------------------------------------------- */
666
0
    if (msOWSRequestIsEnabled(map, NULL, "F", "ListStoredQueries", MS_TRUE)) {
667
668
0
      psNode =
669
0
          xmlAddChild(psMainNode, msOWSCommonOperationsMetadataOperation(
670
0
                                      psNsOws, psNsXLink, "ListStoredQueries",
671
0
                                      OWS_METHOD_GETPOST, script_url));
672
0
      xmlAddChild(psMainNode, psNode);
673
0
    }
674
675
    /* -------------------------------------------------------------------- */
676
    /*      DescribeStoredQueries                                           */
677
    /* -------------------------------------------------------------------- */
678
0
    if (msOWSRequestIsEnabled(map, NULL, "F", "DescribeStoredQueries",
679
0
                              MS_TRUE)) {
680
681
0
      psNode = xmlAddChild(psMainNode,
682
0
                           msOWSCommonOperationsMetadataOperation(
683
0
                               psNsOws, psNsXLink, "DescribeStoredQueries",
684
0
                               OWS_METHOD_GETPOST, script_url));
685
0
      xmlAddChild(psMainNode, psNode);
686
0
    }
687
688
0
    xmlAddChild(psMainNode, msOWSCommonOperationsMetadataDomainType(
689
0
                                ows_version, psNsOws, "Parameter", "version",
690
0
                                "2.0.0,1.1.0,1.0.0"));
691
692
    /* Conformance declaration */
693
0
    xmlAddChild(psMainNode,
694
0
                msWFSConstraintDefaultValue(psNsOws, psNsOws,
695
0
                                            "ImplementsBasicWFS", "TRUE"));
696
0
    xmlAddChild(psMainNode,
697
0
                msWFSConstraintDefaultValue(
698
0
                    psNsOws, psNsOws, "ImplementsTransactionalWFS", "FALSE"));
699
0
    xmlAddChild(psMainNode,
700
0
                msWFSConstraintDefaultValue(psNsOws, psNsOws,
701
0
                                            "ImplementsLockingWFS", "FALSE"));
702
0
    xmlAddChild(psMainNode, msWFSConstraintDefaultValue(psNsOws, psNsOws,
703
0
                                                        "KVPEncoding", "TRUE"));
704
0
    xmlAddChild(psMainNode, msWFSConstraintDefaultValue(psNsOws, psNsOws,
705
0
                                                        "XMLEncoding", "TRUE"));
706
0
    xmlAddChild(psMainNode, msWFSConstraintDefaultValue(
707
0
                                psNsOws, psNsOws, "SOAPEncoding", "FALSE"));
708
0
    xmlAddChild(psMainNode,
709
0
                msWFSConstraintDefaultValue(psNsOws, psNsOws,
710
0
                                            "ImplementsInheritance", "FALSE"));
711
0
    xmlAddChild(psMainNode,
712
0
                msWFSConstraintDefaultValue(
713
0
                    psNsOws, psNsOws, "ImplementsRemoteResolve", "FALSE"));
714
0
    xmlAddChild(psMainNode,
715
0
                msWFSConstraintDefaultValue(psNsOws, psNsOws,
716
0
                                            "ImplementsResultPaging", "TRUE"));
717
0
    xmlAddChild(psMainNode,
718
0
                msWFSConstraintDefaultValue(
719
0
                    psNsOws, psNsOws, "ImplementsStandardJoins", "FALSE"));
720
0
    xmlAddChild(psMainNode,
721
0
                msWFSConstraintDefaultValue(psNsOws, psNsOws,
722
0
                                            "ImplementsSpatialJoins", "FALSE"));
723
0
    xmlAddChild(psMainNode,
724
0
                msWFSConstraintDefaultValue(
725
0
                    psNsOws, psNsOws, "ImplementsTemporalJoins", "FALSE"));
726
0
    xmlAddChild(psMainNode,
727
0
                msWFSConstraintDefaultValue(
728
0
                    psNsOws, psNsOws, "ImplementsFeatureVersioning", "FALSE"));
729
0
    xmlAddChild(psMainNode,
730
0
                msWFSConstraintDefaultValue(psNsOws, psNsOws,
731
0
                                            "ManageStoredQueries", "FALSE"));
732
733
    /* Capacity declaration */
734
0
    xmlAddChild(psMainNode,
735
0
                msWFSConstraintDefaultValue(
736
0
                    psNsOws, psNsOws, "PagingIsTransactionSafe", "FALSE"));
737
738
0
    value = msOWSLookupMetadata(&(map->web.metadata), "FO", "maxfeatures");
739
0
    if (value) {
740
0
      xmlAddChild(psMainNode, msWFSConstraintDefaultValue(
741
0
                                  psNsOws, psNsOws, "CountDefault", value));
742
0
    }
743
744
0
    xmlAddChild(psMainNode,
745
0
                msOWSCommonOperationsMetadataDomainType(
746
0
                    ows_version, psNsOws, "Constraint", "QueryExpressions",
747
0
                    "wfs:Query,wfs:StoredQuery"));
748
749
    /* Add Inspire Download Services extended capabilities */
750
0
    if (psNsInspireDls != NULL) {
751
0
      msIOContext *old_context;
752
0
      msIOContext *new_context;
753
0
      msIOBuffer *buffer;
754
0
      xmlNodePtr pRoot;
755
0
      xmlNodePtr pOWSExtendedCapabilities;
756
0
      xmlNodePtr pDlsExtendedCapabilities;
757
0
      xmlNodePtr pChild;
758
759
0
      old_context = msIO_pushStdoutToBufferAndGetOldContext();
760
0
      msOWSPrintInspireCommonExtendedCapabilities(
761
0
          stdout, map, "FO", OWS_WARN, "foo",
762
0
          "xmlns:" MS_INSPIRE_COMMON_NAMESPACE_PREFIX
763
0
          "=\"" MS_INSPIRE_COMMON_NAMESPACE_URI "\" "
764
0
          "xmlns:" MS_INSPIRE_DLS_NAMESPACE_PREFIX
765
0
          "=\"" MS_INSPIRE_DLS_NAMESPACE_URI "\" "
766
0
          "xmlns:xsi=\"" MS_OWSCOMMON_W3C_XSI_NAMESPACE_URI "\"",
767
0
          validated_language, OWS_WFS);
768
769
0
      new_context = msIO_getHandler(stdout);
770
0
      buffer = (msIOBuffer *)new_context->cbData;
771
772
      /* Remove spaces between > and < to get properly indented result */
773
0
      msXMLStripIndentation((char *)buffer->data);
774
775
0
      pInspireTmpDoc = xmlParseDoc((const xmlChar *)buffer->data);
776
0
      pRoot = xmlDocGetRootElement(pInspireTmpDoc);
777
0
      xmlReconciliateNs(psDoc, pRoot);
778
779
0
      pOWSExtendedCapabilities =
780
0
          xmlNewNode(psNsOws, BAD_CAST "ExtendedCapabilities");
781
0
      xmlAddChild(psMainNode, pOWSExtendedCapabilities);
782
783
0
      pDlsExtendedCapabilities =
784
0
          xmlNewNode(psNsInspireDls, BAD_CAST "ExtendedCapabilities");
785
0
      xmlAddChild(pOWSExtendedCapabilities, pDlsExtendedCapabilities);
786
787
0
      pChild = pRoot->children;
788
0
      while (pChild != NULL) {
789
0
        xmlNodePtr pNext = pChild->next;
790
0
        xmlUnlinkNode(pChild);
791
0
        xmlAddChild(pDlsExtendedCapabilities, pChild);
792
0
        pChild = pNext;
793
0
      }
794
795
0
      msWFSAddInspireDSID(map, psNsInspireDls, psNsInspireCommon,
796
0
                          pDlsExtendedCapabilities);
797
798
0
      msIO_restoreOldStdoutContext(old_context);
799
0
    }
800
0
  }
801
802
  /* -------------------------------------------------------------------- */
803
  /*      FeatureTypeList                                                 */
804
  /* -------------------------------------------------------------------- */
805
0
  if (msWFSIncludeSection(params, "FeatureTypeList")) {
806
0
    psFtNode = xmlNewNode(NULL, BAD_CAST "FeatureTypeList");
807
0
    xmlAddChild(psRootNode, psFtNode);
808
0
  }
809
810
0
  for (i = 0; i < map->numlayers; i++) {
811
0
    layerObj *lp;
812
0
    lp = GET_LAYER(map, i);
813
814
0
    if (!msIntegerInArray(lp->index, ows_request->enabled_layers,
815
0
                          ows_request->numlayers))
816
0
      continue;
817
818
0
    if (msIsLayerSupportedForWFSOrOAPIF(lp)) {
819
0
      if (psFtNode != NULL) {
820
0
        xmlAddChild(psFtNode, msWFSDumpLayer11(map, lp, psNsOws, OWS_2_0_0,
821
0
                                               validated_language, script_url));
822
0
      }
823
824
      /* As soon as at least one layer supports sorting, advertise sorting */
825
0
      if (msLayerSupportsSorting(lp))
826
0
        bImplementsSorting = MS_TRUE;
827
0
    }
828
0
  }
829
830
  /* -------------------------------------------------------------------- */
831
  /*      Filter capabilities.                                            */
832
  /* -------------------------------------------------------------------- */
833
0
  if (msWFSIncludeSection(params, "Filter_Capabilities")) {
834
0
    psNsFES = xmlNewNs(NULL, BAD_CAST MS_OWSCOMMON_FES_20_NAMESPACE_URI,
835
0
                       BAD_CAST MS_OWSCOMMON_FES_20_NAMESPACE_PREFIX);
836
0
    xmlAddChild(psRootNode, msWFS20FilterCapabilities(psNsFES, psNsOws,
837
0
                                                      bImplementsSorting));
838
0
  }
839
840
  /* -------------------------------------------------------------------- */
841
  /*      Write out the document.                                         */
842
  /* -------------------------------------------------------------------- */
843
844
0
  if (msIO_needBinaryStdout() == MS_FAILURE)
845
0
    return MS_FAILURE;
846
847
0
  msIO_setHeader("Content-Type", "text/xml; charset=UTF-8");
848
0
  msIO_sendHeaders();
849
850
0
  context = msIO_getHandler(stdout);
851
852
0
  xmlDocDumpFormatMemoryEnc(psDoc, &buffer, &size, ("UTF-8"), 1);
853
0
  msIO_contextWrite(context, buffer, size);
854
0
  xmlFree(buffer);
855
856
  /*free buffer and the document */
857
  /*xmlFree(buffer);*/
858
0
  xmlFreeDoc(psDoc);
859
0
  if (psNsFES != NULL)
860
0
    xmlFreeNs(psNsFES);
861
0
  if (pInspireTmpDoc != NULL)
862
0
    xmlFreeDoc(pInspireTmpDoc);
863
864
0
  free(script_url);
865
0
  msFree(validated_language);
866
867
0
  xmlCleanupParser();
868
869
0
  return (MS_SUCCESS);
870
0
}
871
872
/************************************************************************/
873
/*                       msWFSGetStoredQueries                          */
874
/*                                                                      */
875
/* Result must be freed with msFreeCharArray()                          */
876
/************************************************************************/
877
878
0
static char **msWFSGetStoredQueries(mapObj *map, int *pn) {
879
0
  const char *value;
880
0
  char **tokens;
881
0
  int i, n;
882
883
0
  value = msOWSLookupMetadata(&(map->web.metadata), "F", "storedqueries");
884
0
  if (value != NULL) {
885
0
    tokens = msStringSplit(value, ',', &n);
886
0
    for (i = 0; i < n; i++) {
887
0
      if (strcasecmp(tokens[i], URN_GET_FEATURE_BY_ID) == 0)
888
0
        break;
889
0
    }
890
    /* Add mandatory GetFeatureById stored query if not found */
891
0
    if (i == n) {
892
0
      tokens = (char **)realloc(tokens, (n + 1) * sizeof(char *));
893
0
      memmove(tokens + 1, tokens, n * sizeof(char *));
894
0
      tokens[0] = msStrdup(URN_GET_FEATURE_BY_ID);
895
0
      n++;
896
0
    }
897
0
  } else {
898
0
    tokens = (char **)malloc(sizeof(char *));
899
0
    tokens[0] = msStrdup(URN_GET_FEATURE_BY_ID);
900
0
    n = 1;
901
0
  }
902
0
  *pn = n;
903
0
  return tokens;
904
0
}
905
906
/************************************************************************/
907
/*                       msWFSGetStoredQuery                            */
908
/*                                                                      */
909
/* Result must be freed with msFree()                                   */
910
/************************************************************************/
911
912
0
static char *msWFSGetStoredQuery(mapObj *map, const char *pszURN) {
913
0
  const char *value;
914
0
  char szKey[256];
915
916
0
  snprintf(szKey, sizeof(szKey), "%s_inlinedef", pszURN);
917
0
  value = msOWSLookupMetadata(&(map->web.metadata), "F", szKey);
918
0
  if (value != NULL)
919
0
    return msStrdup(value);
920
921
0
  snprintf(szKey, sizeof(szKey), "%s_filedef", pszURN);
922
0
  value = msOWSLookupMetadata(&(map->web.metadata), "F", szKey);
923
0
  if (value != NULL) {
924
0
    FILE *f = fopen(value, "rb");
925
0
    if (f != NULL) {
926
0
      char *pszBuffer;
927
0
      int nread;
928
0
      long length;
929
930
0
      fseek(f, 0, SEEK_END);
931
0
      length = ftell(f);
932
0
      if (length < 0 || length > 1000000) {
933
0
        msSetError(MS_WFSERR, "%s: too big (%ld bytes > 1000000)",
934
0
                   "msWFSGetStoredQuery()", value, length);
935
0
        fclose(f);
936
0
      } else {
937
0
        fseek(f, 0, SEEK_SET);
938
0
        pszBuffer = (char *)malloc((int)length + 1);
939
0
        if (pszBuffer == NULL) {
940
0
          msSetError(MS_WFSERR, "Cannot allocate %d bytes to read %s",
941
0
                     "msWFSGetStoredQuery()", (int)length + 1, value);
942
0
          fclose(f);
943
0
        } else {
944
0
          nread = (int)fread(pszBuffer, 1, length, f);
945
0
          fclose(f);
946
0
          if (nread == length) {
947
0
            pszBuffer[nread] = '\0';
948
0
            return pszBuffer;
949
0
          }
950
0
          msSetError(MS_WFSERR, "Could only read %d bytes / %d of %s",
951
0
                     "msWFSGetStoredQuery()", nread, (int)length, value);
952
0
          msFree(pszBuffer);
953
0
        }
954
0
      }
955
0
    } else {
956
0
      msSetError(MS_WFSERR, "Cannot open %s", "msWFSGetStoredQuery()", value);
957
0
    }
958
0
  }
959
960
0
  if (strcasecmp(pszURN, URN_GET_FEATURE_BY_ID) == 0)
961
0
    return msStrdup(GET_FEATURE_BY_ID);
962
0
  return NULL;
963
0
}
964
965
/************************************************************************/
966
/*                     msWFSGetResolvedStoredQuery20                    */
967
/*                                                                      */
968
/* Result must be freed with msFree()                                   */
969
/************************************************************************/
970
971
char *msWFSGetResolvedStoredQuery20(mapObj *map, wfsParamsObj *wfsparams,
972
0
                                    const char *id, hashTableObj *hashTable) {
973
0
  char *storedQuery;
974
0
  xmlDocPtr psStoredQueryDoc;
975
0
  xmlNodePtr psStoredQueryRoot, pChild;
976
977
0
  storedQuery = msWFSGetStoredQuery(map, id);
978
0
  if (storedQuery == NULL) {
979
0
    msSetError(MS_WFSERR, "Unknown stored query id: %s",
980
0
               "msWFSGetResolvedStoredQuery20()", id);
981
0
    msWFSException(map, "storedqueryid", MS_OWS_ERROR_INVALID_PARAMETER_VALUE,
982
0
                   wfsparams->pszVersion);
983
0
    return NULL;
984
0
  }
985
986
0
  psStoredQueryDoc = xmlParseDoc((const xmlChar *)storedQuery);
987
0
  if (psStoredQueryDoc == NULL) {
988
0
    msSetError(MS_WFSERR, "Definition for stored query '%s' is invalid",
989
0
               "msWFSGetResolvedStoredQuery20()", id);
990
0
    msWFSException(map, "mapserv", MS_OWS_ERROR_NO_APPLICABLE_CODE,
991
0
                   wfsparams->pszVersion);
992
0
    msFree(storedQuery);
993
0
    return NULL;
994
0
  }
995
996
0
  psStoredQueryRoot = xmlDocGetRootElement(psStoredQueryDoc);
997
998
  /* Check that all parameters are provided */
999
0
  pChild = psStoredQueryRoot->children;
1000
0
  while (pChild != NULL) {
1001
0
    if (pChild->type == XML_ELEMENT_NODE &&
1002
0
        strcmp((const char *)pChild->name, "Parameter") == 0) {
1003
0
      xmlChar *parameterName = xmlGetProp(pChild, BAD_CAST "name");
1004
0
      if (parameterName != NULL) {
1005
0
        char szTmp[256];
1006
0
        const char *value =
1007
0
            msLookupHashTable(hashTable, (const char *)parameterName);
1008
0
        if (value == NULL) {
1009
0
          msSetError(MS_WFSERR, "Stored query '%s' requires parameter '%s'",
1010
0
                     "msWFSParseRequest()", id, (const char *)parameterName);
1011
0
          msWFSException(map, (const char *)parameterName,
1012
0
                         MS_OWS_ERROR_MISSING_PARAMETER_VALUE,
1013
0
                         wfsparams->pszVersion);
1014
0
          msFree(storedQuery);
1015
0
          xmlFree(parameterName);
1016
0
          xmlFreeDoc(psStoredQueryDoc);
1017
0
          return NULL;
1018
0
        }
1019
1020
0
        snprintf(szTmp, sizeof(szTmp), "${%s}", (const char *)parameterName);
1021
        // value should already be a valid XML fragment
1022
0
        storedQuery = msReplaceSubstring(storedQuery, szTmp, value);
1023
0
      }
1024
0
      xmlFree(parameterName);
1025
0
    }
1026
0
    pChild = pChild->next;
1027
0
  }
1028
1029
0
  xmlFreeDoc(psStoredQueryDoc);
1030
1031
0
  return storedQuery;
1032
0
}
1033
1034
/************************************************************************/
1035
/*                       msWFSListStoredQueries20                       */
1036
/************************************************************************/
1037
1038
0
int msWFSListStoredQueries20(mapObj *map, owsRequestObj *ows_request) {
1039
0
  xmlDocPtr psDoc;
1040
0
  xmlChar *buffer = NULL;
1041
0
  int size = 0;
1042
0
  msIOContext *context = NULL;
1043
0
  xmlNodePtr psRootNode;
1044
0
  char *xsi_schemaLocation = NULL;
1045
0
  int i, j;
1046
0
  int nStoredQueries = 0;
1047
0
  char **storedQueries = NULL;
1048
1049
0
  xmlDocPtr psStoredQueryDoc;
1050
0
  xmlNodePtr psStoredQueryRoot;
1051
1052
  /* -------------------------------------------------------------------- */
1053
  /*      Create document.                                                */
1054
  /* -------------------------------------------------------------------- */
1055
0
  psDoc = xmlNewDoc(BAD_CAST "1.0");
1056
1057
0
  psRootNode = xmlNewNode(NULL, BAD_CAST "ListStoredQueriesResponse");
1058
1059
0
  xmlDocSetRootElement(psDoc, psRootNode);
1060
1061
  /* -------------------------------------------------------------------- */
1062
  /*      Name spaces                                                     */
1063
  /* -------------------------------------------------------------------- */
1064
1065
  /*default name space*/
1066
0
  xmlNewProp(psRootNode, BAD_CAST "xmlns",
1067
0
             BAD_CAST MS_OWSCOMMON_WFS_20_NAMESPACE_URI);
1068
1069
0
  xmlSetNs(psRootNode,
1070
0
           xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_WFS_20_NAMESPACE_URI,
1071
0
                    BAD_CAST MS_OWSCOMMON_WFS_NAMESPACE_PREFIX));
1072
1073
0
  xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_W3C_XSI_NAMESPACE_URI,
1074
0
           BAD_CAST MS_OWSCOMMON_W3C_XSI_NAMESPACE_PREFIX);
1075
1076
  /*schema*/
1077
0
  xsi_schemaLocation = msStrdup(MS_OWSCOMMON_WFS_20_NAMESPACE_URI);
1078
0
  xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, " ");
1079
0
  xsi_schemaLocation =
1080
0
      msStringConcatenate(xsi_schemaLocation, msOWSGetSchemasLocation(map));
1081
0
  xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation,
1082
0
                                           MS_OWSCOMMON_WFS_20_SCHEMA_LOCATION);
1083
1084
0
  xmlNewNsProp(psRootNode, NULL, BAD_CAST "xsi:schemaLocation",
1085
0
               BAD_CAST xsi_schemaLocation);
1086
0
  free(xsi_schemaLocation);
1087
1088
  /* -------------------------------------------------------------------- */
1089
  /*      Add queries                                                     */
1090
  /* -------------------------------------------------------------------- */
1091
1092
0
  storedQueries = msWFSGetStoredQueries(map, &nStoredQueries);
1093
0
  for (i = 0; i < nStoredQueries; i++) {
1094
0
    char *query = msWFSGetStoredQuery(map, storedQueries[i]);
1095
0
    if (query != NULL) {
1096
0
      xmlNodePtr pChild;
1097
0
      xmlNodePtr psStoredQuery;
1098
1099
0
      psStoredQueryDoc = xmlParseDoc((const xmlChar *)query);
1100
0
      if (psStoredQueryDoc == NULL) {
1101
0
        char szMsg[256];
1102
0
        msFree(query);
1103
0
        snprintf(szMsg, sizeof(szMsg),
1104
0
                 "WARNING: Definition for stored query %s is invalid",
1105
0
                 storedQueries[i]);
1106
0
        xmlAddChild(psRootNode, xmlNewComment(BAD_CAST szMsg));
1107
0
        continue;
1108
0
      }
1109
1110
0
      psStoredQueryRoot = xmlDocGetRootElement(psStoredQueryDoc);
1111
1112
0
      psStoredQuery = xmlNewNode(NULL, BAD_CAST "StoredQuery");
1113
0
      xmlNewProp(psStoredQuery, BAD_CAST "id", BAD_CAST storedQueries[i]);
1114
0
      xmlAddChild(psRootNode, psStoredQuery);
1115
1116
0
      pChild = psStoredQueryRoot->children;
1117
0
      while (pChild != NULL) {
1118
0
        xmlNodePtr pNext = pChild->next;
1119
0
        if (pChild->type == XML_ELEMENT_NODE &&
1120
0
            strcmp((const char *)pChild->name, "Title") == 0) {
1121
0
          xmlUnlinkNode(pChild);
1122
0
          xmlAddChild(psStoredQuery, pChild);
1123
0
        } else if (pChild->type == XML_ELEMENT_NODE &&
1124
0
                   strcmp((const char *)pChild->name, "QueryExpressionText") ==
1125
0
                       0) {
1126
0
          xmlNodePtr psReturnFeatureType;
1127
1128
0
          if (strcasecmp(storedQueries[i], URN_GET_FEATURE_BY_ID) == 0) {
1129
0
            for (j = 0; j < map->numlayers; j++) {
1130
0
              layerObj *lp;
1131
0
              const char *user_namespace_prefix = MS_DEFAULT_NAMESPACE_PREFIX;
1132
0
              const char *user_namespace_uri = MS_DEFAULT_NAMESPACE_URI;
1133
0
              const char *value;
1134
0
              char szValue[256];
1135
1136
0
              lp = GET_LAYER(map, j);
1137
1138
0
              if (!msIntegerInArray(lp->index, ows_request->enabled_layers,
1139
0
                                    ows_request->numlayers) ||
1140
0
                  !msIsLayerSupportedForWFSOrOAPIF(lp))
1141
0
                continue;
1142
1143
0
              value = msOWSLookupMetadata(&(map->web.metadata), "FO",
1144
0
                                          "namespace_uri");
1145
0
              if (value)
1146
0
                user_namespace_uri = value;
1147
1148
0
              value = msOWSLookupMetadata(&(map->web.metadata), "FO",
1149
0
                                          "namespace_prefix");
1150
0
              if (value)
1151
0
                user_namespace_prefix = value;
1152
1153
0
              psReturnFeatureType =
1154
0
                  xmlNewNode(NULL, BAD_CAST "ReturnFeatureType");
1155
0
              xmlNewNs(psReturnFeatureType, BAD_CAST user_namespace_uri,
1156
0
                       BAD_CAST user_namespace_prefix);
1157
1158
0
              xmlAddChild(psStoredQuery, psReturnFeatureType);
1159
0
              snprintf(szValue, sizeof(szValue), "%s:%s", user_namespace_prefix,
1160
0
                       lp->name);
1161
0
              xmlAddChild(psReturnFeatureType, xmlNewText(BAD_CAST szValue));
1162
0
            }
1163
0
          } else {
1164
0
            xmlChar *returnFeatureTypes =
1165
0
                xmlGetProp(pChild, BAD_CAST "returnFeatureTypes");
1166
0
            if (returnFeatureTypes != NULL &&
1167
0
                strlen((const char *)returnFeatureTypes) > 0) {
1168
0
              int ntypes;
1169
0
              char **types =
1170
0
                  msStringSplit((const char *)returnFeatureTypes, ' ', &ntypes);
1171
0
              for (j = 0; j < ntypes; j++) {
1172
0
                psReturnFeatureType =
1173
0
                    xmlNewNode(NULL, BAD_CAST "ReturnFeatureType");
1174
0
                xmlAddChild(psStoredQuery, psReturnFeatureType);
1175
0
                xmlAddChild(psReturnFeatureType, xmlNewText(BAD_CAST types[j]));
1176
0
              }
1177
0
              msFreeCharArray(types, ntypes);
1178
0
            } else {
1179
0
              psReturnFeatureType =
1180
0
                  xmlNewNode(NULL, BAD_CAST "ReturnFeatureType");
1181
0
              xmlAddChild(psStoredQuery, psReturnFeatureType);
1182
0
              xmlAddChild(
1183
0
                  psReturnFeatureType,
1184
0
                  xmlNewComment(BAD_CAST "WARNING: Missing return type"));
1185
0
            }
1186
0
            xmlFree(returnFeatureTypes);
1187
0
          }
1188
0
        }
1189
0
        pChild = pNext;
1190
0
      }
1191
1192
0
      xmlReconciliateNs(psDoc, psStoredQuery);
1193
0
      xmlFreeDoc(psStoredQueryDoc);
1194
0
      msFree(query);
1195
0
    } else {
1196
0
      char szMsg[256];
1197
0
      snprintf(szMsg, sizeof(szMsg),
1198
0
               "WARNING: Definition for stored query %s missing",
1199
0
               storedQueries[i]);
1200
0
      xmlAddChild(psRootNode, xmlNewComment(BAD_CAST szMsg));
1201
0
    }
1202
0
  }
1203
0
  msFreeCharArray(storedQueries, nStoredQueries);
1204
1205
  /* -------------------------------------------------------------------- */
1206
  /*      Write out the document.                                         */
1207
  /* -------------------------------------------------------------------- */
1208
1209
0
  if (msIO_needBinaryStdout() == MS_FAILURE)
1210
0
    return MS_FAILURE;
1211
1212
0
  msIO_setHeader("Content-Type", "text/xml; charset=UTF-8");
1213
0
  msIO_sendHeaders();
1214
1215
0
  context = msIO_getHandler(stdout);
1216
1217
0
  xmlDocDumpFormatMemoryEnc(psDoc, &buffer, &size, ("UTF-8"), 1);
1218
0
  msIO_contextWrite(context, buffer, size);
1219
0
  xmlFree(buffer);
1220
1221
  /*free buffer and the document */
1222
  /*xmlFree(buffer);*/
1223
0
  xmlFreeDoc(psDoc);
1224
1225
0
  xmlCleanupParser();
1226
1227
0
  return (MS_SUCCESS);
1228
0
}
1229
1230
/************************************************************************/
1231
/*                     msWFSDescribeStoredQueries20                     */
1232
/************************************************************************/
1233
1234
int msWFSDescribeStoredQueries20(mapObj *map, wfsParamsObj *params,
1235
0
                                 owsRequestObj *ows_request) {
1236
0
  xmlDocPtr psDoc;
1237
0
  xmlChar *buffer = NULL;
1238
0
  int size = 0;
1239
0
  msIOContext *context = NULL;
1240
0
  xmlNodePtr psRootNode;
1241
0
  char *xsi_schemaLocation = NULL;
1242
0
  int i, j;
1243
0
  int nStoredQueries = 0;
1244
0
  char **storedQueries = NULL;
1245
1246
0
  xmlDocPtr psStoredQueryDoc;
1247
0
  xmlNodePtr psStoredQueryRoot;
1248
1249
0
  if (params->pszStoredQueryId != NULL) {
1250
0
    storedQueries =
1251
0
        msStringSplit(params->pszStoredQueryId, ',', &nStoredQueries);
1252
0
    for (i = 0; i < nStoredQueries; i++) {
1253
0
      char *query = msWFSGetStoredQuery(map, storedQueries[i]);
1254
0
      if (query == NULL) {
1255
0
        msSetError(MS_WFSERR, "Unknown stored query id: %s",
1256
0
                   "msWFSDescribeStoredQueries20()", storedQueries[i]);
1257
0
        msFreeCharArray(storedQueries, nStoredQueries);
1258
0
        return msWFSException(map, "storedqueryid",
1259
0
                              MS_OWS_ERROR_INVALID_PARAMETER_VALUE,
1260
0
                              params->pszVersion);
1261
0
      }
1262
0
      msFree(query);
1263
0
    }
1264
0
  } else {
1265
0
    storedQueries = msWFSGetStoredQueries(map, &nStoredQueries);
1266
0
  }
1267
1268
  /* -------------------------------------------------------------------- */
1269
  /*      Create document.                                                */
1270
  /* -------------------------------------------------------------------- */
1271
0
  psDoc = xmlNewDoc(BAD_CAST "1.0");
1272
1273
0
  psRootNode = xmlNewNode(NULL, BAD_CAST "DescribeStoredQueriesResponse");
1274
1275
0
  xmlDocSetRootElement(psDoc, psRootNode);
1276
1277
  /* -------------------------------------------------------------------- */
1278
  /*      Name spaces                                                     */
1279
  /* -------------------------------------------------------------------- */
1280
1281
  /*default name space*/
1282
0
  xmlNewProp(psRootNode, BAD_CAST "xmlns",
1283
0
             BAD_CAST MS_OWSCOMMON_WFS_20_NAMESPACE_URI);
1284
1285
0
  xmlSetNs(psRootNode,
1286
0
           xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_WFS_20_NAMESPACE_URI,
1287
0
                    BAD_CAST MS_OWSCOMMON_WFS_NAMESPACE_PREFIX));
1288
1289
0
  xmlNewNs(psRootNode, BAD_CAST MS_OWSCOMMON_W3C_XSI_NAMESPACE_URI,
1290
0
           BAD_CAST MS_OWSCOMMON_W3C_XSI_NAMESPACE_PREFIX);
1291
1292
  /*schema*/
1293
0
  xsi_schemaLocation = msStrdup(MS_OWSCOMMON_WFS_20_NAMESPACE_URI);
1294
0
  xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation, " ");
1295
0
  xsi_schemaLocation =
1296
0
      msStringConcatenate(xsi_schemaLocation, msOWSGetSchemasLocation(map));
1297
0
  xsi_schemaLocation = msStringConcatenate(xsi_schemaLocation,
1298
0
                                           MS_OWSCOMMON_WFS_20_SCHEMA_LOCATION);
1299
1300
0
  xmlNewNsProp(psRootNode, NULL, BAD_CAST "xsi:schemaLocation",
1301
0
               BAD_CAST xsi_schemaLocation);
1302
0
  free(xsi_schemaLocation);
1303
1304
  /* -------------------------------------------------------------------- */
1305
  /*      Add queries                                                     */
1306
  /* -------------------------------------------------------------------- */
1307
1308
0
  for (i = 0; i < nStoredQueries; i++) {
1309
0
    char *query = msWFSGetStoredQuery(map, storedQueries[i]);
1310
0
    if (query != NULL) {
1311
0
      xmlNodePtr pChild;
1312
0
      xmlNs *ns;
1313
0
      xmlNodePtr psStoredQuery;
1314
1315
0
      psStoredQueryDoc = xmlParseDoc((const xmlChar *)query);
1316
0
      if (psStoredQueryDoc == NULL) {
1317
0
        char szMsg[256];
1318
0
        msFree(query);
1319
0
        snprintf(szMsg, sizeof(szMsg),
1320
0
                 "WARNING: Definition for stored query %s is invalid",
1321
0
                 storedQueries[i]);
1322
0
        xmlAddChild(psRootNode, xmlNewComment(BAD_CAST szMsg));
1323
0
        continue;
1324
0
      }
1325
1326
0
      psStoredQueryRoot = xmlDocGetRootElement(psStoredQueryDoc);
1327
1328
0
      psStoredQuery = xmlNewNode(NULL, BAD_CAST "StoredQueryDescription");
1329
0
      xmlNewProp(psStoredQuery, BAD_CAST "id", BAD_CAST storedQueries[i]);
1330
0
      xmlAddChild(psRootNode, psStoredQuery);
1331
1332
0
      ns = psStoredQueryRoot->nsDef;
1333
0
      while (ns != NULL) {
1334
0
        xmlNewNs(psStoredQuery, BAD_CAST ns->href, BAD_CAST ns->prefix);
1335
0
        ns = ns->next;
1336
0
      }
1337
1338
0
      pChild = psStoredQueryRoot->children;
1339
0
      while (pChild != NULL) {
1340
0
        xmlNodePtr pNext = pChild->next;
1341
1342
0
        if (pChild->type == XML_ELEMENT_NODE &&
1343
0
            strcmp((const char *)pChild->name, "QueryExpressionText") == 0) {
1344
0
          if (strcasecmp(storedQueries[i], URN_GET_FEATURE_BY_ID) == 0) {
1345
0
            char **arrayNsPrefix =
1346
0
                (char **)malloc(sizeof(char *) * map->numlayers);
1347
0
            char **arrayNsUri =
1348
0
                (char **)malloc(sizeof(char *) * map->numlayers);
1349
0
            int arraysize = 0;
1350
0
            int k;
1351
0
            char *returnFeatureTypes = NULL;
1352
0
            xmlNodePtr psQueryExpressionText;
1353
1354
0
            psQueryExpressionText =
1355
0
                xmlNewNode(NULL, BAD_CAST "QueryExpressionText");
1356
0
            xmlAddChild(psStoredQuery, psQueryExpressionText);
1357
0
            xmlNewProp(psQueryExpressionText, BAD_CAST "isPrivate",
1358
0
                       BAD_CAST "true");
1359
0
            xmlNewProp(
1360
0
                psQueryExpressionText, BAD_CAST "language",
1361
0
                BAD_CAST
1362
0
                "urn:ogc:def:queryLanguage:OGC-WFS::WFS_QueryExpression");
1363
1364
0
            for (j = 0; j < map->numlayers; j++) {
1365
0
              layerObj *lp;
1366
0
              const char *user_namespace_prefix = MS_DEFAULT_NAMESPACE_PREFIX;
1367
0
              const char *user_namespace_uri = MS_DEFAULT_NAMESPACE_URI;
1368
0
              const char *value;
1369
0
              char szValue[256];
1370
1371
0
              lp = GET_LAYER(map, j);
1372
1373
0
              if (!msIntegerInArray(lp->index, ows_request->enabled_layers,
1374
0
                                    ows_request->numlayers) ||
1375
0
                  !msIsLayerSupportedForWFSOrOAPIF(lp))
1376
0
                continue;
1377
1378
0
              value = msOWSLookupMetadata(&(map->web.metadata), "FO",
1379
0
                                          "namespace_uri");
1380
0
              if (value)
1381
0
                user_namespace_uri = value;
1382
1383
0
              value = msOWSLookupMetadata(&(map->web.metadata), "FO",
1384
0
                                          "namespace_prefix");
1385
0
              if (value)
1386
0
                user_namespace_prefix = value;
1387
1388
0
              for (k = 0; k < arraysize; k++) {
1389
0
                if (strcmp(arrayNsPrefix[k], user_namespace_prefix) == 0)
1390
0
                  break;
1391
0
              }
1392
0
              if (k == arraysize) {
1393
0
                arrayNsPrefix[arraysize] = msStrdup(user_namespace_prefix);
1394
0
                arrayNsUri[arraysize] = msStrdup(user_namespace_uri);
1395
0
                arraysize++;
1396
1397
0
                xmlNewNs(psQueryExpressionText, BAD_CAST user_namespace_uri,
1398
0
                         BAD_CAST user_namespace_prefix);
1399
0
              }
1400
1401
0
              if (returnFeatureTypes != NULL)
1402
0
                returnFeatureTypes =
1403
0
                    msStringConcatenate(returnFeatureTypes, " ");
1404
0
              snprintf(szValue, sizeof(szValue), "%s:%s", user_namespace_prefix,
1405
0
                       lp->name);
1406
0
              returnFeatureTypes =
1407
0
                  msStringConcatenate(returnFeatureTypes, szValue);
1408
0
            }
1409
1410
0
            xmlNewProp(psQueryExpressionText, BAD_CAST "returnFeatureTypes",
1411
0
                       BAD_CAST returnFeatureTypes);
1412
1413
0
            msFree(returnFeatureTypes);
1414
0
            msFreeCharArray(arrayNsPrefix, arraysize);
1415
0
            msFreeCharArray(arrayNsUri, arraysize);
1416
0
          } else {
1417
0
            xmlChar *isPrivate = xmlGetProp(pChild, BAD_CAST "isPrivate");
1418
0
            if (isPrivate != NULL &&
1419
0
                strcmp((const char *)isPrivate, "true") == 0) {
1420
0
              xmlNodePtr pSubChild = xmlFirstElementChild(pChild);
1421
0
              xmlUnlinkNode(pSubChild);
1422
0
              xmlFreeNode(pSubChild);
1423
0
            }
1424
0
            xmlUnlinkNode(pChild);
1425
0
            xmlAddChild(psStoredQuery, pChild);
1426
0
            msFree(isPrivate);
1427
0
          }
1428
0
        } else {
1429
0
          xmlUnlinkNode(pChild);
1430
0
          xmlAddChild(psStoredQuery, pChild);
1431
0
        }
1432
0
        pChild = pNext;
1433
0
      }
1434
1435
0
      xmlReconciliateNs(psDoc, psStoredQuery);
1436
0
      xmlFreeDoc(psStoredQueryDoc);
1437
0
      msFree(query);
1438
0
    } else {
1439
0
      char szMsg[256];
1440
0
      snprintf(szMsg, sizeof(szMsg),
1441
0
               "WARNING: Definition for stored query %s missing",
1442
0
               storedQueries[i]);
1443
0
      xmlAddChild(psRootNode, xmlNewComment(BAD_CAST szMsg));
1444
0
    }
1445
0
  }
1446
0
  msFreeCharArray(storedQueries, nStoredQueries);
1447
1448
  /* -------------------------------------------------------------------- */
1449
  /*      Write out the document.                                         */
1450
  /* -------------------------------------------------------------------- */
1451
1452
0
  if (msIO_needBinaryStdout() == MS_FAILURE)
1453
0
    return MS_FAILURE;
1454
1455
0
  msIO_setHeader("Content-Type", "text/xml; charset=UTF-8");
1456
0
  msIO_sendHeaders();
1457
1458
0
  context = msIO_getHandler(stdout);
1459
1460
0
  xmlDocDumpFormatMemoryEnc(psDoc, &buffer, &size, ("UTF-8"), 1);
1461
0
  msIO_contextWrite(context, buffer, size);
1462
0
  xmlFree(buffer);
1463
1464
  /*free buffer and the document */
1465
  /*xmlFree(buffer);*/
1466
0
  xmlFreeDoc(psDoc);
1467
1468
0
  xmlCleanupParser();
1469
1470
0
  return (MS_SUCCESS);
1471
0
}
1472
1473
#endif /* defined(USE_WFS_SVR) && defined(USE_LIBXML2) */
1474
1475
#if defined(USE_WFS_SVR) && !defined(USE_LIBXML2)
1476
1477
int msWFSException20(mapObj *map, const char *locator,
1478
                     const char *exceptionCode) {
1479
  /* fallback to reporting using 1.0 style exceptions. */
1480
  return msWFSException(map, locator, exceptionCode, "1.0.0");
1481
}
1482
1483
int msWFSGetCapabilities20(mapObj *map, wfsParamsObj *params,
1484
                           cgiRequestObj *req, owsRequestObj *ows_request)
1485
1486
{
1487
  msSetError(MS_WFSERR,
1488
             "WFS 2.0 request made, but mapserver requires libxml2 for WFS 2.0 "
1489
             "services and this is not configured.",
1490
             "msWFSGetCapabilities20()");
1491
1492
  return msWFSException11(map, "mapserv", MS_OWS_ERROR_NO_APPLICABLE_CODE,
1493
                          params->pszVersion);
1494
}
1495
1496
int msWFSListStoredQueries20(mapObj *map, wfsParamsObj *params,
1497
                             cgiRequestObj *req, owsRequestObj *ows_request) {
1498
  msSetError(MS_WFSERR,
1499
             "WFS 2.0 request made, but mapserver requires libxml2 for WFS 2.0 "
1500
             "services and this is not configured.",
1501
             "msWFSListStoredQueries20()");
1502
1503
  return msWFSException11(map, "mapserv", MS_OWS_ERROR_NO_APPLICABLE_CODE,
1504
                          params->pszVersion);
1505
}
1506
1507
int msWFSDescribeStoredQueries20(mapObj *map, wfsParamsObj *params,
1508
                                 cgiRequestObj *req,
1509
                                 owsRequestObj *ows_request) {
1510
  msSetError(MS_WFSERR,
1511
             "WFS 2.0 request made, but mapserver requires libxml2 for WFS 2.0 "
1512
             "services and this is not configured.",
1513
             "msWFSDescribeStoredQueries20()");
1514
1515
  return msWFSException11(map, "mapserv", MS_OWS_ERROR_NO_APPLICABLE_CODE,
1516
                          params->pszVersion);
1517
}
1518
1519
char *msWFSGetResolvedStoredQuery20(mapObj *map, wfsParamsObj *params,
1520
                                    const char *id, hashTableObj *hashTable) {
1521
  msSetError(MS_WFSERR,
1522
             "WFS 2.0 request made, but mapserver requires libxml2 for WFS 2.0 "
1523
             "services and this is not configured.",
1524
             "msWFSGetResolvedStoredQuery20()");
1525
1526
  msWFSException11(map, "mapserv", MS_OWS_ERROR_NO_APPLICABLE_CODE,
1527
                   params->pszVersion);
1528
  return NULL;
1529
}
1530
1531
#endif /* defined(USE_WFS_SVR) && !defined(USE_LIBXML2) */