You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by ko...@apache.org on 2014/04/07 15:37:13 UTC

[09/11] [OLINGO-238] Build infrastructure for datajs I

http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/e29bbd8f/datajs/src/odata-batch.js
----------------------------------------------------------------------
diff --git a/datajs/src/odata-batch.js b/datajs/src/odata-batch.js
new file mode 100644
index 0000000..770d875
--- /dev/null
+++ b/datajs/src/odata-batch.js
@@ -0,0 +1,393 @@
+/// <reference path="odata-utils.js" />
+
+// Copyright (c) Microsoft Open Technologies, Inc.  All rights reserved.
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation 
+// files (the "Software"), to deal  in the Software without restriction, including without limitation the rights  to use, copy,
+// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY,  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// odata-batch.js
+
+(function (window, undefined) {
+
+    var datajs = window.datajs || {};
+    var odata = window.OData || {};
+
+    // Imports
+
+    var extend = datajs.extend;
+    var isArray = datajs.isArray;
+    var trimString = datajs.trimString;
+
+    var contentType = odata.contentType;
+    var handler = odata.handler;
+    var isBatch = odata.isBatch;
+    var MAX_DATA_SERVICE_VERSION = odata.MAX_DATA_SERVICE_VERSION;
+    var normalizeHeaders = odata.normalizeHeaders;
+    var payloadTypeOf = odata.payloadTypeOf;
+    var prepareRequest = odata.prepareRequest;
+
+    // CONTENT START
+    var batchMediaType = "multipart/mixed";
+    var responseStatusRegex = /^HTTP\/1\.\d (\d{3}) (.*)$/i;
+    var responseHeaderRegex = /^([^()<>@,;:\\"\/[\]?={} \t]+)\s?:\s?(.*)/;
+
+    var hex16 = function () {
+        /// <summary>
+        /// Calculates a random 16 bit number and returns it in hexadecimal format.
+        /// </summary>
+        /// <returns type="String">A 16-bit number in hex format.</returns>
+
+        return Math.floor((1 + Math.random()) * 0x10000).toString(16).substr(1);
+    };
+
+    var createBoundary = function (prefix) {
+        /// <summary>
+        /// Creates a string that can be used as a multipart request boundary.
+        /// </summary>
+        /// <param name="prefix" type="String" optional="true">String to use as the start of the boundary string</param>
+        /// <returns type="String">Boundary string of the format: <prefix><hex16>-<hex16>-<hex16></returns>
+
+        return prefix + hex16() + "-" + hex16() + "-" + hex16();
+    };
+
+    var partHandler = function (context) {
+        /// <summary>
+        /// Gets the handler for data serialization of individual requests / responses in a batch.
+        /// </summary>
+        /// <param name="context">Context used for data serialization.</param>
+        /// <returns>Handler object.</returns>
+
+        return context.handler.partHandler;
+    };
+
+    var currentBoundary = function (context) {
+        /// <summary>
+        /// Gets the current boundary used for parsing the body of a multipart response.
+        /// </summary>
+        /// <param name="context">Context used for parsing a multipart response.</param>
+        /// <returns type="String">Boundary string.</returns>
+
+        var boundaries = context.boundaries;
+        return boundaries[boundaries.length - 1];
+    };
+
+    var batchParser = function (handler, text, context) {
+        /// <summary>Parses a batch response.</summary>
+        /// <param name="handler">This handler.</param>
+        /// <param name="text" type="String">Batch text.</param>
+        /// <param name="context" type="Object">Object with parsing context.</param>
+        /// <returns>An object representation of the batch.</returns>
+
+        var boundary = context.contentType.properties["boundary"];
+        return { __batchResponses: readBatch(text, { boundaries: [boundary], handlerContext: context }) };
+    };
+
+    var batchSerializer = function (handler, data, context) {
+        /// <summary>Serializes a batch object representation into text.</summary>
+        /// <param name="handler">This handler.</param>
+        /// <param name="data" type="Object">Representation of a batch.</param>
+        /// <param name="context" type="Object">Object with parsing context.</param>
+        /// <returns>An text representation of the batch object; undefined if not applicable.</returns>
+
+        var cType = context.contentType = context.contentType || contentType(batchMediaType);
+        if (cType.mediaType === batchMediaType) {
+            return writeBatch(data, context);
+        }
+    };
+
+    var readBatch = function (text, context) {
+        /// <summary>
+        /// Parses a multipart/mixed response body from from the position defined by the context.
+        /// </summary>
+        /// <param name="text" type="String" optional="false">Body of the multipart/mixed response.</param>
+        /// <param name="context">Context used for parsing.</param>
+        /// <returns>Array of objects representing the individual responses.</returns>
+
+        var delimiter = "--" + currentBoundary(context);
+
+        // Move beyond the delimiter and read the complete batch
+        readTo(text, context, delimiter);
+
+        // Ignore the incoming line
+        readLine(text, context);
+
+        // Read the batch parts
+        var responses = [];
+        var partEnd;
+
+        while (partEnd !== "--" && context.position < text.length) {
+            var partHeaders = readHeaders(text, context);
+            var partContentType = contentType(partHeaders["Content-Type"]);
+
+            var changeResponses;
+            if (partContentType && partContentType.mediaType === batchMediaType) {
+                context.boundaries.push(partContentType.properties["boundary"]);
+                try {
+                    changeResponses = readBatch(text, context);
+                } catch (e) {
+                    e.response = readResponse(text, context, delimiter);
+                    changeResponses = [e];
+                }
+                responses.push({ __changeResponses: changeResponses });
+                context.boundaries.pop();
+                readTo(text, context, "--" + currentBoundary(context));
+            } else {
+                if (!partContentType || partContentType.mediaType !== "application/http") {
+                    throw { message: "invalid MIME part type " };
+                }
+                // Skip empty line
+                readLine(text, context);
+                // Read the response
+                var response = readResponse(text, context, delimiter);
+                try {
+                    if (response.statusCode >= 200 && response.statusCode <= 299) {
+                        partHandler(context.handlerContext).read(response, context.handlerContext);
+                    } else {
+                        // Keep track of failed responses and continue processing the batch.
+                        response = { message: "HTTP request failed", response: response };
+                    }
+                } catch (e) {
+                    response = e;
+                }
+
+                responses.push(response);
+            }
+
+            partEnd = text.substr(context.position, 2);
+
+            // Ignore the incoming line.
+            readLine(text, context);
+        }
+        return responses;
+    };
+
+    var readHeaders = function (text, context) {
+        /// <summary>
+        /// Parses the http headers in the text from the position defined by the context.
+        /// </summary>
+        /// <param name="text" type="String" optional="false">Text containing an http response's headers</param>
+        /// <param name="context">Context used for parsing.</param>
+        /// <returns>Object containing the headers as key value pairs.</returns>
+        /// <remarks>
+        /// This function doesn't support split headers and it will stop reading when it hits two consecutive line breaks.
+        /// </remarks>
+
+        var headers = {};
+        var parts;
+        var line;
+        var pos;
+
+        do {
+            pos = context.position;
+            line = readLine(text, context);
+            parts = responseHeaderRegex.exec(line);
+            if (parts !== null) {
+                headers[parts[1]] = parts[2];
+            } else {
+                // Whatever was found is not a header, so reset the context position.
+                context.position = pos;
+            }
+        } while (line && parts);
+
+        normalizeHeaders(headers);
+
+        return headers;
+    };
+
+    var readResponse = function (text, context, delimiter) {
+        /// <summary>
+        /// Parses an HTTP response.
+        /// </summary>
+        /// <param name="text" type="String" optional="false">Text representing the http response.</param>
+        /// <param name="context" optional="false">Context used for parsing.</param>
+        /// <param name="delimiter" type="String" optional="false">String used as delimiter of the multipart response parts.</param>
+        /// <returns>Object representing the http response.</returns>
+
+        // Read the status line.
+        var pos = context.position;
+        var match = responseStatusRegex.exec(readLine(text, context));
+
+        var statusCode;
+        var statusText;
+        var headers;
+
+        if (match) {
+            statusCode = match[1];
+            statusText = match[2];
+            headers = readHeaders(text, context);
+            readLine(text, context);
+        } else {
+            context.position = pos;
+        }
+
+        return {
+            statusCode: statusCode,
+            statusText: statusText,
+            headers: headers,
+            body: readTo(text, context, "\r\n" + delimiter)
+        };
+    };
+
+    var readLine = function (text, context) {
+        /// <summary>
+        /// Returns a substring from the position defined by the context up to the next line break (CRLF).
+        /// </summary>
+        /// <param name="text" type="String" optional="false">Input string.</param>
+        /// <param name="context" optional="false">Context used for reading the input string.</param>
+        /// <returns type="String">Substring to the first ocurrence of a line break or null if none can be found. </returns>
+
+        return readTo(text, context, "\r\n");
+    };
+
+    var readTo = function (text, context, str) {
+        /// <summary>
+        /// Returns a substring from the position given by the context up to value defined by the str parameter and increments the position in the context.
+        /// </summary>
+        /// <param name="text" type="String" optional="false">Input string.</param>
+        /// <param name="context" type="Object" optional="false">Context used for reading the input string.</param>
+        /// <param name="str" type="String" optional="true">Substring to read up to.</param>
+        /// <returns type="String">Substring to the first ocurrence of str or the end of the input string if str is not specified. Null if the marker is not found.</returns>
+
+        var start = context.position || 0;
+        var end = text.length;
+        if (str) {
+            end = text.indexOf(str, start);
+            if (end === -1) {
+                return null;
+            }
+            context.position = end + str.length;
+        } else {
+            context.position = end;
+        }
+
+        return text.substring(start, end);
+    };
+
+    var writeBatch = function (data, context) {
+        /// <summary>
+        /// Serializes a batch request object to a string.
+        /// </summary>
+        /// <param name="data" optional="false">Batch request object in payload representation format</param>
+        /// <param name="context" optional="false">Context used for the serialization</param>
+        /// <returns type="String">String representing the batch request</returns>
+
+        if (!isBatch(data)) {
+            throw { message: "Data is not a batch object." };
+        }
+
+        var batchBoundary = createBoundary("batch_");
+        var batchParts = data.__batchRequests;
+        var batch = "";
+        var i, len;
+        for (i = 0, len = batchParts.length; i < len; i++) {
+            batch += writeBatchPartDelimiter(batchBoundary, false) +
+                     writeBatchPart(batchParts[i], context);
+        }
+        batch += writeBatchPartDelimiter(batchBoundary, true);
+
+        // Register the boundary with the request content type.
+        var contentTypeProperties = context.contentType.properties;
+        contentTypeProperties.boundary = batchBoundary;
+
+        return batch;
+    };
+
+    var writeBatchPartDelimiter = function (boundary, close) {
+        /// <summary>
+        /// Creates the delimiter that indicates that start or end of an individual request.
+        /// </summary>
+        /// <param name="boundary" type="String" optional="false">Boundary string used to indicate the start of the request</param>
+        /// <param name="close" type="Boolean">Flag indicating that a close delimiter string should be generated</param>
+        /// <returns type="String">Delimiter string</returns>
+
+        var result = "\r\n--" + boundary;
+        if (close) {
+            result += "--";
+        }
+
+        return result + "\r\n";
+    };
+
+    var writeBatchPart = function (part, context, nested) {
+        /// <summary>
+        /// Serializes a part of a batch request to a string. A part can be either a GET request or
+        /// a change set grouping several CUD (create, update, delete) requests.
+        /// </summary>
+        /// <param name="part" optional="false">Request or change set object in payload representation format</param>
+        /// <param name="context" optional="false">Object containing context information used for the serialization</param>
+        /// <param name="nested" type="boolean" optional="true">Flag indicating that the part is nested inside a change set</param>
+        /// <returns type="String">String representing the serialized part</returns>
+        /// <remarks>
+        /// A change set is an array of request objects and they cannot be nested inside other change sets.
+        /// </remarks>
+
+        var changeSet = part.__changeRequests;
+        var result;
+        if (isArray(changeSet)) {
+            if (nested) {
+                throw { message: "Not Supported: change set nested in other change set" };
+            }
+
+            var changeSetBoundary = createBoundary("changeset_");
+            result = "Content-Type: " + batchMediaType + "; boundary=" + changeSetBoundary + "\r\n";
+            var i, len;
+            for (i = 0, len = changeSet.length; i < len; i++) {
+                result += writeBatchPartDelimiter(changeSetBoundary, false) +
+                     writeBatchPart(changeSet[i], context, true);
+            }
+
+            result += writeBatchPartDelimiter(changeSetBoundary, true);
+        } else {
+            result = "Content-Type: application/http\r\nContent-Transfer-Encoding: binary\r\n\r\n";
+            var partContext = extend({}, context);
+            partContext.handler = handler;
+            partContext.request = part;
+            partContext.contentType = null;
+
+            prepareRequest(part, partHandler(context), partContext);
+            result += writeRequest(part);
+        }
+
+        return result;
+    };
+
+    var writeRequest = function (request) {
+        /// <summary>
+        /// Serializes a request object to a string.
+        /// </summary>
+        /// <param name="request" optional="false">Request object to serialize</param>
+        /// <returns type="String">String representing the serialized request</returns>
+
+        var result = (request.method ? request.method : "GET") + " " + request.requestUri + " HTTP/1.1\r\n";
+        for (var name in request.headers) {
+            if (request.headers[name]) {
+                result = result + name + ": " + request.headers[name] + "\r\n";
+            }
+        }
+
+        result += "\r\n";
+
+        if (request.body) {
+            result += request.body;
+        }
+
+        return result;
+    };
+
+    odata.batchHandler = handler(batchParser, batchSerializer, batchMediaType, MAX_DATA_SERVICE_VERSION);
+
+    // DATAJS INTERNAL START
+    odata.batchSerializer = batchSerializer;
+    odata.writeRequest = writeRequest;
+    // DATAJS INTERNAL END
+
+    // CONTENT END
+})(this);
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/e29bbd8f/datajs/src/odata-gml.js
----------------------------------------------------------------------
diff --git a/datajs/src/odata-gml.js b/datajs/src/odata-gml.js
new file mode 100644
index 0000000..2bcf5f5
--- /dev/null
+++ b/datajs/src/odata-gml.js
@@ -0,0 +1,831 @@
+// Copyright (c) Microsoft Open Technologies, Inc.  All rights reserved.
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation 
+// files (the "Software"), to deal  in the Software without restriction, including without limitation the rights  to use, copy,
+// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY,  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// odata-gml.js
+
+(function (window, undefined) {
+
+    var datajs = window.datajs || {};
+    var odata = window.OData || {};
+
+    // Imports.
+
+    var contains = datajs.contains;
+    var djsassert = datajs.djsassert;
+    var http = datajs.http;
+    var isArray = datajs.isArray;
+    var xmlAppendChild = datajs.xmlAppendChild;
+    var xmlAttributeValue = datajs.xmlAttributeValue;
+    var xmlChildElements = datajs.xmlChildElements;
+    var xmlFirstChildElement = datajs.xmlFirstChildElement;
+    var xmlInnerText = datajs.xmlInnerText;
+    var xmlLocalName = datajs.xmlLocalName;
+    var xmlNamespaceURI = datajs.xmlNamespaceURI;
+    var xmlNewElement = datajs.xmlNewElement;
+    var xmlQualifiedName = datajs.xmlQualifiedName;
+    var GEOJSON_POINT = odata.GEOJSON_POINT;
+    var GEOJSON_LINESTRING = odata.GEOJSON_LINESTRING;
+    var GEOJSON_POLYGON = odata.GEOJSON_POLYGON;
+    var GEOJSON_MULTIPOINT = odata.GEOJSON_MULTIPOINT;
+    var GEOJSON_MULTILINESTRING = odata.GEOJSON_MULTILINESTRING;
+    var GEOJSON_MULTIPOLYGON = odata.GEOJSON_MULTIPOLYGON;
+    var GEOJSON_GEOMETRYCOLLECTION = odata.GEOJSON_GEOMETRYCOLLECTION;
+
+    // CONTENT START
+    var gmlOpenGis = http + "www.opengis.net";           // http://www.opengis.net
+    var gmlXmlNs = gmlOpenGis + "/gml";                 // http://www.opengis.net/gml
+    var gmlSrsPrefix = gmlOpenGis + "/def/crs/EPSG/0/"; // http://www.opengis.net/def/crs/EPSG/0/
+
+    var gmlPrefix = "gml";
+
+    var gmlCreateGeoJSONOBject = function (type, member, data) {
+        /// <summary>Creates a GeoJSON object with the specified type, member and value.</summary>
+        /// <param name="type" type="String">GeoJSON object type.</param>
+        /// <param name="member" type="String">Name for the data member in the GeoJSON object.</param>
+        /// <param name="data">Data to be contained by the GeoJSON object.</param>
+        /// <returns type="Object">GeoJSON object.</returns>
+
+        var result = { type: type };
+        result[member] = data;
+        return result;
+    };
+
+    var gmlSwapLatLong = function (coordinates) {
+        /// <summary>Swaps the longitude and latitude in the coordinates array.</summary>
+        /// <param name="coordinates" type="Array">Array of doubles descrbing a set of coordinates.</param>
+        /// <returns type="Array">Array of doubles with the latitude and longitude components swapped.</returns>
+
+        if (isArray(coordinates) && coordinates.length >= 2) {
+            var tmp = coordinates[0];
+            coordinates[0] = coordinates[1];
+            coordinates[1] = tmp;
+        }
+        return coordinates;
+    };
+
+    var gmlReadODataMultiItem = function (domElement, type, member, members, valueReader, isGeography) {
+        /// <summary>
+        ///    Reads a GML DOM element that represents a composite structure like a multi-point or a
+        ///    multi-geometry returnig its GeoJSON representation.
+        /// </summary>
+        /// <param name="domElement">GML DOM element.</param>
+        /// <param name="type" type="String">GeoJSON object type.</param>
+        /// <param name="member" type="String">Name for the child element representing a single item in the composite structure.</param>
+        /// <param name="members" type="String">Name for the child element representing a collection of items in the composite structure.</param>
+        /// <param name="valueReader" type="Function">Callback function invoked to get the coordinates of each item in the comoposite structure.</param>
+        /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
+        /// <remarks>
+        ///    When using a geographic reference system, the first component of all the coordinates in each <pos> element in the GML DOM tree is the Latitude and
+        ///    will be deserialized as the second component of each <pos> element in the GML DOM tree.
+        /// </remarks>
+        /// <returns type="Object">GeoJSON object.</returns>
+
+        var coordinates = gmlReadODataMultiItemValue(domElement, member, members, valueReader, isGeography);
+        return gmlCreateGeoJSONOBject(type, "coordinates", coordinates);
+    };
+
+    var gmlReadODataMultiItemValue = function (domElement, member, members, valueReader, isGeography) {
+        /// <summary>
+        ///    Reads the value of a GML DOM element that represents a composite structure like a multi-point or a
+        ///    multi-geometry returnig its items.
+        /// </summary>
+        /// <param name="domElement">GML DOM element.</param>
+        /// <param name="type" type="String">GeoJSON object type.</param>
+        /// <param name="member" type="String">Name for the child element representing a single item in the composite structure.</param>
+        /// <param name="members" type="String">Name for the child element representing a collection of items in the composite structure.</param>
+        /// <param name="valueReader" type="Function">Callback function invoked to get the transformed value of each item in the comoposite structure.</param>
+        /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
+        /// <remarks>
+        ///    When using a geographic reference system, the first component of all the coordinates in each <pos> element in the GML DOM tree is the Latitude and
+        ///    will be deserialized as the second component of each <pos> element in the GML DOM tree.
+        /// </remarks>
+        /// <returns type="Array">Array containing the transformed value of each item in the multi-item.</returns>
+
+        var items = [];
+
+        xmlChildElements(domElement, function (child) {
+            if (xmlNamespaceURI(child) !== gmlXmlNs) {
+                return;
+            }
+
+            var localName = xmlLocalName(child);
+
+            if (localName === member) {
+                var valueElement = xmlFirstChildElement(child, gmlXmlNs);
+                if (valueElement) {
+                    var value = valueReader(valueElement, isGeography);
+                    if (value) {
+                        items.push(value);
+                    }
+                }
+                return;
+            }
+
+            if (localName === members) {
+                xmlChildElements(child, function (valueElement) {
+                    if (xmlNamespaceURI(valueElement) !== gmlXmlNs) {
+                        return;
+                    }
+
+                    var value = valueReader(valueElement, isGeography);
+                    if (value) {
+                        items.push(value);
+                    }
+                });
+            }
+        });
+        return items;
+    };
+
+    var gmlReadODataCollection = function (domElement, isGeography) {
+        /// <summary>Reads a GML DOM element representing a multi-geometry returning its GeoJSON representation.</summary>
+        /// <param name="domElement">DOM element.</param>
+        /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
+        /// <remarks>
+        ///    When using a geographic reference system, the first component of all the coordinates in each <pos> element in the GML DOM tree is the Latitude and
+        ///    will be deserialized as the second component of each <pos> element in the GML DOM tree.
+        /// </remarks>
+        /// <returns type="Object">MultiGeometry object in GeoJSON format.</returns>
+
+        var geometries = gmlReadODataMultiItemValue(domElement, "geometryMember", "geometryMembers", gmlReadODataSpatialValue, isGeography);
+        return gmlCreateGeoJSONOBject(GEOJSON_GEOMETRYCOLLECTION, "geometries", geometries);
+    };
+
+    var gmlReadODataLineString = function (domElement, isGeography) {
+        /// <summary>Reads a GML DOM element representing a line string returning its GeoJSON representation.</summary>
+        /// <param name="domElement">DOM element.</param>
+        /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
+        /// <remarks>
+        ///    When using a geographic reference system, the first component of all the coordinates in each <pos> element in the GML DOM tree is the Latitude and
+        ///    will be deserialized as the second component of each <pos> element in the GML DOM tree.
+        /// </remarks>
+        /// <returns type="Object">LineString object in GeoJSON format.</returns>
+
+        return gmlCreateGeoJSONOBject(GEOJSON_LINESTRING, "coordinates", gmlReadODataLineValue(domElement, isGeography));
+    };
+
+    var gmlReadODataMultiLineString = function (domElement, isGeography) {
+        /// <summary>Reads a GML DOM element representing a multi-line string returning its GeoJSON representation.</summary>
+        /// <param name="domElement">DOM element.</param>
+        /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
+        /// <remarks>
+        ///    When using a geographic reference system, the first component of all the coordinates in each <pos> element in the GML DOM tree is the Latitude and
+        ///    will be deserialized as the second component of each <pos> element in the GML DOM tree.
+        /// </remarks>
+        /// <returns type="Object">MultiLineString object in GeoJSON format.</returns>
+
+        return gmlReadODataMultiItem(domElement, GEOJSON_MULTILINESTRING, "curveMember", "curveMembers", gmlReadODataLineValue, isGeography);
+    };
+
+    var gmlReadODataMultiPoint = function (domElement, isGeography) {
+        /// <summary>Reads a GML DOM element representing a multi-point returning its GeoJSON representation.</summary>
+        /// <param name="domElement">DOM element.</param>
+        /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
+        /// <remarks>
+        ///    When using a geographic reference system, the first component of all the coordinates in each <pos> element in the GML DOM tree is the Latitude and
+        ///    will be deserialized as the second component of each <pos> element in the GML DOM tree.
+        /// </remarks>
+        /// <returns type="Object">MultiPoint object in GeoJSON format.</returns>
+
+        return gmlReadODataMultiItem(domElement, GEOJSON_MULTIPOINT, "pointMember", "pointMembers", gmlReadODataPointValue, isGeography);
+    };
+
+    var gmlReadODataMultiPolygon = function (domElement, isGeography) {
+        /// <summary>Reads a GML DOM element representing a multi-polygon returning its GeoJSON representation.</summary>
+        /// <param name="domElement">DOM element.</param>
+        /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
+        /// <remarks>
+        ///    When using a geographic reference system, the first component of all the coordinates in each <pos> element in the GML DOM tree is the Latitude and
+        ///    will be deserialized as the second component of each <pos> element in the GML DOM tree.
+        /// </remarks>
+        /// <returns type="Object">MultiPolygon object in GeoJSON format.</returns>
+
+        return gmlReadODataMultiItem(domElement, GEOJSON_MULTIPOLYGON, "surfaceMember", "surfaceMembers", gmlReadODataPolygonValue, isGeography);
+    };
+
+    var gmlReadODataPoint = function (domElement, isGeography) {
+        /// <summary>Reads a GML DOM element representing a point returning its GeoJSON representation.</summary>
+        /// <param name="domElement">DOM element.</param>
+        /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
+        /// <remarks>
+        ///    When using a geographic reference system, the first component of all the coordinates in each <pos> element in the GML DOM tree is the Latitude and
+        ///    will be deserialized as the second component of each <pos> element in the GML DOM tree.
+        /// </remarks>
+        /// <returns type="Object">Point object in GeoJSON format.</returns>
+
+        return gmlCreateGeoJSONOBject(GEOJSON_POINT, "coordinates", gmlReadODataPointValue(domElement, isGeography));
+    };
+
+    var gmlReadODataPolygon = function (domElement, isGeography) {
+        /// <summary>Reads a GML DOM element representing a polygon returning its GeoJSON representation.</summary>
+        /// <param name="domElement">DOM element.</param>
+        /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
+        /// <remarks>
+        ///    When using a geographic reference system, the first component of all the coordinates in each <pos> element in the GML DOM tree is the Latitude and
+        ///    will be deserialized as the second component of each <pos> element in the GML DOM tree.
+        /// </remarks>
+        /// <returns type="Object">Polygon object in GeoJSON format.</returns>
+
+        return gmlCreateGeoJSONOBject(GEOJSON_POLYGON, "coordinates", gmlReadODataPolygonValue(domElement, isGeography));
+    };
+
+    var gmlReadODataLineValue = function (domElement, isGeography) {
+        /// <summary>Reads the value of a GML DOM element representing a line returning its set of coordinates.</summary>
+        /// <param name="domElement">DOM element.</param>
+        /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
+        /// <remarks>
+        ///    When using a geographic reference system, the first component of all the coordinates in each <pos> element in the GML DOM tree is the Latitude and
+        ///    will be deserialized as the second component of each <pos> element in the GML DOM tree.
+        /// </remarks>
+        /// <returns type="Array">Array containing an array of doubles for each coordinate of the line.</returns>
+
+        var coordinates = [];
+
+        xmlChildElements(domElement, function (child) {
+            var nsURI = xmlNamespaceURI(child);
+
+            if (nsURI !== gmlXmlNs) {
+                return;
+            }
+
+            var localName = xmlLocalName(child);
+
+            if (localName === "posList") {
+                coordinates = gmlReadODataPosListValue(child, isGeography);
+                return;
+            }
+            if (localName === "pointProperty") {
+                coordinates.push(gmlReadODataPointWrapperValue(child, isGeography));
+                return;
+            }
+            if (localName === "pos") {
+                coordinates.push(gmlReadODataPosValue(child, isGeography));
+                return;
+            }
+        });
+
+        return coordinates;
+    };
+
+    var gmlReadODataPointValue = function (domElement, isGeography) {
+        /// <summary>Reads the value of a GML DOM element representing a point returning its coordinates.</summary>
+        /// <param name="domElement">DOM element.</param>
+        /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
+        /// <remarks>
+        ///    When using a geographic reference system, the first component of all the coordinates in each <pos> element in the GML DOM tree is the Latitude and
+        ///    will be deserialized as the second component of each <pos> element in the GML DOM tree.
+        /// </remarks>
+        /// <returns type="Array">Array of doubles containing the point coordinates.</returns>
+
+        var pos = xmlFirstChildElement(domElement, gmlXmlNs, "pos");
+        return pos ? gmlReadODataPosValue(pos, isGeography) : [];
+    };
+
+    var gmlReadODataPointWrapperValue = function (domElement, isGeography) {
+        /// <summary>Reads the value of a GML DOM element wrapping an element representing a point returning its coordinates.</summary>
+        /// <param name="domElement">DOM element.</param>
+        /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
+        /// <remarks>
+        ///    When using a geographic reference system, the first component of all the coordinates in each <pos> element in the GML DOM tree is the Latitude and
+        ///    will be deserialized as the second component of each <pos> element in the GML DOM tree.
+        /// </remarks>
+        /// <returns type="Array">Array of doubles containing the point coordinates.</returns>
+
+        var point = xmlFirstChildElement(domElement, gmlXmlNs, "Point");
+        return point ? gmlReadODataPointValue(point, isGeography) : [];
+    };
+
+    var gmlReadODataPolygonValue = function (domElement, isGeography) {
+        /// <summary>Reads the value of a GML DOM element representing a polygon returning its set of coordinates.</summary>
+        /// <param name="domElement">DOM element.</param>
+        /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
+        /// <remarks>
+        ///    When using a geographic reference system, the first component of all the coordinates in each <pos> element in the GML DOM tree is the Latitude and
+        ///    will be deserialized as the second component of each <pos> element in the GML DOM tree.
+        /// </remarks>
+        /// <returns type="Array">Array containing an array of array of doubles for each ring of the polygon.</returns>
+
+        var coordinates = [];
+        var exteriorFound = false;
+        xmlChildElements(domElement, function (child) {
+            if (xmlNamespaceURI(child) !== gmlXmlNs) {
+                return;
+            }
+
+            // Only the exterior and the interior rings are interesting
+            var localName = xmlLocalName(child);
+            if (localName === "exterior") {
+                exteriorFound = true;
+                coordinates.unshift(gmlReadODataPolygonRingValue(child, isGeography));
+                return;
+            }
+            if (localName === "interior") {
+                coordinates.push(gmlReadODataPolygonRingValue(child, isGeography));
+                return;
+            }
+        });
+
+        if (!exteriorFound && coordinates.length > 0) {
+            // Push an empty exterior ring.
+            coordinates.unshift([[]]);
+        }
+
+        return coordinates;
+    };
+
+    var gmlReadODataPolygonRingValue = function (domElement, isGeography) {
+        /// <summary>Reads the value of a GML DOM element representing a linear ring in a GML Polygon element.</summary>
+        /// <param name="domElement">DOM element.</param>
+        /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
+        /// <remarks>
+        ///    When using a geographic reference system, the first component of all the coordinates in each <pos> element in the GML DOM tree is the Latitude and
+        ///    will be deserialized as the second component of each <pos> element in the GML DOM tree.
+        /// </remarks>
+        /// <returns type="Array">Array containing an array of doubles for each coordinate of the linear ring.</returns>
+
+        var value = [];
+        xmlChildElements(domElement, function (child) {
+            if (xmlNamespaceURI(child) !== gmlXmlNs || xmlLocalName(child) !== "LinearRing") {
+                return;
+            }
+            value = gmlReadODataLineValue(child, isGeography);
+        });
+        return value;
+    };
+
+    var gmlReadODataPosListValue = function (domElement, isGeography) {
+        /// <summary>Reads the value of a GML DOM element representing a list of positions retruning its set of coordinates.</summary>
+        /// <param name="domElement">DOM element.</param>
+        /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
+        /// <remarks>
+        ///    When using a geographic reference system, the first component of all the coordinates in each <pos> element in the GML DOM tree is the Latitude and
+        ///    will be deserialized as the second component of each <pos> element in the GML DOM tree.
+        ///
+        ///    The positions described by the list are assumed to be 2D, so 
+        ///    an exception will be thrown if the list has an odd number elements.
+        /// </remarks>
+        /// <returns type="Array">Array containing an array of doubles for each coordinate in the list.</returns>
+
+        var coordinates = gmlReadODataPosValue(domElement, false);
+        var len = coordinates.length;
+
+        if (len % 2 !== 0) {
+            throw { message: "GML posList element has an uneven number of numeric values" };
+        }
+
+        var value = [];
+        for (var i = 0; i < len; i += 2) {
+            var pos = coordinates.slice(i, i + 2);
+            value.push(isGeography ? gmlSwapLatLong(pos) : pos);
+        }
+        return value;
+    };
+
+    var gmlReadODataPosValue = function (domElement, isGeography) {
+        /// <summary>Reads the value of a GML element describing a position or a set of coordinates in an OData spatial property value.</summary>
+        /// <param name="property">DOM element for the GML element.</param>
+        /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
+        /// <remarks>
+        ///    When using a geographic reference system, the first component of all the coordinates in each <pos> element in the GML DOM tree is the Latitude and
+        ///    will be deserialized as the second component of each <pos> element in the GML DOM tree.
+        /// </remarks>
+        /// <returns type="Array">Array of doubles containing the coordinates.</returns>
+
+        var value = [];
+        var delims = " \t\r\n";
+        var text = xmlInnerText(domElement);
+
+        if (text) {
+            var len = text.length;
+            var start = 0;
+            var end = 0;
+
+            while (end <= len) {
+                if (delims.indexOf(text.charAt(end)) !== -1) {
+                    var coord = text.substring(start, end);
+                    if (coord) {
+                        value.push(parseFloat(coord));
+                    }
+                    start = end + 1;
+                }
+                end++;
+            }
+        }
+
+        return isGeography ? gmlSwapLatLong(value) : value;
+    };
+
+    var gmlReadODataSpatialValue = function (domElement, isGeography) {
+        /// <summary>Reads the value of a GML DOM element a spatial value in an OData XML document.</summary>
+        /// <param name="domElement">DOM element.</param>
+        /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
+        /// <remarks>
+        ///    When using a geographic reference system, the first component of all the coordinates in each <pos> element in the GML DOM tree is the Latitude and
+        ///    will be deserialized as the second component of each position coordinates in the resulting GeoJSON object.
+        /// </remarks>
+        /// <returns type="Array">Array containing an array of doubles for each coordinate of the polygon.</returns>
+
+        var localName = xmlLocalName(domElement);
+        var reader;
+
+        switch (localName) {
+            case "Point":
+                reader = gmlReadODataPoint;
+                break;
+            case "Polygon":
+                reader = gmlReadODataPolygon;
+                break;
+            case "LineString":
+                reader = gmlReadODataLineString;
+                break;
+            case "MultiPoint":
+                reader = gmlReadODataMultiPoint;
+                break;
+            case "MultiCurve":
+                reader = gmlReadODataMultiLineString;
+                break;
+            case "MultiSurface":
+                reader = gmlReadODataMultiPolygon;
+                break;
+            case "MultiGeometry":
+                reader = gmlReadODataCollection;
+                break;
+            default:
+                throw { message: "Unsupported element: " + localName, element: domElement };
+        }
+
+        var value = reader(domElement, isGeography);
+        // Read the CRS
+        // WCF Data Services qualifies the srsName attribute withing the GML namespace; however
+        // other end points might no do this as per the standard.
+
+        var srsName = xmlAttributeValue(domElement, "srsName", gmlXmlNs) ||
+                      xmlAttributeValue(domElement, "srsName");
+
+        if (srsName) {
+            if (srsName.indexOf(gmlSrsPrefix) !== 0) {
+                throw { message: "Unsupported srs name: " + srsName, element: domElement };
+            }
+
+            var crsId = srsName.substring(gmlSrsPrefix.length);
+            if (crsId) {
+                value.crs = {
+                    type: "name",
+                    properties: {
+                        name: "EPSG:" + crsId
+                    }
+                };
+            }
+        }
+        return value;
+    };
+
+    var gmlNewODataSpatialValue = function (dom, value, type, isGeography) {
+        /// <summary>Creates a new GML DOM element for the value of an OData spatial property or GeoJSON object.</summary>
+        /// <param name="dom">DOM document used for creating the new DOM Element.</param>
+        /// <param name="value" type="Object">Spatial property value in GeoJSON format.</param>
+        /// <param name="type" type="String">String indicating the GeoJSON type of the value to serialize.</param>
+        /// <param name="isGeography" type="Boolean" Optional="True">Flag indicating if the value uses a geographic reference system or not.<param>
+        /// <remarks>
+        ///    When using a geographic reference system, the first component of all the coordinates in the GeoJSON value is the Longitude and
+        ///    will be serialized as the second component of each <pos> element in the GML DOM tree.
+        /// </remarks>
+        /// <returns>New DOM element in the GML namespace for the spatial value. </returns>
+
+        var gmlWriter;
+
+        switch (type) {
+            case GEOJSON_POINT:
+                gmlWriter = gmlNewODataPoint;
+                break;
+            case GEOJSON_LINESTRING:
+                gmlWriter = gmlNewODataLineString;
+                break;
+            case GEOJSON_POLYGON:
+                gmlWriter = gmlNewODataPolygon;
+                break;
+            case GEOJSON_MULTIPOINT:
+                gmlWriter = gmlNewODataMultiPoint;
+                break;
+            case GEOJSON_MULTILINESTRING:
+                gmlWriter = gmlNewODataMultiLineString;
+                break;
+            case GEOJSON_MULTIPOLYGON:
+                gmlWriter = gmlNewODataMultiPolygon;
+                break;
+            case GEOJSON_GEOMETRYCOLLECTION:
+                gmlWriter = gmlNewODataGeometryCollection;
+                break;
+            default:
+                djsassert(false, "gmlNewODataSpatialValue - Unknown GeoJSON type <" + type + ">!!");
+                return null;
+        }
+
+        var gml = gmlWriter(dom, value, isGeography);
+
+        // Set the srsName attribute if applicable.
+        var crs = value.crs;
+        if (crs) {
+            if (crs.type === "name") {
+                var properties = crs.properties;
+                var name = properties && properties.name;
+                if (name && name.indexOf("ESPG:") === 0 && name.length > 5) {
+                    var crsId = name.substring(5);
+                    var srsName = xmlNewAttribute(dom, null, "srsName", gmlPrefix + crsId);
+                    xmlAppendChild(gml, srsName);
+                }
+            }
+        }
+
+        return gml;
+    };
+
+    var gmlNewODataElement = function (dom, name, children) {
+        /// <summary>Creates a new DOM element in the GML namespace.</summary>
+        /// <param name="dom">DOM document used for creating the new DOM Element.</param>
+        /// <param name="name" type="String">Local name of the GML element to create.</param>
+        /// <param name="children" type="Array">Array containing DOM nodes or string values that will be added as children of the new DOM element.</param>
+        /// <returns>New DOM element in the GML namespace.</returns>
+        /// <remarks>
+        ///    If a value in the children collection is a string, then a new DOM text node is going to be created
+        ///    for it and then appended as a child of the new DOM Element.
+        /// </remarks>
+
+        return xmlNewElement(dom, gmlXmlNs, xmlQualifiedName(gmlPrefix, name), children);
+    };
+
+    var gmlNewODataPosElement = function (dom, coordinates, isGeography) {
+        /// <summary>Creates a new GML pos DOM element.</summary>
+        /// <param name="dom">DOM document used for creating the new DOM Element.</param>
+        /// <param name="coordinates" type="Array">Array of doubles describing the coordinates of the pos element.</param>
+        /// <param name="isGeography" type="Boolean">Flag indicating if the coordinates use a geographic reference system or not.<param>
+        /// <remarks>
+        ///    When using a geographic reference system, the first coordinate is the Longitude and
+        ///    will be serialized as the second component of the <pos> element in the GML DOM tree.
+        /// </remarks>
+        /// <returns>New pos DOM element in the GML namespace.</returns>
+
+        var posValue = isArray(coordinates) ? coordinates : [];
+
+        // If using a geographic reference system, then the first coordinate is the longitude and it has to
+        // swapped with the latitude.
+        posValue = isGeography ? gmlSwapLatLong(posValue) : posValue;
+
+        return gmlNewODataElement(dom, "pos", posValue.join(" "));
+    };
+
+    var gmlNewODataLineElement = function (dom, name, coordinates, isGeography) {
+        /// <summary>Creates a new GML DOM element representing a line.</summary>
+        /// <param name="dom">DOM document used for creating the new DOM Element.</param>
+        /// <param name="name" type="String">Name of the element to create.</param>
+        /// <param name="coordinates" type="Array">Array of array of doubles describing the coordinates of the line element.</param>
+        /// <param name="isGeography" type="Boolean">Flag indicating if the coordinates use a geographic reference system or not.<param>
+        /// <remarks>
+        ///    When using a geographic reference system, the first component of all the coordinates is the Longitude and
+        ///    will be serialized as the second component of each <pos> element in the GML DOM tree.
+        /// </remarks>
+        /// <returns>New DOM element in the GML namespace.</returns>
+
+        var element = gmlNewODataElement(dom, name);
+        if (isArray(coordinates)) {
+            var i, len;
+            for (i = 0, len = coordinates.length; i < len; i++) {
+                xmlAppendChild(element, gmlNewODataPosElement(dom, coordinates[i], isGeography));
+            }
+
+            if (len === 0) {
+                xmlAppendChild(element, gmlNewODataElement(dom, "posList"));
+            }
+        }
+        return element;
+    };
+
+    var gmlNewODataPointElement = function (dom, coordinates, isGeography) {
+        /// <summary>Creates a new GML Point DOM element.</summary>
+        /// <param name="dom">DOM document used for creating the new DOM Element.</param>
+        /// <param name="value" type="Object">GeoJSON Point object.</param>
+        /// <param name="isGeography" type="Boolean">Flag indicating if the value uses a geographic reference system or not.<param>
+        /// <remarks>
+        ///    When using a geographic reference system, the first component of all the coordinates in the GeoJSON value is the Longitude and
+        ///    will be serialized as the second component of each <pos> element in the GML DOM tree.
+        /// </remarks>
+        /// <returns>New DOM element in the GML namespace for the GeoJSON Point.</returns>
+
+        return gmlNewODataElement(dom, "Point", gmlNewODataPosElement(dom, coordinates, isGeography));
+    };
+
+    var gmlNewODataLineStringElement = function (dom, coordinates, isGeography) {
+        /// <summary>Creates a new GML LineString DOM element.</summary>
+        /// <param name="dom">DOM document used for creating the new DOM Element.</param>
+        /// <param name="coordinates" type="Array">Array of array of doubles describing the coordinates of the line element.</param>
+        /// <param name="isGeography" type="Boolean">Flag indicating if the value uses a geographic reference system or not.<param>
+        /// <remarks>
+        ///    When using a geographic reference system, the first component of all the coordinates in the GeoJSON value is the Longitude and
+        ///    will be serialized as the second component of each <pos> element in the GML DOM tree.
+        /// </remarks>
+        /// <returns>New DOM element in the GML namespace for the GeoJSON LineString.</returns>
+
+        return gmlNewODataLineElement(dom, "LineString", coordinates, isGeography);
+    };
+
+    var gmlNewODataPolygonRingElement = function (dom, name, coordinates, isGeography) {
+        /// <summary>Creates a new GML DOM element representing a polygon ring.</summary>
+        /// <param name="dom">DOM document used for creating the new DOM Element.</param>
+        /// <param name="name" type="String">Name of the element to create.</param>
+        /// <param name="coordinates" type="Array">Array of array of doubles describing the coordinates of the polygon ring.</param>
+        /// <param name="isGeography" type="Boolean">Flag indicating if the coordinates use a geographic reference system or not.<param>
+        /// <remarks>
+        ///    When using a geographic reference system, the first component of all the coordinates is the Longitude and
+        ///    will be serialized as the second component of each <pos> element in the GML DOM tree.
+        /// </remarks>
+        /// <returns>New DOM element in the GML namespace.</returns>
+
+        var ringElement = gmlNewODataElement(dom, name);
+        if (isArray(coordinates) && coordinates.length > 0) {
+            var linearRing = gmlNewODataLineElement(dom, "LinearRing", coordinates, isGeography);
+            xmlAppendChild(ringElement, linearRing);
+        }
+        return ringElement;
+    };
+
+    var gmlNewODataPolygonElement = function (dom, coordinates, isGeography) {
+        /// <summary>Creates a new GML Polygon DOM element for a GeoJSON Polygon object.</summary>
+        /// <param name="dom">DOM document used for creating the new DOM Element.</param>
+        /// <param name="coordinates" type="Array">Array of array of array of doubles describing the coordinates of the polygon.</param>
+        /// <param name="isGeography" type="Boolean">Flag indicating if the value uses a geographic reference system or not.<param>
+        /// <remarks>
+        ///    When using a geographic reference system, the first component of all the coordinates in the GeoJSON value is the Longitude and
+        ///    will be serialized as the second component of each <pos> element in the GML DOM tree.
+        /// </remarks>
+        /// <returns>New DOM element in the GML namespace.</returns>
+
+        var len = coordinates && coordinates.length;
+        var element = gmlNewODataElement(dom, "Polygon");
+
+        if (isArray(coordinates) && len > 0) {
+            xmlAppendChild(element, gmlNewODataPolygonRingElement(dom, "exterior", coordinates[0], isGeography));
+
+            var i;
+            for (i = 1; i < len; i++) {
+                xmlAppendChild(element, gmlNewODataPolygonRingElement(dom, "interior", coordinates[i], isGeography));
+            }
+        }
+        return element;
+    };
+
+    var gmlNewODataPoint = function (dom, value, isGeography) {
+        /// <summary>Creates a new GML Point DOM element for a GeoJSON Point object.</summary>
+        /// <param name="dom">DOM document used for creating the new DOM Element.</param>
+        /// <param name="value" type="Object">GeoJSON Point object.</param>
+        /// <param name="isGeography" type="Boolean">Flag indicating if the value uses a geographic reference system or not.<param>
+        /// <remarks>
+        ///    When using a geographic reference system, the first component of all the coordinates in the GeoJSON value is the Longitude and
+        ///    will be serialized as the second component of each <pos> element in the GML DOM tree.
+        /// </remarks>
+        /// <returns>New DOM element in the GML namespace for the GeoJSON Point.</returns>
+
+        return gmlNewODataPointElement(dom, value.coordinates, isGeography);
+    };
+
+    var gmlNewODataLineString = function (dom, value, isGeography) {
+        /// <summary>Creates a new GML LineString DOM element for a GeoJSON LineString object.</summary>
+        /// <param name="dom">DOM document used for creating the new DOM Element.</param>
+        /// <param name="value" type="Object">GeoJSON LineString object.</param>
+        /// <param name="isGeography" type="Boolean">Flag indicating if the value uses a geographic reference system or not.<param>
+        /// <remarks>
+        ///    When using a geographic reference system, the first component of all the coordinates in the GeoJSON value is the Longitude and
+        ///    will be serialized as the second component of each <pos> element in the GML DOM tree.
+        /// </remarks>
+        /// <returns>New DOM element in the GML namespace for the GeoJSON LineString.</returns>
+
+        return gmlNewODataLineStringElement(dom, value.coordinates, isGeography);
+    };
+
+    var gmlNewODataPolygon = function (dom, value, isGeography) {
+        /// <summary>Creates a new GML Polygon DOM element for a GeoJSON Polygon object.</summary>
+        /// <param name="dom">DOM document used for creating the new DOM Element.</param>
+        /// <param name="value" type="Object">GeoJSON Polygon object.</param>
+        /// <param name="isGeography" type="Boolean">Flag indicating if the value uses a geographic reference system or not.<param>
+        /// <remarks>
+        ///    When using a geographic reference system, the first component of all the coordinates in the GeoJSON value is the Longitude and
+        ///    will be serialized as the second component of each <pos> element in the GML DOM tree.
+        /// </remarks>
+        /// <returns>New DOM element in the GML namespace for the GeoJSON Polygon.</returns>
+
+        return gmlNewODataPolygonElement(dom, value.coordinates, isGeography);
+    };
+
+    var gmlNewODataMultiItem = function (dom, name, members, items, itemWriter, isGeography) {
+        /// <summary>Creates a new GML DOM element for a composite structure like a multi-point or a multi-geometry.</summary>
+        /// <param name="dom">DOM document used for creating the new DOM Element.</param>
+        /// <param name="name" type="String">Name of the element to create.</param>
+        /// <param name="items" type="Array">Array of items in the composite structure.</param>
+        /// <param name="isGeography" type="Boolean">Flag indicating if the multi-item uses a geographic reference system or not.<param>
+        /// <remarks>
+        ///    When using a geographic reference system, the first component of all the coordinates in each of the items is the Longitude and
+        ///    will be serialized as the second component of each <pos> element in the GML DOM tree.
+        /// </remarks>
+        /// <returns>New DOM element in the GML namespace.</returns>
+
+        var len = items && items.length;
+        var element = gmlNewODataElement(dom, name);
+
+        if (isArray(items) && len > 0) {
+            var membersElement = gmlNewODataElement(dom, members);
+            var i;
+            for (i = 0; i < len; i++) {
+                xmlAppendChild(membersElement, itemWriter(dom, items[i], isGeography));
+            }
+            xmlAppendChild(element, membersElement);
+        }
+        return element;
+    };
+
+    var gmlNewODataMultiPoint = function (dom, value, isGeography) {
+        /// <summary>Creates a new GML MultiPoint DOM element for a GeoJSON MultiPoint object.</summary>
+        /// <param name="dom">DOM document used for creating the new DOM Element.</param>
+        /// <param name="value" type="Object">GeoJSON MultiPoint object.</param>
+        /// <param name="isGeography" type="Boolean">Flag indicating if the value uses a geographic reference system or not.<param>
+        /// <remarks>
+        ///    When using a geographic reference system, the first component of all the coordinates in the GeoJSON value is the Longitude and
+        ///    will be serialized as the second component of each <pos> element in the GML DOM tree.
+        /// </remarks>
+        /// <returns>New DOM element in the GML namespace for the GeoJSON MultiPoint.</returns>
+
+        return gmlNewODataMultiItem(dom, "MultiPoint", "pointMembers", value.coordinates, gmlNewODataPointElement, isGeography);
+    };
+
+    var gmlNewODataMultiLineString = function (dom, value, isGeography) {
+        /// <summary>Creates a new GML MultiCurve DOM element for a GeoJSON MultiLineString object.</summary>
+        /// <param name="dom">DOM document used for creating the new DOM Element.</param>
+        /// <param name="value" type="Object">GeoJSON MultiLineString object.</param>
+        /// <param name="isGeography" type="Boolean">Flag indicating if the value uses a geographic reference system or not.<param>
+        /// <remarks>
+        ///    When using a geographic reference system, the first component of all the coordinates in the GeoJSON value is the Longitude and
+        ///    will be serialized as the second component of each <pos> element in the GML DOM tree.
+        /// </remarks>
+        /// <returns>New DOM element in the GML namespace for the GeoJSON MultiLineString.</returns>
+
+        return gmlNewODataMultiItem(dom, "MultiCurve", "curveMembers", value.coordinates, gmlNewODataLineStringElement, isGeography);
+    };
+
+    var gmlNewODataMultiPolygon = function (dom, value, isGeography) {
+        /// <summary>Creates a new GML MultiSurface DOM element for a GeoJSON MultiPolygon object.</summary>
+        /// <param name="dom">DOM document used for creating the new DOM Element.</param>
+        /// <param name="value" type="Object">GeoJSON MultiPolygon object.</param>
+        /// <param name="isGeography" type="Boolean">Flag indicating if the value uses a geographic reference system or not.<param>
+        /// <remarks>
+        ///    When using a geographic reference system, the first component of all the coordinates in the GeoJSON value is the Longitude and
+        ///    will be serialized as the second component of each <pos> element in the GML DOM tree.
+        /// </remarks>
+        /// <returns>New DOM element in the GML namespace for the GeoJSON MultiPolygon.</returns>
+
+        return gmlNewODataMultiItem(dom, "MultiSurface", "surfaceMembers", value.coordinates, gmlNewODataPolygonElement, isGeography);
+    };
+
+    var gmlNewODataGeometryCollectionItem = function (dom, value, isGeography) {
+        /// <summary>Creates a new GML element for an item in a geometry collection object.</summary>
+        /// <param name="dom">DOM document used for creating the new DOM Element.</param>
+        /// <param name="item" type="Object">GeoJSON object in the geometry collection.</param>
+        /// <param name="isGeography" type="Boolean">Flag indicating if the value uses a geographic reference system or not.<param>
+        /// <remarks>
+        ///    When using a geographic reference system, the first component of all the coordinates in the GeoJSON value is the Longitude and
+        ///    will be serialized as the second component of each <pos> element in the GML DOM tree.
+        /// </remarks>
+        /// <returns>New DOM element in the GML namespace.</returns>
+
+        return gmlNewODataSpatialValue(dom, value, value.type, isGeography);
+    };
+
+    var gmlNewODataGeometryCollection = function (dom, value, isGeography) {
+        /// <summary>Creates a new GML MultiGeometry DOM element for a GeoJSON GeometryCollection object.</summary>
+        /// <param name="dom">DOM document used for creating the new DOM Element.</param>
+        /// <param name="value" type="Object">GeoJSON GeometryCollection object.</param>
+        /// <param name="isGeography" type="Boolean">Flag indicating if the value uses a geographic reference system or not.<param>
+        /// <remarks>
+        ///    When using a geographic reference system, the first component of all the coordinates in the GeoJSON value is the Longitude and
+        ///    will be serialized as the second component of each <pos> element in the GML DOM tree.
+        /// </remarks>
+        /// <returns>New DOM element in the GML namespace for the GeoJSON GeometryCollection.</returns>
+
+        return gmlNewODataMultiItem(dom, "MultiGeometry", "geometryMembers", value.geometries, gmlNewODataGeometryCollectionItem, isGeography);
+    };
+
+    // DATAJS INTERNAL START
+    odata.gmlNewODataSpatialValue = gmlNewODataSpatialValue;
+    odata.gmlReadODataSpatialValue = gmlReadODataSpatialValue;
+    odata.gmlXmlNs = gmlXmlNs;
+    // DATAJS INTERNAL END
+
+    // CONTENT END
+})(this);
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/e29bbd8f/datajs/src/odata-handler.js
----------------------------------------------------------------------
diff --git a/datajs/src/odata-handler.js b/datajs/src/odata-handler.js
new file mode 100644
index 0000000..5f83429
--- /dev/null
+++ b/datajs/src/odata-handler.js
@@ -0,0 +1,276 @@
+// Copyright (c) Microsoft Open Technologies, Inc.  All rights reserved.
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal  in the Software without restriction, including without limitation the rights  to use, copy,
+// modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+// WARRANTIES OF MERCHANTABILITY,  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+// odata-handler.js
+
+(function (window, undefined) {
+
+    var datajs = window.datajs || {};
+    var odata = window.OData || {};
+
+    // Imports.
+    var assigned = datajs.assigned;
+    var extend = datajs.extend;
+    var trimString = datajs.trimString;
+
+    var maxVersion = odata.maxVersion;
+
+    // CONTENT START
+
+    var MAX_DATA_SERVICE_VERSION = "3.0";
+
+    var contentType = function (str) {
+        /// <summary>Parses a string into an object with media type and properties.</summary>
+        /// <param name="str" type="String">String with media type to parse.</param>
+        /// <returns>null if the string is empty; an object with 'mediaType' and a 'properties' dictionary otherwise.</returns>
+
+        if (!str) {
+            return null;
+        }
+
+        var contentTypeParts = str.split(";");
+        var properties = {};
+
+        var i, len;
+        for (i = 1, len = contentTypeParts.length; i < len; i++) {
+            var contentTypeParams = contentTypeParts[i].split("=");
+            properties[trimString(contentTypeParams[0])] = contentTypeParams[1];
+        }
+
+        return { mediaType: trimString(contentTypeParts[0]), properties: properties };
+    };
+
+    var contentTypeToString = function (contentType) {
+        /// <summary>Serializes an object with media type and properties dictionary into a string.</summary>
+        /// <param name="contentType">Object with media type and properties dictionary to serialize.</param>
+        /// <returns>String representation of the media type object; undefined if contentType is null or undefined.</returns>
+
+        if (!contentType) {
+            return undefined;
+        }
+
+        var result = contentType.mediaType;
+        var property;
+        for (property in contentType.properties) {
+            result += ";" + property + "=" + contentType.properties[property];
+        }
+        return result;
+    };
+
+    var createReadWriteContext = function (contentType, dataServiceVersion, context, handler) {
+        /// <summary>Creates an object that is going to be used as the context for the handler's parser and serializer.</summary>
+        /// <param name="contentType">Object with media type and properties dictionary.</param>
+        /// <param name="dataServiceVersion" type="String">String indicating the version of the protocol to use.</param>
+        /// <param name="context">Operation context.</param>
+        /// <param name="handler">Handler object that is processing a resquest or response.</param>
+        /// <returns>Context object.</returns>
+
+        var rwContext = {};
+        extend(rwContext, context);
+        extend(rwContext, {
+            contentType: contentType,
+            dataServiceVersion: dataServiceVersion,
+            handler: handler
+        });
+
+        return rwContext;
+    };
+
+    var fixRequestHeader = function (request, name, value) {
+        /// <summary>Sets a request header's value. If the header has already a value other than undefined, null or empty string, then this method does nothing.</summary>
+        /// <param name="request">Request object on which the header will be set.</param>
+        /// <param name="name" type="String">Header name.</param>
+        /// <param name="value" type="String">Header value.</param>
+        if (!request) {
+            return;
+        }
+
+        var headers = request.headers;
+        if (!headers[name]) {
+            headers[name] = value;
+        }
+    };
+
+    var fixDataServiceVersionHeader = function (request, version) {
+        /// <summary>Sets the DataServiceVersion header of the request if its value is not yet defined or of a lower version.</summary>
+        /// <param name="request">Request object on which the header will be set.</param>
+        /// <param name="version" type="String">Version value.</param>
+        /// <remarks>
+        /// If the request has already a version value higher than the one supplied the this function does nothing.
+        /// </remarks>
+
+        if (request) {
+            var headers = request.headers;
+            var dsv = headers["DataServiceVersion"];
+            headers["DataServiceVersion"] = dsv ? maxVersion(dsv, version) : version;
+        }
+    };
+
+    var getRequestOrResponseHeader = function (requestOrResponse, name) {
+        /// <summary>Gets the value of a request or response header.</summary>
+        /// <param name="requestOrResponse">Object representing a request or a response.</param>
+        /// <param name="name" type="String">Name of the header to retrieve.</param>
+        /// <returns type="String">String value of the header; undefined if the header cannot be found.</returns>
+
+        var headers = requestOrResponse.headers;
+        return (headers && headers[name]) || undefined;
+    };
+
+    var getContentType = function (requestOrResponse) {
+        /// <summary>Gets the value of the Content-Type header from a request or response.</summary>
+        /// <param name="requestOrResponse">Object representing a request or a response.</param>
+        /// <returns type="Object">Object with 'mediaType' and a 'properties' dictionary; null in case that the header is not found or doesn't have a value.</returns>
+
+        return contentType(getRequestOrResponseHeader(requestOrResponse, "Content-Type"));
+    };
+
+    var versionRE = /^\s?(\d+\.\d+);?.*$/;
+    var getDataServiceVersion = function (requestOrResponse) {
+        /// <summary>Gets the value of the DataServiceVersion header from a request or response.</summary>
+        /// <param name="requestOrResponse">Object representing a request or a response.</param>
+        /// <returns type="String">Data service version; undefined if the header cannot be found.</returns>
+
+        var value = getRequestOrResponseHeader(requestOrResponse, "DataServiceVersion");
+        if (value) {
+            var matches = versionRE.exec(value);
+            if (matches && matches.length) {
+                return matches[1];
+            }
+        }
+
+        // Fall through and return undefined.
+    };
+
+    var handlerAccepts = function (handler, cType) {
+        /// <summary>Checks that a handler can process a particular mime type.</summary>
+        /// <param name="handler">Handler object that is processing a resquest or response.</param>
+        /// <param name="cType">Object with 'mediaType' and a 'properties' dictionary.</param>
+        /// <returns type="Boolean">True if the handler can process the mime type; false otherwise.</returns>
+
+        // The following check isn't as strict because if cType.mediaType = application/; it will match an accept value of "application/xml";
+        // however in practice we don't not expect to see such "suffixed" mimeTypes for the handlers.
+        return handler.accept.indexOf(cType.mediaType) >= 0;
+    };
+
+    var handlerRead = function (handler, parseCallback, response, context) {
+        /// <summary>Invokes the parser associated with a handler for reading the payload of a HTTP response.</summary>
+        /// <param name="handler">Handler object that is processing the response.</param>
+        /// <param name="parseCallback" type="Function">Parser function that will process the response payload.</param>
+        /// <param name="response">HTTP response whose payload is going to be processed.</param>
+        /// <param name="context">Object used as the context for processing the response.</param>
+        /// <returns type="Boolean">True if the handler processed the response payload and the response.data property was set; false otherwise.</returns>
+
+        if (!response || !response.headers) {
+            return false;
+        }
+
+        var cType = getContentType(response);
+        var version = getDataServiceVersion(response) || "";
+        var body = response.body;
+
+        if (!assigned(body)) {
+            return false;
+        }
+
+        if (handlerAccepts(handler, cType)) {
+            var readContext = createReadWriteContext(cType, version, context, handler);
+            readContext.response = response;
+            response.data = parseCallback(handler, body, readContext);
+            return response.data !== undefined;
+        }
+
+        return false;
+    };
+
+    var handlerWrite = function (handler, serializeCallback, request, context) {
+        /// <summary>Invokes the serializer associated with a handler for generating the payload of a HTTP request.</summary>
+        /// <param name="handler">Handler object that is processing the request.</param>
+        /// <param name="serializeCallback" type="Function">Serializer function that will generate the request payload.</param>
+        /// <param name="response">HTTP request whose payload is going to be generated.</param>
+        /// <param name="context">Object used as the context for serializing the request.</param>
+        /// <returns type="Boolean">True if the handler serialized the request payload and the request.body property was set; false otherwise.</returns>
+        if (!request || !request.headers) {
+            return false;
+        }
+
+        var cType = getContentType(request);
+        var version = getDataServiceVersion(request);
+
+        if (!cType || handlerAccepts(handler, cType)) {
+            var writeContext = createReadWriteContext(cType, version, context, handler);
+            writeContext.request = request;
+
+            request.body = serializeCallback(handler, request.data, writeContext);
+
+            if (request.body !== undefined) {
+                fixDataServiceVersionHeader(request, writeContext.dataServiceVersion || "1.0");
+
+                fixRequestHeader(request, "Content-Type", contentTypeToString(writeContext.contentType));
+                fixRequestHeader(request, "MaxDataServiceVersion", handler.maxDataServiceVersion);
+                return true;
+            }
+        }
+
+        return false;
+    };
+
+    var handler = function (parseCallback, serializeCallback, accept, maxDataServiceVersion) {
+        /// <summary>Creates a handler object for processing HTTP requests and responses.</summary>
+        /// <param name="parseCallback" type="Function">Parser function that will process the response payload.</param>
+        /// <param name="serializeCallback" type="Function">Serializer function that will generate the request payload.</param>
+        /// <param name="accept" type="String">String containing a comma separated list of the mime types that this handler can work with.</param>
+        /// <param name="maxDataServiceVersion" type="String">String indicating the highest version of the protocol that this handler can work with.</param>
+        /// <returns type="Object">Handler object.</returns>
+
+        return {
+            accept: accept,
+            maxDataServiceVersion: maxDataServiceVersion,
+
+            read: function (response, context) {
+                return handlerRead(this, parseCallback, response, context);
+            },
+
+            write: function (request, context) {
+                return handlerWrite(this, serializeCallback, request, context);
+            }
+        };
+    };
+
+    var textParse = function (handler, body /*, context */) {
+        return body;
+    };
+
+    var textSerialize = function (handler, data /*, context */) {
+        if (assigned(data)) {
+            return data.toString();
+        } else {
+            return undefined;
+        }
+    };
+
+    odata.textHandler = handler(textParse, textSerialize, "text/plain", MAX_DATA_SERVICE_VERSION);
+
+    // DATAJS INTERNAL START
+    odata.contentType = contentType;
+    odata.contentTypeToString = contentTypeToString;
+    odata.handler = handler;
+    odata.createReadWriteContext = createReadWriteContext;
+    odata.fixRequestHeader = fixRequestHeader;
+    odata.getRequestOrResponseHeader = getRequestOrResponseHeader;
+    odata.getContentType = getContentType;
+    odata.getDataServiceVersion = getDataServiceVersion;
+    odata.MAX_DATA_SERVICE_VERSION = MAX_DATA_SERVICE_VERSION;
+    // DATAJS INTERNAL END
+
+    // CONTENT END
+})(this);
\ No newline at end of file