v1.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  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/WFST.js
  8. * @requires OpenLayers/Filter/Spatial.js
  9. * @requires OpenLayers/Filter/FeatureId.js
  10. */
  11. /**
  12. * Class: OpenLayers.Format.WFST.v1
  13. * Superclass for WFST parsers.
  14. *
  15. * Inherits from:
  16. * - <OpenLayers.Format.XML>
  17. */
  18. OpenLayers.Format.WFST.v1 = OpenLayers.Class(OpenLayers.Format.XML, {
  19. /**
  20. * Property: namespaces
  21. * {Object} Mapping of namespace aliases to namespace URIs.
  22. */
  23. namespaces: {
  24. xlink: "http://www.w3.org/1999/xlink",
  25. xsi: "http://www.w3.org/2001/XMLSchema-instance",
  26. wfs: "http://www.opengis.net/wfs",
  27. gml: "http://www.opengis.net/gml",
  28. ogc: "http://www.opengis.net/ogc",
  29. ows: "http://www.opengis.net/ows"
  30. },
  31. /**
  32. * Property: defaultPrefix
  33. */
  34. defaultPrefix: "wfs",
  35. /**
  36. * Property: version
  37. * {String} WFS version number.
  38. */
  39. version: null,
  40. /**
  41. * Property: schemaLocation
  42. * {String} Schema location for a particular minor version.
  43. */
  44. schemaLocations: null,
  45. /**
  46. * APIProperty: srsName
  47. * {String} URI for spatial reference system.
  48. */
  49. srsName: null,
  50. /**
  51. * APIProperty: extractAttributes
  52. * {Boolean} Extract attributes from GML. Default is true.
  53. */
  54. extractAttributes: true,
  55. /**
  56. * APIProperty: xy
  57. * {Boolean} Order of the GML coordinate true:(x,y) or false:(y,x)
  58. * Changing is not recommended, a new Format should be instantiated.
  59. */
  60. xy: true,
  61. /**
  62. * Property: stateName
  63. * {Object} Maps feature states to node names.
  64. */
  65. stateName: null,
  66. /**
  67. * Constructor: OpenLayers.Format.WFST.v1
  68. * Instances of this class are not created directly. Use the
  69. * <OpenLayers.Format.WFST.v1_0_0> or <OpenLayers.Format.WFST.v1_1_0>
  70. * constructor instead.
  71. *
  72. * Parameters:
  73. * options - {Object} An optional object whose properties will be set on
  74. * this instance.
  75. */
  76. initialize: function(options) {
  77. // set state name mapping
  78. this.stateName = {};
  79. this.stateName[OpenLayers.State.INSERT] = "wfs:Insert";
  80. this.stateName[OpenLayers.State.UPDATE] = "wfs:Update";
  81. this.stateName[OpenLayers.State.DELETE] = "wfs:Delete";
  82. OpenLayers.Format.XML.prototype.initialize.apply(this, [options]);
  83. },
  84. /**
  85. * Method: getSrsName
  86. */
  87. getSrsName: function(feature, options) {
  88. var srsName = options && options.srsName;
  89. if(!srsName) {
  90. if(feature && feature.layer) {
  91. srsName = feature.layer.projection.getCode();
  92. } else {
  93. srsName = this.srsName;
  94. }
  95. }
  96. return srsName;
  97. },
  98. /**
  99. * APIMethod: read
  100. * Parse the response from a transaction. Because WFS is split into
  101. * Transaction requests (create, update, and delete) and GetFeature
  102. * requests (read), this method handles parsing of both types of
  103. * responses.
  104. *
  105. * Parameters:
  106. * data - {String | Document} The WFST document to read
  107. * options - {Object} Options for the reader
  108. *
  109. * Valid options properties:
  110. * output - {String} either "features" or "object". The default is
  111. * "features", which means that the method will return an array of
  112. * features. If set to "object", an object with a "features" property
  113. * and other properties read by the parser will be returned.
  114. *
  115. * Returns:
  116. * {Array | Object} Output depending on the output option.
  117. */
  118. read: function(data, options) {
  119. options = options || {};
  120. OpenLayers.Util.applyDefaults(options, {
  121. output: "features"
  122. });
  123. if(typeof data == "string") {
  124. data = OpenLayers.Format.XML.prototype.read.apply(this, [data]);
  125. }
  126. if(data && data.nodeType == 9) {
  127. data = data.documentElement;
  128. }
  129. var obj = {};
  130. if(data) {
  131. this.readNode(data, obj, true);
  132. }
  133. if(obj.features && options.output === "features") {
  134. obj = obj.features;
  135. }
  136. return obj;
  137. },
  138. /**
  139. * Property: readers
  140. * Contains public functions, grouped by namespace prefix, that will
  141. * be applied when a namespaced node is found matching the function
  142. * name. The function will be applied in the scope of this parser
  143. * with two arguments: the node being read and a context object passed
  144. * from the parent.
  145. */
  146. readers: {
  147. "wfs": {
  148. "FeatureCollection": function(node, obj) {
  149. obj.features = [];
  150. this.readChildNodes(node, obj);
  151. }
  152. }
  153. },
  154. /**
  155. * Method: write
  156. * Given an array of features, write a WFS transaction. This assumes
  157. * the features have a state property that determines the operation
  158. * type - insert, update, or delete.
  159. *
  160. * Parameters:
  161. * features - {Array(<OpenLayers.Feature.Vector>)} A list of features. See
  162. * below for a more detailed description of the influence of the
  163. * feature's *modified* property.
  164. * options - {Object}
  165. *
  166. * feature.modified rules:
  167. * If a feature has a modified property set, the following checks will be
  168. * made before a feature's geometry or attribute is included in an Update
  169. * transaction:
  170. * - *modified* is not set at all: The geometry and all attributes will be
  171. * included.
  172. * - *modified.geometry* is set (null or a geometry): The geometry will be
  173. * included. If *modified.attributes* is not set, all attributes will
  174. * be included.
  175. * - *modified.attributes* is set: Only the attributes set (i.e. to null or
  176. * a value) in *modified.attributes* will be included.
  177. * If *modified.geometry* is not set, the geometry will not be included.
  178. *
  179. * Valid options include:
  180. * - *multi* {Boolean} If set to true, geometries will be casted to
  181. * Multi geometries before writing.
  182. *
  183. * Returns:
  184. * {String} A serialized WFS transaction.
  185. */
  186. write: function(features, options) {
  187. var node = this.writeNode("wfs:Transaction", {
  188. features:features,
  189. options: options
  190. });
  191. var value = this.schemaLocationAttr();
  192. if(value) {
  193. this.setAttributeNS(
  194. node, this.namespaces["xsi"], "xsi:schemaLocation", value
  195. );
  196. }
  197. return OpenLayers.Format.XML.prototype.write.apply(this, [node]);
  198. },
  199. /**
  200. * Property: writers
  201. * As a compliment to the readers property, this structure contains public
  202. * writing functions grouped by namespace alias and named like the
  203. * node names they produce.
  204. */
  205. writers: {
  206. "wfs": {
  207. "GetFeature": function(options) {
  208. var node = this.createElementNSPlus("wfs:GetFeature", {
  209. attributes: {
  210. service: "WFS",
  211. version: this.version,
  212. handle: options && options.handle,
  213. outputFormat: options && options.outputFormat,
  214. maxFeatures: options && options.maxFeatures,
  215. "xsi:schemaLocation": this.schemaLocationAttr(options)
  216. }
  217. });
  218. if (typeof this.featureType == "string") {
  219. this.writeNode("Query", options, node);
  220. } else {
  221. for (var i=0,len = this.featureType.length; i<len; i++) {
  222. options.featureType = this.featureType[i];
  223. this.writeNode("Query", options, node);
  224. }
  225. }
  226. return node;
  227. },
  228. "Transaction": function(obj) {
  229. obj = obj || {};
  230. var options = obj.options || {};
  231. var node = this.createElementNSPlus("wfs:Transaction", {
  232. attributes: {
  233. service: "WFS",
  234. version: this.version,
  235. handle: options.handle
  236. }
  237. });
  238. var i, len;
  239. var features = obj.features;
  240. if(features) {
  241. // temporarily re-assigning geometry types
  242. if (options.multi === true) {
  243. OpenLayers.Util.extend(this.geometryTypes, {
  244. "OpenLayers.Geometry.Point": "MultiPoint",
  245. "OpenLayers.Geometry.LineString": (this.multiCurve === true) ? "MultiCurve": "MultiLineString",
  246. "OpenLayers.Geometry.Polygon": (this.multiSurface === true) ? "MultiSurface" : "MultiPolygon"
  247. });
  248. }
  249. var name, feature;
  250. for(i=0, len=features.length; i<len; ++i) {
  251. feature = features[i];
  252. name = this.stateName[feature.state];
  253. if(name) {
  254. this.writeNode(name, {
  255. feature: feature,
  256. options: options
  257. }, node);
  258. }
  259. }
  260. // switch back to original geometry types assignment
  261. if (options.multi === true) {
  262. this.setGeometryTypes();
  263. }
  264. }
  265. if (options.nativeElements) {
  266. for (i=0, len=options.nativeElements.length; i<len; ++i) {
  267. this.writeNode("wfs:Native",
  268. options.nativeElements[i], node);
  269. }
  270. }
  271. return node;
  272. },
  273. "Native": function(nativeElement) {
  274. var node = this.createElementNSPlus("wfs:Native", {
  275. attributes: {
  276. vendorId: nativeElement.vendorId,
  277. safeToIgnore: nativeElement.safeToIgnore
  278. },
  279. value: nativeElement.value
  280. });
  281. return node;
  282. },
  283. "Insert": function(obj) {
  284. var feature = obj.feature;
  285. var options = obj.options;
  286. var node = this.createElementNSPlus("wfs:Insert", {
  287. attributes: {
  288. handle: options && options.handle
  289. }
  290. });
  291. this.srsName = this.getSrsName(feature);
  292. this.writeNode("feature:_typeName", feature, node);
  293. return node;
  294. },
  295. "Update": function(obj) {
  296. var feature = obj.feature;
  297. var options = obj.options;
  298. var node = this.createElementNSPlus("wfs:Update", {
  299. attributes: {
  300. handle: options && options.handle,
  301. typeName: (this.featureNS ? this.featurePrefix + ":" : "") +
  302. this.featureType
  303. }
  304. });
  305. if(this.featureNS) {
  306. node.setAttribute("xmlns:" + this.featurePrefix, this.featureNS);
  307. }
  308. // add in geometry
  309. var modified = feature.modified;
  310. if (this.geometryName !== null && (!modified || modified.geometry !== undefined)) {
  311. this.srsName = this.getSrsName(feature);
  312. this.writeNode(
  313. "Property", {name: this.geometryName, value: feature.geometry}, node
  314. );
  315. }
  316. // add in attributes
  317. for(var key in feature.attributes) {
  318. if(feature.attributes[key] !== undefined &&
  319. (!modified || !modified.attributes ||
  320. (modified.attributes && modified.attributes[key] !== undefined))) {
  321. this.writeNode(
  322. "Property", {name: key, value: feature.attributes[key]}, node
  323. );
  324. }
  325. }
  326. // add feature id filter
  327. this.writeNode("ogc:Filter", new OpenLayers.Filter.FeatureId({
  328. fids: [feature.fid]
  329. }), node);
  330. return node;
  331. },
  332. "Property": function(obj) {
  333. var node = this.createElementNSPlus("wfs:Property");
  334. this.writeNode("Name", obj.name, node);
  335. if(obj.value !== null) {
  336. this.writeNode("Value", obj.value, node);
  337. }
  338. return node;
  339. },
  340. "Name": function(name) {
  341. return this.createElementNSPlus("wfs:Name", {value: name});
  342. },
  343. "Value": function(obj) {
  344. var node;
  345. if(obj instanceof OpenLayers.Geometry) {
  346. node = this.createElementNSPlus("wfs:Value");
  347. var geom = this.writeNode("feature:_geometry", obj).firstChild;
  348. node.appendChild(geom);
  349. } else {
  350. node = this.createElementNSPlus("wfs:Value", {value: obj});
  351. }
  352. return node;
  353. },
  354. "Delete": function(obj) {
  355. var feature = obj.feature;
  356. var options = obj.options;
  357. var node = this.createElementNSPlus("wfs:Delete", {
  358. attributes: {
  359. handle: options && options.handle,
  360. typeName: (this.featureNS ? this.featurePrefix + ":" : "") +
  361. this.featureType
  362. }
  363. });
  364. if(this.featureNS) {
  365. node.setAttribute("xmlns:" + this.featurePrefix, this.featureNS);
  366. }
  367. this.writeNode("ogc:Filter", new OpenLayers.Filter.FeatureId({
  368. fids: [feature.fid]
  369. }), node);
  370. return node;
  371. }
  372. }
  373. },
  374. /**
  375. * Method: schemaLocationAttr
  376. * Generate the xsi:schemaLocation attribute value.
  377. *
  378. * Returns:
  379. * {String} The xsi:schemaLocation attribute or undefined if none.
  380. */
  381. schemaLocationAttr: function(options) {
  382. options = OpenLayers.Util.extend({
  383. featurePrefix: this.featurePrefix,
  384. schema: this.schema
  385. }, options);
  386. var schemaLocations = OpenLayers.Util.extend({}, this.schemaLocations);
  387. if(options.schema) {
  388. schemaLocations[options.featurePrefix] = options.schema;
  389. }
  390. var parts = [];
  391. var uri;
  392. for(var key in schemaLocations) {
  393. uri = this.namespaces[key];
  394. if(uri) {
  395. parts.push(uri + " " + schemaLocations[key]);
  396. }
  397. }
  398. var value = parts.join(" ") || undefined;
  399. return value;
  400. },
  401. /**
  402. * Method: setFilterProperty
  403. * Set the property of each spatial filter.
  404. *
  405. * Parameters:
  406. * filter - {<OpenLayers.Filter>}
  407. */
  408. setFilterProperty: function(filter) {
  409. if(filter.filters) {
  410. for(var i=0, len=filter.filters.length; i<len; ++i) {
  411. OpenLayers.Format.WFST.v1.prototype.setFilterProperty.call(this, filter.filters[i]);
  412. }
  413. } else {
  414. if(filter instanceof OpenLayers.Filter.Spatial && !filter.property) {
  415. // got a spatial filter without property, so set it
  416. filter.property = this.geometryName;
  417. }
  418. }
  419. },
  420. CLASS_NAME: "OpenLayers.Format.WFST.v1"
  421. });