blob: b2d00f6e2a206f516e6881cc95d894a124e82571 [file] [log] [blame]
// 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-xml.js
(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);