Base.js 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645
  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/Format/GML.js
  8. */
  9. /**
  10. * Though required in the full build, if the GML format is excluded, we set
  11. * the namespace here.
  12. */
  13. if(!OpenLayers.Format.GML) {
  14. OpenLayers.Format.GML = {};
  15. }
  16. /**
  17. * Class: OpenLayers.Format.GML.Base
  18. * Superclass for GML parsers.
  19. *
  20. * Inherits from:
  21. * - <OpenLayers.Format.XML>
  22. */
  23. OpenLayers.Format.GML.Base = OpenLayers.Class(OpenLayers.Format.XML, {
  24. /**
  25. * Property: namespaces
  26. * {Object} Mapping of namespace aliases to namespace URIs.
  27. */
  28. namespaces: {
  29. gml: "http://www.opengis.net/gml",
  30. xlink: "http://www.w3.org/1999/xlink",
  31. xsi: "http://www.w3.org/2001/XMLSchema-instance",
  32. wfs: "http://www.opengis.net/wfs" // this is a convenience for reading wfs:FeatureCollection
  33. },
  34. /**
  35. * Property: defaultPrefix
  36. */
  37. defaultPrefix: "gml",
  38. /**
  39. * Property: schemaLocation
  40. * {String} Schema location for a particular minor version.
  41. */
  42. schemaLocation: null,
  43. /**
  44. * APIProperty: featureType
  45. * {Array(String) or String} The local (without prefix) feature typeName(s).
  46. */
  47. featureType: null,
  48. /**
  49. * APIProperty: featureNS
  50. * {String} The feature namespace. Must be set in the options at
  51. * construction.
  52. */
  53. featureNS: null,
  54. /**
  55. * APIProperty: geometry
  56. * {String} Name of geometry element. Defaults to "geometry". If null, it
  57. * will be set on <read> when the first geometry is parsed.
  58. */
  59. geometryName: "geometry",
  60. /**
  61. * APIProperty: extractAttributes
  62. * {Boolean} Extract attributes from GML. Default is true.
  63. */
  64. extractAttributes: true,
  65. /**
  66. * APIProperty: srsName
  67. * {String} URI for spatial reference system. This is optional for
  68. * single part geometries and mandatory for collections and multis.
  69. * If set, the srsName attribute will be written for all geometries.
  70. * Default is null.
  71. */
  72. srsName: null,
  73. /**
  74. * APIProperty: xy
  75. * {Boolean} Order of the GML coordinate true:(x,y) or false:(y,x)
  76. * Changing is not recommended, a new Format should be instantiated.
  77. */
  78. xy: true,
  79. /**
  80. * Property: geometryTypes
  81. * {Object} Maps OpenLayers geometry class names to GML element names.
  82. * Use <setGeometryTypes> before accessing this property.
  83. */
  84. geometryTypes: null,
  85. /**
  86. * Property: singleFeatureType
  87. * {Boolean} True if there is only 1 featureType, and not an array
  88. * of featuretypes.
  89. */
  90. singleFeatureType: null,
  91. /**
  92. * Property: autoConfig
  93. * {Boolean} Indicates if the format was configured without a <featureNS>,
  94. * but auto-configured <featureNS> and <featureType> during read.
  95. * Subclasses making use of <featureType> auto-configuration should make
  96. * the first call to the <readNode> method (usually in the read method)
  97. * with true as 3rd argument, so the auto-configured featureType can be
  98. * reset and the format can be reused for subsequent reads with data from
  99. * different featureTypes. Set to false after read if you want to keep the
  100. * auto-configured values.
  101. */
  102. /**
  103. * Property: regExes
  104. * Compiled regular expressions for manipulating strings.
  105. */
  106. regExes: {
  107. trimSpace: (/^\s*|\s*$/g),
  108. removeSpace: (/\s*/g),
  109. splitSpace: (/\s+/),
  110. trimComma: (/\s*,\s*/g),
  111. featureMember: (/^(.*:)?featureMembers?$/)
  112. },
  113. /**
  114. * Constructor: OpenLayers.Format.GML.Base
  115. * Instances of this class are not created directly. Use the
  116. * <OpenLayers.Format.GML.v2> or <OpenLayers.Format.GML.v3> constructor
  117. * instead.
  118. *
  119. * Parameters:
  120. * options - {Object} An optional object whose properties will be set on
  121. * this instance.
  122. *
  123. * Valid options properties:
  124. * featureType - {Array(String) or String} Local (without prefix) feature
  125. * typeName(s) (required for write).
  126. * featureNS - {String} Feature namespace (required for write).
  127. * geometryName - {String} Geometry element name (required for write).
  128. */
  129. initialize: function(options) {
  130. OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
  131. this.setGeometryTypes();
  132. if(options && options.featureNS) {
  133. this.setNamespace("feature", options.featureNS);
  134. }
  135. this.singleFeatureType = !options || (typeof options.featureType === "string");
  136. },
  137. /**
  138. * Method: read
  139. *
  140. * Parameters:
  141. * data - {DOMElement} A gml:featureMember element, a gml:featureMembers
  142. * element, or an element containing either of the above at any level.
  143. *
  144. * Returns:
  145. * {Array(<OpenLayers.Feature.Vector>)} An array of features.
  146. */
  147. read: function(data) {
  148. if(typeof data == "string") {
  149. data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
  150. }
  151. if(data && data.nodeType == 9) {
  152. data = data.documentElement;
  153. }
  154. var features = [];
  155. this.readNode(data, {features: features}, true);
  156. if(features.length == 0) {
  157. // look for gml:featureMember elements
  158. var elements = this.getElementsByTagNameNS(
  159. data, this.namespaces.gml, "featureMember"
  160. );
  161. if(elements.length) {
  162. for(var i=0, len=elements.length; i<len; ++i) {
  163. this.readNode(elements[i], {features: features}, true);
  164. }
  165. } else {
  166. // look for gml:featureMembers elements (this is v3, but does no harm here)
  167. var elements = this.getElementsByTagNameNS(
  168. data, this.namespaces.gml, "featureMembers"
  169. );
  170. if(elements.length) {
  171. // there can be only one
  172. this.readNode(elements[0], {features: features}, true);
  173. }
  174. }
  175. }
  176. return features;
  177. },
  178. /**
  179. * Method: readNode
  180. * Shorthand for applying one of the named readers given the node
  181. * namespace and local name. Readers take two args (node, obj) and
  182. * generally extend or modify the second.
  183. *
  184. * Parameters:
  185. * node - {DOMElement} The node to be read (required).
  186. * obj - {Object} The object to be modified (optional).
  187. * first - {Boolean} Should be set to true for the first node read. This
  188. * is usually the readNode call in the read method. Without this being
  189. * set, auto-configured properties will stick on subsequent reads.
  190. *
  191. * Returns:
  192. * {Object} The input object, modified (or a new one if none was provided).
  193. */
  194. readNode: function(node, obj, first) {
  195. // on subsequent calls of format.read(), we want to reset auto-
  196. // configured properties and auto-configure again.
  197. if (first === true && this.autoConfig === true) {
  198. this.featureType = null;
  199. delete this.namespaceAlias[this.featureNS];
  200. delete this.namespaces["feature"];
  201. this.featureNS = null;
  202. }
  203. // featureType auto-configuration
  204. if (!this.featureNS && (!(node.prefix in this.namespaces) &&
  205. node.parentNode.namespaceURI == this.namespaces["gml"] &&
  206. this.regExes.featureMember.test(node.parentNode.nodeName))) {
  207. this.featureType = node.nodeName.split(":").pop();
  208. this.setNamespace("feature", node.namespaceURI);
  209. this.featureNS = node.namespaceURI;
  210. this.autoConfig = true;
  211. }
  212. return OpenLayers.Format.XML.prototype.readNode.apply(this, [node, obj]);
  213. },
  214. /**
  215. * Property: readers
  216. * Contains public functions, grouped by namespace prefix, that will
  217. * be applied when a namespaced node is found matching the function
  218. * name. The function will be applied in the scope of this parser
  219. * with two arguments: the node being read and a context object passed
  220. * from the parent.
  221. */
  222. readers: {
  223. "gml": {
  224. "_inherit": function(node, obj, container) {
  225. // To be implemented by version specific parsers
  226. },
  227. "featureMember": function(node, obj) {
  228. this.readChildNodes(node, obj);
  229. },
  230. "featureMembers": function(node, obj) {
  231. this.readChildNodes(node, obj);
  232. },
  233. "name": function(node, obj) {
  234. obj.name = this.getChildValue(node);
  235. },
  236. "boundedBy": function(node, obj) {
  237. var container = {};
  238. this.readChildNodes(node, container);
  239. if(container.components && container.components.length > 0) {
  240. obj.bounds = container.components[0];
  241. }
  242. },
  243. "Point": function(node, container) {
  244. var obj = {points: []};
  245. this.readChildNodes(node, obj);
  246. if(!container.components) {
  247. container.components = [];
  248. }
  249. container.components.push(obj.points[0]);
  250. },
  251. "coordinates": function(node, obj) {
  252. var str = this.getChildValue(node).replace(
  253. this.regExes.trimSpace, ""
  254. );
  255. str = str.replace(this.regExes.trimComma, ",");
  256. var pointList = str.split(this.regExes.splitSpace);
  257. var coords;
  258. var numPoints = pointList.length;
  259. var points = new Array(numPoints);
  260. for(var i=0; i<numPoints; ++i) {
  261. coords = pointList[i].split(",");
  262. if (this.xy) {
  263. points[i] = new OpenLayers.Geometry.Point(
  264. coords[0], coords[1], coords[2]
  265. );
  266. } else {
  267. points[i] = new OpenLayers.Geometry.Point(
  268. coords[1], coords[0], coords[2]
  269. );
  270. }
  271. }
  272. obj.points = points;
  273. },
  274. "coord": function(node, obj) {
  275. var coord = {};
  276. this.readChildNodes(node, coord);
  277. if(!obj.points) {
  278. obj.points = [];
  279. }
  280. obj.points.push(new OpenLayers.Geometry.Point(
  281. coord.x, coord.y, coord.z
  282. ));
  283. },
  284. "X": function(node, coord) {
  285. coord.x = this.getChildValue(node);
  286. },
  287. "Y": function(node, coord) {
  288. coord.y = this.getChildValue(node);
  289. },
  290. "Z": function(node, coord) {
  291. coord.z = this.getChildValue(node);
  292. },
  293. "MultiPoint": function(node, container) {
  294. var obj = {components: []};
  295. this.readers.gml._inherit.apply(this, [node, obj, container]);
  296. this.readChildNodes(node, obj);
  297. container.components = [
  298. new OpenLayers.Geometry.MultiPoint(obj.components)
  299. ];
  300. },
  301. "pointMember": function(node, obj) {
  302. this.readChildNodes(node, obj);
  303. },
  304. "LineString": function(node, container) {
  305. var obj = {};
  306. this.readers.gml._inherit.apply(this, [node, obj, container]);
  307. this.readChildNodes(node, obj);
  308. if(!container.components) {
  309. container.components = [];
  310. }
  311. container.components.push(
  312. new OpenLayers.Geometry.LineString(obj.points)
  313. );
  314. },
  315. "MultiLineString": function(node, container) {
  316. var obj = {components: []};
  317. this.readers.gml._inherit.apply(this, [node, obj, container]);
  318. this.readChildNodes(node, obj);
  319. container.components = [
  320. new OpenLayers.Geometry.MultiLineString(obj.components)
  321. ];
  322. },
  323. "lineStringMember": function(node, obj) {
  324. this.readChildNodes(node, obj);
  325. },
  326. "Polygon": function(node, container) {
  327. var obj = {outer: null, inner: []};
  328. this.readers.gml._inherit.apply(this, [node, obj, container]);
  329. this.readChildNodes(node, obj);
  330. obj.inner.unshift(obj.outer);
  331. if(!container.components) {
  332. container.components = [];
  333. }
  334. container.components.push(
  335. new OpenLayers.Geometry.Polygon(obj.inner)
  336. );
  337. },
  338. "LinearRing": function(node, obj) {
  339. var container = {};
  340. this.readers.gml._inherit.apply(this, [node, container]);
  341. this.readChildNodes(node, container);
  342. obj.components = [new OpenLayers.Geometry.LinearRing(
  343. container.points
  344. )];
  345. },
  346. "MultiPolygon": function(node, container) {
  347. var obj = {components: []};
  348. this.readers.gml._inherit.apply(this, [node, obj, container]);
  349. this.readChildNodes(node, obj);
  350. container.components = [
  351. new OpenLayers.Geometry.MultiPolygon(obj.components)
  352. ];
  353. },
  354. "polygonMember": function(node, obj) {
  355. this.readChildNodes(node, obj);
  356. },
  357. "GeometryCollection": function(node, container) {
  358. var obj = {components: []};
  359. this.readers.gml._inherit.apply(this, [node, obj, container]);
  360. this.readChildNodes(node, obj);
  361. container.components = [
  362. new OpenLayers.Geometry.Collection(obj.components)
  363. ];
  364. },
  365. "geometryMember": function(node, obj) {
  366. this.readChildNodes(node, obj);
  367. }
  368. },
  369. "feature": {
  370. "*": function(node, obj) {
  371. // The node can either be named like the featureType, or it
  372. // can be a child of the feature:featureType. Children can be
  373. // geometry or attributes.
  374. var name;
  375. var local = node.localName || node.nodeName.split(":").pop();
  376. // Since an attribute can have the same name as the feature type
  377. // we only want to read the node as a feature if the parent
  378. // node can have feature nodes as children. In this case, the
  379. // obj.features property is set.
  380. if (obj.features) {
  381. if (!this.singleFeatureType &&
  382. (OpenLayers.Util.indexOf(this.featureType, local) !== -1)) {
  383. name = "_typeName";
  384. } else if(local === this.featureType) {
  385. name = "_typeName";
  386. }
  387. } else {
  388. // Assume attribute elements have one child node and that the child
  389. // is a text node. Otherwise assume it is a geometry node.
  390. if(node.childNodes.length == 0 ||
  391. (node.childNodes.length == 1 && node.firstChild.nodeType == 3)) {
  392. if(this.extractAttributes) {
  393. name = "_attribute";
  394. }
  395. } else {
  396. name = "_geometry";
  397. }
  398. }
  399. if(name) {
  400. this.readers.feature[name].apply(this, [node, obj]);
  401. }
  402. },
  403. "_typeName": function(node, obj) {
  404. var container = {components: [], attributes: {}};
  405. this.readChildNodes(node, container);
  406. // look for common gml namespaced elements
  407. if(container.name) {
  408. container.attributes.name = container.name;
  409. }
  410. var feature = new OpenLayers.Feature.Vector(
  411. container.components[0], container.attributes
  412. );
  413. if (!this.singleFeatureType) {
  414. feature.type = node.nodeName.split(":").pop();
  415. feature.namespace = node.namespaceURI;
  416. }
  417. var fid = node.getAttribute("fid") ||
  418. this.getAttributeNS(node, this.namespaces["gml"], "id");
  419. if(fid) {
  420. feature.fid = fid;
  421. }
  422. if(this.internalProjection && this.externalProjection &&
  423. feature.geometry) {
  424. feature.geometry.transform(
  425. this.externalProjection, this.internalProjection
  426. );
  427. }
  428. if(container.bounds) {
  429. feature.bounds = container.bounds;
  430. }
  431. obj.features.push(feature);
  432. },
  433. "_geometry": function(node, obj) {
  434. if (!this.geometryName) {
  435. this.geometryName = node.nodeName.split(":").pop();
  436. }
  437. this.readChildNodes(node, obj);
  438. },
  439. "_attribute": function(node, obj) {
  440. var local = node.localName || node.nodeName.split(":").pop();
  441. var value = this.getChildValue(node);
  442. obj.attributes[local] = value;
  443. }
  444. },
  445. "wfs": {
  446. "FeatureCollection": function(node, obj) {
  447. this.readChildNodes(node, obj);
  448. }
  449. }
  450. },
  451. /**
  452. * Method: write
  453. *
  454. * Parameters:
  455. * features - {Array(<OpenLayers.Feature.Vector>) | OpenLayers.Feature.Vector}
  456. * An array of features or a single feature.
  457. *
  458. * Returns:
  459. * {String} Given an array of features, a doc with a gml:featureMembers
  460. * element will be returned. Given a single feature, a doc with a
  461. * gml:featureMember element will be returned.
  462. */
  463. write: function(features) {
  464. var name;
  465. if(OpenLayers.Util.isArray(features)) {
  466. name = "featureMembers";
  467. } else {
  468. name = "featureMember";
  469. }
  470. var root = this.writeNode("gml:" + name, features);
  471. this.setAttributeNS(
  472. root, this.namespaces["xsi"],
  473. "xsi:schemaLocation", this.schemaLocation
  474. );
  475. return OpenLayers.Format.XML.prototype.write.apply(this, [root]);
  476. },
  477. /**
  478. * Property: writers
  479. * As a compliment to the readers property, this structure contains public
  480. * writing functions grouped by namespace alias and named like the
  481. * node names they produce.
  482. */
  483. writers: {
  484. "gml": {
  485. "featureMember": function(feature) {
  486. var node = this.createElementNSPlus("gml:featureMember");
  487. this.writeNode("feature:_typeName", feature, node);
  488. return node;
  489. },
  490. "MultiPoint": function(geometry) {
  491. var node = this.createElementNSPlus("gml:MultiPoint");
  492. var components = geometry.components || [geometry];
  493. for(var i=0, ii=components.length; i<ii; ++i) {
  494. this.writeNode("pointMember", components[i], node);
  495. }
  496. return node;
  497. },
  498. "pointMember": function(geometry) {
  499. var node = this.createElementNSPlus("gml:pointMember");
  500. this.writeNode("Point", geometry, node);
  501. return node;
  502. },
  503. "MultiLineString": function(geometry) {
  504. var node = this.createElementNSPlus("gml:MultiLineString");
  505. var components = geometry.components || [geometry];
  506. for(var i=0, ii=components.length; i<ii; ++i) {
  507. this.writeNode("lineStringMember", components[i], node);
  508. }
  509. return node;
  510. },
  511. "lineStringMember": function(geometry) {
  512. var node = this.createElementNSPlus("gml:lineStringMember");
  513. this.writeNode("LineString", geometry, node);
  514. return node;
  515. },
  516. "MultiPolygon": function(geometry) {
  517. var node = this.createElementNSPlus("gml:MultiPolygon");
  518. var components = geometry.components || [geometry];
  519. for(var i=0, ii=components.length; i<ii; ++i) {
  520. this.writeNode(
  521. "polygonMember", components[i], node
  522. );
  523. }
  524. return node;
  525. },
  526. "polygonMember": function(geometry) {
  527. var node = this.createElementNSPlus("gml:polygonMember");
  528. this.writeNode("Polygon", geometry, node);
  529. return node;
  530. },
  531. "GeometryCollection": function(geometry) {
  532. var node = this.createElementNSPlus("gml:GeometryCollection");
  533. for(var i=0, len=geometry.components.length; i<len; ++i) {
  534. this.writeNode("geometryMember", geometry.components[i], node);
  535. }
  536. return node;
  537. },
  538. "geometryMember": function(geometry) {
  539. var node = this.createElementNSPlus("gml:geometryMember");
  540. var child = this.writeNode("feature:_geometry", geometry);
  541. node.appendChild(child.firstChild);
  542. return node;
  543. }
  544. },
  545. "feature": {
  546. "_typeName": function(feature) {
  547. var node = this.createElementNSPlus("feature:" + this.featureType, {
  548. attributes: {fid: feature.fid}
  549. });
  550. if(feature.geometry) {
  551. this.writeNode("feature:_geometry", feature.geometry, node);
  552. }
  553. for(var name in feature.attributes) {
  554. var value = feature.attributes[name];
  555. if(value != null) {
  556. this.writeNode(
  557. "feature:_attribute",
  558. {name: name, value: value}, node
  559. );
  560. }
  561. }
  562. return node;
  563. },
  564. "_geometry": function(geometry) {
  565. if(this.externalProjection && this.internalProjection) {
  566. geometry = geometry.clone().transform(
  567. this.internalProjection, this.externalProjection
  568. );
  569. }
  570. var node = this.createElementNSPlus(
  571. "feature:" + this.geometryName
  572. );
  573. var type = this.geometryTypes[geometry.CLASS_NAME];
  574. var child = this.writeNode("gml:" + type, geometry, node);
  575. if(this.srsName) {
  576. child.setAttribute("srsName", this.srsName);
  577. }
  578. return node;
  579. },
  580. "_attribute": function(obj) {
  581. return this.createElementNSPlus("feature:" + obj.name, {
  582. value: obj.value
  583. });
  584. }
  585. },
  586. "wfs": {
  587. "FeatureCollection": function(features) {
  588. /**
  589. * This is only here because GML2 only describes abstract
  590. * feature collections. Typically, you would not be using
  591. * the GML format to write wfs elements. This just provides
  592. * some way to write out lists of features. GML3 defines the
  593. * featureMembers element, so that is used by default instead.
  594. */
  595. var node = this.createElementNSPlus("wfs:FeatureCollection");
  596. for(var i=0, len=features.length; i<len; ++i) {
  597. this.writeNode("gml:featureMember", features[i], node);
  598. }
  599. return node;
  600. }
  601. }
  602. },
  603. /**
  604. * Method: setGeometryTypes
  605. * Sets the <geometryTypes> mapping.
  606. */
  607. setGeometryTypes: function() {
  608. this.geometryTypes = {
  609. "OpenLayers.Geometry.Point": "Point",
  610. "OpenLayers.Geometry.MultiPoint": "MultiPoint",
  611. "OpenLayers.Geometry.LineString": "LineString",
  612. "OpenLayers.Geometry.MultiLineString": "MultiLineString",
  613. "OpenLayers.Geometry.Polygon": "Polygon",
  614. "OpenLayers.Geometry.MultiPolygon": "MultiPolygon",
  615. "OpenLayers.Geometry.Collection": "GeometryCollection"
  616. };
  617. },
  618. CLASS_NAME: "OpenLayers.Format.GML.Base"
  619. });