Project

General

Profile

Download (34.6 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/Feature/Vector.js
9
 * @requires OpenLayers/Geometry/Point.js
10
 * @requires OpenLayers/Geometry/MultiPoint.js
11
 * @requires OpenLayers/Geometry/LineString.js
12
 * @requires OpenLayers/Geometry/MultiLineString.js
13
 * @requires OpenLayers/Geometry/Polygon.js
14
 * @requires OpenLayers/Geometry/MultiPolygon.js
15
 */
16

    
17
/**
18
 * Class: OpenLayers.Format.GML
19
 * Read/Write GML. Create a new instance with the <OpenLayers.Format.GML>
20
 *     constructor.  Supports the GML simple features profile.
21
 * 
22
 * Inherits from:
23
 *  - <OpenLayers.Format.XML>
24
 */
25
OpenLayers.Format.GML = OpenLayers.Class(OpenLayers.Format.XML, {
26
    
27
    /**
28
     * APIProperty: featureNS
29
     * {String} Namespace used for feature attributes.  Default is
30
     *     "http://mapserver.gis.umn.edu/mapserver".
31
     */
32
    featureNS: "http://mapserver.gis.umn.edu/mapserver",
33
    
34
    /**
35
     * APIProperty: featurePrefix
36
     * {String} Namespace alias (or prefix) for feature nodes.  Default is
37
     *     "feature".
38
     */
39
    featurePrefix: "feature",
40
    
41
    /**
42
     * APIProperty: featureName
43
     * {String} Element name for features. Default is "featureMember".
44
     */
45
    featureName: "featureMember", 
46
    
47
    /**
48
     * APIProperty: layerName
49
     * {String} Name of data layer. Default is "features".
50
     */
51
    layerName: "features",
52
    
53
    /**
54
     * APIProperty: geometryName
55
     * {String} Name of geometry element.  Defaults to "geometry".
56
     */
57
    geometryName: "geometry",
58
    
59
    /** 
60
     * APIProperty: collectionName
61
     * {String} Name of featureCollection element.
62
     */
63
    collectionName: "FeatureCollection",
64
    
65
    /**
66
     * APIProperty: gmlns
67
     * {String} GML Namespace.
68
     */
69
    gmlns: "http://www.opengis.net/gml",
70

    
71
    /**
72
     * APIProperty: extractAttributes
73
     * {Boolean} Extract attributes from GML.
74
     */
75
    extractAttributes: true,
76
    
77
    /**
78
     * APIProperty: xy
79
     * {Boolean} Order of the GML coordinate true:(x,y) or false:(y,x)
80
     * Changing is not recommended, a new Format should be instantiated.
81
     */ 
82
    xy: true,
83
    
84
    /**
85
     * Constructor: OpenLayers.Format.GML
86
     * Create a new parser for GML.
87
     *
88
     * Parameters:
89
     * options - {Object} An optional object whose properties will be set on
90
     *     this instance.
91
     */
92
    initialize: function(options) {
93
        // compile regular expressions once instead of every time they are used
94
        this.regExes = {
95
            trimSpace: (/^\s*|\s*$/g),
96
            removeSpace: (/\s*/g),
97
            splitSpace: (/\s+/),
98
            trimComma: (/\s*,\s*/g)
99
        };
100
        OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
101
    },
102

    
103
    /**
104
     * APIMethod: read
105
     * Read data from a string, and return a list of features. 
106
     * 
107
     * Parameters:
108
     * data - {String} or {DOMElement} data to read/parse.
109
     *
110
     * Returns:
111
     * {Array(<OpenLayers.Feature.Vector>)} An array of features.
112
     */
113
    read: function(data) {
114
        if(typeof data == "string") { 
115
            data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
116
        }
117
        var featureNodes = this.getElementsByTagNameNS(data.documentElement,
118
                                                       this.gmlns,
119
                                                       this.featureName);
120
        var features = [];
121
        for(var i=0; i<featureNodes.length; i++) {
122
            var feature = this.parseFeature(featureNodes[i]);
123
            if(feature) {
124
                features.push(feature);
125
            }
126
        }
127
        return features;
128
    },
129
    
130
    /**
131
     * Method: parseFeature
132
     * This function is the core of the GML parsing code in OpenLayers.
133
     *    It creates the geometries that are then attached to the returned
134
     *    feature, and calls parseAttributes() to get attribute data out.
135
     *    
136
     * Parameters:
137
     * node - {DOMElement} A GML feature node. 
138
     */
139
    parseFeature: function(node) {
140
        // only accept one geometry per feature - look for highest "order"
141
        var order = ["MultiPolygon", "Polygon",
142
                     "MultiLineString", "LineString",
143
                     "MultiPoint", "Point", "Envelope"];
144
        // FIXME: In case we parse a feature with no geometry, but boundedBy an Envelope,
145
        // this code creates a geometry derived from the Envelope. This is not correct.
146
        var type, nodeList, geometry, parser;
147
        for(var i=0; i<order.length; ++i) {
148
            type = order[i];
149
            nodeList = this.getElementsByTagNameNS(node, this.gmlns, type);
150
            if(nodeList.length > 0) {
151
                // only deal with first geometry of this type
152
                parser = this.parseGeometry[type.toLowerCase()];
153
                if(parser) {
154
                    geometry = parser.apply(this, [nodeList[0]]);
155
                    if (this.internalProjection && this.externalProjection) {
156
                        geometry.transform(this.externalProjection, 
157
                                           this.internalProjection); 
158
                    }                       
159
                } else {
160
                    throw new TypeError("Unsupported geometry type: " + type);
161
                }
162
                // stop looking for different geometry types
163
                break;
164
            }
165
        }
166

    
167
        var bounds;
168
        var boxNodes = this.getElementsByTagNameNS(node, this.gmlns, "Box");
169
        for(i=0; i<boxNodes.length; ++i) {
170
            var boxNode = boxNodes[i];
171
            var box = this.parseGeometry["box"].apply(this, [boxNode]);
172
            var parentNode = boxNode.parentNode;
173
            var parentName = parentNode.localName ||
174
                             parentNode.nodeName.split(":").pop();
175
            if(parentName === "boundedBy") {
176
                bounds = box;
177
            } else {
178
                geometry = box.toGeometry();
179
            }
180
        }
181
        
182
        // construct feature (optionally with attributes)
183
        var attributes;
184
        if(this.extractAttributes) {
185
            attributes = this.parseAttributes(node);
186
        }
187
        var feature = new OpenLayers.Feature.Vector(geometry, attributes);
188
        feature.bounds = bounds;
189
        
190
        feature.gml = {
191
            featureType: node.firstChild.nodeName.split(":")[1],
192
            featureNS: node.firstChild.namespaceURI,
193
            featureNSPrefix: node.firstChild.prefix
194
        };
195
                
196
        // assign fid - this can come from a "fid" or "id" attribute
197
        var childNode = node.firstChild;
198
        var fid;
199
        while(childNode) {
200
            if(childNode.nodeType == 1) {
201
                fid = childNode.getAttribute("fid") ||
202
                      childNode.getAttribute("id");
203
                if(fid) {
204
                    break;
205
                }
206
            }
207
            childNode = childNode.nextSibling;
208
        }
209
        feature.fid = fid;
210
        return feature;
211
    },
212
    
213
    /**
214
     * Property: parseGeometry
215
     * Properties of this object are the functions that parse geometries based
216
     *     on their type.
217
     */
218
    parseGeometry: {
219
        
220
        /**
221
         * Method: parseGeometry.point
222
         * Given a GML node representing a point geometry, create an OpenLayers
223
         *     point geometry.
224
         *
225
         * Parameters:
226
         * node - {DOMElement} A GML node.
227
         *
228
         * Returns:
229
         * {<OpenLayers.Geometry.Point>} A point geometry.
230
         */
231
        point: function(node) {
232
            /**
233
             * Three coordinate variations to consider:
234
             * 1) <gml:pos>x y z</gml:pos>
235
             * 2) <gml:coordinates>x, y, z</gml:coordinates>
236
             * 3) <gml:coord><gml:X>x</gml:X><gml:Y>y</gml:Y></gml:coord>
237
             */
238
            var nodeList, coordString;
239
            var coords = [];
240

    
241
            // look for <gml:pos>
242
            var nodeList = this.getElementsByTagNameNS(node, this.gmlns, "pos");
243
            if(nodeList.length > 0) {
244
                coordString = nodeList[0].firstChild.nodeValue;
245
                coordString = coordString.replace(this.regExes.trimSpace, "");
246
                coords = coordString.split(this.regExes.splitSpace);
247
            }
248

    
249
            // look for <gml:coordinates>
250
            if(coords.length == 0) {
251
                nodeList = this.getElementsByTagNameNS(node, this.gmlns,
252
                                                       "coordinates");
253
                if(nodeList.length > 0) {
254
                    coordString = nodeList[0].firstChild.nodeValue;
255
                    coordString = coordString.replace(this.regExes.removeSpace,
256
                                                      "");
257
                    coords = coordString.split(",");
258
                }
259
            }
260

    
261
            // look for <gml:coord>
262
            if(coords.length == 0) {
263
                nodeList = this.getElementsByTagNameNS(node, this.gmlns,
264
                                                       "coord");
265
                if(nodeList.length > 0) {
266
                    var xList = this.getElementsByTagNameNS(nodeList[0],
267
                                                            this.gmlns, "X");
268
                    var yList = this.getElementsByTagNameNS(nodeList[0],
269
                                                            this.gmlns, "Y");
270
                    if(xList.length > 0 && yList.length > 0) {
271
                        coords = [xList[0].firstChild.nodeValue,
272
                                  yList[0].firstChild.nodeValue];
273
                    }
274
                }
275
            }
276
                
277
            // preserve third dimension
278
            if(coords.length == 2) {
279
                coords[2] = null;
280
            }
281
            
282
            if (this.xy) {
283
                return new OpenLayers.Geometry.Point(coords[0], coords[1],
284
                                                 coords[2]);
285
            }
286
            else{
287
                return new OpenLayers.Geometry.Point(coords[1], coords[0],
288
                                                 coords[2]);
289
            }
290
        },
291
        
292
        /**
293
         * Method: parseGeometry.multipoint
294
         * Given a GML node representing a multipoint geometry, create an
295
         *     OpenLayers multipoint geometry.
296
         *
297
         * Parameters:
298
         * node - {DOMElement} A GML node.
299
         *
300
         * Returns:
301
         * {<OpenLayers.Geometry.MultiPoint>} A multipoint geometry.
302
         */
303
        multipoint: function(node) {
304
            var nodeList = this.getElementsByTagNameNS(node, this.gmlns,
305
                                                       "Point");
306
            var components = [];
307
            if(nodeList.length > 0) {
308
                var point;
309
                for(var i=0; i<nodeList.length; ++i) {
310
                    point = this.parseGeometry.point.apply(this, [nodeList[i]]);
311
                    if(point) {
312
                        components.push(point);
313
                    }
314
                }
315
            }
316
            return new OpenLayers.Geometry.MultiPoint(components);
317
        },
318
        
319
        /**
320
         * Method: parseGeometry.linestring
321
         * Given a GML node representing a linestring geometry, create an
322
         *     OpenLayers linestring geometry.
323
         *
324
         * Parameters:
325
         * node - {DOMElement} A GML node.
326
         *
327
         * Returns:
328
         * {<OpenLayers.Geometry.LineString>} A linestring geometry.
329
         */
330
        linestring: function(node, ring) {
331
            /**
332
             * Two coordinate variations to consider:
333
             * 1) <gml:posList dimension="d">x0 y0 z0 x1 y1 z1</gml:posList>
334
             * 2) <gml:coordinates>x0, y0, z0 x1, y1, z1</gml:coordinates>
335
             */
336
            var nodeList, coordString;
337
            var coords = [];
338
            var points = [];
339

    
340
            // look for <gml:posList>
341
            nodeList = this.getElementsByTagNameNS(node, this.gmlns, "posList");
342
            if(nodeList.length > 0) {
343
                coordString = this.getChildValue(nodeList[0]);
344
                coordString = coordString.replace(this.regExes.trimSpace, "");
345
                coords = coordString.split(this.regExes.splitSpace);
346
                var dim = parseInt(nodeList[0].getAttribute("dimension"));
347
                var j, x, y, z;
348
                for(var i=0; i<coords.length/dim; ++i) {
349
                    j = i * dim;
350
                    x = coords[j];
351
                    y = coords[j+1];
352
                    z = (dim == 2) ? null : coords[j+2];
353
                    if (this.xy) {
354
                        points.push(new OpenLayers.Geometry.Point(x, y, z));
355
                    } else {
356
                        points.push(new OpenLayers.Geometry.Point(y, x, z));
357
                    }
358
                }
359
            }
360

    
361
            // look for <gml:coordinates>
362
            if(coords.length == 0) {
363
                nodeList = this.getElementsByTagNameNS(node, this.gmlns,
364
                                                       "coordinates");
365
                if(nodeList.length > 0) {
366
                    coordString = this.getChildValue(nodeList[0]);
367
                    coordString = coordString.replace(this.regExes.trimSpace,
368
                                                      "");
369
                    coordString = coordString.replace(this.regExes.trimComma,
370
                                                      ",");
371
                    var pointList = coordString.split(this.regExes.splitSpace);
372
                    for(var i=0; i<pointList.length; ++i) {
373
                        coords = pointList[i].split(",");
374
                        if(coords.length == 2) {
375
                            coords[2] = null;
376
                        }
377
                        if (this.xy) {
378
                            points.push(new OpenLayers.Geometry.Point(coords[0],
379
                                                                  coords[1],
380
                                                                  coords[2]));
381
                        } else {
382
                            points.push(new OpenLayers.Geometry.Point(coords[1],
383
                                                                  coords[0],
384
                                                                  coords[2]));
385
                        }
386
                    }
387
                }
388
            }
389

    
390
            var line = null;
391
            if(points.length != 0) {
392
                if(ring) {
393
                    line = new OpenLayers.Geometry.LinearRing(points);
394
                } else {
395
                    line = new OpenLayers.Geometry.LineString(points);
396
                }
397
            }
398
            return line;
399
        },
400
        
401
        /**
402
         * Method: parseGeometry.multilinestring
403
         * Given a GML node representing a multilinestring geometry, create an
404
         *     OpenLayers multilinestring geometry.
405
         *
406
         * Parameters:
407
         * node - {DOMElement} A GML node.
408
         *
409
         * Returns:
410
         * {<OpenLayers.Geometry.MultiLineString>} A multilinestring geometry.
411
         */
412
        multilinestring: function(node) {
413
            var nodeList = this.getElementsByTagNameNS(node, this.gmlns,
414
                                                       "LineString");
415
            var components = [];
416
            if(nodeList.length > 0) {
417
                var line;
418
                for(var i=0; i<nodeList.length; ++i) {
419
                    line = this.parseGeometry.linestring.apply(this,
420
                                                               [nodeList[i]]);
421
                    if(line) {
422
                        components.push(line);
423
                    }
424
                }
425
            }
426
            return new OpenLayers.Geometry.MultiLineString(components);
427
        },
428
        
429
        /**
430
         * Method: parseGeometry.polygon
431
         * Given a GML node representing a polygon geometry, create an
432
         *     OpenLayers polygon geometry.
433
         *
434
         * Parameters:
435
         * node - {DOMElement} A GML node.
436
         *
437
         * Returns:
438
         * {<OpenLayers.Geometry.Polygon>} A polygon geometry.
439
         */
440
        polygon: function(node) {
441
            var nodeList = this.getElementsByTagNameNS(node, this.gmlns,
442
                                                       "LinearRing");
443
            var components = [];
444
            if(nodeList.length > 0) {
445
                // this assumes exterior ring first, inner rings after
446
                var ring;
447
                for(var i=0; i<nodeList.length; ++i) {
448
                    ring = this.parseGeometry.linestring.apply(this,
449
                                                        [nodeList[i], true]);
450
                    if(ring) {
451
                        components.push(ring);
452
                    }
453
                }
454
            }
455
            return new OpenLayers.Geometry.Polygon(components);
456
        },
457
        
458
        /**
459
         * Method: parseGeometry.multipolygon
460
         * Given a GML node representing a multipolygon geometry, create an
461
         *     OpenLayers multipolygon geometry.
462
         *
463
         * Parameters:
464
         * node - {DOMElement} A GML node.
465
         *
466
         * Returns:
467
         * {<OpenLayers.Geometry.MultiPolygon>} A multipolygon geometry.
468
         */
469
        multipolygon: function(node) {
470
            var nodeList = this.getElementsByTagNameNS(node, this.gmlns,
471
                                                       "Polygon");
472
            var components = [];
473
            if(nodeList.length > 0) {
474
                var polygon;
475
                for(var i=0; i<nodeList.length; ++i) {
476
                    polygon = this.parseGeometry.polygon.apply(this,
477
                                                               [nodeList[i]]);
478
                    if(polygon) {
479
                        components.push(polygon);
480
                    }
481
                }
482
            }
483
            return new OpenLayers.Geometry.MultiPolygon(components);
484
        },
485
        
486
        envelope: function(node) {
487
            var components = [];
488
            var coordString;
489
            var envelope;
490
            
491
            var lpoint = this.getElementsByTagNameNS(node, this.gmlns, "lowerCorner");
492
            if (lpoint.length > 0) {
493
                var coords = [];
494
                
495
                if(lpoint.length > 0) {
496
                    coordString = lpoint[0].firstChild.nodeValue;
497
                    coordString = coordString.replace(this.regExes.trimSpace, "");
498
                    coords = coordString.split(this.regExes.splitSpace);
499
                }
500
                
501
                if(coords.length == 2) {
502
                    coords[2] = null;
503
                }
504
                if (this.xy) {
505
                    var lowerPoint = new OpenLayers.Geometry.Point(coords[0], coords[1],coords[2]);
506
                } else {
507
                    var lowerPoint = new OpenLayers.Geometry.Point(coords[1], coords[0],coords[2]);
508
                }
509
            }
510
            
511
            var upoint = this.getElementsByTagNameNS(node, this.gmlns, "upperCorner");
512
            if (upoint.length > 0) {
513
                var coords = [];
514
                
515
                if(upoint.length > 0) {
516
                    coordString = upoint[0].firstChild.nodeValue;
517
                    coordString = coordString.replace(this.regExes.trimSpace, "");
518
                    coords = coordString.split(this.regExes.splitSpace);
519
                }
520
                
521
                if(coords.length == 2) {
522
                    coords[2] = null;
523
                }
524
                if (this.xy) {
525
                    var upperPoint = new OpenLayers.Geometry.Point(coords[0], coords[1],coords[2]);
526
                } else {
527
                    var upperPoint = new OpenLayers.Geometry.Point(coords[1], coords[0],coords[2]);
528
                }
529
            }
530
            
531
            if (lowerPoint && upperPoint) {
532
                components.push(new OpenLayers.Geometry.Point(lowerPoint.x, lowerPoint.y));
533
                components.push(new OpenLayers.Geometry.Point(upperPoint.x, lowerPoint.y));
534
                components.push(new OpenLayers.Geometry.Point(upperPoint.x, upperPoint.y));
535
                components.push(new OpenLayers.Geometry.Point(lowerPoint.x, upperPoint.y));
536
                components.push(new OpenLayers.Geometry.Point(lowerPoint.x, lowerPoint.y));
537
                
538
                var ring = new OpenLayers.Geometry.LinearRing(components);
539
                envelope = new OpenLayers.Geometry.Polygon([ring]);
540
            }
541
            return envelope; 
542
        },
543

    
544
        /**
545
         * Method: parseGeometry.box
546
         * Given a GML node representing a box geometry, create an
547
         *     OpenLayers.Bounds.
548
         *
549
         * Parameters:
550
         * node - {DOMElement} A GML node.
551
         *
552
         * Returns:
553
         * {<OpenLayers.Bounds>} A bounds representing the box.
554
         */
555
        box: function(node) {
556
            var nodeList = this.getElementsByTagNameNS(node, this.gmlns,
557
                                                   "coordinates");
558
            var coordString;
559
            var coords, beginPoint = null, endPoint = null;
560
            if (nodeList.length > 0) {
561
                coordString = nodeList[0].firstChild.nodeValue;
562
                coords = coordString.split(" ");
563
                if (coords.length == 2) {
564
                    beginPoint = coords[0].split(",");
565
                    endPoint = coords[1].split(",");
566
                }
567
            }
568
            if (beginPoint !== null && endPoint !== null) {
569
                return new OpenLayers.Bounds(parseFloat(beginPoint[0]),
570
                    parseFloat(beginPoint[1]),
571
                    parseFloat(endPoint[0]),
572
                    parseFloat(endPoint[1]) );
573
            }
574
        }
575
        
576
    },
577
    
578
    /**
579
     * Method: parseAttributes
580
     *
581
     * Parameters:
582
     * node - {DOMElement}
583
     *
584
     * Returns:
585
     * {Object} An attributes object.
586
     */
587
    parseAttributes: function(node) {
588
        var attributes = {};
589
        // assume attributes are children of the first type 1 child
590
        var childNode = node.firstChild;
591
        var children, i, child, grandchildren, grandchild, name, value;
592
        while(childNode) {
593
            if(childNode.nodeType == 1) {
594
                // attributes are type 1 children with one type 3 child
595
                children = childNode.childNodes;
596
                for(i=0; i<children.length; ++i) {
597
                    child = children[i];
598
                    if(child.nodeType == 1) {
599
                        grandchildren = child.childNodes;
600
                        if(grandchildren.length == 1) {
601
                            grandchild = grandchildren[0];
602
                            if(grandchild.nodeType == 3 ||
603
                               grandchild.nodeType == 4) {
604
                                name = (child.prefix) ?
605
                                        child.nodeName.split(":")[1] :
606
                                        child.nodeName;
607
                                value = grandchild.nodeValue.replace(
608
                                                this.regExes.trimSpace, "");
609
                                attributes[name] = value;
610
                            }
611
                        } else {
612
                            // If child has no childNodes (grandchildren),
613
                            // set an attribute with null value.
614
                            // e.g. <prefix:fieldname/> becomes
615
                            // {fieldname: null}
616
                            attributes[child.nodeName.split(":").pop()] = null;
617
                        }
618
                    }
619
                }
620
                break;
621
            }
622
            childNode = childNode.nextSibling;
623
        }
624
        return attributes;
625
    },
626
    
627
    /**
628
     * APIMethod: write
629
     * Generate a GML document string given a list of features. 
630
     * 
631
     * Parameters:
632
     * features - {Array(<OpenLayers.Feature.Vector>)} List of features to
633
     *     serialize into a string.
634
     *
635
     * Returns:
636
     * {String} A string representing the GML document.
637
     */
638
    write: function(features) {
639
        if(!(OpenLayers.Util.isArray(features))) {
640
            features = [features];
641
        }
642
        var gml = this.createElementNS("http://www.opengis.net/wfs",
643
                                       "wfs:" + this.collectionName);
644
        for(var i=0; i<features.length; i++) {
645
            gml.appendChild(this.createFeatureXML(features[i]));
646
        }
647
        return OpenLayers.Format.XML.prototype.write.apply(this, [gml]);
648
    },
649

    
650
    /** 
651
     * Method: createFeatureXML
652
     * Accept an OpenLayers.Feature.Vector, and build a GML node for it.
653
     *
654
     * Parameters:
655
     * feature - {<OpenLayers.Feature.Vector>} The feature to be built as GML.
656
     *
657
     * Returns:
658
     * {DOMElement} A node reprensting the feature in GML.
659
     */
660
    createFeatureXML: function(feature) {
661
        var geometry = feature.geometry;
662
        var geometryNode = this.buildGeometryNode(geometry);
663
        var geomContainer = this.createElementNS(this.featureNS,
664
                                                 this.featurePrefix + ":" +
665
                                                 this.geometryName);
666
        geomContainer.appendChild(geometryNode);
667
        var featureNode = this.createElementNS(this.gmlns,
668
                                               "gml:" + this.featureName);
669
        var featureContainer = this.createElementNS(this.featureNS,
670
                                                    this.featurePrefix + ":" +
671
                                                    this.layerName);
672
        var fid = feature.fid || feature.id;
673
        featureContainer.setAttribute("fid", fid);
674
        featureContainer.appendChild(geomContainer);
675
        for(var attr in feature.attributes) {
676
            var attrText = this.createTextNode(feature.attributes[attr]); 
677
            var nodename = attr.substring(attr.lastIndexOf(":") + 1);
678
            var attrContainer = this.createElementNS(this.featureNS,
679
                                                     this.featurePrefix + ":" +
680
                                                     nodename);
681
            attrContainer.appendChild(attrText);
682
            featureContainer.appendChild(attrContainer);
683
        }    
684
        featureNode.appendChild(featureContainer);
685
        return featureNode;
686
    },
687
    
688
    /**
689
     * APIMethod: buildGeometryNode
690
     */
691
    buildGeometryNode: function(geometry) {
692
        if (this.externalProjection && this.internalProjection) {
693
            geometry = geometry.clone();
694
            geometry.transform(this.internalProjection, 
695
                               this.externalProjection);
696
        }    
697
        var className = geometry.CLASS_NAME;
698
        var type = className.substring(className.lastIndexOf(".") + 1);
699
        var builder = this.buildGeometry[type.toLowerCase()];
700
        return builder.apply(this, [geometry]);
701
    },
702

    
703
    /**
704
     * Property: buildGeometry
705
     * Object containing methods to do the actual geometry node building
706
     *     based on geometry type.
707
     */
708
    buildGeometry: {
709
        // TBD retrieve the srs from layer
710
        // srsName is non-standard, so not including it until it's right.
711
        // gml.setAttribute("srsName",
712
        //                  "http://www.opengis.net/gml/srs/epsg.xml#4326");
713

    
714
        /**
715
         * Method: buildGeometry.point
716
         * Given an OpenLayers point geometry, create a GML point.
717
         *
718
         * Parameters:
719
         * geometry - {<OpenLayers.Geometry.Point>} A point geometry.
720
         *
721
         * Returns:
722
         * {DOMElement} A GML point node.
723
         */
724
        point: function(geometry) {
725
            var gml = this.createElementNS(this.gmlns, "gml:Point");
726
            gml.appendChild(this.buildCoordinatesNode(geometry));
727
            return gml;
728
        },
729
        
730
        /**
731
         * Method: buildGeometry.multipoint
732
         * Given an OpenLayers multipoint geometry, create a GML multipoint.
733
         *
734
         * Parameters:
735
         * geometry - {<OpenLayers.Geometry.MultiPoint>} A multipoint geometry.
736
         *
737
         * Returns:
738
         * {DOMElement} A GML multipoint node.
739
         */
740
        multipoint: function(geometry) {
741
            var gml = this.createElementNS(this.gmlns, "gml:MultiPoint");
742
            var points = geometry.components;
743
            var pointMember, pointGeom;
744
            for(var i=0; i<points.length; i++) { 
745
                pointMember = this.createElementNS(this.gmlns,
746
                                                   "gml:pointMember");
747
                pointGeom = this.buildGeometry.point.apply(this,
748
                                                               [points[i]]);
749
                pointMember.appendChild(pointGeom);
750
                gml.appendChild(pointMember);
751
            }
752
            return gml;            
753
        },
754
        
755
        /**
756
         * Method: buildGeometry.linestring
757
         * Given an OpenLayers linestring geometry, create a GML linestring.
758
         *
759
         * Parameters:
760
         * geometry - {<OpenLayers.Geometry.LineString>} A linestring geometry.
761
         *
762
         * Returns:
763
         * {DOMElement} A GML linestring node.
764
         */
765
        linestring: function(geometry) {
766
            var gml = this.createElementNS(this.gmlns, "gml:LineString");
767
            gml.appendChild(this.buildCoordinatesNode(geometry));
768
            return gml;
769
        },
770
        
771
        /**
772
         * Method: buildGeometry.multilinestring
773
         * Given an OpenLayers multilinestring geometry, create a GML
774
         *     multilinestring.
775
         *
776
         * Parameters:
777
         * geometry - {<OpenLayers.Geometry.MultiLineString>} A multilinestring
778
         *     geometry.
779
         *
780
         * Returns:
781
         * {DOMElement} A GML multilinestring node.
782
         */
783
        multilinestring: function(geometry) {
784
            var gml = this.createElementNS(this.gmlns, "gml:MultiLineString");
785
            var lines = geometry.components;
786
            var lineMember, lineGeom;
787
            for(var i=0; i<lines.length; ++i) {
788
                lineMember = this.createElementNS(this.gmlns,
789
                                                  "gml:lineStringMember");
790
                lineGeom = this.buildGeometry.linestring.apply(this,
791
                                                                   [lines[i]]);
792
                lineMember.appendChild(lineGeom);
793
                gml.appendChild(lineMember);
794
            }
795
            return gml;
796
        },
797
        
798
        /**
799
         * Method: buildGeometry.linearring
800
         * Given an OpenLayers linearring geometry, create a GML linearring.
801
         *
802
         * Parameters:
803
         * geometry - {<OpenLayers.Geometry.LinearRing>} A linearring geometry.
804
         *
805
         * Returns:
806
         * {DOMElement} A GML linearring node.
807
         */
808
        linearring: function(geometry) {
809
            var gml = this.createElementNS(this.gmlns, "gml:LinearRing");
810
            gml.appendChild(this.buildCoordinatesNode(geometry));
811
            return gml;
812
        },
813
        
814
        /**
815
         * Method: buildGeometry.polygon
816
         * Given an OpenLayers polygon geometry, create a GML polygon.
817
         *
818
         * Parameters:
819
         * geometry - {<OpenLayers.Geometry.Polygon>} A polygon geometry.
820
         *
821
         * Returns:
822
         * {DOMElement} A GML polygon node.
823
         */
824
        polygon: function(geometry) {
825
            var gml = this.createElementNS(this.gmlns, "gml:Polygon");
826
            var rings = geometry.components;
827
            var ringMember, ringGeom, type;
828
            for(var i=0; i<rings.length; ++i) {
829
                type = (i==0) ? "outerBoundaryIs" : "innerBoundaryIs";
830
                ringMember = this.createElementNS(this.gmlns,
831
                                                  "gml:" + type);
832
                ringGeom = this.buildGeometry.linearring.apply(this,
833
                                                                   [rings[i]]);
834
                ringMember.appendChild(ringGeom);
835
                gml.appendChild(ringMember);
836
            }
837
            return gml;
838
        },
839
        
840
        /**
841
         * Method: buildGeometry.multipolygon
842
         * Given an OpenLayers multipolygon geometry, create a GML multipolygon.
843
         *
844
         * Parameters:
845
         * geometry - {<OpenLayers.Geometry.MultiPolygon>} A multipolygon
846
         *     geometry.
847
         *
848
         * Returns:
849
         * {DOMElement} A GML multipolygon node.
850
         */
851
        multipolygon: function(geometry) {
852
            var gml = this.createElementNS(this.gmlns, "gml:MultiPolygon");
853
            var polys = geometry.components;
854
            var polyMember, polyGeom;
855
            for(var i=0; i<polys.length; ++i) {
856
                polyMember = this.createElementNS(this.gmlns,
857
                                                  "gml:polygonMember");
858
                polyGeom = this.buildGeometry.polygon.apply(this,
859
                                                                [polys[i]]);
860
                polyMember.appendChild(polyGeom);
861
                gml.appendChild(polyMember);
862
            }
863
            return gml;
864

    
865
        },
866
 
867
        /**
868
         * Method: buildGeometry.bounds
869
         * Given an OpenLayers bounds, create a GML box.
870
         *
871
         * Parameters:
872
         * bounds - {<OpenLayers.Geometry.Bounds>} A bounds object.
873
         *
874
         * Returns:
875
         * {DOMElement} A GML box node.
876
         */
877
        bounds: function(bounds) {
878
            var gml = this.createElementNS(this.gmlns, "gml:Box");
879
            gml.appendChild(this.buildCoordinatesNode(bounds));
880
            return gml;
881
        }
882
    },
883

    
884
    /**
885
     * Method: buildCoordinates
886
     * builds the coordinates XmlNode
887
     * (code)
888
     * <gml:coordinates decimal="." cs="," ts=" ">...</gml:coordinates>
889
     * (end)
890
     *
891
     * Parameters: 
892
     * geometry - {<OpenLayers.Geometry>} 
893
     *
894
     * Returns:
895
     * {XmlNode} created xmlNode
896
     */
897
    buildCoordinatesNode: function(geometry) {
898
        var coordinatesNode = this.createElementNS(this.gmlns,
899
                                                   "gml:coordinates");
900
        coordinatesNode.setAttribute("decimal", ".");
901
        coordinatesNode.setAttribute("cs", ",");
902
        coordinatesNode.setAttribute("ts", " ");
903

    
904
        var parts = [];
905

    
906
        if(geometry instanceof OpenLayers.Bounds){
907
            parts.push(geometry.left + "," + geometry.bottom);
908
            parts.push(geometry.right + "," + geometry.top);
909
        } else {
910
            var points = (geometry.components) ? geometry.components : [geometry];
911
            for(var i=0; i<points.length; i++) {
912
                parts.push(points[i].x + "," + points[i].y);                
913
            }            
914
        }
915

    
916
        var txtNode = this.createTextNode(parts.join(" "));
917
        coordinatesNode.appendChild(txtNode);
918
        
919
        return coordinatesNode;
920
    },
921

    
922
    CLASS_NAME: "OpenLayers.Format.GML" 
923
});
(9-9/41)