Project

General

Profile

Download (23.3 KB) Statistics
| Branch: | Tag: | Revision:
1
/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
2
 * full list of contributors). Published under the 2-clause BSD license.
3
 * See license.txt in the OpenLayers distribution or repository for the
4
 * full text of the license. */
5

    
6
/**
7
 * @requires OpenLayers/Format/XML.js
8
 * @requires OpenLayers/Format/KML.js
9
 * @requires OpenLayers/Format/GML.js
10
 * @requires OpenLayers/Format/GML/v2.js
11
 * @requires OpenLayers/Format/SLD/v1_0_0.js
12
 * @requires OpenLayers/Format/OWSContext.js
13
 * @requires OpenLayers/Format/OWSCommon/v1_0_0.js
14
 */
15

    
16
/**
17
 * Class: OpenLayers.Format.OWSContext.v0_3_1
18
 * Read and write OWSContext version 0.3.1.
19
 *
20
 * Inherits from:
21
 *  - <OpenLayers.Format.XML>
22
 */
23
OpenLayers.Format.OWSContext.v0_3_1 = OpenLayers.Class(OpenLayers.Format.XML, {
24
    
25
    /**
26
     * Property: namespaces
27
     * {Object} Mapping of namespace aliases to namespace URIs.
28
     */
29
    namespaces: {
30
        owc: "http://www.opengis.net/ows-context",
31
        gml: "http://www.opengis.net/gml",
32
        kml: "http://www.opengis.net/kml/2.2",
33
        ogc: "http://www.opengis.net/ogc",
34
        ows: "http://www.opengis.net/ows",
35
        sld: "http://www.opengis.net/sld",
36
        xlink: "http://www.w3.org/1999/xlink",
37
        xsi: "http://www.w3.org/2001/XMLSchema-instance"
38
    },
39

    
40
    /**
41
     * Constant: VERSION
42
     * {String} 0.3.1
43
     */
44
    VERSION: "0.3.1", 
45

    
46
    /**
47
     * Property: schemaLocation
48
     * {String} Schema location
49
     */
50
    schemaLocation: "http://www.opengis.net/ows-context http://www.ogcnetwork.net/schemas/owc/0.3.1/owsContext.xsd",
51

    
52
    /**
53
     * Property: defaultPrefix
54
     * {String} Default namespace prefix to use.
55
     */
56
    defaultPrefix: "owc",
57

    
58
    /**
59
     * APIProperty: extractAttributes
60
     * {Boolean} Extract attributes from GML.  Default is true.
61
     */
62
    extractAttributes: true,
63
    
64
    /**
65
     * APIProperty: xy
66
     * {Boolean} Order of the GML coordinate true:(x,y) or false:(y,x)
67
     * Changing is not recommended, a new Format should be instantiated.
68
     */ 
69
    xy: true, 
70

    
71
    /**
72
     * Property: regExes
73
     * Compiled regular expressions for manipulating strings.
74
     */
75
    regExes: {
76
        trimSpace: (/^\s*|\s*$/g),
77
        removeSpace: (/\s*/g),
78
        splitSpace: (/\s+/),
79
        trimComma: (/\s*,\s*/g)
80
    },
81

    
82
    /**
83
     * Property: featureNS
84
     * {String} The namespace uri to use for writing InlineGeometry
85
     */
86
    featureNS: "http://mapserver.gis.umn.edu/mapserver",
87

    
88
    /**
89
     * Property: featureType
90
     * {String} The name to use as the feature type when writing out
91
     *     InlineGeometry
92
     */
93
    featureType: 'vector',
94
              
95
    /**
96
     * Property: geometryName
97
     * {String} The name to use for the geometry attribute when writing out
98
     *     InlineGeometry
99
     */
100
    geometryName: 'geometry',
101

    
102
    /**
103
     * Property: nestingLayerLookup
104
     * {Object} Hashtable lookup for nesting layer nodes. Used while writing 
105
     *     the OWS context document. It is necessary to keep track of the 
106
     *     nestingPaths for which nesting layer nodes have already been 
107
     *     created, so (nesting) layer nodes are added to those nodes.
108
     *
109
     * For example:
110
     *
111
     *     If there are three layers with nestingPaths:
112
     *         layer1.metadata.nestingPath = "a/b/"
113
     *         layer2.metadata.nestingPath = "a/b/"
114
     *         layer2.metadata.nestingPath = "a/c"
115
     *
116
     *     then a nesting layer node "a" should be created once and added 
117
     *     to the resource list, a nesting layer node "b" should be created 
118
     *     once and added under "a", and a nesting layer node "c" should be 
119
     *     created and added under "a". The lookup paths for these nodes 
120
     *     will be "a", "a/b", and "a/c" respectively.
121
     */
122
    nestingLayerLookup: null,
123

    
124
    /**
125
     * Constructor: OpenLayers.Format.OWSContext.v0_3_1
126
     * Instances of this class are not created directly.  Use the
127
     *     <OpenLayers.Format.OWSContext> constructor instead.
128
     *
129
     * Parameters:
130
     * options - {Object} An optional object whose properties will be set on
131
     *     this instance.
132
     */
133
    initialize: function(options) {
134
        OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
135
        OpenLayers.Format.GML.v2.prototype.setGeometryTypes.call(this);
136
    },
137

    
138
    /**
139
     * Method: setNestingPath
140
     * Set the nestingPath property of the layer depending on the position
141
     *     of the layer in hierarchy of layers.
142
     *
143
     * Parameters:
144
     * l - {Object} An object that may have a layersContext array property.
145
     * 
146
     */
147
    setNestingPath : function(l){
148
        if(l.layersContext){
149
            for (var i = 0, len = l.layersContext.length; i < len; i++) {
150
                var layerContext = l.layersContext[i];
151
                var nPath = [];
152
                var nTitle = l.title || "";
153
                if(l.metadata && l.metadata.nestingPath){
154
                    nPath = l.metadata.nestingPath.slice();
155
                }
156
                if (nTitle != "") {
157
                    nPath.push(nTitle);
158
                }
159
                layerContext.metadata.nestingPath = nPath;
160
                if(layerContext.layersContext){
161
                    this.setNestingPath(layerContext);
162
                }
163
            }
164
        }
165
    },
166

    
167
    /**
168
     * Function: decomposeNestingPath
169
     * Takes a nestingPath like "a/b/c" and decomposes it into subpaths:
170
     * "a", "a/b", "a/b/c"
171
     *
172
     * Parameters:
173
     * nPath  - {Array} the nesting path
174
     *
175
     * Returns:
176
     * Array({String}) Array with subpaths, or empty array if there is nothing
177
     *     to decompose
178
     */
179
    decomposeNestingPath: function(nPath){
180
        var a = [];
181
        if (OpenLayers.Util.isArray(nPath)) {
182
            var path = nPath.slice();
183
            while (path.length > 0) {
184
                a.push(path.slice());
185
                path.pop();
186
            }
187
            a.reverse();
188
        }
189
        return a;
190
    },
191

    
192
    /**
193
     * APIMethod: read
194
     * Read OWS context data from a string or DOMElement, and return a list 
195
     *     of layers. 
196
     * 
197
     * Parameters: 
198
     * data - {String} or {DOMElement} data to read/parse.
199
     *
200
     * Returns:
201
     * {Object} The context object with a flat layer list as a property named
202
     *     layersContext.
203
     */
204
    read: function(data) {
205
        if(typeof data == "string") {
206
            data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
207
        }
208
        if(data && data.nodeType == 9) {
209
            data = data.documentElement;
210
        }
211
        var context = {};
212
        this.readNode(data, context);
213
        // since an OWSContext can be nested we need to go through this
214
        // structure recursively      
215
        this.setNestingPath({layersContext : context.layersContext});
216
        // after nesting path has been set, create a flat list of layers
217
        var layers = [];
218
        this.processLayer(layers, context);
219
        delete context.layersContext;
220
        context.layersContext = layers;
221
        return context;
222
    },
223

    
224
    /**
225
     * Method: processLayer
226
     * Recursive function to get back a flat list of layers from the hierarchic
227
     *     layer structure.
228
     *
229
     * Parameters:
230
     * layerArray - {Array({Object})} Array of layerContext objects
231
     * layer - {Object} layerContext object
232
     */
233
    processLayer: function(layerArray, layer) {
234
        if (layer.layersContext) {
235
            for (var i=0, len = layer.layersContext.length; i<len; i++) {
236
                var l = layer.layersContext[i];
237
                layerArray.push(l);
238
                if (l.layersContext) {
239
                    this.processLayer(layerArray, l);
240
                }
241
            }
242
        }
243
    },
244

    
245
    /**
246
     * APIMethod: write
247
     *
248
     * Parameters:
249
     * context - {Object} An object representing the map context.
250
     * options - {Object} Optional object.
251
     *
252
     * Returns:
253
     * {String} An OWS Context document string.
254
     */
255
    write: function(context, options) {
256
        var name = "OWSContext";
257
        this.nestingLayerLookup = {}; //start with empty lookup
258
        options = options || {};
259
        OpenLayers.Util.applyDefaults(options, context);
260
        var root = this.writeNode(name, options);
261
        this.nestingLayerLookup = null; //clear lookup
262
        this.setAttributeNS(
263
            root, this.namespaces["xsi"],
264
            "xsi:schemaLocation", this.schemaLocation
265
        );
266
        return OpenLayers.Format.XML.prototype.write.apply(this, [root]);
267
    }, 
268

    
269
    /**
270
     * Property: readers
271
     * Contains public functions, grouped by namespace prefix, that will
272
     *     be applied when a namespaced node is found matching the function
273
     *     name.  The function will be applied in the scope of this parser
274
     *     with two arguments: the node being read and a context object passed
275
     *     from the parent.
276
     */
277
    readers: {
278
        "kml": {
279
            "Document": function(node, obj) {
280
                obj.features = new OpenLayers.Format.KML(
281
                    {kmlns: this.namespaces.kml, 
282
                        extractStyles: true}).read(node);
283
            }
284
        },
285
        "owc": { 
286
            "OWSContext": function(node, obj) {
287
                this.readChildNodes(node, obj);
288
            }, 
289
            "General": function(node, obj) {
290
                this.readChildNodes(node, obj);
291
            },
292
            "ResourceList": function(node, obj) {
293
                this.readChildNodes(node, obj);
294
            },
295
            "Layer": function(node, obj) {
296
                var layerContext = {
297
                    metadata: {},
298
                    visibility: (node.getAttribute("hidden") != "1"),
299
                    queryable: (node.getAttribute("queryable") == "1"),
300
                    opacity: ((node.getAttribute("opacity") != null) ? 
301
                        parseFloat(node.getAttribute("opacity")) : null),
302
                    name: node.getAttribute("name"),
303
                    /* A category layer is a dummy layer meant for creating
304
                       hierarchies. It is not a physical layer in the 
305
                       OpenLayers sense. The assumption we make here is that
306
                       category layers do not have a name attribute */
307
                    categoryLayer: (node.getAttribute("name") == null),
308
                    formats: [],
309
                    styles: []
310
                };
311
                if (!obj.layersContext) {
312
                    obj.layersContext = [];
313
                }
314
                obj.layersContext.push(layerContext);
315
                this.readChildNodes(node, layerContext);
316
            },
317
            "InlineGeometry": function(node, obj) {
318
                obj.features = [];
319
                var elements = this.getElementsByTagNameNS(node, 
320
                    this.namespaces.gml, "featureMember");
321
                var el;
322
                if (elements.length >= 1) {
323
                    el = elements[0];
324
                }
325
                if (el && el.firstChild) {
326
                    var featurenode = (el.firstChild.nextSibling) ? 
327
                        el.firstChild.nextSibling : el.firstChild;
328
                    this.setNamespace("feature", featurenode.namespaceURI);
329
                    this.featureType = featurenode.localName || 
330
                        featurenode.nodeName.split(":").pop();
331
                    this.readChildNodes(node, obj);
332
                }
333
            },
334
            "Server": function(node, obj) {
335
                // when having multiple Server types, we prefer WMS
336
                if ((!obj.service && !obj.version) || 
337
                    (obj.service != 
338
                        OpenLayers.Format.Context.serviceTypes.WMS)) {
339
                            obj.service = node.getAttribute("service");
340
                            obj.version = node.getAttribute("version");
341
                            this.readChildNodes(node, obj);
342
                }
343
            },
344
            "Name": function(node, obj) {
345
                obj.name = this.getChildValue(node);
346
                this.readChildNodes(node, obj);
347
            },
348
            "Title": function(node, obj) {
349
                obj.title = this.getChildValue(node);
350
                this.readChildNodes(node, obj);
351
            },
352
            "StyleList": function(node, obj) {
353
                this.readChildNodes(node, obj.styles);
354
            },
355
            "Style": function(node, obj) {
356
                var style = {};
357
                obj.push(style);
358
                this.readChildNodes(node, style);
359
            },
360
            "LegendURL": function(node, obj) {
361
                var legend = {};
362
                obj.legend = legend;
363
                this.readChildNodes(node, legend);
364
            },
365
            "OnlineResource": function(node, obj) {
366
                obj.url = this.getAttributeNS(node, this.namespaces.xlink, 
367
                    "href");
368
                this.readChildNodes(node, obj);
369
            }
370
        },
371
        "ows": OpenLayers.Format.OWSCommon.v1_0_0.prototype.readers.ows,
372
        "gml": OpenLayers.Format.GML.v2.prototype.readers.gml,
373
        "sld": OpenLayers.Format.SLD.v1_0_0.prototype.readers.sld,
374
        "feature": OpenLayers.Format.GML.v2.prototype.readers.feature
375
    },
376

    
377
    /**
378
     * Property: writers
379
     * As a compliment to the readers property, this structure contains public
380
     *     writing functions grouped by namespace alias and named like the
381
     *     node names they produce.
382
     */
383
    writers: {
384
        "owc": {
385
            "OWSContext": function(options) {
386
                var node = this.createElementNSPlus("OWSContext", {
387
                    attributes: {
388
                        version: this.VERSION,
389
                        id: options.id || OpenLayers.Util.createUniqueID("OpenLayers_OWSContext_")
390
                    } 
391
                }); 
392
                this.writeNode("General", options, node);
393
                this.writeNode("ResourceList", options, node);
394
                return node; 
395
            },
396
            "General": function(options) {
397
                var node = this.createElementNSPlus("General");
398
                this.writeNode("ows:BoundingBox", options, node);
399
                this.writeNode("ows:Title", options.title || 'OpenLayers OWSContext', node);
400
                return node;
401
            },
402
            "ResourceList": function(options) {
403
                var node = this.createElementNSPlus("ResourceList");
404
                for (var i=0, len=options.layers.length; i<len; i++) {
405
                    var layer = options.layers[i];
406
                    var decomposedPath = this.decomposeNestingPath(layer.metadata.nestingPath);
407
                    this.writeNode("_Layer", {layer: layer, subPaths: decomposedPath}, node);
408
                }
409
                return node;
410
            },
411
            "Server": function(options) {
412
                var node = this.createElementNSPlus("Server", {attributes: {
413
                    version: options.version,
414
                    service: options.service }
415
                });
416
                this.writeNode("OnlineResource", options, node);
417
                return node;
418
            },
419
            "OnlineResource": function(options) {
420
                var node = this.createElementNSPlus("OnlineResource", {attributes: {
421
                    "xlink:href": options.url }
422
                });
423
                return node;
424
            },
425
            "InlineGeometry": function(layer) {
426
                var node = this.createElementNSPlus("InlineGeometry"),
427
                    dataExtent = layer.getDataExtent();
428
                if (dataExtent !== null) {
429
                    this.writeNode("gml:boundedBy", dataExtent, node);
430
                }
431
                for (var i=0, len=layer.features.length; i<len; i++) {
432
                    this.writeNode("gml:featureMember", layer.features[i], node);
433
                }
434
                return node;
435
            },
436
            "StyleList": function(styles) {
437
                var node = this.createElementNSPlus("StyleList");
438
                for (var i=0, len=styles.length; i<len; i++) {
439
                    this.writeNode("Style", styles[i], node);
440
                }
441
                return node;
442
            },
443
            "Style": function(style) {
444
                var node = this.createElementNSPlus("Style");
445
                this.writeNode("Name", style, node);
446
                this.writeNode("Title", style, node);
447
                if (style.legend) {
448
                    this.writeNode("LegendURL", style, node);
449
                }
450
                return node;
451
            },
452
            "Name": function(obj) {
453
                var node = this.createElementNSPlus("Name", {
454
                    value: obj.name });
455
                return node;
456
            },
457
            "Title": function(obj) {
458
                var node = this.createElementNSPlus("Title", {
459
                    value: obj.title });
460
                return node;
461
            },
462
            "LegendURL": function(style) {
463
                var node = this.createElementNSPlus("LegendURL");
464
                this.writeNode("OnlineResource", style.legend, node);
465
                return node;
466
            },
467
            "_WMS": function(layer) {
468
                var node = this.createElementNSPlus("Layer", {attributes: {
469
                    name: layer.params.LAYERS,
470
                    queryable: layer.queryable ? "1" : "0",
471
                    hidden: layer.visibility ? "0" : "1",
472
                    opacity: layer.hasOwnProperty("opacity") ? layer.opacity : null}
473
                });
474
                this.writeNode("ows:Title", layer.name, node);
475
                this.writeNode("ows:OutputFormat", layer.params.FORMAT, node);
476
                this.writeNode("Server", {service: 
477
                    OpenLayers.Format.Context.serviceTypes.WMS,
478
                    version: layer.params.VERSION, url: layer.url}, node);
479
                if (layer.metadata.styles && layer.metadata.styles.length > 0) {
480
                    this.writeNode("StyleList", layer.metadata.styles, node);
481
                }
482
                return node;
483
            },
484
            "_Layer": function(options) {
485
                var layer, subPaths, node, title;
486
                layer = options.layer;
487
                subPaths = options.subPaths;
488
                node = null;
489
                title = null;
490
                // subPaths is an array of an array
491
                // recursively calling _Layer writer eats up subPaths, until a 
492
                // real writer is called and nodes are returned.
493
                if(subPaths.length > 0){
494
                    var path = subPaths[0].join("/");
495
                    var index = path.lastIndexOf("/");
496
                    node = this.nestingLayerLookup[path];
497
                    title = (index > 0)?path.substring(index + 1, path.length):path;
498
                    if(!node){
499
                        // category layer
500
                        node = this.createElementNSPlus("Layer");
501
                        this.writeNode("ows:Title", title, node);
502
                        this.nestingLayerLookup[path] = node;
503
                    }
504
                    options.subPaths.shift();//remove a path after each call
505
                    this.writeNode("_Layer", options, node);
506
                    return node;
507
                } else {
508
                    // write out the actual layer
509
                    if (layer instanceof OpenLayers.Layer.WMS) {
510
                        node = this.writeNode("_WMS", layer);
511
                    } else if (layer instanceof OpenLayers.Layer.Vector) {
512
                        if (layer.protocol instanceof OpenLayers.Protocol.WFS.v1) {
513
                            node = this.writeNode("_WFS", layer);
514
                        } else if (layer.protocol instanceof OpenLayers.Protocol.HTTP) {
515
                            if (layer.protocol.format instanceof OpenLayers.Format.GML) {
516
                                layer.protocol.format.version = "2.1.2";
517
                                node = this.writeNode("_GML", layer);
518
                            } else if (layer.protocol.format instanceof OpenLayers.Format.KML) {
519
                                layer.protocol.format.version = "2.2";
520
                                node = this.writeNode("_KML", layer);
521
                            }
522
                        } else {
523
                            // write out as inline GML since we have no idea
524
                            // about the original Format
525
                            this.setNamespace("feature", this.featureNS);
526
                            node = this.writeNode("_InlineGeometry", layer);
527
                        }
528
                    }
529
                    if (layer.options.maxScale) {
530
                        this.writeNode("sld:MinScaleDenominator", 
531
                            layer.options.maxScale, node);
532
                    }
533
                    if (layer.options.minScale) {
534
                        this.writeNode("sld:MaxScaleDenominator", 
535
                            layer.options.minScale, node);
536
                    }
537
                    this.nestingLayerLookup[layer.name] = node;
538
                    return node;
539
                }
540
            },
541
            "_WFS": function(layer) {
542
                var node = this.createElementNSPlus("Layer", {attributes: {
543
                    name: layer.protocol.featurePrefix + ":" + layer.protocol.featureType,
544
                    hidden: layer.visibility ? "0" : "1" }
545
                });
546
                this.writeNode("ows:Title", layer.name, node);
547
                this.writeNode("Server", {service: 
548
                    OpenLayers.Format.Context.serviceTypes.WFS, 
549
                    version: layer.protocol.version, 
550
                    url: layer.protocol.url}, node);
551
                return node;
552
            },
553
            "_InlineGeometry": function(layer) {
554
                var node = this.createElementNSPlus("Layer", {attributes: {
555
                    name: this.featureType,
556
                    hidden: layer.visibility ? "0" : "1" }
557
                });
558
                this.writeNode("ows:Title", layer.name, node);
559
                this.writeNode("InlineGeometry", layer, node);
560
                return node;
561
            },
562
            "_GML": function(layer) {
563
                var node = this.createElementNSPlus("Layer");
564
                this.writeNode("ows:Title", layer.name, node);
565
                this.writeNode("Server", {service: 
566
                    OpenLayers.Format.Context.serviceTypes.GML, 
567
                    url: layer.protocol.url, version: 
568
                    layer.protocol.format.version}, node);
569
                return node;
570
            },
571
            "_KML": function(layer) {
572
                var node = this.createElementNSPlus("Layer");
573
                this.writeNode("ows:Title", layer.name, node);
574
                this.writeNode("Server", {service: 
575
                    OpenLayers.Format.Context.serviceTypes.KML,
576
                    version: layer.protocol.format.version, url: 
577
                    layer.protocol.url}, node);
578
                return node;
579
            }
580
        },
581
        "gml": OpenLayers.Util.applyDefaults({
582
            "boundedBy": function(bounds) {
583
                var node = this.createElementNSPlus("gml:boundedBy");
584
                this.writeNode("gml:Box", bounds, node);
585
                return node;
586
            }
587
        }, OpenLayers.Format.GML.v2.prototype.writers.gml),
588
        "ows": OpenLayers.Format.OWSCommon.v1_0_0.prototype.writers.ows,
589
        "sld": OpenLayers.Format.SLD.v1_0_0.prototype.writers.sld,
590
        "feature": OpenLayers.Format.GML.v2.prototype.writers.feature
591
    },
592
    
593
    CLASS_NAME: "OpenLayers.Format.OWSContext.v0_3_1" 
594

    
595
});
    (1-1/1)