GML.js 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923
  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. * @requires OpenLayers/Format/XML.js
  7. * @requires OpenLayers/Feature/Vector.js
  8. * @requires OpenLayers/Geometry/Point.js
  9. * @requires OpenLayers/Geometry/MultiPoint.js
  10. * @requires OpenLayers/Geometry/LineString.js
  11. * @requires OpenLayers/Geometry/MultiLineString.js
  12. * @requires OpenLayers/Geometry/Polygon.js
  13. * @requires OpenLayers/Geometry/MultiPolygon.js
  14. */
  15. /**
  16. * Class: OpenLayers.Format.GML
  17. * Read/Write GML. Create a new instance with the <OpenLayers.Format.GML>
  18. * constructor. Supports the GML simple features profile.
  19. *
  20. * Inherits from:
  21. * - <OpenLayers.Format.XML>
  22. */
  23. OpenLayers.Format.GML = OpenLayers.Class(OpenLayers.Format.XML, {
  24. /**
  25. * APIProperty: featureNS
  26. * {String} Namespace used for feature attributes. Default is
  27. * "http://mapserver.gis.umn.edu/mapserver".
  28. */
  29. featureNS: "http://mapserver.gis.umn.edu/mapserver",
  30. /**
  31. * APIProperty: featurePrefix
  32. * {String} Namespace alias (or prefix) for feature nodes. Default is
  33. * "feature".
  34. */
  35. featurePrefix: "feature",
  36. /**
  37. * APIProperty: featureName
  38. * {String} Element name for features. Default is "featureMember".
  39. */
  40. featureName: "featureMember",
  41. /**
  42. * APIProperty: layerName
  43. * {String} Name of data layer. Default is "features".
  44. */
  45. layerName: "features",
  46. /**
  47. * APIProperty: geometryName
  48. * {String} Name of geometry element. Defaults to "geometry".
  49. */
  50. geometryName: "geometry",
  51. /**
  52. * APIProperty: collectionName
  53. * {String} Name of featureCollection element.
  54. */
  55. collectionName: "FeatureCollection",
  56. /**
  57. * APIProperty: gmlns
  58. * {String} GML Namespace.
  59. */
  60. gmlns: "http://www.opengis.net/gml",
  61. /**
  62. * APIProperty: extractAttributes
  63. * {Boolean} Extract attributes from GML.
  64. */
  65. extractAttributes: true,
  66. /**
  67. * APIProperty: xy
  68. * {Boolean} Order of the GML coordinate true:(x,y) or false:(y,x)
  69. * Changing is not recommended, a new Format should be instantiated.
  70. */
  71. xy: true,
  72. /**
  73. * Constructor: OpenLayers.Format.GML
  74. * Create a new parser for GML.
  75. *
  76. * Parameters:
  77. * options - {Object} An optional object whose properties will be set on
  78. * this instance.
  79. */
  80. initialize: function(options) {
  81. // compile regular expressions once instead of every time they are used
  82. this.regExes = {
  83. trimSpace: (/^\s*|\s*$/g),
  84. removeSpace: (/\s*/g),
  85. splitSpace: (/\s+/),
  86. trimComma: (/\s*,\s*/g)
  87. };
  88. OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
  89. },
  90. /**
  91. * APIMethod: read
  92. * Read data from a string, and return a list of features.
  93. *
  94. * Parameters:
  95. * data - {String} or {DOMElement} data to read/parse.
  96. *
  97. * Returns:
  98. * {Array(<OpenLayers.Feature.Vector>)} An array of features.
  99. */
  100. read: function(data) {
  101. if(typeof data == "string") {
  102. data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
  103. }
  104. var featureNodes = this.getElementsByTagNameNS(data.documentElement,
  105. this.gmlns,
  106. this.featureName);
  107. var features = [];
  108. for(var i=0; i<featureNodes.length; i++) {
  109. var feature = this.parseFeature(featureNodes[i]);
  110. if(feature) {
  111. features.push(feature);
  112. }
  113. }
  114. return features;
  115. },
  116. /**
  117. * Method: parseFeature
  118. * This function is the core of the GML parsing code in OpenLayers.
  119. * It creates the geometries that are then attached to the returned
  120. * feature, and calls parseAttributes() to get attribute data out.
  121. *
  122. * Parameters:
  123. * node - {DOMElement} A GML feature node.
  124. */
  125. parseFeature: function(node) {
  126. // only accept one geometry per feature - look for highest "order"
  127. var order = ["MultiPolygon", "Polygon",
  128. "MultiLineString", "LineString",
  129. "MultiPoint", "Point", "Envelope"];
  130. // FIXME: In case we parse a feature with no geometry, but boundedBy an Envelope,
  131. // this code creates a geometry derived from the Envelope. This is not correct.
  132. var type, nodeList, geometry, parser;
  133. for(var i=0; i<order.length; ++i) {
  134. type = order[i];
  135. nodeList = this.getElementsByTagNameNS(node, this.gmlns, type);
  136. if(nodeList.length > 0) {
  137. // only deal with first geometry of this type
  138. parser = this.parseGeometry[type.toLowerCase()];
  139. if(parser) {
  140. geometry = parser.apply(this, [nodeList[0]]);
  141. if (this.internalProjection && this.externalProjection) {
  142. geometry.transform(this.externalProjection,
  143. this.internalProjection);
  144. }
  145. } else {
  146. throw new TypeError("Unsupported geometry type: " + type);
  147. }
  148. // stop looking for different geometry types
  149. break;
  150. }
  151. }
  152. var bounds;
  153. var boxNodes = this.getElementsByTagNameNS(node, this.gmlns, "Box");
  154. for(i=0; i<boxNodes.length; ++i) {
  155. var boxNode = boxNodes[i];
  156. var box = this.parseGeometry["box"].apply(this, [boxNode]);
  157. var parentNode = boxNode.parentNode;
  158. var parentName = parentNode.localName ||
  159. parentNode.nodeName.split(":").pop();
  160. if(parentName === "boundedBy") {
  161. bounds = box;
  162. } else {
  163. geometry = box.toGeometry();
  164. }
  165. }
  166. // construct feature (optionally with attributes)
  167. var attributes;
  168. if(this.extractAttributes) {
  169. attributes = this.parseAttributes(node);
  170. }
  171. var feature = new OpenLayers.Feature.Vector(geometry, attributes);
  172. feature.bounds = bounds;
  173. feature.gml = {
  174. featureType: node.firstChild.nodeName.split(":")[1],
  175. featureNS: node.firstChild.namespaceURI,
  176. featureNSPrefix: node.firstChild.prefix
  177. };
  178. // assign fid - this can come from a "fid" or "id" attribute
  179. var childNode = node.firstChild;
  180. var fid;
  181. while(childNode) {
  182. if(childNode.nodeType == 1) {
  183. fid = childNode.getAttribute("fid") ||
  184. childNode.getAttribute("id");
  185. if(fid) {
  186. break;
  187. }
  188. }
  189. childNode = childNode.nextSibling;
  190. }
  191. feature.fid = fid;
  192. return feature;
  193. },
  194. /**
  195. * Property: parseGeometry
  196. * Properties of this object are the functions that parse geometries based
  197. * on their type.
  198. */
  199. parseGeometry: {
  200. /**
  201. * Method: parseGeometry.point
  202. * Given a GML node representing a point geometry, create an OpenLayers
  203. * point geometry.
  204. *
  205. * Parameters:
  206. * node - {DOMElement} A GML node.
  207. *
  208. * Returns:
  209. * {<OpenLayers.Geometry.Point>} A point geometry.
  210. */
  211. point: function(node) {
  212. /**
  213. * Three coordinate variations to consider:
  214. * 1) <gml:pos>x y z</gml:pos>
  215. * 2) <gml:coordinates>x, y, z</gml:coordinates>
  216. * 3) <gml:coord><gml:X>x</gml:X><gml:Y>y</gml:Y></gml:coord>
  217. */
  218. var nodeList, coordString;
  219. var coords = [];
  220. // look for <gml:pos>
  221. var nodeList = this.getElementsByTagNameNS(node, this.gmlns, "pos");
  222. if(nodeList.length > 0) {
  223. coordString = nodeList[0].firstChild.nodeValue;
  224. coordString = coordString.replace(this.regExes.trimSpace, "");
  225. coords = coordString.split(this.regExes.splitSpace);
  226. }
  227. // look for <gml:coordinates>
  228. if(coords.length == 0) {
  229. nodeList = this.getElementsByTagNameNS(node, this.gmlns,
  230. "coordinates");
  231. if(nodeList.length > 0) {
  232. coordString = nodeList[0].firstChild.nodeValue;
  233. coordString = coordString.replace(this.regExes.removeSpace,
  234. "");
  235. coords = coordString.split(",");
  236. }
  237. }
  238. // look for <gml:coord>
  239. if(coords.length == 0) {
  240. nodeList = this.getElementsByTagNameNS(node, this.gmlns,
  241. "coord");
  242. if(nodeList.length > 0) {
  243. var xList = this.getElementsByTagNameNS(nodeList[0],
  244. this.gmlns, "X");
  245. var yList = this.getElementsByTagNameNS(nodeList[0],
  246. this.gmlns, "Y");
  247. if(xList.length > 0 && yList.length > 0) {
  248. coords = [xList[0].firstChild.nodeValue,
  249. yList[0].firstChild.nodeValue];
  250. }
  251. }
  252. }
  253. // preserve third dimension
  254. if(coords.length == 2) {
  255. coords[2] = null;
  256. }
  257. if (this.xy) {
  258. return new OpenLayers.Geometry.Point(coords[0], coords[1],
  259. coords[2]);
  260. }
  261. else{
  262. return new OpenLayers.Geometry.Point(coords[1], coords[0],
  263. coords[2]);
  264. }
  265. },
  266. /**
  267. * Method: parseGeometry.multipoint
  268. * Given a GML node representing a multipoint geometry, create an
  269. * OpenLayers multipoint geometry.
  270. *
  271. * Parameters:
  272. * node - {DOMElement} A GML node.
  273. *
  274. * Returns:
  275. * {<OpenLayers.Geometry.MultiPoint>} A multipoint geometry.
  276. */
  277. multipoint: function(node) {
  278. var nodeList = this.getElementsByTagNameNS(node, this.gmlns,
  279. "Point");
  280. var components = [];
  281. if(nodeList.length > 0) {
  282. var point;
  283. for(var i=0; i<nodeList.length; ++i) {
  284. point = this.parseGeometry.point.apply(this, [nodeList[i]]);
  285. if(point) {
  286. components.push(point);
  287. }
  288. }
  289. }
  290. return new OpenLayers.Geometry.MultiPoint(components);
  291. },
  292. /**
  293. * Method: parseGeometry.linestring
  294. * Given a GML node representing a linestring geometry, create an
  295. * OpenLayers linestring geometry.
  296. *
  297. * Parameters:
  298. * node - {DOMElement} A GML node.
  299. *
  300. * Returns:
  301. * {<OpenLayers.Geometry.LineString>} A linestring geometry.
  302. */
  303. linestring: function(node, ring) {
  304. /**
  305. * Two coordinate variations to consider:
  306. * 1) <gml:posList dimension="d">x0 y0 z0 x1 y1 z1</gml:posList>
  307. * 2) <gml:coordinates>x0, y0, z0 x1, y1, z1</gml:coordinates>
  308. */
  309. var nodeList, coordString;
  310. var coords = [];
  311. var points = [];
  312. // look for <gml:posList>
  313. nodeList = this.getElementsByTagNameNS(node, this.gmlns, "posList");
  314. if(nodeList.length > 0) {
  315. coordString = this.getChildValue(nodeList[0]);
  316. coordString = coordString.replace(this.regExes.trimSpace, "");
  317. coords = coordString.split(this.regExes.splitSpace);
  318. var dim = parseInt(nodeList[0].getAttribute("dimension"));
  319. var j, x, y, z;
  320. for(var i=0; i<coords.length/dim; ++i) {
  321. j = i * dim;
  322. x = coords[j];
  323. y = coords[j+1];
  324. z = (dim == 2) ? null : coords[j+2];
  325. if (this.xy) {
  326. points.push(new OpenLayers.Geometry.Point(x, y, z));
  327. } else {
  328. points.push(new OpenLayers.Geometry.Point(y, x, z));
  329. }
  330. }
  331. }
  332. // look for <gml:coordinates>
  333. if(coords.length == 0) {
  334. nodeList = this.getElementsByTagNameNS(node, this.gmlns,
  335. "coordinates");
  336. if(nodeList.length > 0) {
  337. coordString = this.getChildValue(nodeList[0]);
  338. coordString = coordString.replace(this.regExes.trimSpace,
  339. "");
  340. coordString = coordString.replace(this.regExes.trimComma,
  341. ",");
  342. var pointList = coordString.split(this.regExes.splitSpace);
  343. for(var i=0; i<pointList.length; ++i) {
  344. coords = pointList[i].split(",");
  345. if(coords.length == 2) {
  346. coords[2] = null;
  347. }
  348. if (this.xy) {
  349. points.push(new OpenLayers.Geometry.Point(coords[0],
  350. coords[1],
  351. coords[2]));
  352. } else {
  353. points.push(new OpenLayers.Geometry.Point(coords[1],
  354. coords[0],
  355. coords[2]));
  356. }
  357. }
  358. }
  359. }
  360. var line = null;
  361. if(points.length != 0) {
  362. if(ring) {
  363. line = new OpenLayers.Geometry.LinearRing(points);
  364. } else {
  365. line = new OpenLayers.Geometry.LineString(points);
  366. }
  367. }
  368. return line;
  369. },
  370. /**
  371. * Method: parseGeometry.multilinestring
  372. * Given a GML node representing a multilinestring geometry, create an
  373. * OpenLayers multilinestring geometry.
  374. *
  375. * Parameters:
  376. * node - {DOMElement} A GML node.
  377. *
  378. * Returns:
  379. * {<OpenLayers.Geometry.MultiLineString>} A multilinestring geometry.
  380. */
  381. multilinestring: function(node) {
  382. var nodeList = this.getElementsByTagNameNS(node, this.gmlns,
  383. "LineString");
  384. var components = [];
  385. if(nodeList.length > 0) {
  386. var line;
  387. for(var i=0; i<nodeList.length; ++i) {
  388. line = this.parseGeometry.linestring.apply(this,
  389. [nodeList[i]]);
  390. if(line) {
  391. components.push(line);
  392. }
  393. }
  394. }
  395. return new OpenLayers.Geometry.MultiLineString(components);
  396. },
  397. /**
  398. * Method: parseGeometry.polygon
  399. * Given a GML node representing a polygon geometry, create an
  400. * OpenLayers polygon geometry.
  401. *
  402. * Parameters:
  403. * node - {DOMElement} A GML node.
  404. *
  405. * Returns:
  406. * {<OpenLayers.Geometry.Polygon>} A polygon geometry.
  407. */
  408. polygon: function(node) {
  409. var nodeList = this.getElementsByTagNameNS(node, this.gmlns,
  410. "LinearRing");
  411. var components = [];
  412. if(nodeList.length > 0) {
  413. // this assumes exterior ring first, inner rings after
  414. var ring;
  415. for(var i=0; i<nodeList.length; ++i) {
  416. ring = this.parseGeometry.linestring.apply(this,
  417. [nodeList[i], true]);
  418. if(ring) {
  419. components.push(ring);
  420. }
  421. }
  422. }
  423. return new OpenLayers.Geometry.Polygon(components);
  424. },
  425. /**
  426. * Method: parseGeometry.multipolygon
  427. * Given a GML node representing a multipolygon geometry, create an
  428. * OpenLayers multipolygon geometry.
  429. *
  430. * Parameters:
  431. * node - {DOMElement} A GML node.
  432. *
  433. * Returns:
  434. * {<OpenLayers.Geometry.MultiPolygon>} A multipolygon geometry.
  435. */
  436. multipolygon: function(node) {
  437. var nodeList = this.getElementsByTagNameNS(node, this.gmlns,
  438. "Polygon");
  439. var components = [];
  440. if(nodeList.length > 0) {
  441. var polygon;
  442. for(var i=0; i<nodeList.length; ++i) {
  443. polygon = this.parseGeometry.polygon.apply(this,
  444. [nodeList[i]]);
  445. if(polygon) {
  446. components.push(polygon);
  447. }
  448. }
  449. }
  450. return new OpenLayers.Geometry.MultiPolygon(components);
  451. },
  452. envelope: function(node) {
  453. var components = [];
  454. var coordString;
  455. var envelope;
  456. var lpoint = this.getElementsByTagNameNS(node, this.gmlns, "lowerCorner");
  457. if (lpoint.length > 0) {
  458. var coords = [];
  459. if(lpoint.length > 0) {
  460. coordString = lpoint[0].firstChild.nodeValue;
  461. coordString = coordString.replace(this.regExes.trimSpace, "");
  462. coords = coordString.split(this.regExes.splitSpace);
  463. }
  464. if(coords.length == 2) {
  465. coords[2] = null;
  466. }
  467. if (this.xy) {
  468. var lowerPoint = new OpenLayers.Geometry.Point(coords[0], coords[1],coords[2]);
  469. } else {
  470. var lowerPoint = new OpenLayers.Geometry.Point(coords[1], coords[0],coords[2]);
  471. }
  472. }
  473. var upoint = this.getElementsByTagNameNS(node, this.gmlns, "upperCorner");
  474. if (upoint.length > 0) {
  475. var coords = [];
  476. if(upoint.length > 0) {
  477. coordString = upoint[0].firstChild.nodeValue;
  478. coordString = coordString.replace(this.regExes.trimSpace, "");
  479. coords = coordString.split(this.regExes.splitSpace);
  480. }
  481. if(coords.length == 2) {
  482. coords[2] = null;
  483. }
  484. if (this.xy) {
  485. var upperPoint = new OpenLayers.Geometry.Point(coords[0], coords[1],coords[2]);
  486. } else {
  487. var upperPoint = new OpenLayers.Geometry.Point(coords[1], coords[0],coords[2]);
  488. }
  489. }
  490. if (lowerPoint && upperPoint) {
  491. components.push(new OpenLayers.Geometry.Point(lowerPoint.x, lowerPoint.y));
  492. components.push(new OpenLayers.Geometry.Point(upperPoint.x, lowerPoint.y));
  493. components.push(new OpenLayers.Geometry.Point(upperPoint.x, upperPoint.y));
  494. components.push(new OpenLayers.Geometry.Point(lowerPoint.x, upperPoint.y));
  495. components.push(new OpenLayers.Geometry.Point(lowerPoint.x, lowerPoint.y));
  496. var ring = new OpenLayers.Geometry.LinearRing(components);
  497. envelope = new OpenLayers.Geometry.Polygon([ring]);
  498. }
  499. return envelope;
  500. },
  501. /**
  502. * Method: parseGeometry.box
  503. * Given a GML node representing a box geometry, create an
  504. * OpenLayers.Bounds.
  505. *
  506. * Parameters:
  507. * node - {DOMElement} A GML node.
  508. *
  509. * Returns:
  510. * {<OpenLayers.Bounds>} A bounds representing the box.
  511. */
  512. box: function(node) {
  513. var nodeList = this.getElementsByTagNameNS(node, this.gmlns,
  514. "coordinates");
  515. var coordString;
  516. var coords, beginPoint = null, endPoint = null;
  517. if (nodeList.length > 0) {
  518. coordString = nodeList[0].firstChild.nodeValue;
  519. coords = coordString.split(" ");
  520. if (coords.length == 2) {
  521. beginPoint = coords[0].split(",");
  522. endPoint = coords[1].split(",");
  523. }
  524. }
  525. if (beginPoint !== null && endPoint !== null) {
  526. return new OpenLayers.Bounds(parseFloat(beginPoint[0]),
  527. parseFloat(beginPoint[1]),
  528. parseFloat(endPoint[0]),
  529. parseFloat(endPoint[1]) );
  530. }
  531. }
  532. },
  533. /**
  534. * Method: parseAttributes
  535. *
  536. * Parameters:
  537. * node - {DOMElement}
  538. *
  539. * Returns:
  540. * {Object} An attributes object.
  541. */
  542. parseAttributes: function(node) {
  543. var attributes = {};
  544. // assume attributes are children of the first type 1 child
  545. var childNode = node.firstChild;
  546. var children, i, child, grandchildren, grandchild, name, value;
  547. while(childNode) {
  548. if(childNode.nodeType == 1) {
  549. // attributes are type 1 children with one type 3 child
  550. children = childNode.childNodes;
  551. for(i=0; i<children.length; ++i) {
  552. child = children[i];
  553. if(child.nodeType == 1) {
  554. grandchildren = child.childNodes;
  555. if(grandchildren.length == 1) {
  556. grandchild = grandchildren[0];
  557. if(grandchild.nodeType == 3 ||
  558. grandchild.nodeType == 4) {
  559. name = (child.prefix) ?
  560. child.nodeName.split(":")[1] :
  561. child.nodeName;
  562. value = grandchild.nodeValue.replace(
  563. this.regExes.trimSpace, "");
  564. attributes[name] = value;
  565. }
  566. } else {
  567. // If child has no childNodes (grandchildren),
  568. // set an attribute with null value.
  569. // e.g. <prefix:fieldname/> becomes
  570. // {fieldname: null}
  571. attributes[child.nodeName.split(":").pop()] = null;
  572. }
  573. }
  574. }
  575. break;
  576. }
  577. childNode = childNode.nextSibling;
  578. }
  579. return attributes;
  580. },
  581. /**
  582. * APIMethod: write
  583. * Generate a GML document string given a list of features.
  584. *
  585. * Parameters:
  586. * features - {Array(<OpenLayers.Feature.Vector>)} List of features to
  587. * serialize into a string.
  588. *
  589. * Returns:
  590. * {String} A string representing the GML document.
  591. */
  592. write: function(features) {
  593. if(!(OpenLayers.Util.isArray(features))) {
  594. features = [features];
  595. }
  596. var gml = this.createElementNS("http://www.opengis.net/wfs",
  597. "wfs:" + this.collectionName);
  598. for(var i=0; i<features.length; i++) {
  599. gml.appendChild(this.createFeatureXML(features[i]));
  600. }
  601. return OpenLayers.Format.XML.prototype.write.apply(this, [gml]);
  602. },
  603. /**
  604. * Method: createFeatureXML
  605. * Accept an OpenLayers.Feature.Vector, and build a GML node for it.
  606. *
  607. * Parameters:
  608. * feature - {<OpenLayers.Feature.Vector>} The feature to be built as GML.
  609. *
  610. * Returns:
  611. * {DOMElement} A node reprensting the feature in GML.
  612. */
  613. createFeatureXML: function(feature) {
  614. var geometry = feature.geometry;
  615. var geometryNode = this.buildGeometryNode(geometry);
  616. var geomContainer = this.createElementNS(this.featureNS,
  617. this.featurePrefix + ":" +
  618. this.geometryName);
  619. geomContainer.appendChild(geometryNode);
  620. var featureNode = this.createElementNS(this.gmlns,
  621. "gml:" + this.featureName);
  622. var featureContainer = this.createElementNS(this.featureNS,
  623. this.featurePrefix + ":" +
  624. this.layerName);
  625. var fid = feature.fid || feature.id;
  626. featureContainer.setAttribute("fid", fid);
  627. featureContainer.appendChild(geomContainer);
  628. for(var attr in feature.attributes) {
  629. var attrText = this.createTextNode(feature.attributes[attr]);
  630. var nodename = attr.substring(attr.lastIndexOf(":") + 1);
  631. var attrContainer = this.createElementNS(this.featureNS,
  632. this.featurePrefix + ":" +
  633. nodename);
  634. attrContainer.appendChild(attrText);
  635. featureContainer.appendChild(attrContainer);
  636. }
  637. featureNode.appendChild(featureContainer);
  638. return featureNode;
  639. },
  640. /**
  641. * APIMethod: buildGeometryNode
  642. */
  643. buildGeometryNode: function(geometry) {
  644. if (this.externalProjection && this.internalProjection) {
  645. geometry = geometry.clone();
  646. geometry.transform(this.internalProjection,
  647. this.externalProjection);
  648. }
  649. var className = geometry.CLASS_NAME;
  650. var type = className.substring(className.lastIndexOf(".") + 1);
  651. var builder = this.buildGeometry[type.toLowerCase()];
  652. return builder.apply(this, [geometry]);
  653. },
  654. /**
  655. * Property: buildGeometry
  656. * Object containing methods to do the actual geometry node building
  657. * based on geometry type.
  658. */
  659. buildGeometry: {
  660. // TBD retrieve the srs from layer
  661. // srsName is non-standard, so not including it until it's right.
  662. // gml.setAttribute("srsName",
  663. // "http://www.opengis.net/gml/srs/epsg.xml#4326");
  664. /**
  665. * Method: buildGeometry.point
  666. * Given an OpenLayers point geometry, create a GML point.
  667. *
  668. * Parameters:
  669. * geometry - {<OpenLayers.Geometry.Point>} A point geometry.
  670. *
  671. * Returns:
  672. * {DOMElement} A GML point node.
  673. */
  674. point: function(geometry) {
  675. var gml = this.createElementNS(this.gmlns, "gml:Point");
  676. gml.appendChild(this.buildCoordinatesNode(geometry));
  677. return gml;
  678. },
  679. /**
  680. * Method: buildGeometry.multipoint
  681. * Given an OpenLayers multipoint geometry, create a GML multipoint.
  682. *
  683. * Parameters:
  684. * geometry - {<OpenLayers.Geometry.MultiPoint>} A multipoint geometry.
  685. *
  686. * Returns:
  687. * {DOMElement} A GML multipoint node.
  688. */
  689. multipoint: function(geometry) {
  690. var gml = this.createElementNS(this.gmlns, "gml:MultiPoint");
  691. var points = geometry.components;
  692. var pointMember, pointGeom;
  693. for(var i=0; i<points.length; i++) {
  694. pointMember = this.createElementNS(this.gmlns,
  695. "gml:pointMember");
  696. pointGeom = this.buildGeometry.point.apply(this,
  697. [points[i]]);
  698. pointMember.appendChild(pointGeom);
  699. gml.appendChild(pointMember);
  700. }
  701. return gml;
  702. },
  703. /**
  704. * Method: buildGeometry.linestring
  705. * Given an OpenLayers linestring geometry, create a GML linestring.
  706. *
  707. * Parameters:
  708. * geometry - {<OpenLayers.Geometry.LineString>} A linestring geometry.
  709. *
  710. * Returns:
  711. * {DOMElement} A GML linestring node.
  712. */
  713. linestring: function(geometry) {
  714. var gml = this.createElementNS(this.gmlns, "gml:LineString");
  715. gml.appendChild(this.buildCoordinatesNode(geometry));
  716. return gml;
  717. },
  718. /**
  719. * Method: buildGeometry.multilinestring
  720. * Given an OpenLayers multilinestring geometry, create a GML
  721. * multilinestring.
  722. *
  723. * Parameters:
  724. * geometry - {<OpenLayers.Geometry.MultiLineString>} A multilinestring
  725. * geometry.
  726. *
  727. * Returns:
  728. * {DOMElement} A GML multilinestring node.
  729. */
  730. multilinestring: function(geometry) {
  731. var gml = this.createElementNS(this.gmlns, "gml:MultiLineString");
  732. var lines = geometry.components;
  733. var lineMember, lineGeom;
  734. for(var i=0; i<lines.length; ++i) {
  735. lineMember = this.createElementNS(this.gmlns,
  736. "gml:lineStringMember");
  737. lineGeom = this.buildGeometry.linestring.apply(this,
  738. [lines[i]]);
  739. lineMember.appendChild(lineGeom);
  740. gml.appendChild(lineMember);
  741. }
  742. return gml;
  743. },
  744. /**
  745. * Method: buildGeometry.linearring
  746. * Given an OpenLayers linearring geometry, create a GML linearring.
  747. *
  748. * Parameters:
  749. * geometry - {<OpenLayers.Geometry.LinearRing>} A linearring geometry.
  750. *
  751. * Returns:
  752. * {DOMElement} A GML linearring node.
  753. */
  754. linearring: function(geometry) {
  755. var gml = this.createElementNS(this.gmlns, "gml:LinearRing");
  756. gml.appendChild(this.buildCoordinatesNode(geometry));
  757. return gml;
  758. },
  759. /**
  760. * Method: buildGeometry.polygon
  761. * Given an OpenLayers polygon geometry, create a GML polygon.
  762. *
  763. * Parameters:
  764. * geometry - {<OpenLayers.Geometry.Polygon>} A polygon geometry.
  765. *
  766. * Returns:
  767. * {DOMElement} A GML polygon node.
  768. */
  769. polygon: function(geometry) {
  770. var gml = this.createElementNS(this.gmlns, "gml:Polygon");
  771. var rings = geometry.components;
  772. var ringMember, ringGeom, type;
  773. for(var i=0; i<rings.length; ++i) {
  774. type = (i==0) ? "outerBoundaryIs" : "innerBoundaryIs";
  775. ringMember = this.createElementNS(this.gmlns,
  776. "gml:" + type);
  777. ringGeom = this.buildGeometry.linearring.apply(this,
  778. [rings[i]]);
  779. ringMember.appendChild(ringGeom);
  780. gml.appendChild(ringMember);
  781. }
  782. return gml;
  783. },
  784. /**
  785. * Method: buildGeometry.multipolygon
  786. * Given an OpenLayers multipolygon geometry, create a GML multipolygon.
  787. *
  788. * Parameters:
  789. * geometry - {<OpenLayers.Geometry.MultiPolygon>} A multipolygon
  790. * geometry.
  791. *
  792. * Returns:
  793. * {DOMElement} A GML multipolygon node.
  794. */
  795. multipolygon: function(geometry) {
  796. var gml = this.createElementNS(this.gmlns, "gml:MultiPolygon");
  797. var polys = geometry.components;
  798. var polyMember, polyGeom;
  799. for(var i=0; i<polys.length; ++i) {
  800. polyMember = this.createElementNS(this.gmlns,
  801. "gml:polygonMember");
  802. polyGeom = this.buildGeometry.polygon.apply(this,
  803. [polys[i]]);
  804. polyMember.appendChild(polyGeom);
  805. gml.appendChild(polyMember);
  806. }
  807. return gml;
  808. },
  809. /**
  810. * Method: buildGeometry.bounds
  811. * Given an OpenLayers bounds, create a GML box.
  812. *
  813. * Parameters:
  814. * bounds - {<OpenLayers.Geometry.Bounds>} A bounds object.
  815. *
  816. * Returns:
  817. * {DOMElement} A GML box node.
  818. */
  819. bounds: function(bounds) {
  820. var gml = this.createElementNS(this.gmlns, "gml:Box");
  821. gml.appendChild(this.buildCoordinatesNode(bounds));
  822. return gml;
  823. }
  824. },
  825. /**
  826. * Method: buildCoordinates
  827. * builds the coordinates XmlNode
  828. * (code)
  829. * <gml:coordinates decimal="." cs="," ts=" ">...</gml:coordinates>
  830. * (end)
  831. *
  832. * Parameters:
  833. * geometry - {<OpenLayers.Geometry>}
  834. *
  835. * Returns:
  836. * {XmlNode} created xmlNode
  837. */
  838. buildCoordinatesNode: function(geometry) {
  839. var coordinatesNode = this.createElementNS(this.gmlns,
  840. "gml:coordinates");
  841. coordinatesNode.setAttribute("decimal", ".");
  842. coordinatesNode.setAttribute("cs", ",");
  843. coordinatesNode.setAttribute("ts", " ");
  844. var parts = [];
  845. if(geometry instanceof OpenLayers.Bounds){
  846. parts.push(geometry.left + "," + geometry.bottom);
  847. parts.push(geometry.right + "," + geometry.top);
  848. } else {
  849. var points = (geometry.components) ? geometry.components : [geometry];
  850. for(var i=0; i<points.length; i++) {
  851. parts.push(points[i].x + "," + points[i].y);
  852. }
  853. }
  854. var txtNode = this.createTextNode(parts.join(" "));
  855. coordinatesNode.appendChild(txtNode);
  856. return coordinatesNode;
  857. },
  858. CLASS_NAME: "OpenLayers.Format.GML"
  859. });