(function (window, undefined)()

in JSLib/src/odata-xml.js [16:850]


(function (window, undefined) {

    var datajs = window.datajs || {};
    var odata = window.OData || {};

    // Imports.

    var djsassert = datajs.djsassert;
    var http = datajs.http;
    var isArray = datajs.isArray;
    var isDate = datajs.isDate;
    var isObject = datajs.isObject;
    var normalizeURI = datajs.normalizeURI;
    var parseInt10 = datajs.parseInt10;
    var xmlAppendChild = datajs.xmlAppendChild;
    var xmlAppendChildren = datajs.xmlAppendChildren;
    var xmlAttributes = datajs.xmlAttributes;
    var xmlBaseURI = datajs.xmlBaseURI;
    var xmlChildElements = datajs.xmlChildElements;
    var xmlDom = datajs.xmlDom;
    var xmlFirstChildElement = datajs.xmlFirstChildElement;
    var xmlInnerText = datajs.xmlInnerText;
    var xmlLocalName = datajs.xmlLocalName;
    var xmlNamespaceURI = datajs.xmlNamespaceURI;
    var xmlNewAttribute = datajs.xmlNewAttribute;
    var xmlNewElement = datajs.xmlNewElement;
    var xmlNodeValue = datajs.xmlNodeValue;
    var xmlNS = datajs.xmlNS;
    var xmlnsNS = datajs.xmlnsNS;
    var xmlParse = datajs.xmlParse;
    var xmlQualifiedName = datajs.xmlQualifiedName;
    var xmlSerialize = datajs.xmlSerialize;
    var xmlSiblingElement = datajs.xmlSiblingElement;
    var w3org = datajs.w3org;

    var dataItemTypeName = odata.dataItemTypeName;
    var EDM_BINARY = odata.EDM_BINARY;
    var EDM_BOOLEAN = odata.EDM_BOOLEAN;
    var EDM_BYTE = odata.EDM_BYTE;
    var EDM_DATETIME = odata.EDM_DATETIME;
    var EDM_DATETIMEOFFSET = odata.EDM_DATETIMEOFFSET;
    var EDM_DECIMAL = odata.EDM_DECIMAL;
    var EDM_DOUBLE = odata.EDM_DOUBLE;
    var EDM_GEOGRAPHY = odata.EDM_GEOGRAPHY;
    var EDM_GEOGRAPHY_POINT = odata.EDM_GEOGRAPHY_POINT;
    var EDM_GEOGRAPHY_LINESTRING = odata.EDM_GEOGRAPHY_LINESTRING;
    var EDM_GEOGRAPHY_POLYGON = odata.EDM_GEOGRAPHY_POLYGON;
    var EDM_GEOGRAPHY_COLLECTION = odata.EDM_GEOGRAPHY_COLLECTION;
    var EDM_GEOGRAPHY_MULTIPOLYGON = odata.EDM_GEOGRAPHY_MULTIPOLYGON;
    var EDM_GEOGRAPHY_MULTILINESTRING = odata.EDM_GEOGRAPHY_MULTILINESTRING;
    var EDM_GEOGRAPHY_MULTIPOINT = odata.EDM_GEOGRAPHY_MULTIPOINT;
    var EDM_GEOMETRY = odata.EDM_GEOMETRY;
    var EDM_GEOMETRY_POINT = odata.EDM_GEOMETRY_POINT;
    var EDM_GEOMETRY_LINESTRING = odata.EDM_GEOMETRY_LINESTRING;
    var EDM_GEOMETRY_POLYGON = odata.EDM_GEOMETRY_POLYGON;
    var EDM_GEOMETRY_COLLECTION = odata.EDM_GEOMETRY_COLLECTION;
    var EDM_GEOMETRY_MULTIPOLYGON = odata.EDM_GEOMETRY_MULTIPOLYGON;
    var EDM_GEOMETRY_MULTILINESTRING = odata.EDM_GEOMETRY_MULTILINESTRING;
    var EDM_GEOMETRY_MULTIPOINT = odata.EDM_GEOMETRY_MULTIPOINT;
    var EDM_GUID = odata.EDM_GUID;
    var EDM_INT16 = odata.EDM_INT16;
    var EDM_INT32 = odata.EDM_INT32;
    var EDM_INT64 = odata.EDM_INT64;
    var EDM_SBYTE = odata.EDM_SBYTE;
    var EDM_SINGLE = odata.EDM_SINGLE;
    var EDM_STRING = odata.EDM_STRING;
    var EDM_TIME = odata.EDM_TIME;
    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;
    var formatDateTimeOffset = odata.formatDateTimeOffset;
    var formatDuration = odata.formatDuration;
    var getCollectionType = odata.getCollectionType;
    var gmlNewODataSpatialValue = odata.gmlNewODataSpatialValue;
    var gmlReadODataSpatialValue = odata.gmlReadODataSpatialValue;
    var gmlXmlNs = odata.gmlXmlNs;
    var handler = odata.handler;
    var isCollection = odata.isCollection;
    var isCollectionType = odata.isCollectionType;
    var isDeferred = odata.isDeferred;
    var isNamedStream = odata.isNamedStream;
    var isGeographyEdmType = odata.isGeographyEdmType;
    var isGeometryEdmType = odata.isGeometryEdmType;
    var isPrimitive = odata.isPrimitive;
    var isPrimitiveEdmType = odata.isPrimitiveEdmType;
    var lookupComplexType = odata.lookupComplexType;
    var lookupProperty = odata.lookupProperty;
    var maxVersion = odata.maxVersion;
    var navigationPropertyKind = odata.navigationPropertyKind;
    var MAX_DATA_SERVICE_VERSION = odata.MAX_DATA_SERVICE_VERSION;
    var parseBool = odata.parseBool;
    var parseDateTime = odata.parseDateTime;
    var parseDateTimeOffset = odata.parseDateTimeOffset;
    var parseDuration = odata.parseDuration;
    var parseTimezone = odata.parseTimezone;

    // CONTENT START

    var xmlMediaType = "application/xml";

    var ado = http + "schemas.microsoft.com/ado/";      // http://schemas.microsoft.com/ado/
    var adoDs = ado + "2007/08/dataservices";           // http://schemas.microsoft.com/ado/2007/08/dataservices

    var edmxNs = ado + "2007/06/edmx";                  // http://schemas.microsoft.com/ado/2007/06/edmx
    var edmNs1 = ado + "2006/04/edm";                   // http://schemas.microsoft.com/ado/2006/04/edm
    var edmNs1_1 = ado + "2007/05/edm";                 // http://schemas.microsoft.com/ado/2007/05/edm
    var edmNs1_2 = ado + "2008/01/edm";                 // http://schemas.microsoft.com/ado/2008/01/edm

    // There are two valid namespaces for Edm 2.0
    var edmNs2a = ado + "2008/09/edm";                  // http://schemas.microsoft.com/ado/2008/09/edm
    var edmNs2b = ado + "2009/08/edm";                  // http://schemas.microsoft.com/ado/2009/08/edm

    var edmNs3 = ado + "2009/11/edm";                   // http://schemas.microsoft.com/ado/2009/11/edm

    var odataXmlNs = adoDs;                             // http://schemas.microsoft.com/ado/2007/08/dataservices
    var odataMetaXmlNs = adoDs + "/metadata";           // http://schemas.microsoft.com/ado/2007/08/dataservices/metadata
    var odataRelatedPrefix = adoDs + "/related/";       // http://schemas.microsoft.com/ado/2007/08/dataservices/related
    var odataScheme = adoDs + "/scheme";                // http://schemas.microsoft.com/ado/2007/08/dataservices/scheme

    var odataPrefix = "d";
    var odataMetaPrefix = "m";

    var createAttributeExtension = function (domNode, useNamespaceURI) {
        /// <summary>Creates an extension object for the specified attribute.</summary>
        /// <param name="domNode">DOM node for the attribute.</param>
        /// <param name="useNamespaceURI" type="Boolean">Flag indicating if the namespaceURI property should be added to the extension object instead of the namespace property.</param>
        /// <remarks>
        ///    The useNamespaceURI flag is used to prevent a breaking change from older versions of datajs in which extension
        ///    objects created for Atom extension attributes have the namespaceURI property instead of the namespace one.
        ///    
        ///    This flag and the namespaceURI property should be deprecated in future major versions of the library.
        /// </remarks>
        /// <returns type="Object">The new extension object.</returns>

        djsassert(domNode.nodeType === 2, "createAttributeExtension - domNode is not an attribute node!!");
        var extension = { name: xmlLocalName(domNode), value: domNode.value };
        extension[useNamespaceURI ? "namespaceURI" : "namespace"] = xmlNamespaceURI(domNode);

        return extension;
    };

    var createElementExtension = function (domNode, useNamespaceURI) {
        /// <summary>Creates an extension object for the specified element.</summary>
        /// <param name="domNode">DOM node for the element.</param>
        /// <param name="useNamespaceURI" type="Boolean">Flag indicating if the namespaceURI property should be added to the extension object instead of the namespace property.</param>
        /// <remarks>
        ///    The useNamespaceURI flag is used to prevent a breaking change from older versions of datajs in which extension
        ///    objects created for Atom extension attributes have the namespaceURI property instead of the namespace one.
        ///    
        ///    This flag and the namespaceURI property should be deprecated in future major versions of the library.
        /// </remarks>
        /// <returns type="Object">The new extension object.</returns>

        djsassert(domNode.nodeType === 1, "createAttributeExtension - domNode is not an element node!!");

        var attributeExtensions = [];
        var childrenExtensions = [];

        var i, len;
        var attributes = domNode.attributes;
        for (i = 0, len = attributes.length; i < len; i++) {
            var attr = attributes[i];
            if (xmlNamespaceURI(attr) !== xmlnsNS) {
                attributeExtensions.push(createAttributeExtension(attr, useNamespaceURI));
            }
        }

        var child = domNode.firstChild;
        while (child != null) {
            if (child.nodeType === 1) {
                childrenExtensions.push(createElementExtension(child, useNamespaceURI));
            }
            child = child.nextSibling;
        }

        var extension = {
            name: xmlLocalName(domNode),
            value: xmlInnerText(domNode),
            attributes: attributeExtensions,
            children: childrenExtensions
        };

        extension[useNamespaceURI ? "namespaceURI" : "namespace"] = xmlNamespaceURI(domNode);
        return extension;
    };

    var isCollectionItemElement = function (domElement) {
        /// <summary>Checks whether the domElement is a collection item.</summary>
        /// <param name="domElement">DOM element possibliy represnting a collection item.</param>
        /// <returns type="Boolean">True if the domeElement belongs to the OData metadata namespace and its local name is "element"; false otherwise.</returns>

        return xmlNamespaceURI(domElement) === odataXmlNs && xmlLocalName(domElement) === "element";
    };

    var makePropertyMetadata = function (type, extensions) {
        /// <summary>Creates an object containing property metadata.</summary>
        /// <param type="String" name="type">Property type name.</param>
        /// <param type="Array" name="extensions">Array of attribute extension objects.</param>
        /// <returns type="Object">Property metadata object cotaining type and extensions fields.</returns>

        return { type: type, extensions: extensions };
    };

    var odataInferTypeFromPropertyXmlDom = function (domElement) {
        /// <summary>Infers type of a property based on its xml DOM tree.</summary>
        /// <param name="domElement">DOM element for the property.</param>
        /// <returns type="String">Inferred type name; null if the type cannot be determined.</returns>

        if (xmlFirstChildElement(domElement, gmlXmlNs)) {
            return EDM_GEOMETRY;
        }

        var firstChild = xmlFirstChildElement(domElement, odataXmlNs);
        if (!firstChild) {
            return EDM_STRING;
        }

        if (isCollectionItemElement(firstChild)) {
            var sibling = xmlSiblingElement(firstChild, odataXmlNs);
            if (sibling && isCollectionItemElement(sibling)) {
                // More than one <element> tag have been found, it can be safely assumed that this is a collection property.
                return "Collection()";
            }
        }

        return null;
    };

    var xmlReadODataPropertyAttributes = function (domElement) {
        /// <summary>Reads the attributes of a property DOM element in an OData XML document.</summary>
        /// <param name="domElement">DOM element for the property.</param>
        /// <returns type="Object">Object containing the property type, if it is null, and its attribute extensions.</returns>

        var type = null;
        var isNull = false;
        var extensions = [];

        xmlAttributes(domElement, function (attribute) {
            var nsURI = xmlNamespaceURI(attribute);
            var localName = xmlLocalName(attribute);
            var value = xmlNodeValue(attribute);

            if (nsURI === odataMetaXmlNs) {
                if (localName === "null") {
                    isNull = (value.toLowerCase() === "true");
                    return;
                }

                if (localName === "type") {
                    type = value;
                    return;
                }
            }

            if (nsURI !== xmlNS && nsURI !== xmlnsNS) {
                extensions.push(createAttributeExtension(attribute, true));
                return;
            }
        });

        return { type: (!type && isNull ? EDM_STRING : type), isNull: isNull, extensions: extensions };
    };

    var xmlReadODataProperty = function (domElement) {
        /// <summary>Reads a property DOM element in an OData XML document.</summary>
        /// <param name="domElement">DOM element for the property.</param>
        /// <returns type="Object">Object with name, value, and metadata for the property.</returns>

        if (xmlNamespaceURI(domElement) !== odataXmlNs) {
            // domElement is not a proprety element because it is not in the odata xml namespace.
            return null;
        }

        var propertyName = xmlLocalName(domElement);
        var propertyAttributes = xmlReadODataPropertyAttributes(domElement);

        var propertyIsNull = propertyAttributes.isNull;
        var propertyType = propertyAttributes.type;

        var propertyMetadata = makePropertyMetadata(propertyType, propertyAttributes.extensions);
        var propertyValue = propertyIsNull ? null : xmlReadODataPropertyValue(domElement, propertyType, propertyMetadata);

        return { name: propertyName, value: propertyValue, metadata: propertyMetadata };
    };

    var xmlReadODataPropertyValue = function (domElement, propertyType, propertyMetadata) {
        /// <summary>Reads the value of a property in an OData XML document.</summary>
        /// <param name="domElement">DOM element for the property.</param>
        /// <param name="propertyType" type="String">Property type name.</param>
        /// <param name="propertyMetadata" type="Object">Object that will store metadata about the property.</param>
        /// <returns>Property value.</returns>

        if (!propertyType) {
            propertyType = odataInferTypeFromPropertyXmlDom(domElement);
            propertyMetadata.type = propertyType;
        }

        var isGeograhpyType = isGeographyEdmType(propertyType);
        if (isGeograhpyType || isGeometryEdmType(propertyType)) {
            return xmlReadODataSpatialPropertyValue(domElement, propertyType, isGeograhpyType);
        }

        if (isPrimitiveEdmType(propertyType)) {
            return xmlReadODataEdmPropertyValue(domElement, propertyType);
        }

        if (isCollectionType(propertyType)) {
            return xmlReadODataCollectionPropertyValue(domElement, propertyType, propertyMetadata);
        }

        return xmlReadODataComplexPropertyValue(domElement, propertyType, propertyMetadata);
    };

    var xmlReadODataSpatialPropertyValue = function (domElement, propertyType, isGeography) {
        /// <summary>Reads the value of an spatial property in an OData XML document.</summary>
        /// <param name="property">DOM element for the spatial property.</param>
        /// <param name="propertyType" type="String">Property type name.</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>Spatial property value in GeoJSON format.</returns>

        var gmlRoot = xmlFirstChildElement(domElement, gmlXmlNs);
        djsassert(gmlRoot, "xmlReadODataSpatialPropertyValue - domElement doesn't have a child element that belongs to the gml namespace!!");

        var value = gmlReadODataSpatialValue(gmlRoot, isGeography);
        value.__metadata = { type: propertyType };
        return value;
    };

    var xmlReadODataEdmPropertyValue = function (domNode, propertyType) {
        /// <summary>Reads the value of an EDM property in an OData XML document.</summary>
        /// <param name="donNode">DOM node for the EDM property.</param>
        /// <param name="propertyType" type="String">Property type name.</param>
        /// <returns>EDM property value.</returns>

        var propertyValue = xmlNodeValue(domNode) || "";

        switch (propertyType) {
            case EDM_BOOLEAN:
                return parseBool(propertyValue);
            case EDM_BINARY:
            case EDM_DECIMAL:
            case EDM_GUID:
            case EDM_INT64:
            case EDM_STRING:
                return propertyValue;
            case EDM_BYTE:
            case EDM_INT16:
            case EDM_INT32:
            case EDM_SBYTE:
                return parseInt10(propertyValue);
            case EDM_DOUBLE:
            case EDM_SINGLE:
                return parseFloat(propertyValue);
            case EDM_TIME:
                return parseDuration(propertyValue);
            case EDM_DATETIME:
                return parseDateTime(propertyValue);
            case EDM_DATETIMEOFFSET:
                return parseDateTimeOffset(propertyValue);
        }

        return propertyValue;
    };

    var xmlReadODataComplexPropertyValue = function(domElement, propertyType, propertyMetadata) {
        /// <summary>Reads the value of a complex type property in an OData XML document.</summary>
        /// <param name="property">DOM element for the complex type property.</param>
        /// <param name="propertyType" type="String">Property type name.</param>
        /// <param name="propertyMetadata" type="Object">Object that will store metadata about the property.</param>
        /// <returns type="Object">Complex type property value.</returns>

        var propertyValue = { __metadata: { type: propertyType } };
        xmlChildElements(domElement, function(child) {
            var childProperty = xmlReadODataProperty(child);
            var childPropertyName = childProperty.name;

            propertyMetadata.properties = propertyMetadata.properties || {};
            propertyMetadata.properties[childPropertyName] = childProperty.metadata;
            propertyValue[childPropertyName] = childProperty.value;
        });

        return propertyValue;
    };

    var xmlReadODataCollectionPropertyValue = function (domElement, propertyType, propertyMetadata) {
        /// <summary>Reads the value of a collection property in an OData XML document.</summary>
        /// <param name="property">DOM element for the collection property.</param>
        /// <param name="propertyType" type="String">Property type name.</param>
        /// <param name="propertyMetadata" type="Object">Object that will store metadata about the property.</param>
        /// <returns type="Object">Collection property value.</returns>

        var items = [];
        var itemsMetadata = propertyMetadata.elements = [];
        var collectionType = getCollectionType(propertyType);

        xmlChildElements(domElement, function (child) {
            if (isCollectionItemElement(child)) {
                var itemAttributes = xmlReadODataPropertyAttributes(child);
                var itemExtensions = itemAttributes.extensions;
                var itemType = itemAttributes.type || collectionType;
                var itemMetadata = makePropertyMetadata(itemType, itemExtensions);

                var item = xmlReadODataPropertyValue(child, itemType, itemMetadata);

                items.push(item);
                itemsMetadata.push(itemMetadata);
            }
        });

        return { __metadata: { type: propertyType === "Collection()" ? null : propertyType }, results: items };
    };

    var readODataXmlDocument = function (xmlRoot, baseURI) {
        /// <summary>Reads an OData link(s) producing an object model in return.</summary>
        /// <param name="xmlRoot">Top-level element to read.</param>
        /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the XML payload.</param>
        /// <returns type="Object">The object model representing the specified element.</returns>

        if (xmlNamespaceURI(xmlRoot) === odataXmlNs) {
            baseURI = xmlBaseURI(xmlRoot, baseURI);
            var localName = xmlLocalName(xmlRoot);

            if (localName === "links") {
                return readLinks(xmlRoot, baseURI);
            }
            if (localName === "uri") {
                return readUri(xmlRoot, baseURI);
            }
        }
        return undefined;
    };

    var readLinks = function (linksElement, baseURI) {
        /// <summary>Deserializes an OData XML links element.</summary>
        /// <param name="linksElement">XML links element.</param>
        /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the XML payload.</param>
        /// <returns type="Object">A new object representing the links collection.</returns>

        var uris = [];

        xmlChildElements(linksElement, function (child) {
            if (xmlLocalName(child) === "uri" && xmlNamespaceURI(child) === odataXmlNs) {
                uris.push(readUri(child, baseURI));
            }
        });

        return { results: uris };
    };

    var readUri = function (uriElement, baseURI) {
        /// <summary>Deserializes an OData XML uri element.</summary>
        /// <param name="uriElement">XML uri element.</param>
        /// <param name="baseURI" type="String">Base URI for normalizing relative URIs found in the XML payload.</param>
        /// <returns type="Object">A new object representing the uri.</returns>

        var uri = xmlInnerText(uriElement) || "";
        return { uri: normalizeURI(uri, baseURI) };
    };

    var xmlODataInferSpatialValueGeoJsonType = function (value, edmType) {
        /// <summary>Infers the GeoJSON type from the spatial property value and the edm type name.</summary>
        /// <param name="value" type="Object">Spatial property value in GeoJSON format.</param>
        /// <param name="edmType" type="String" mayBeNull="true" optional="true">Spatial property edm type.<param>
        /// <remarks>
        ///   If the edmType parameter is null, undefined, "Edm.Geometry" or "Edm.Geography", then the function returns
        ///   the GeoJSON type indicated by the value's type property.
        ///
        ///   If the edmType parameter is specified or is not one of the base spatial types, then it is used to
        ///   determine the GeoJSON type and the value's type property is ignored.
        /// </remarks>
        /// <returns>New DOM element in the GML namespace for the spatial value. </returns>

        if (edmType === EDM_GEOMETRY || edmType === EDM_GEOGRAPHY) {
            return value && value.type;
        }

        if (edmType === EDM_GEOMETRY_POINT || edmType === EDM_GEOGRAPHY_POINT) {
            return GEOJSON_POINT;
        }

        if (edmType === EDM_GEOMETRY_LINESTRING || edmType === EDM_GEOGRAPHY_LINESTRING) {
            return GEOJSON_LINESTRING;
        }

        if (edmType === EDM_GEOMETRY_POLYGON || edmType === EDM_GEOGRAPHY_POLYGON) {
            return GEOJSON_POLYGON;
        }

        if (edmType === EDM_GEOMETRY_COLLECTION || edmType === EDM_GEOGRAPHY_COLLECTION) {
            return GEOJSON_GEOMETRYCOLLECTION;
        }

        if (edmType === EDM_GEOMETRY_MULTIPOLYGON || edmType === EDM_GEOGRAPHY_MULTIPOLYGON) {
            return GEOJSON_MULTIPOLYGON;
        }

        if (edmType === EDM_GEOMETRY_MULTILINESTRING || edmType === EDM_GEOGRAPHY_MULTILINESTRING) {
            return GEOJSON_MULTILINESTRING;
        }

        if (edmType === EDM_GEOMETRY_MULTIPOINT || edmType === EDM_GEOGRAPHY_MULTIPOINT) {
            return GEOJSON_MULTIPOINT;
        }

        djsassert(false, "gmlInferGeoJsonType - edm type <" + edmType + "> was unexpected!!");
        return null;
    };

    var xmlNewODataMetaElement = function (dom, name, children) {
        /// <summary>Creates a new DOM element in the OData metadata namespace.</summary>
        /// <param name="dom">DOM document used for creating the new DOM Element.</param>
        /// <param name="name" type="String">Local name of the OData metadata 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 OData metadata 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, odataMetaXmlNs, xmlQualifiedName(odataMetaPrefix, name), children);
    };

    var xmlNewODataMetaAttribute = function (dom, name, value) {
        /// <summary>Creates a new DOM attribute in the odata namespace.</summary>
        /// <param name="dom">DOM document used for creating the new DOM Element.</param>
        /// <param name="name" type="String">Local name of the OData attribute to create.</param>
        /// <param name="value">Attribute value.</param>
        /// <returns>New DOM attribute in the odata namespace.</returns>

        return xmlNewAttribute(dom, odataMetaXmlNs, xmlQualifiedName(odataMetaPrefix, name), value);
    };

    var xmlNewODataElement = function (dom, name, children) {
        /// <summary>Creates a new DOM element in the OData namespace.</summary>
        /// <param name="dom">DOM document used for creating the new DOM Element.</param>
        /// <param name="name" type="String">Local name of the OData 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 OData 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, odataXmlNs, xmlQualifiedName(odataPrefix, name), children);
    };

    var xmlNewODataPrimitiveValue = function (value, typeName) {
        /// <summary>Returns the string representation of primitive value for an OData XML document.</summary>
        /// <param name="value">Primivite value to format.</param>
        /// <param name="typeName" type="String" optional="true">Type name of the primitive value.</param>
        /// <returns type="String">Formatted primitive value.</returns>

        if (typeName === EDM_DATETIME || typeName === EDM_DATETIMEOFFSET || isDate(value)) {
            return formatDateTimeOffset(value);
        }
        if (typeName === EDM_TIME) {
            return formatDuration(value);
        }
        return value.toString();
    };

    var xmlNewODataElementInfo = function (domElement, dataServiceVersion) {
        /// <summary>Creates an object that represents a new DOM element for an OData XML document and the data service version it requires.</summary>
        /// <param name="domElement">New DOM element for an OData XML document.</param>
        /// <param name="dataServiceVersion" type="String">Required data service version by the new DOM element.</param>
        /// <returns type="Object">Object containing new DOM element and its required data service version.</returns>

        return { element: domElement, dsv: dataServiceVersion };
    };

    var xmlNewODataProperty = function (dom, name, typeName, children) {
        /// <summary>Creates a new DOM element for an entry property in an OData XML document.</summary>
        /// <param name="dom">DOM document used for creating the new DOM Element.</param>
        /// <param name="name" type="String">Property name.</param>
        /// <param name="typeName" type="String" optional="true">Property type name.</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>
        /// <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>
        /// <returns>New DOM element in the OData namespace for the entry property.</returns>

        var typeAttribute = typeName ? xmlNewODataMetaAttribute(dom, "type", typeName) : null;
        var property = xmlNewODataElement(dom, name, typeAttribute);
        return xmlAppendChildren(property, children);
    };

    var xmlNewODataEdmProperty = function (dom, name, value, typeName) {
        /// <summary>Creates a new DOM element for an EDM property in an OData XML document.</summary>
        /// <param name="dom">DOM document used for creating the new DOM Element.</param>
        /// <param name="name" type="String">Property name.</param>
        /// <param name="value">Property value.</param>
        /// <param name="typeName" type="String" optional="true">Property type name.</param>
        /// <returns type="Object">
        ///     Object containing the new DOM element in the OData namespace for the EDM property and the
        ///     required data service version for this property.
        /// </returns>

        var propertyValue = xmlNewODataPrimitiveValue(value, typeName);
        var property = xmlNewODataProperty(dom, name, typeName, propertyValue);
        return xmlNewODataElementInfo(property, /*dataServiceVersion*/"1.0");
    };

    var xmlNewODataNullProperty = function (dom, name, typeName, model) {
        /// <summary>Creates a new DOM element for a null property in an OData XML document.</summary>
        /// <param name="dom">DOM document used for creating the new DOM Element.</param>
        /// <param name="name" type="String">Property name.</param>
        /// <param name="typeName" type="String" optional="true">Property type name.</param>
        /// <param name="model" type="Object" optional="true">Object describing an OData conceptual schema.</param>
        /// <remarks>
        ///     If no typeName is specified, then it will be assumed that this is a primitive type property.
        /// </remarks>
        /// <returns type="Object">
        ///     Object containing the new DOM element in the OData namespace for the null property and the 
        ///     required data service version for this property.
        /// </returns>

        var nullAttribute = xmlNewODataMetaAttribute(dom, "null", "true");
        var property = xmlNewODataProperty(dom, name, typeName, nullAttribute);
        var dataServiceVersion = lookupComplexType(typeName, model) ? "2.0" : "1.0";

        return xmlNewODataElementInfo(property, dataServiceVersion);
    };

    var xmlNewODataCollectionProperty = function (dom, name, value, typeName, collectionMetadata, collectionModel, model) {
        /// <summary>Creates a new DOM element for a collection property in an OData XML document.</summary>
        /// <param name="dom">DOM document used for creating the new DOM Element.</param>
        /// <param name="name" type="String">Property name.</param>
        /// <param name="value">Property value either as an array or an object representing a collection in the library's internal representation.</param>
        /// <param name="typeName" type="String" optional="true">Property type name.</param>
        /// <param name="collectionMetadata" type="Object" optional="true">Object containing metadata about the collection property.</param>
        /// <param name="collectionModel" type="Object" optional="true">Object describing the collection property in an OData conceptual schema.</param>
        /// <param name="model" type="Object" optional="true">Object describing an OData conceptual schema.</param>
        /// <returns type="Object">
        ///     Object containing the new DOM element in the OData namespace for the collection property and the
        ///     required data service version for this property.
        /// </returns>

        var itemTypeName = getCollectionType(typeName);
        var items = isArray(value) ? value : value.results;
        var itemMetadata = typeName ? { type: itemTypeName} : {};
        itemMetadata.properties = collectionMetadata.properties;

        var xmlProperty = xmlNewODataProperty(dom, name, itemTypeName ? typeName : null);

        var i, len;
        for (i = 0, len = items.length; i < len; i++) {
            var itemValue = items[i];
            var item = xmlNewODataDataElement(dom, "element", itemValue, itemMetadata, collectionModel, model);

            xmlAppendChild(xmlProperty, item.element);
        }
        return xmlNewODataElementInfo(xmlProperty, /*dataServiceVersion*/"3.0");
    };

    var xmlNewODataComplexProperty = function (dom, name, value, typeName, propertyMetadata, propertyModel, model) {
        /// <summary>Creates a new DOM element for a complex type property in an OData XML document.</summary>
        /// <param name="dom">DOM document used for creating the new DOM Element.</param>
        /// <param name="name" type="String">Property name.</param>
        /// <param name="value">Property value as an object in the library's internal representation.</param>
        /// <param name="typeName" type="String" optional="true">Property type name.</param>
        /// <param name="propertyMetadata" type="Object" optional="true">Object containing metadata about the complex type property.</param>
        /// <param name="propertyModel" type="Object" optional="true">Object describing the complex type property in an OData conceptual schema.</param>
        /// <param name="model" type="Object" optional="true">Object describing an OData conceptual schema.</param>
        /// <returns type="Object">
        ///     Object containing the new DOM element in the OData namespace for the complex type property and the
        ///     required data service version for this property.
        /// </returns>

        var xmlProperty = xmlNewODataProperty(dom, name, typeName);
        var complexTypePropertiesMetadata = propertyMetadata.properties || {};
        var complexTypeModel = lookupComplexType(typeName, model) || {};

        var dataServiceVersion = "1.0";

        for (var key in value) {
            if (key !== "__metadata") {
                var memberValue = value[key];
                var memberModel = lookupProperty(complexTypeModel.property, key);
                var memberMetadata = complexTypePropertiesMetadata[key] || {};
                var member = xmlNewODataDataElement(dom, key, memberValue, memberMetadata, memberModel, model);

                dataServiceVersion = maxVersion(dataServiceVersion, member.dsv);
                xmlAppendChild(xmlProperty, member.element);
            }
        }
        return xmlNewODataElementInfo(xmlProperty, dataServiceVersion);
    };

    var xmlNewODataSpatialProperty = function (dom, name, value, typeName, isGeography) {
        /// <summary>Creates a new DOM element for an EDM spatial property in an OData XML document.</summary>
        /// <param name="dom">DOM document used for creating the new DOM Element.</param>
        /// <param name="name" type="String">Property name.</param>
        /// <param name="value" type="Object">GeoJSON object containing the property value.</param>
        /// <param name="typeName" type="String" optional="true">Property type name.</param>
        /// <returns type="Object">
        ///     Object containing the new DOM element in the OData namespace for the EDM property and the
        ///     required data service version for this property.
        /// </returns>

        var geoJsonType = xmlODataInferSpatialValueGeoJsonType(value, typeName);

        var gmlRoot = gmlNewODataSpatialValue(dom, value, geoJsonType, isGeography);
        var xmlProperty = xmlNewODataProperty(dom, name, typeName, gmlRoot);

        return xmlNewODataElementInfo(xmlProperty, "3.0");
    };

    var xmlNewODataDataElement = function (dom, name, value, dataItemMetadata, dataItemModel, model) {
        /// <summary>Creates a new DOM element for a data item in an entry, complex property, or collection property.</summary>
        /// <param name="dom">DOM document used for creating the new DOM Element.</param>
        /// <param name="name" type="String">Data item name.</param>
        /// <param name="value" optional="true" mayBeNull="true">Value of the data item, if any.</param>
        /// <param name="dataItemMetadata" type="Object" optional="true">Object containing metadata about the data item.</param>
        /// <param name="dataItemModel" type="Object" optional="true">Object describing the data item in an OData conceptual schema.</param>
        /// <param name="model" type="Object" optional="true">Object describing an OData conceptual schema.</param>
        /// <returns type="Object">
        ///     Object containing the new DOM element in the appropriate namespace for the data item and the
        ///     required data service version for it.
        /// </returns>

        var typeName = dataItemTypeName(value, dataItemMetadata, dataItemModel);
        if (isPrimitive(value)) {
            return xmlNewODataEdmProperty(dom, name, value, typeName || EDM_STRING);
        }

        var isGeography = isGeographyEdmType(typeName);
        if (isGeography || isGeometryEdmType(typeName)) {
            return xmlNewODataSpatialProperty(dom, name, value, typeName, isGeography);
        }

        if (isCollection(value, typeName)) {
            return xmlNewODataCollectionProperty(dom, name, value, typeName, dataItemMetadata, dataItemModel, model);
        }

        if (isNamedStream(value)) {
            return null;
        }

        // This may be a navigation property.
        var navPropKind = navigationPropertyKind(value, dataItemModel);
        if (navPropKind !== null) {
            return null;
        }

        if (value === null) {
            return xmlNewODataNullProperty(dom, name, typeName);
        }

        djsassert(isObject(value), "xmlNewODataEntryProperty - property '" + name + "' is not an object");
        return xmlNewODataComplexProperty(dom, name, value, typeName, dataItemMetadata, dataItemModel, model);
    };

    var odataNewLinkDocument = function (data) {
        /// <summary>Writes the specified data into an OData XML document.</summary>
        /// <param name="data">Data to write.</param>
        /// <returns>The root of the DOM tree built.</returns>

        if (data && isObject(data)) {
            var dom = xmlDom();
            return xmlAppendChild(dom, xmlNewODataElement(dom, "uri", data.uri));
        }
        // Allow for undefined to be returned.
    };

    var xmlParser = function (handler, text) {
        /// <summary>Parses an OData XML document.</summary>
        /// <param name="handler">This handler.</param>
        /// <param name="text" type="String">Document text.</param>
        /// <returns>An object representation of the document; undefined if not applicable.</returns>

        if (text) {
            var doc = xmlParse(text);
            var root = xmlFirstChildElement(doc);
            if (root) {
                return readODataXmlDocument(root);
            }
        }

        // Allow for undefined to be returned.
    };

    var xmlSerializer = function (handler, data, context) {
        /// <summary>Serializes an OData XML object into a document.</summary>
        /// <param name="handler">This handler.</param>
        /// <param name="data" type="Object">Representation of feed or entry.</param>
        /// <param name="context" type="Object">Object with parsing context.</param>
        /// <returns>A text representation of the data object; undefined if not applicable.</returns>

        var cType = context.contentType = context.contentType || contentType(xmlMediaType);
        if (cType && cType.mediaType === xmlMediaType) {
            return xmlSerialize(odataNewLinkDocument(data));
        }
        return undefined;
    };

    odata.xmlHandler = handler(xmlParser, xmlSerializer, xmlMediaType, MAX_DATA_SERVICE_VERSION);

    // DATAJS INTERNAL START
    odata.adoDs = adoDs;
    odata.createAttributeExtension = createAttributeExtension;
    odata.createElementExtension = createElementExtension;
    odata.edmxNs = edmxNs;
    odata.edmNs1 = edmNs1;
    odata.edmNs1_1 = edmNs1_1;
    odata.edmNs1_2 = edmNs1_2
    odata.edmNs2a = edmNs2a;
    odata.edmNs2b = edmNs2b;
    odata.edmNs3 = edmNs3;
    odata.odataMetaXmlNs = odataMetaXmlNs;
    odata.odataMetaPrefix = odataMetaPrefix;
    odata.odataXmlNs = odataXmlNs;
    odata.odataPrefix = odataPrefix;
    odata.odataScheme = odataScheme;
    odata.odataRelatedPrefix = odataRelatedPrefix;
    odata.xmlNewODataElement = xmlNewODataElement;
    odata.xmlNewODataElementInfo = xmlNewODataElementInfo;
    odata.xmlNewODataMetaAttribute = xmlNewODataMetaAttribute;
    odata.xmlNewODataMetaElement = xmlNewODataMetaElement;
    odata.xmlNewODataDataElement = xmlNewODataDataElement;
    odata.xmlReadODataEdmPropertyValue = xmlReadODataEdmPropertyValue;
    odata.xmlReadODataProperty = xmlReadODataProperty;

    // DATAJS INTERNAL END

    // CONTENT END
})(this);