summaryrefslogtreecommitdiff
path: root/misc/openlayers/lib/OpenLayers/Format/Atom.js
diff options
context:
space:
mode:
Diffstat (limited to 'misc/openlayers/lib/OpenLayers/Format/Atom.js')
-rw-r--r--misc/openlayers/lib/OpenLayers/Format/Atom.js712
1 files changed, 712 insertions, 0 deletions
diff --git a/misc/openlayers/lib/OpenLayers/Format/Atom.js b/misc/openlayers/lib/OpenLayers/Format/Atom.js
new file mode 100644
index 0000000..8eb5792
--- /dev/null
+++ b/misc/openlayers/lib/OpenLayers/Format/Atom.js
@@ -0,0 +1,712 @@
+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the 2-clause BSD license.
+ * See license.txt in the OpenLayers distribution or repository for the
+ * full text of the license. */
+
+/**
+ * @requires OpenLayers/Format/XML.js
+ * @requires OpenLayers/Format/GML/v3.js
+ * @requires OpenLayers/Feature/Vector.js
+ */
+
+/**
+ * Class: OpenLayers.Format.Atom
+ * Read/write Atom feeds. Create a new instance with the
+ * <OpenLayers.Format.AtomFeed> constructor.
+ *
+ * Inherits from:
+ * - <OpenLayers.Format.XML>
+ */
+OpenLayers.Format.Atom = OpenLayers.Class(OpenLayers.Format.XML, {
+
+ /**
+ * Property: namespaces
+ * {Object} Mapping of namespace aliases to namespace URIs. Properties
+ * of this object should not be set individually. Read-only. All
+ * XML subclasses should have their own namespaces object. Use
+ * <setNamespace> to add or set a namespace alias after construction.
+ */
+ namespaces: {
+ atom: "http://www.w3.org/2005/Atom",
+ georss: "http://www.georss.org/georss"
+ },
+
+ /**
+ * APIProperty: feedTitle
+ * {String} Atom feed elements require a title. Default is "untitled".
+ */
+ feedTitle: "untitled",
+
+ /**
+ * APIProperty: defaultEntryTitle
+ * {String} Atom entry elements require a title. In cases where one is
+ * not provided in the feature attributes, this will be used. Default
+ * is "untitled".
+ */
+ defaultEntryTitle: "untitled",
+
+ /**
+ * Property: gmlParse
+ * {Object} GML Format object for parsing features
+ * Non-API and only created if necessary
+ */
+ gmlParser: null,
+
+ /**
+ * APIProperty: xy
+ * {Boolean} Order of the GML coordinate: true:(x,y) or false:(y,x)
+ * For GeoRSS the default is (y,x), therefore: false
+ */
+ xy: false,
+
+ /**
+ * Constructor: OpenLayers.Format.AtomEntry
+ * Create a new parser for Atom.
+ *
+ * Parameters:
+ * options - {Object} An optional object whose properties will be set on
+ * this instance.
+ */
+
+ /**
+ * APIMethod: read
+ * Return a list of features from an Atom feed or entry document.
+
+ * Parameters:
+ * doc - {Element} or {String}
+ *
+ * Returns:
+ * Array({<OpenLayers.Feature.Vector>})
+ */
+ read: function(doc) {
+ if (typeof doc == "string") {
+ doc = OpenLayers.Format.XML.prototype.read.apply(this, [doc]);
+ }
+ return this.parseFeatures(doc);
+ },
+
+ /**
+ * APIMethod: write
+ * Serialize or more feature nodes to Atom documents.
+ *
+ * Parameters:
+ * features - {<OpenLayers.Feature.Vector>} or Array({<OpenLayers.Feature.Vector>})
+ *
+ * Returns:
+ * {String} an Atom entry document if passed one feature node, or a feed
+ * document if passed an array of feature nodes.
+ */
+ write: function(features) {
+ var doc;
+ if (OpenLayers.Util.isArray(features)) {
+ doc = this.createElementNSPlus("atom:feed");
+ doc.appendChild(
+ this.createElementNSPlus("atom:title", {
+ value: this.feedTitle
+ })
+ );
+ for (var i=0, ii=features.length; i<ii; i++) {
+ doc.appendChild(this.buildEntryNode(features[i]));
+ }
+ }
+ else {
+ doc = this.buildEntryNode(features);
+ }
+ return OpenLayers.Format.XML.prototype.write.apply(this, [doc]);
+ },
+
+ /**
+ * Method: buildContentNode
+ *
+ * Parameters:
+ * content - {Object}
+ *
+ * Returns:
+ * {DOMElement} an Atom content node.
+ *
+ * TODO: types other than text.
+ */
+ buildContentNode: function(content) {
+ var node = this.createElementNSPlus("atom:content", {
+ attributes: {
+ type: content.type || null
+ }
+ });
+ if (content.src) {
+ node.setAttribute("src", content.src);
+ } else {
+ if (content.type == "text" || content.type == null) {
+ node.appendChild(
+ this.createTextNode(content.value)
+ );
+ } else if (content.type == "html") {
+ if (typeof content.value != "string") {
+ throw "HTML content must be in form of an escaped string";
+ }
+ node.appendChild(
+ this.createTextNode(content.value)
+ );
+ } else if (content.type == "xhtml") {
+ node.appendChild(content.value);
+ } else if (content.type == "xhtml" ||
+ content.type.match(/(\+|\/)xml$/)) {
+ node.appendChild(content.value);
+ }
+ else { // MUST be a valid Base64 encoding
+ node.appendChild(
+ this.createTextNode(content.value)
+ );
+ }
+ }
+ return node;
+ },
+
+ /**
+ * Method: buildEntryNode
+ * Build an Atom entry node from a feature object.
+ *
+ * Parameters:
+ * feature - {<OpenLayers.Feature.Vector>}
+ *
+ * Returns:
+ * {DOMElement} an Atom entry node.
+ *
+ * These entries are geared for publication using AtomPub.
+ *
+ * TODO: support extension elements
+ */
+ buildEntryNode: function(feature) {
+ var attrib = feature.attributes;
+ var atomAttrib = attrib.atom || {};
+ var entryNode = this.createElementNSPlus("atom:entry");
+
+ // atom:author
+ if (atomAttrib.authors) {
+ var authors = OpenLayers.Util.isArray(atomAttrib.authors) ?
+ atomAttrib.authors : [atomAttrib.authors];
+ for (var i=0, ii=authors.length; i<ii; i++) {
+ entryNode.appendChild(
+ this.buildPersonConstructNode(
+ "author", authors[i]
+ )
+ );
+ }
+ }
+
+ // atom:category
+ if (atomAttrib.categories) {
+ var categories = OpenLayers.Util.isArray(atomAttrib.categories) ?
+ atomAttrib.categories : [atomAttrib.categories];
+ var category;
+ for (var i=0, ii=categories.length; i<ii; i++) {
+ category = categories[i];
+ entryNode.appendChild(
+ this.createElementNSPlus("atom:category", {
+ attributes: {
+ term: category.term,
+ scheme: category.scheme || null,
+ label: category.label || null
+ }
+ })
+ );
+ }
+ }
+
+ // atom:content
+ if (atomAttrib.content) {
+ entryNode.appendChild(this.buildContentNode(atomAttrib.content));
+ }
+
+ // atom:contributor
+ if (atomAttrib.contributors) {
+ var contributors = OpenLayers.Util.isArray(atomAttrib.contributors) ?
+ atomAttrib.contributors : [atomAttrib.contributors];
+ for (var i=0, ii=contributors.length; i<ii; i++) {
+ entryNode.appendChild(
+ this.buildPersonConstructNode(
+ "contributor",
+ contributors[i]
+ )
+ );
+ }
+ }
+
+ // atom:id
+ if (feature.fid) {
+ entryNode.appendChild(
+ this.createElementNSPlus("atom:id", {
+ value: feature.fid
+ })
+ );
+ }
+
+ // atom:link
+ if (atomAttrib.links) {
+ var links = OpenLayers.Util.isArray(atomAttrib.links) ?
+ atomAttrib.links : [atomAttrib.links];
+ var link;
+ for (var i=0, ii=links.length; i<ii; i++) {
+ link = links[i];
+ entryNode.appendChild(
+ this.createElementNSPlus("atom:link", {
+ attributes: {
+ href: link.href,
+ rel: link.rel || null,
+ type: link.type || null,
+ hreflang: link.hreflang || null,
+ title: link.title || null,
+ length: link.length || null
+ }
+ })
+ );
+ }
+ }
+
+ // atom:published
+ if (atomAttrib.published) {
+ entryNode.appendChild(
+ this.createElementNSPlus("atom:published", {
+ value: atomAttrib.published
+ })
+ );
+ }
+
+ // atom:rights
+ if (atomAttrib.rights) {
+ entryNode.appendChild(
+ this.createElementNSPlus("atom:rights", {
+ value: atomAttrib.rights
+ })
+ );
+ }
+
+ // atom:source not implemented
+
+ // atom:summary
+ if (atomAttrib.summary || attrib.description) {
+ entryNode.appendChild(
+ this.createElementNSPlus("atom:summary", {
+ value: atomAttrib.summary || attrib.description
+ })
+ );
+ }
+
+ // atom:title
+ entryNode.appendChild(
+ this.createElementNSPlus("atom:title", {
+ value: atomAttrib.title || attrib.title || this.defaultEntryTitle
+ })
+ );
+
+ // atom:updated
+ if (atomAttrib.updated) {
+ entryNode.appendChild(
+ this.createElementNSPlus("atom:updated", {
+ value: atomAttrib.updated
+ })
+ );
+ }
+
+ // georss:where
+ if (feature.geometry) {
+ var whereNode = this.createElementNSPlus("georss:where");
+ whereNode.appendChild(
+ this.buildGeometryNode(feature.geometry)
+ );
+ entryNode.appendChild(whereNode);
+ }
+
+ return entryNode;
+ },
+
+ /**
+ * Method: initGmlParser
+ * Creates a GML parser.
+ */
+ initGmlParser: function() {
+ this.gmlParser = new OpenLayers.Format.GML.v3({
+ xy: this.xy,
+ featureNS: "http://example.com#feature",
+ internalProjection: this.internalProjection,
+ externalProjection: this.externalProjection
+ });
+ },
+
+ /**
+ * Method: buildGeometryNode
+ * builds a GeoRSS node with a given geometry
+ *
+ * Parameters:
+ * geometry - {<OpenLayers.Geometry>}
+ *
+ * Returns:
+ * {DOMElement} A gml node.
+ */
+ buildGeometryNode: function(geometry) {
+ if (!this.gmlParser) {
+ this.initGmlParser();
+ }
+ var node = this.gmlParser.writeNode("feature:_geometry", geometry);
+ return node.firstChild;
+ },
+
+ /**
+ * Method: buildPersonConstructNode
+ *
+ * Parameters:
+ * name - {String}
+ * value - {Object}
+ *
+ * Returns:
+ * {DOMElement} an Atom person construct node.
+ *
+ * Example:
+ * >>> buildPersonConstructNode("author", {name: "John Smith"})
+ * {<author><name>John Smith</name></author>}
+ *
+ * TODO: how to specify extension elements? Add to the oNames array?
+ */
+ buildPersonConstructNode: function(name, value) {
+ var oNames = ["uri", "email"];
+ var personNode = this.createElementNSPlus("atom:" + name);
+ personNode.appendChild(
+ this.createElementNSPlus("atom:name", {
+ value: value.name
+ })
+ );
+ for (var i=0, ii=oNames.length; i<ii; i++) {
+ if (value[oNames[i]]) {
+ personNode.appendChild(
+ this.createElementNSPlus("atom:" + oNames[i], {
+ value: value[oNames[i]]
+ })
+ );
+ }
+ }
+ return personNode;
+ },
+
+ /**
+ * Method: getFirstChildValue
+ *
+ * Parameters:
+ * node - {DOMElement}
+ * nsuri - {String} Child node namespace uri ("*" for any).
+ * name - {String} Child node name.
+ * def - {String} Optional string default to return if no child found.
+ *
+ * Returns:
+ * {String} The value of the first child with the given tag name. Returns
+ * default value or empty string if none found.
+ */
+ getFirstChildValue: function(node, nsuri, name, def) {
+ var value;
+ var nodes = this.getElementsByTagNameNS(node, nsuri, name);
+ if (nodes && nodes.length > 0) {
+ value = this.getChildValue(nodes[0], def);
+ } else {
+ value = def;
+ }
+ return value;
+ },
+
+ /**
+ * Method: parseFeature
+ * Parse feature from an Atom entry node..
+ *
+ * Parameters:
+ * node - {DOMElement} An Atom entry or feed node.
+ *
+ * Returns:
+ * {<OpenLayers.Feature.Vector>}
+ */
+ parseFeature: function(node) {
+ var atomAttrib = {};
+ var value = null;
+ var nodes = null;
+ var attval = null;
+ var atomns = this.namespaces.atom;
+
+ // atomAuthor*
+ this.parsePersonConstructs(node, "author", atomAttrib);
+
+ // atomCategory*
+ nodes = this.getElementsByTagNameNS(node, atomns, "category");
+ if (nodes.length > 0) {
+ atomAttrib.categories = [];
+ }
+ for (var i=0, ii=nodes.length; i<ii; i++) {
+ value = {};
+ value.term = nodes[i].getAttribute("term");
+ attval = nodes[i].getAttribute("scheme");
+ if (attval) { value.scheme = attval; }
+ attval = nodes[i].getAttribute("label");
+ if (attval) { value.label = attval; }
+ atomAttrib.categories.push(value);
+ }
+
+ // atomContent?
+ nodes = this.getElementsByTagNameNS(node, atomns, "content");
+ if (nodes.length > 0) {
+ value = {};
+ attval = nodes[0].getAttribute("type");
+ if (attval) {
+ value.type = attval;
+ }
+ attval = nodes[0].getAttribute("src");
+ if (attval) {
+ value.src = attval;
+ } else {
+ if (value.type == "text" ||
+ value.type == "html" ||
+ value.type == null ) {
+ value.value = this.getFirstChildValue(
+ node,
+ atomns,
+ "content",
+ null
+ );
+ } else if (value.type == "xhtml" ||
+ value.type.match(/(\+|\/)xml$/)) {
+ value.value = this.getChildEl(nodes[0]);
+ } else { // MUST be base64 encoded
+ value.value = this.getFirstChildValue(
+ node,
+ atomns,
+ "content",
+ null
+ );
+ }
+ atomAttrib.content = value;
+ }
+ }
+
+ // atomContributor*
+ this.parsePersonConstructs(node, "contributor", atomAttrib);
+
+ // atomId
+ atomAttrib.id = this.getFirstChildValue(node, atomns, "id", null);
+
+ // atomLink*
+ nodes = this.getElementsByTagNameNS(node, atomns, "link");
+ if (nodes.length > 0) {
+ atomAttrib.links = new Array(nodes.length);
+ }
+ var oAtts = ["rel", "type", "hreflang", "title", "length"];
+ for (var i=0, ii=nodes.length; i<ii; i++) {
+ value = {};
+ value.href = nodes[i].getAttribute("href");
+ for (var j=0, jj=oAtts.length; j<jj; j++) {
+ attval = nodes[i].getAttribute(oAtts[j]);
+ if (attval) {
+ value[oAtts[j]] = attval;
+ }
+ }
+ atomAttrib.links[i] = value;
+ }
+
+ // atomPublished?
+ value = this.getFirstChildValue(node, atomns, "published", null);
+ if (value) {
+ atomAttrib.published = value;
+ }
+
+ // atomRights?
+ value = this.getFirstChildValue(node, atomns, "rights", null);
+ if (value) {
+ atomAttrib.rights = value;
+ }
+
+ // atomSource? -- not implemented
+
+ // atomSummary?
+ value = this.getFirstChildValue(node, atomns, "summary", null);
+ if (value) {
+ atomAttrib.summary = value;
+ }
+
+ // atomTitle
+ atomAttrib.title = this.getFirstChildValue(
+ node, atomns, "title", null
+ );
+
+ // atomUpdated
+ atomAttrib.updated = this.getFirstChildValue(
+ node, atomns, "updated", null
+ );
+
+ var featureAttrib = {
+ title: atomAttrib.title,
+ description: atomAttrib.summary,
+ atom: atomAttrib
+ };
+ var geometry = this.parseLocations(node)[0];
+ var feature = new OpenLayers.Feature.Vector(geometry, featureAttrib);
+ feature.fid = atomAttrib.id;
+ return feature;
+ },
+
+ /**
+ * Method: parseFeatures
+ * Return features from an Atom entry or feed.
+ *
+ * Parameters:
+ * node - {DOMElement} An Atom entry or feed node.
+ *
+ * Returns:
+ * Array({<OpenLayers.Feature.Vector>})
+ */
+ parseFeatures: function(node) {
+ var features = [];
+ var entries = this.getElementsByTagNameNS(
+ node, this.namespaces.atom, "entry"
+ );
+ if (entries.length == 0) {
+ entries = [node];
+ }
+ for (var i=0, ii=entries.length; i<ii; i++) {
+ features.push(this.parseFeature(entries[i]));
+ }
+ return features;
+ },
+
+ /**
+ * Method: parseLocations
+ * Parse the locations from an Atom entry or feed.
+ *
+ * Parameters:
+ * node - {DOMElement} An Atom entry or feed node.
+ *
+ * Returns:
+ * Array({<OpenLayers.Geometry>})
+ */
+ parseLocations: function(node) {
+ var georssns = this.namespaces.georss;
+
+ var locations = {components: []};
+ var where = this.getElementsByTagNameNS(node, georssns, "where");
+ if (where && where.length > 0) {
+ if (!this.gmlParser) {
+ this.initGmlParser();
+ }
+ for (var i=0, ii=where.length; i<ii; i++) {
+ this.gmlParser.readChildNodes(where[i], locations);
+ }
+ }
+
+ var components = locations.components;
+ var point = this.getElementsByTagNameNS(node, georssns, "point");
+ if (point && point.length > 0) {
+ for (var i=0, ii=point.length; i<ii; i++) {
+ var xy = OpenLayers.String.trim(
+ point[i].firstChild.nodeValue
+ ).split(/\s+/);
+ if (xy.length !=2) {
+ xy = OpenLayers.String.trim(
+ point[i].firstChild.nodeValue
+ ).split(/\s*,\s*/);
+ }
+ components.push(new OpenLayers.Geometry.Point(xy[1], xy[0]));
+ }
+ }
+
+ var line = this.getElementsByTagNameNS(node, georssns, "line");
+ if (line && line.length > 0) {
+ var coords;
+ var p;
+ var points;
+ for (var i=0, ii=line.length; i<ii; i++) {
+ coords = OpenLayers.String.trim(
+ line[i].firstChild.nodeValue
+ ).split(/\s+/);
+ points = [];
+ for (var j=0, jj=coords.length; j<jj; j+=2) {
+ p = new OpenLayers.Geometry.Point(coords[j+1], coords[j]);
+ points.push(p);
+ }
+ components.push(
+ new OpenLayers.Geometry.LineString(points)
+ );
+ }
+ }
+
+ var polygon = this.getElementsByTagNameNS(node, georssns, "polygon");
+ if (polygon && polygon.length > 0) {
+ var coords;
+ var p;
+ var points;
+ for (var i=0, ii=polygon.length; i<ii; i++) {
+ coords = OpenLayers.String.trim(
+ polygon[i].firstChild.nodeValue
+ ).split(/\s+/);
+ points = [];
+ for (var j=0, jj=coords.length; j<jj; j+=2) {
+ p = new OpenLayers.Geometry.Point(coords[j+1], coords[j]);
+ points.push(p);
+ }
+ components.push(
+ new OpenLayers.Geometry.Polygon(
+ [new OpenLayers.Geometry.LinearRing(points)]
+ )
+ );
+ }
+ }
+
+ if (this.internalProjection && this.externalProjection) {
+ for (var i=0, ii=components.length; i<ii; i++) {
+ if (components[i]) {
+ components[i].transform(
+ this.externalProjection,
+ this.internalProjection
+ );
+ }
+ }
+ }
+
+ return components;
+ },
+
+ /**
+ * Method: parsePersonConstruct
+ * Parse Atom person constructs from an Atom entry node.
+ *
+ * Parameters:
+ * node - {DOMElement} An Atom entry or feed node.
+ * name - {String} Construcy name ("author" or "contributor")
+ * data = {Object} Object in which to put parsed persons.
+ *
+ * Returns:
+ * An {Object}.
+ */
+ parsePersonConstructs: function(node, name, data) {
+ var persons = [];
+ var atomns = this.namespaces.atom;
+ var nodes = this.getElementsByTagNameNS(node, atomns, name);
+ var oAtts = ["uri", "email"];
+ for (var i=0, ii=nodes.length; i<ii; i++) {
+ var value = {};
+ value.name = this.getFirstChildValue(
+ nodes[i],
+ atomns,
+ "name",
+ null
+ );
+ for (var j=0, jj=oAtts.length; j<jj; j++) {
+ var attval = this.getFirstChildValue(
+ nodes[i],
+ atomns,
+ oAtts[j],
+ null);
+ if (attval) {
+ value[oAtts[j]] = attval;
+ }
+ }
+ persons.push(value);
+ }
+ if (persons.length > 0) {
+ data[name + "s"] = persons;
+ }
+ },
+
+ CLASS_NAME: "OpenLayers.Format.Atom"
+});