tinyows 1.2.2
wfs_describe.c
Go to the documentation of this file.
1/*
2 Copyright (c) <2007-2012> <Barbara Philippot - Olivier Courtin>
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20 IN THE SOFTWARE.
21*/
22
23
24#include <stdlib.h>
25#include <stdio.h>
26#include <string.h>
27#include <assert.h>
28
29#include "../ows/ows.h"
30
31
32/*
33 * Describe the layer_name in GML according
34 * with PostGIS table definition
35 */
36static void wfs_complex_type(ows * o, wfs_request * wr, buffer * layer_name)
37{
38 buffer *id_name;
39 array *table;
40 array_node *an;
41 list *mandatory_prop;
42 char * xsd_type;
43 buffer *table_name;
44 buffer *character_maximum_length;
45 buffer *constraint_name;
46 list *check_constraints;
47 list_node *ln;
48
49 assert(o);
50 assert(wr);
51 assert(layer_name);
52
53 layer_name = ows_layer_prefix_to_uri(o->layers, layer_name);
54 mandatory_prop = ows_psql_not_null_properties(o, layer_name);
55
56 fprintf(o->output, "<xs:complexType name='");
57 buffer_flush(ows_layer_no_uri(o->layers, layer_name), o->output);
58 fprintf(o->output, "Type'>\n");
59 fprintf(o->output, " <xs:complexContent>\n");
60 fprintf(o->output, " <xs:extension base='gml:AbstractFeatureType'>\n");
61 fprintf(o->output, " <xs:sequence>\n");
62
63 table = ows_psql_describe_table(o, layer_name);
64 id_name = ows_psql_id_column(o, layer_name);
65
66 assert(table);
67
68 /* Output the description of the layer_name */
69 for (an = table->first ; an ; an = an->next) {
70
71 /* Handle GML namespace */
72 if ( (ows_layer_get(o->layers, layer_name))->gml_ns
73 && in_list((ows_layer_get(o->layers, layer_name))->gml_ns, an->key)) {
74
75 if ( !strcmp("name", an->key->buf)
76 || !strcmp("description", an->key->buf)
77 || !strcmp("boundedBy", an->key->buf)) {
78 continue;
79 }
80
81 fprintf(o->output, " <xs:element ref='gml:%s'/>\n", an->key->buf);
82 continue;
83 }
84
85 /* Avoid to expose PK if not specificaly wanted */
86 if (id_name && buffer_cmp(an->key, id_name->buf) && !o->expose_pk) {
87 continue;
88 }
89 /* Avoid to expose elements in mapfile gml_exclude_items */
90 if ( (ows_layer_get(o->layers, layer_name))->exclude_items
91 && in_list((ows_layer_get(o->layers, layer_name))->exclude_items, an->key)) {
92 continue;
93 }
94
95 xsd_type = ows_psql_to_xsd(an->value, o->request->request.wfs->format);
96
97 if(!strcmp(xsd_type, "string")) {
98 table_name = ows_psql_table_name(o, layer_name);
99 /* Read string constraint from database and convert to gml restrictions*/
100 constraint_name = ows_psql_column_constraint_name(o, an->key, table_name);
101 if(strcmp(constraint_name->buf, "")) {
102 fprintf(o->output, " <xs:element name ='%s' ", an->key->buf);
103 if (mandatory_prop && in_list(mandatory_prop, an->key))
104 fprintf(o->output, "nillable='false' minOccurs='1' ");
105 else
106 fprintf(o->output, "nillable='true' minOccurs='0' ");
107 fprintf(o->output, "maxOccurs='1'>\n");
108
109 fprintf(o->output, "<xs:simpleType><xs:restriction base='string'>");
110 check_constraints = ows_psql_column_check_constraint(o, constraint_name);
111 for (ln = check_constraints->first ; ln ; ln = ln->next) {
112 fprintf(o->output, "<xs:enumeration value='%s'/>", ln->value->buf);
113 }
114 fprintf(o->output, "</xs:restriction></xs:simpleType></xs:element>");
115 } else {
116 character_maximum_length = ows_psql_column_character_maximum_length(o, an->key, table_name);
117 if(strcmp(character_maximum_length->buf, "")) {
118 fprintf(o->output, " <xs:element name ='%s' ", an->key->buf);
119 if (mandatory_prop && in_list(mandatory_prop, an->key))
120 fprintf(o->output, "nillable='false' minOccurs='1' ");
121 else
122 fprintf(o->output, "nillable='true' minOccurs='0' ");
123 fprintf(o->output, "maxOccurs='1'>\n");
124 fprintf(o->output, "<xs:simpleType><xs:restriction base='string'>");
125 fprintf(o->output, "<xs:maxLength value='%s'/>", character_maximum_length->buf);
126 fprintf(o->output, "</xs:restriction></xs:simpleType></xs:element>");
127 } else {
128 fprintf(o->output, " <xs:element name ='%s' type='%s' ",
129 an->key->buf, ows_psql_to_xsd(an->value, o->request->request.wfs->format));
130
131 if (mandatory_prop && in_list(mandatory_prop, an->key))
132 fprintf(o->output, "nillable='false' minOccurs='1' ");
133 else
134 fprintf(o->output, "nillable='true' minOccurs='0' ");
135 fprintf(o->output, "maxOccurs='1'/>\n");
136 }
137 buffer_free(character_maximum_length);
138 }
139 buffer_free(constraint_name);
140 } else {
141 fprintf(o->output, " <xs:element name ='%s' type='%s' ",
142 an->key->buf, ows_psql_to_xsd(an->value, o->request->request.wfs->format));
143
144 if (mandatory_prop && in_list(mandatory_prop, an->key))
145 fprintf(o->output, "nillable='false' minOccurs='1' ");
146 else
147 fprintf(o->output, "nillable='true' minOccurs='0' ");
148
149 fprintf(o->output, "maxOccurs='1'/>\n");
150 }
151 }
152
153 fprintf(o->output, " </xs:sequence>\n");
154 fprintf(o->output, " </xs:extension>\n");
155 fprintf(o->output, " </xs:complexContent>\n");
156 fprintf(o->output, "</xs:complexType>\n");
157}
158
159
160/*
161 * Execute the DescribeFeatureType request according to version
162 * (GML version differ between WFS 1.0.0 and WFS 1.1.0)
163 */
165{
166 int wfs_version;
167 buffer *namespace;
168 list_node *elemt, *ln;
169 list *ns_prefix, *typ, *layer_name;
170
171 assert(o && wr);
172
173 wfs_version = ows_version_get(o->request->version);
174 layer_name = ows_layer_list_prefix_to_uri(o->layers, wr->typename);
175 ns_prefix = ows_layer_list_ns_prefix(o->layers, layer_name);
176 list_free(layer_name);
177 if (!ns_prefix || !ns_prefix->first) {
178 list_free(ns_prefix);
180 "Not a single layer is available. Check config file", "describe");
181 return;
182 }
183
184 if (wr->format == WFS_GML212 || wr->format == WFS_XML_SCHEMA)
185 fprintf(o->output, "Content-Type: text/xml; subtype=gml/2.1.2;\n\n");
186 else if (wr->format == WFS_GML311)
187 fprintf(o->output, "Content-Type: text/xml; subtype=gml/3.1.1;\n\n");
188
189 fprintf(o->output, "<?xml version='1.0' encoding='%s'?>\n", o->encoding->buf);
190
191 if (buffer_cmp(ns_prefix->last->value, "gml"))
192 list_pop(ns_prefix);
193
194
195 /* if all layers belong to different prefixes, import the matching namespaces */
196 if (ns_prefix->first->next) {
197 fprintf(o->output, "<xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema'");
198 fprintf(o->output, " xmlns='http://www.w3.org/2001/XMLSchema'");
199 fprintf(o->output, " elementFormDefault='qualified'> ");
200
201 for (elemt = ns_prefix->first ; elemt ; elemt = elemt->next) {
202 if (buffer_cmp(elemt->value, "gml")) {
203 continue;
204 }
205 namespace = ows_layer_ns_prefix_to_ns_uri(o->layers, elemt->value);
206 if( namespace == NULL ) {
207 fprintf(stderr, "Cannot find namespace URI for prefix %s\n",
208 elemt->value->buf);
209 continue;
210 }
211
212 fprintf(o->output, "<xs:import namespace='%s' ", namespace->buf);
213 fprintf(o->output, "schemaLocation='%s?service=WFS&amp;version=",
214 o->online_resource->buf);
215
216 if (wfs_version == 100)
217 fprintf(o->output, "1.0.0&amp;request=DescribeFeatureType&amp;typename=");
218 else
219 fprintf(o->output, "1.1.0&amp;request=DescribeFeatureType&amp;typename=");
220
221 /* print the describeFeatureType request with typenames for each prefix */
222 typ = ows_layer_list_by_ns_prefix(o->layers, wr->typename, elemt->value);
223
224 for (ln = typ->first ; ln ; ln = ln->next) {
225 fprintf(o->output, "%s", ln->value->buf);
226
227 if (ln->next) fprintf(o->output, ",");
228 }
229
230 list_free(typ);
231 fprintf(o->output, "' />\n\n");
232 }
233
234 fprintf(o->output, "</xs:schema>\n");
235 }
236 /* if all layers belong to the same prefix, print the xsd schema describing features */
237 else {
238 namespace = ows_layer_ns_prefix_to_ns_uri(o->layers, ns_prefix->first->value);
239 fprintf(o->output, "<xs:schema targetNamespace='%s' ", namespace->buf);
240 fprintf(o->output, "xmlns:%s='%s' ", ns_prefix->first->value->buf, namespace->buf);
241 fprintf(o->output, "xmlns:ogc='http://www.opengis.net/ogc' ");
242 fprintf(o->output, "xmlns:xs='http://www.w3.org/2001/XMLSchema' ");
243 fprintf(o->output, "xmlns='http://www.w3.org/2001/XMLSchema' ");
244 fprintf(o->output, "xmlns:gml='http://www.opengis.net/gml' ");
245 fprintf(o->output, "elementFormDefault='qualified' ");
246
247 if (wfs_version == 100) fprintf(o->output, "version='1.0'>\n");
248 else fprintf(o->output, "version='1.1'>\n");
249
250 fprintf(o->output, "<xs:import namespace='http://www.opengis.net/gml'");
251
252 if (wfs_version == 100)
253 fprintf(o->output, " schemaLocation='http://schemas.opengis.net/gml/2.1.2/feature.xsd'/>\n");
254 else
255 fprintf(o->output, " schemaLocation='http://schemas.opengis.net/gml/3.1.1/base/gml.xsd'/>\n");
256
257 /* Describe each feature type specified in the request */
258 for (elemt = wr->typename->first ; elemt ; elemt = elemt->next) {
259 fprintf(o->output, "<xs:element name='");
260 buffer_flush(ows_layer_no_uri(o->layers, ows_layer_prefix_to_uri(o->layers, elemt->value)), o->output);
261 fprintf(o->output, "' type='");
262 buffer_flush(elemt->value, o->output);
263 fprintf(o->output, "Type' substitutionGroup='gml:_Feature' />\n");
264 wfs_complex_type(o, wr, elemt->value);
265 }
266
267 fprintf(o->output, "</xs:schema>");
268 }
269
270 list_free(ns_prefix);
271}
272
273
274/*
275 * Generate a WFS Schema related to current Server (all valid layers)
276 * with GML XSD import
277 * This is needed by WFS Insert operation validation as libxml2 only handle
278 * a single schema validation at a time
279 */
281{
282 list *ns_prefix, *typename, *layers, *layers_name_prefix;
283 buffer *namespace, *schema;
284 list_node *elemt, *t;
285 int wfs_version;
286
287 assert(o && version);
288
289 schema = buffer_init();
290 wfs_version = ows_version_get(version);
292
293 layers_name_prefix = list_init();
294 for (elemt = layers->first; elemt ; elemt = elemt->next) {
295 list_add_by_copy(layers_name_prefix, ows_layer_uri_to_prefix(o->layers, elemt->value));
296 }
297
298 buffer_add_str(schema, "<?xml version='1.0' encoding='utf-8'?>\n");
299
300 ns_prefix = ows_layer_list_ns_prefix(o->layers, layers);
301
302 buffer_add_str(schema, "<xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema'");
303 buffer_add_str(schema, " xmlns='http://www.w3.org/2001/XMLSchema' elementFormDefault='qualified'>\n");
304 buffer_add_str(schema, "<xs:import namespace='http://www.opengis.net/wfs' schemaLocation='");
305 buffer_copy(schema, o->schema_dir);
306
307 if (wfs_version == 100) buffer_add_str(schema, WFS_SCHEMA_100);
308 else buffer_add_str(schema, WFS_SCHEMA_110);
309
310 buffer_add_str(schema, "'/>\n");
311
312 for (elemt = ns_prefix->first ; elemt ; elemt = elemt->next) {
313 if (buffer_cmp(elemt->value, "gml")) {
314 continue;
315 }
316 namespace = ows_layer_ns_prefix_to_ns_uri(o->layers, elemt->value);
317 if( namespace == NULL ) {
318 fprintf(stderr, "Cannot find namespace URI for prefix %s\n",
319 elemt->value->buf);
320 continue;
321 }
322 buffer_add_str(schema, "<xs:import namespace='");
323 buffer_copy(schema, namespace);
324 buffer_add_str(schema, "' schemaLocation='");
325
326 buffer_copy(schema, o->online_resource);
327 buffer_add_str(schema, "?service=WFS&amp;request=DescribeFeatureType");
328
329 if (elemt->next || elemt != ns_prefix->first) {
330 buffer_add_str(schema, "&amp;Typename=");
331
332 typename = ows_layer_list_by_ns_prefix(o->layers, layers_name_prefix, elemt->value);
333 for (t = typename->first ; t ; t = t->next) {
334 buffer_copy(schema, t->value);
335 if (t->next) buffer_add(schema, ',');
336 }
337 list_free(typename);
338 }
339
340 if (wfs_version == 100) buffer_add_str(schema, "&amp;version=1.0.0");
341 else buffer_add_str(schema, "&amp;version=1.1.0");
342
343 buffer_add_str(schema, "'/>\n");
344 }
345
346 buffer_add_str(schema, "</xs:schema>");
347 list_free(ns_prefix);
348 list_free(layers);
349 list_free(layers_name_prefix);
350
351 return schema;
352}
list * ows_psql_not_null_properties(ows *o, buffer *layer_name)
Definition ows_psql.c:185
void buffer_add(buffer *buf, char c)
Definition buffer.c:123
int ows_version_get(ows_version *v)
void list_add_by_copy(list *l, buffer *value)
Definition list.c:187
buffer * ows_psql_column_constraint_name(ows *o, buffer *column_name, buffer *table_name)
Definition ows_psql.c:206
void buffer_copy(buffer *dest, const buffer *src)
Definition buffer.c:350
buffer * ows_psql_column_character_maximum_length(ows *o, buffer *column_name, buffer *table_name)
Definition ows_psql.c:335
bool buffer_cmp(const buffer *buf, const char *str)
Definition buffer.c:290
bool in_list(const list *l, const buffer *value)
Definition list.c:259
void list_free(list *l)
Definition list.c:54
void buffer_add_str(buffer *buf, const char *str)
Definition buffer.c:254
list * list_init()
Definition list.c:36
void buffer_flush(buffer *buf, FILE *output)
Definition buffer.c:112
buffer * ows_psql_id_column(ows *o, buffer *layer_name)
Definition ows_psql.c:36
void ows_error(ows *o, enum ows_error_code code, char *message, char *locator)
Definition ows_error.c:71
buffer * ows_layer_ns_prefix_to_ns_uri(ows_layer_list *ll, buffer *ns_prefix)
Definition ows_layer.c:359
list * ows_psql_column_check_constraint(ows *o, buffer *constraint_name)
Definition ows_psql.c:244
list * ows_layer_list_ns_prefix(ows_layer_list *ll, list *layer_name_prefix)
Definition ows_layer.c:281
array * ows_psql_describe_table(ows *o, buffer *layer_name)
Definition ows_psql.c:373
void buffer_free(buffer *buf)
Definition buffer.c:83
list * ows_layer_list_having_storage(const ows_layer_list *ll)
Definition ows_layer.c:105
buffer * ows_layer_uri_to_prefix(ows_layer_list *ll, buffer *layer_name)
Definition ows_layer.c:327
char * ows_psql_to_xsd(buffer *type, enum wfs_format format)
Definition ows_psql.c:445
buffer * ows_layer_no_uri(ows_layer_list *ll, buffer *layer_name)
Definition ows_layer.c:376
ows_layer * ows_layer_get(const ows_layer_list *ll, const buffer *name)
Definition ows_layer.c:66
void list_pop(list *l)
Definition list.c:129
list * ows_layer_list_prefix_to_uri(ows_layer_list *ll, list *layer_name_prefix)
Definition ows_layer.c:308
list * ows_layer_list_by_ns_prefix(ows_layer_list *ll, list *layer_name_prefix, buffer *ns_prefix)
Definition ows_layer.c:255
buffer * buffer_init()
Definition buffer.c:61
buffer * ows_psql_table_name(ows *o, buffer *layer_name)
Definition ows_psql.c:116
buffer * ows_layer_prefix_to_uri(ows_layer_list *ll, buffer *layer_name_prefix)
Definition ows_layer.c:343
#define WFS_SCHEMA_100
Definition ows_define.h:36
#define WFS_SCHEMA_110
Definition ows_define.h:37
@ WFS_XML_SCHEMA
Definition ows_struct.h:279
@ WFS_GML311
Definition ows_struct.h:281
@ WFS_GML212
Definition ows_struct.h:280
@ OWS_ERROR_CONFIG_FILE
Definition ows_struct.h:165
wfs_request
Definition ows_struct.h:269
buffer * value
Definition ows_struct.h:83
buffer * key
Definition ows_struct.h:82
struct Array_node * next
Definition ows_struct.h:84
array_node * first
Definition ows_struct.h:88
char * buf
size to next realloc
Definition ows_struct.h:39
struct List_node * next
Definition ows_struct.h:45
buffer * value
Definition ows_struct.h:44
list_node * last
Definition ows_struct.h:51
list_node * first
Definition ows_struct.h:50
union Ows_request::@0 request
ows_version * version
Definition ows_struct.h:353
wfs_request * wfs
Definition ows_struct.h:357
ows_request * request
Definition ows_struct.h:403
buffer * encoding
Definition ows_struct.h:375
bool expose_pk
Definition ows_struct.h:394
buffer * schema_dir
Definition ows_struct.h:372
ows_layer_list * layers
Definition ows_struct.h:402
FILE * output
Definition ows_struct.h:382
buffer * wfs_generate_schema(ows *o, ows_version *version)
void wfs_describe_feature_type(ows *o, wfs_request *wr)
static void wfs_complex_type(ows *o, wfs_request *wr, buffer *layer_name)

Generated for tinyows by doxygen 1.12.0