You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by bi...@apache.org on 2014/05/09 09:22:16 UTC

[07/24] a) Convert all the DataJS supported functionality from V3 to V4. 1. Remove all the Json verbose logic, make the DataJS accepted and returned javascript object be in Json light format. (Since Json verbose has been completely removed on V4, making

http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/e387fc92/JSLib/tests/code/atomreader.cs
----------------------------------------------------------------------
diff --git a/JSLib/tests/code/atomreader.cs b/JSLib/tests/code/atomreader.cs
index 6391d87..8ef38a6 100644
--- a/JSLib/tests/code/atomreader.cs
+++ b/JSLib/tests/code/atomreader.cs
@@ -1,796 +1,796 @@
-/// <summary>
-/// Class used to parse the Content section of the feed to return the properties data and metadata
-/// </summary>
-
-namespace DataJS.Tests
-{
-    using System;
-    using System.Collections.Generic;
-    using System.IO;
-    using System.Linq;
-    using System.ServiceModel.Syndication;
-    using System.Spatial;
-    using System.Xml;
-    using System.Xml.Linq;
-
-    public static class AtomReader
-    {
-        const string atomXmlNs = "http://www.w3.org/2005/Atom";
-        const string gmlXmlNs = "http://www.opengis.net/gml";
-        const string odataRelatedPrefix = "http://schemas.microsoft.com/ado/2007/08/dataservices/related";
-        const string odataRelatedLinksPrefix = "http://schemas.microsoft.com/ado/2007/08/dataservices/relatedlinks";
-        const string odataXmlNs = "http://schemas.microsoft.com/ado/2007/08/dataservices";
-        const string odataMetaXmlNs = "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata";
-        const string odataEditMediaPrefix = "http://schemas.microsoft.com/ado/2007/08/dataservices/edit-media";
-        const string odataMediaResourcePrefix = "http://schemas.microsoft.com/ado/2007/08/dataservices/mediaresource";
-
-        const string hrefAttribute = "href";
-        const string titleElement = "title";
-        const string workspaceElement = "workspace";
-        const string workspacesProperty = "workspaces";
-        const string collectionElement = "collection";
-        const string collectionsProperty = "collections";
-        const string extensionsProperty = "extensions";
-        static string baseUri = string.Empty;
-
-        /// <summary>
-        /// Creates a service document object
-        /// </summary>
-        /// <param name="container">The XML container</param>
-        /// <param name="uri">Uri to append to the href value</param>
-        /// <returns>The service document JsonObject</returns>
-        public static JsonObject ReadServiceDocument(TextReader payload, string baseUri)
-        {
-            JsonObject jsonObject = new JsonObject();
-            XElement container = XElement.Load(payload);
-
-            if (container != null && container.HasElements)
-            {
-                jsonObject["workspaces"] =
-                    container
-                        .Elements()
-                            .Where(element => element.Name.LocalName.Equals(workspaceElement))
-                            .Select(element => ReadWorkspaceObject(element, baseUri))
-                            .ToArray();
-
-                jsonObject["extensions"] =
-                    container
-                        .Elements()
-                            .Where(element => !element.Name.LocalName.Equals(workspaceElement))
-                            .Select(element => ReadExtensionElement(element))
-                            .ToArray();
-            }
-
-            return jsonObject;
-        }
-
-        public static JsonObject ReadEntry(TextReader payload)
-        {
-            SyndicationItem item = SyndicationItem.Load(XmlReader.Create(payload));
-            return ReadEntry(item);
-        }
-
-        public static JsonObject ReadFeed(TextReader payload)
-        {
-            SyndicationFeed feed = SyndicationFeed.Load(XmlReader.Create(payload));
-            JsonObject feedData = new JsonObject();
-            JsonObject feedMetadata = new JsonObject();
-
-            feedData["results"] = feed.Items.Select(item => ReadEntry(item)).ToArray();
-            feedData["__metadata"] = feedMetadata;
-
-            feedMetadata["feed_extensions"] = feed.AttributeExtensions.Select(pair => ReadExtension(pair)).ToArray();
-
-            if (feed.Id != null)
-            {
-                feedMetadata["uri"] = feed.Id;
-                feedMetadata["uri_extensions"] = new JsonObject[] { };
-            }
-
-            if (feed.Title != null)
-            {
-                feedMetadata["title"] = feed.Title.Text;
-                feedMetadata["title_extensions"] = GetTitleExtensions(feed.Title);
-            }
-
-            SyndicationLink feedSelfLink = GetLink("self", feed.Links);
-            if (feedSelfLink != null)
-            {
-                feedMetadata["self"] = feedSelfLink.GetAbsoluteUri().AbsoluteUri;
-                feedMetadata["self_extensions"] = GetLinkExtensions(feedSelfLink);
-            }
-
-            long? count = GetInlineCount(feed);
-            if (count.HasValue)
-            {
-                feedData["__count"] = count.Value;
-            }
-
-            SyndicationLink feedNextLink = GetLink("next", feed.Links);
-            if (feedNextLink != null)
-            {
-                feedData["__next"] = feedNextLink.GetAbsoluteUri().AbsoluteUri;
-                feedMetadata["next_extensions"] = GetLinkExtensions(feedNextLink);
-            }
-
-            return feedData;
-        }
-
-        private static JsonObject ReadEntry(SyndicationItem item)
-        {
-            SyndicationLink entryEditLink = GetLink("edit", item.Links);
-            SyndicationCategory entryCategory = item.Categories.FirstOrDefault();
-
-            XElement propertiesElement = GetPropertiesElement(item);
-            JsonObject entryData = ReadObject(propertiesElement);
-            entryData = JsonObject.Merge(entryData, ReadNavigationProperties(item));
-            entryData = JsonObject.Merge(entryData, ReadNamedStreams(item));
-
-            JsonObject propertiesMetadata = ReadPropertiesMetadata(propertiesElement);
-            propertiesMetadata = JsonObject.Merge(propertiesMetadata, ReadNavigationPropertiesMetadata(item));
-            propertiesMetadata = JsonObject.Merge(propertiesMetadata, ReadNamedStreamMetadata(item));
-
-            JsonObject entryMetadata = new JsonObject();
-            entryData["__metadata"] = entryMetadata;
-            entryMetadata["properties"] = propertiesMetadata;
-
-            if (item.Id != null)
-            {
-                entryMetadata["uri"] = item.Id;
-                entryMetadata["uri_extensions"] = new JsonObject[] { };
-            }
-
-            if (entryCategory != null)
-            {
-                entryMetadata["type"] = entryCategory.Name;
-                entryMetadata["type_extensions"] = new JsonObject[] { };
-            }
-
-            if (entryEditLink != null)
-            {
-                entryMetadata["edit"] = entryEditLink.GetAbsoluteUri().AbsoluteUri;
-                entryMetadata["edit_link_extensions"] = GetLinkExtensions(entryEditLink);
-            }
-
-            return entryData;
-        }
-
-        private static JsonObject ReadExtension(KeyValuePair<XmlQualifiedName, string> pair)
-        {
-            return ReaderUtils.CreateExtension(pair.Key.Name, pair.Key.Namespace, pair.Value);
-        }
-
-        private static string GetCollectionType(string type)
-        {
-            if (type != null && type.StartsWith("Collection("))
-            {
-                int start = 11;
-                int end = type.IndexOf(")") - 11;
-                return type.Substring(start, end);
-            }
-            return null;
-        }
-
-        /// <summary>
-        /// Find the m:properties element within a feed entry
-        /// </summary>
-        /// <param name="item">The feed entry</param>
-        /// <returns>The m:properties element</returns>
-        private static XElement GetPropertiesElement(SyndicationItem item)
-        {
-            // Check if the m:properties element is within the content element
-            XmlSyndicationContent xmlContent = item.Content as XmlSyndicationContent;
-            if (xmlContent != null)
-            {
-                XElement contentElement = XElement.Load(xmlContent.GetReaderAtContent());
-                return contentElement.Elements().FirstOrDefault(e => e.Name == XName.Get("properties", odataMetaXmlNs));
-            }
-            // If we're here, then we are dealing with a feed that has an MLE
-            // i.e. the m:properties element is a peer of the content element, and shows up
-            // in the elementExtensions instead
-            SyndicationElementExtension propertiesElementExtension = item.ElementExtensions.FirstOrDefault(e => e.OuterName.Equals("properties"));
-            if (propertiesElementExtension != null)
-            {
-                XNode propertiesElement = XNode.ReadFrom(propertiesElementExtension.GetReader());
-                return (XElement)propertiesElement;
-            }
-
-            throw new NotSupportedException("Unsupported feed entry format");
-        }
-
-        /// <summary>
-        /// Gets the inline count within a feed
-        /// </summary>
-        /// <param name="feed">The feed</param>
-        /// <returns>The inline count, or null if none exists</returns>
-        private static long? GetInlineCount(SyndicationFeed feed)
-        {
-            SyndicationElementExtension countElementExtension = feed.ElementExtensions.SingleOrDefault(extension =>
-                extension.OuterName.Equals("count", StringComparison.OrdinalIgnoreCase) &&
-                extension.OuterNamespace.Equals(odataMetaXmlNs));
-
-            if (countElementExtension != null)
-            {
-                XElement countElement = (XElement)XNode.ReadFrom(countElementExtension.GetReader());
-                return XmlConvert.ToInt64(countElement.Value);
-            }
-            else
-            {
-                return null;
-            }
-        }
-
-        /// <summary>
-        /// Gets the link with the specified relationship type
-        /// </summary>
-        /// <param name="rel">Relationship type</param>
-        /// <param name="links">The set of links to search from</param>
-        /// <returns>The link with the specified relationship type, or null if none exists</returns>
-        private static SyndicationLink GetLink(string rel, IEnumerable<SyndicationLink> links)
-        {
-            return links.SingleOrDefault(link => link.RelationshipType.Equals(rel, StringComparison.InvariantCultureIgnoreCase));
-        }
-
-        private static IEnumerable<SyndicationLink> GetLinks(string rel, IEnumerable<SyndicationLink> links)
-        {
-            return links.Where(link => link.RelationshipType.StartsWith(rel, StringComparison.Ordinal));
-        }
-
-        //TODO refactor the extraction of extensions into extension elements and extension attribute methods.
-        private static JsonObject[] GetLinkExtensions(SyndicationLink link)
-        {
-            List<JsonObject> extensions = new List<JsonObject>();
-            //TODO: fix the inclusion of title as extension.  Title attribute is not required in the link element and its
-            //inclusion as an extension should be tested for the precesence of the attribute in the xml element.  Unfortunately,
-            //SyndicationLink doesn't allow for accessing the underlying XML document.. perhaps using an AtomFormatter10?? 
-            extensions.Add(ReaderUtils.CreateExtension("title", null, link.Title));
-            extensions.AddRange(link.AttributeExtensions.Select(pair => ReadExtension(pair)));
-
-            return extensions.ToArray();
-        }
-
-        private static JsonObject[] GetTitleExtensions(TextSyndicationContent title)
-        {
-            List<JsonObject> extensions = new List<JsonObject>();
-            extensions.Add(ReaderUtils.CreateExtension("type", null, title.Type));
-            extensions.AddRange(title.AttributeExtensions.Select(pair => ReadExtension(pair)));
-
-            return extensions.ToArray();
-        }
-
-        /// <summary>
-        /// Gets the "type" value from a property element
-        /// </summary>
-        /// <param name="propertyElement">The property element</param>
-        /// <returns>The "type" value, or default (Edm.String) if none specified</returns>
-        private static string GetTypeAttribute(XElement propertyElement)
-        {
-            XAttribute typeAttribute = propertyElement.Attribute(XName.Get("type", odataMetaXmlNs));
-            if (typeAttribute == null)
-            {
-                if (propertyElement.HasElements)
-                {
-                    return null;
-                }
-                return "Edm.String";
-            }
-            return typeAttribute.Value;
-        }
-
-        private static bool HasTypeAttribute(XElement propertyElement)
-        {
-            return propertyElement.Attribute(XName.Get("type", odataMetaXmlNs)) != null;
-        }
-
-        private static bool IsCollectionProperty(XElement propertyElement)
-        {
-            string type = GetTypeAttribute(propertyElement);
-            if (type != null && type.StartsWith("Collection("))
-            {
-                return true;
-
-            }
-            return propertyElement.Elements().Count(pe => pe.Name == XName.Get("element", odataXmlNs)) > 1;
-        }
-
-        private static JsonObject ReadWorkspaceObject(XElement container, string baseUri)
-        {
-            JsonObject jsonObject = new JsonObject();
-
-            jsonObject["collections"] =
-                container
-                    .Elements()
-                        .Where(element => element.Name.LocalName.Equals("collection"))
-                        .Select(element => ReadWorkspaceCollections(element, baseUri))
-                        .ToArray();
-
-            jsonObject["extensions"] =
-                container
-                    .Elements()
-                        .Where(element =>
-                            !(element.Name.LocalName.Equals("collection") ||
-                              element.Name.LocalName.Equals("title")))
-                        .Select(element => ReadExtensionElement(element))
-                        .ToArray();
-
-            jsonObject["title"] =
-                container
-                    .Elements()
-                    .Where(element => element.Name.LocalName.Equals("title"))
-                    .First()
-                    .Value;
-
-            return jsonObject;
-        }
-
-        private static JsonObject ReadWorkspaceCollections(XElement container, string baseUri)
-        {
-            JsonObject jsonObject = new JsonObject();
-            string title = string.Empty;
-
-            jsonObject["extensions"] =
-                container
-                    .Elements()
-                        .Where(element =>
-                            !(element.Name.LocalName.Equals(collectionElement) ||
-                              element.Name.LocalName.Equals(titleElement)))
-                        .Select(element => ReadExtensionElement(element))
-                        .ToArray();
-
-            jsonObject["title"] =
-                container
-                    .Elements()
-                        .Where(element => element.Name.LocalName.Equals("title"))
-                        .First()
-                        .Value;
-
-            IEnumerable<XAttribute> hrefAttributes =
-                container
-                    .Attributes()
-                        .Where(element => element.Name.LocalName.Equals("href"));
-
-            jsonObject["href"] = baseUri + hrefAttributes.First().Value;
-
-            return jsonObject;
-        }
-
-        private static JsonObject ReadExtensionElement(XElement element)
-        {
-            JsonObject jsonObject = ReaderUtils.CreateExtension(element.Name.LocalName, element.BaseUri, null);
-            jsonObject.Remove("value");
-            jsonObject["attributes"] = ReadExtensionAttributes(element);
-            jsonObject["children"] = element.Elements().Select(child => ReadExtensionElement(element)).ToArray();
-
-            return jsonObject;
-        }
-
-        private static JsonObject ReadExtensionAttribute(XAttribute attribute)
-        {
-            return ReaderUtils.CreateExtension(attribute.Name.LocalName, attribute.BaseUri, attribute.Value);
-        }
-
-        private static JsonObject[] ReadExtensionAttributes(XElement container)
-        {
-            List<JsonObject> attributes = new List<JsonObject>();
-            foreach (XAttribute attribute in container.Attributes())
-            {
-                attributes.Add(ReadExtensionAttribute(attribute));
-            }
-            return attributes.ToArray();
-        }
-
-        private static JsonObject ReadNamedStreamMetadata(SyndicationItem item)
-        {
-            JsonObject propertiesMetadata = new JsonObject();
-            JsonObject streamMetadata;
-            string propertyName;
-
-            foreach (SyndicationLink link in GetLinks(odataEditMediaPrefix, item.Links))
-            {
-                streamMetadata = new JsonObject();
-                streamMetadata["edit_media_extensions"] = GetLinkExtensions(link);
-                streamMetadata["media_src_extensions"] = new JsonObject[0];
-
-                propertyName = link.RelationshipType.Substring(odataEditMediaPrefix.Length + 1);
-                propertiesMetadata[propertyName] = streamMetadata;
-            }
-
-            foreach (SyndicationLink link in GetLinks(odataMediaResourcePrefix, item.Links))
-            {
-                streamMetadata = new JsonObject();
-                streamMetadata["media_src_extensions"] = GetLinkExtensions(link);
-
-                propertyName = link.RelationshipType.Substring(odataMediaResourcePrefix.Length + 1);
-                if (propertiesMetadata.ContainsKey(propertyName))
-                {
-                    streamMetadata = JsonObject.Merge((JsonObject)propertiesMetadata[propertyName], streamMetadata);
-                }
-                propertiesMetadata[propertyName] = streamMetadata;
-            }
-            return propertiesMetadata;
-        }
-
-        private static JsonObject ReadNamedStreams(SyndicationItem item)
-        {
-            // Not very elegant, but quick and easy, do it in two passes.
-            JsonObject streams = new JsonObject();
-            JsonObject streamValue;
-            JsonObject mediaResource;
-            string propertyName;
-
-            foreach (SyndicationLink link in GetLinks(odataEditMediaPrefix, item.Links))
-            {
-                propertyName = link.RelationshipType.Substring(odataEditMediaPrefix.Length + 1);
-                streamValue = new JsonObject();
-                mediaResource = new JsonObject();
-
-                streams[propertyName] = streamValue;
-
-                streamValue["__mediaresource"] = mediaResource;
-
-                mediaResource["edit_media"] = link.GetAbsoluteUri().AbsoluteUri;
-                mediaResource["content_type"] = link.MediaType;
-                mediaResource["media_src"] = link.GetAbsoluteUri().AbsoluteUri;
-
-                var etagAttributeName = new XmlQualifiedName("etag", odataMetaXmlNs);
-                if (link.AttributeExtensions.ContainsKey(etagAttributeName))
-                {
-                    mediaResource["media_etag"] = link.AttributeExtensions[etagAttributeName];
-                    link.AttributeExtensions.Remove(etagAttributeName);
-                }
-            }
-
-            foreach (SyndicationLink link in GetLinks(odataMediaResourcePrefix, item.Links))
-            {
-                propertyName = link.RelationshipType.Substring(odataMediaResourcePrefix.Length + 1);
-                mediaResource = new JsonObject();
-                mediaResource["content_type"] = link.MediaType;
-                mediaResource["media_src"] = link.GetAbsoluteUri().AbsoluteUri;
-
-                if (streams.ContainsKey(propertyName))
-                {
-                    streamValue = streams[propertyName] as JsonObject;
-                    mediaResource = JsonObject.Merge(streamValue["__mediaresource"] as JsonObject, mediaResource);
-                }
-                else
-                {
-                    streamValue = new JsonObject();
-                }
-                streamValue["__mediaresource"] = mediaResource;
-                streams[propertyName] = streamValue;
-            }
-            return streams;
-        }
-
-        private static JsonObject ReadNavigationProperties(SyndicationItem item)
-        {
-            JsonObject navProperties = new JsonObject();
-            SyndicationElementExtension inline;
-
-            string propertyName;
-            JsonObject propertyValue = null;
-
-            foreach (SyndicationLink link in GetLinks(odataRelatedPrefix, item.Links))
-            {
-                propertyName = link.RelationshipType.Substring(odataRelatedPrefix.Length + 1);
-                inline = link.ElementExtensions.SingleOrDefault(e =>
-                    odataMetaXmlNs.Equals(e.OuterNamespace, StringComparison.Ordinal) &&
-                    e.OuterName.Equals("inline", StringComparison.Ordinal));
-
-                if (inline != null)
-                {
-                    XElement inlineElement = (XElement)XNode.ReadFrom(inline.GetReader());
-                    XElement innerElement = inlineElement.Elements().FirstOrDefault();
-
-                    if (innerElement != null)
-                    {
-                        // By default the inner feed/entry does not have the xml:base attribute, so we need to
-                        // add it so that the parsed SyndicationFeed or SyndicationItem retains the baseUri
-                        if (link.BaseUri != null)
-                        {
-                            innerElement.SetAttributeValue(XNamespace.Xml + "base", link.BaseUri.OriginalString);
-                        }
-
-                        // We are converting to a string before creating the reader to strip out extra indenting,
-                        // otherwise the reader creates extra XmlText nodes that SyndicationFeed/SyndicationItem cannot handle
-                        try
-                        {
-                            propertyValue = ReadFeed(new StringReader(innerElement.ToString()));
-                        }
-                        catch (XmlException)
-                        {
-                            // Try with entry instead .. 
-
-                            propertyValue = ReadEntry(new StringReader(innerElement.ToString()));
-                        }
-                    }
-                }
-                else
-                {
-                    JsonObject deferred = new JsonObject();
-                    deferred["uri"] = link.GetAbsoluteUri().AbsoluteUri;
-
-                    propertyValue = new JsonObject();
-                    propertyValue["__deferred"] = deferred;
-                }
-                navProperties[propertyName] = propertyValue;
-            }
-            return navProperties;
-        }
-
-        private static JsonObject ReadNavigationPropertiesMetadata(SyndicationItem item)
-        {
-            JsonObject propertiesMetadata = new JsonObject();
-            JsonObject navMetadata;
-            string propertyName;
-
-            foreach (SyndicationLink link in GetLinks(odataRelatedPrefix, item.Links))
-            {
-                navMetadata = new JsonObject();
-                navMetadata["extensions"] = GetLinkExtensions(link).Where(e =>
-                    !(string.Equals(e["name"] as string, "inline", StringComparison.Ordinal) &&
-                        string.Equals(e["namespaceURI"] as string, odataMetaXmlNs, StringComparison.Ordinal))
-                ).ToArray();
-
-                propertyName = link.RelationshipType.Substring(odataRelatedPrefix.Length + 1);
-                propertiesMetadata[propertyName] = navMetadata;
-            }
-
-            foreach (SyndicationLink link in GetLinks(odataRelatedLinksPrefix, item.Links))
-            {
-                navMetadata = new JsonObject();
-                navMetadata["associationuri"] = link.GetAbsoluteUri().AbsoluteUri;
-                navMetadata["associationuri_extensions"] = link.GetAbsoluteUri().AbsoluteUri;
-
-                propertyName = link.RelationshipType.Substring(odataRelatedLinksPrefix.Length + 1);
-                if (propertiesMetadata.ContainsKey(propertyName))
-                {
-                    navMetadata = JsonObject.Merge(propertiesMetadata[propertyName] as JsonObject, navMetadata);
-                }
-                propertiesMetadata[propertyName] = navMetadata;
-            }
-
-            return propertiesMetadata;
-        }
-
-        private static JsonObject ReadPropertiesMetadata(XElement container)
-        {
-            JsonObject json = null;
-            if (container != null && container.Elements().Any(e => e.Name.NamespaceName == odataXmlNs))
-            {
-                json = new JsonObject();
-                foreach (XElement propertyElement in container.Elements())
-                {
-                    json[propertyElement.Name.LocalName] = ReadPropertyMetadata(propertyElement);
-                }
-            }
-            return json;
-        }
-
-        private static JsonObject ReadPropertyMetadata(XElement property)
-        {
-            var metadata = ReaderUtils.CreateEntryPropertyMetadata(GetTypeAttribute(property));
-
-            if (IsCollectionProperty(property))
-            {
-                string collectionType = GetCollectionType(GetTypeAttribute(property));
-                if (collectionType == null)
-                {
-                    metadata["type"] = "Collection()";
-                }
-
-                List<JsonObject> elements = new List<JsonObject>();
-                foreach (XElement item in property.Elements(XName.Get("element", odataXmlNs)))
-                {
-                    string itemType =
-                        HasTypeAttribute(item) ? GetTypeAttribute(item) :
-                        IsCollectionProperty(item) ? "Collection()" : collectionType;
-
-                    var itemMetadata = ReaderUtils.CreateEntryPropertyMetadata(itemType);
-                    if (item.Elements().Any(e => e.Name.NamespaceName == odataXmlNs))
-                    {
-                        itemMetadata["properties"] = ReadPropertiesMetadata(item);
-                    }
-                    elements.Add(itemMetadata);
-                }
-                metadata["elements"] = elements.ToArray();
-            }
-            else if (property != null && property.Elements().Any(e => e.Name.NamespaceName == odataXmlNs))
-            {
-                metadata["properties"] = ReadPropertiesMetadata(property);
-            }
-
-            return metadata;
-        }
-
-        /// <summary>
-        /// Creates a JsonObject from an XML container element (e.g. the m:properties element) of an OData ATOM feed entry. 
-        /// </summary>
-        /// <param name="container">The XML container</param>
-        /// <param name="buildValue">Function that builds a value from a property element</param>
-        /// <returns>The JsonObject containing the name-value pairs</returns>
-        private static JsonObject ReadObject(XElement container)
-        {
-            if (container == null)
-            {
-                return null;
-            }
-
-            var json = new JsonObject();
-            foreach (XElement propertyElement in container.Elements())
-            {
-                json[propertyElement.Name.LocalName] = ReadDataItem(propertyElement);
-            }
-            return json;
-        }
-
-        private static JsonObject ReadCollectionProperty(XElement property, string typeName)
-        {
-            var collectionType = GetCollectionType(typeName);
-
-            var json = new JsonObject();
-            var results = new List<object>();
-
-            foreach (XElement item in property.Elements())
-            {
-                object resultItem = ReadDataItem(item);
-                results.Add(resultItem);
-
-                JsonObject complexValue = resultItem as JsonObject;
-                if (complexValue != null)
-                {
-                    var metadata = complexValue["__metadata"] as JsonObject;
-                    if (!string.IsNullOrEmpty(collectionType) && metadata["type"] == null)
-                    {
-                        metadata["type"] = collectionType;
-                    }
-                }
-            }
-
-            json["results"] = results;
-            json["__metadata"] = ReaderUtils.CreateEntryPropertyMetadata(typeName, false);
-
-            return json;
-        }
-
-        private static JsonObject ReadComplexProperty(XElement container, string typeName)
-        {
-            JsonObject json = ReadObject(container);
-            json["__metadata"] = ReaderUtils.CreateEntryPropertyMetadata(GetTypeAttribute(container), false);
-            return json;
-        }
-
-        private static JsonObject ReadJsonSpatialProperty(XElement container, XElement gmlValue, bool isGeography)
-        {
-            GmlFormatter gmlFormatter = GmlFormatter.Create();
-            GeoJsonObjectFormatter jsonformatter = GeoJsonObjectFormatter.Create();
-
-            bool ignoreCrc = !gmlValue.Attributes().Any(a => a.Name.LocalName == "srsName");
-
-            ISpatial spatialValue;
-            if (isGeography)
-            {
-                spatialValue = gmlFormatter.Read<Geography>(gmlValue.CreateReader());
-            }
-            else
-            {
-                spatialValue = gmlFormatter.Read<Geometry>(gmlValue.CreateReader());
-            }
-
-            IDictionary<string, object> geoJsonData = jsonformatter.Write(spatialValue);
-            JsonObject json = new JsonObject();
-
-            Queue<object> geoJsonScopes = new Queue<object>();
-            Queue<object> jsonScopes = new Queue<object>();
-
-            geoJsonScopes.Enqueue(geoJsonData);
-            jsonScopes.Enqueue(json);
-
-            Func<object, object> convertScope = (scope) =>
-            {
-                object newScope =
-                        scope is List<object> || scope is object[] ? (object)new List<Object>() :
-                        scope is IDictionary<string, object> ? (object)new JsonObject() :
-                        null;
-
-                if (newScope != null)
-                {
-                    geoJsonScopes.Enqueue(scope);
-                    jsonScopes.Enqueue(newScope);
-                }
-
-                return newScope ?? scope;
-            };
-
-            while (jsonScopes.Count > 0)
-            {
-                if (jsonScopes.Peek() is JsonObject)
-                {
-                    var currentGeoJson = (IDictionary<string, object>)geoJsonScopes.Dequeue();
-                    var currentJson = (JsonObject)jsonScopes.Dequeue();
-
-                    foreach (var item in currentGeoJson)
-                    {
-                        if (!ignoreCrc || item.Key != "crs")
-                        {
-                            currentJson[item.Key] = convertScope(item.Value);
-                        }
-                    }
-                }
-                else
-                {
-                    var currentGeoJson = (IEnumerable<object>)geoJsonScopes.Dequeue();
-                    var currentJson = (List<object>)jsonScopes.Dequeue();
-
-                    foreach (var item in currentGeoJson)
-                    {
-                        currentJson.Add(convertScope(item));
-                    }
-                }
-            }
-            json["__metadata"] = ReaderUtils.CreateEntryPropertyMetadata(GetTypeAttribute(container), false);
-            return json;
-        }
-
-        public static object ReadDataItem(XElement item)
-        {
-            string typeName = GetTypeAttribute(item);
-            XElement gmlRoot = item.Elements().SingleOrDefault(e => e.Name.NamespaceName == gmlXmlNs);
-
-            if (gmlRoot != null)
-            {
-                bool isGeography = typeName.StartsWith("Edm.Geography");
-                return ReadJsonSpatialProperty(item, gmlRoot, isGeography);
-            }
-
-            bool isCollection = IsCollectionProperty(item);
-            if (item.HasElements || isCollection)
-            {
-                // Complex type, Collection Type: parse recursively
-                return isCollection ? ReadCollectionProperty(item, typeName) : ReadComplexProperty(item, typeName);
-            }
-
-            // Primitive type: null value
-            XNamespace mNamespace = item.GetNamespaceOfPrefix("m");
-            XAttribute nullAttribute = mNamespace == null ? null : item.Attribute(mNamespace.GetName("null"));
-            if (nullAttribute != null && nullAttribute.Value.Equals("true", StringComparison.InvariantCultureIgnoreCase))
-            {
-                return null;
-            }
-
-            // Primitive type: check type and parse value accordingly
-            string value = item.Value;
-            switch (typeName)
-            {
-                case "Edm.Byte":
-                    return XmlConvert.ToByte(value);
-                case "Edm.Int16":
-                    return XmlConvert.ToInt16(value);
-                case "Edm.Int32":
-                    return XmlConvert.ToInt32(value);
-                case "Edm.SByte":
-                    return XmlConvert.ToSByte(value);
-                case "Edm.Boolean":
-                    return XmlConvert.ToBoolean(value);
-                case "Edm.Double":
-                    return XmlConvert.ToDouble(value);
-                case "Edm.Single":
-                    return XmlConvert.ToSingle(value);
-                case "Edm.Guid":
-                    return XmlConvert.ToGuid(value);
-                case "Edm.DateTime":
-                    return new JsDate(XmlConvert.ToDateTime(value, XmlDateTimeSerializationMode.Utc));
-                case "Edm.DateTimeOffset":
-                    return new JsDate(XmlConvert.ToDateTimeOffset(value));
-                case "Edm.Time":
-                    throw new NotSupportedException(typeName + " is not supported");
-                // Decimal and Int64 values are sent as strings over the wire.  This is the same behavior as WCF Data Services JSON serializer.
-                case "Edm.Decimal":
-                case "Edm.Int64":
-                case "":
-                default:
-                    return value;
-            }
-        }
-    }
+/// <summary>
+/// Class used to parse the Content section of the feed to return the properties data and metadata
+/// </summary>
+
+namespace DataJS.Tests
+{
+    using System;
+    using System.Collections.Generic;
+    using System.IO;
+    using System.Linq;
+    using System.ServiceModel.Syndication;
+    using Microsoft.Spatial;
+    using System.Xml;
+    using System.Xml.Linq;
+
+    public static class AtomReader
+    {
+        const string atomXmlNs = "http://www.w3.org/2005/Atom";
+        const string gmlXmlNs = "http://www.opengis.net/gml";
+        const string odataRelatedPrefix = "http://schemas.microsoft.com/ado/2007/08/dataservices/related";
+        const string odataRelatedLinksPrefix = "http://schemas.microsoft.com/ado/2007/08/dataservices/relatedlinks";
+        const string odataXmlNs = "http://schemas.microsoft.com/ado/2007/08/dataservices";
+        const string odataMetaXmlNs = "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata";
+        const string odataEditMediaPrefix = "http://schemas.microsoft.com/ado/2007/08/dataservices/edit-media";
+        const string odataMediaResourcePrefix = "http://schemas.microsoft.com/ado/2007/08/dataservices/mediaresource";
+
+        const string hrefAttribute = "href";
+        const string titleElement = "title";
+        const string workspaceElement = "workspace";
+        const string workspacesProperty = "workspaces";
+        const string collectionElement = "collection";
+        const string collectionsProperty = "collections";
+        const string extensionsProperty = "extensions";
+        static string baseUri = string.Empty;
+
+        /// <summary>
+        /// Creates a service document object
+        /// </summary>
+        /// <param name="container">The XML container</param>
+        /// <param name="uri">Uri to append to the href value</param>
+        /// <returns>The service document JsonObject</returns>
+        public static JsonObject ReadServiceDocument(TextReader payload, string baseUri)
+        {
+            JsonObject jsonObject = new JsonObject();
+            XElement container = XElement.Load(payload);
+
+            if (container != null && container.HasElements)
+            {
+                jsonObject["workspaces"] =
+                    container
+                        .Elements()
+                            .Where(element => element.Name.LocalName.Equals(workspaceElement))
+                            .Select(element => ReadWorkspaceObject(element, baseUri))
+                            .ToArray();
+
+                jsonObject["extensions"] =
+                    container
+                        .Elements()
+                            .Where(element => !element.Name.LocalName.Equals(workspaceElement))
+                            .Select(element => ReadExtensionElement(element))
+                            .ToArray();
+            }
+
+            return jsonObject;
+        }
+
+        public static JsonObject ReadEntry(TextReader payload)
+        {
+            SyndicationItem item = SyndicationItem.Load(XmlReader.Create(payload));
+            return ReadEntry(item);
+        }
+
+        public static JsonObject ReadFeed(TextReader payload)
+        {
+            SyndicationFeed feed = SyndicationFeed.Load(XmlReader.Create(payload));
+            JsonObject feedData = new JsonObject();
+            JsonObject feedMetadata = new JsonObject();
+
+            feedData["results"] = feed.Items.Select(item => ReadEntry(item)).ToArray();
+            feedData["__metadata"] = feedMetadata;
+
+            feedMetadata["feed_extensions"] = feed.AttributeExtensions.Select(pair => ReadExtension(pair)).ToArray();
+
+            if (feed.Id != null)
+            {
+                feedMetadata["uri"] = feed.Id;
+                feedMetadata["uri_extensions"] = new JsonObject[] { };
+            }
+
+            if (feed.Title != null)
+            {
+                feedMetadata["title"] = feed.Title.Text;
+                feedMetadata["title_extensions"] = GetTitleExtensions(feed.Title);
+            }
+
+            SyndicationLink feedSelfLink = GetLink("self", feed.Links);
+            if (feedSelfLink != null)
+            {
+                feedMetadata["self"] = feedSelfLink.GetAbsoluteUri().AbsoluteUri;
+                feedMetadata["self_extensions"] = GetLinkExtensions(feedSelfLink);
+            }
+
+            long? count = GetInlineCount(feed);
+            if (count.HasValue)
+            {
+                feedData["__count"] = count.Value;
+            }
+
+            SyndicationLink feedNextLink = GetLink("next", feed.Links);
+            if (feedNextLink != null)
+            {
+                feedData["__next"] = feedNextLink.GetAbsoluteUri().AbsoluteUri;
+                feedMetadata["next_extensions"] = GetLinkExtensions(feedNextLink);
+            }
+
+            return feedData;
+        }
+
+        private static JsonObject ReadEntry(SyndicationItem item)
+        {
+            SyndicationLink entryEditLink = GetLink("edit", item.Links);
+            SyndicationCategory entryCategory = item.Categories.FirstOrDefault();
+
+            XElement propertiesElement = GetPropertiesElement(item);
+            JsonObject entryData = ReadObject(propertiesElement);
+            entryData = JsonObject.Merge(entryData, ReadNavigationProperties(item));
+            entryData = JsonObject.Merge(entryData, ReadNamedStreams(item));
+
+            JsonObject propertiesMetadata = ReadPropertiesMetadata(propertiesElement);
+            propertiesMetadata = JsonObject.Merge(propertiesMetadata, ReadNavigationPropertiesMetadata(item));
+            propertiesMetadata = JsonObject.Merge(propertiesMetadata, ReadNamedStreamMetadata(item));
+
+            JsonObject entryMetadata = new JsonObject();
+            entryData["__metadata"] = entryMetadata;
+            entryMetadata["properties"] = propertiesMetadata;
+
+            if (item.Id != null)
+            {
+                entryMetadata["uri"] = item.Id;
+                entryMetadata["uri_extensions"] = new JsonObject[] { };
+            }
+
+            if (entryCategory != null)
+            {
+                entryMetadata["type"] = entryCategory.Name;
+                entryMetadata["type_extensions"] = new JsonObject[] { };
+            }
+
+            if (entryEditLink != null)
+            {
+                entryMetadata["edit"] = entryEditLink.GetAbsoluteUri().AbsoluteUri;
+                entryMetadata["edit_link_extensions"] = GetLinkExtensions(entryEditLink);
+            }
+
+            return entryData;
+        }
+
+        private static JsonObject ReadExtension(KeyValuePair<XmlQualifiedName, string> pair)
+        {
+            return ReaderUtils.CreateExtension(pair.Key.Name, pair.Key.Namespace, pair.Value);
+        }
+
+        private static string GetCollectionType(string type)
+        {
+            if (type != null && type.StartsWith("Collection("))
+            {
+                int start = 11;
+                int end = type.IndexOf(")") - 11;
+                return type.Substring(start, end);
+            }
+            return null;
+        }
+
+        /// <summary>
+        /// Find the m:properties element within a feed entry
+        /// </summary>
+        /// <param name="item">The feed entry</param>
+        /// <returns>The m:properties element</returns>
+        private static XElement GetPropertiesElement(SyndicationItem item)
+        {
+            // Check if the m:properties element is within the content element
+            XmlSyndicationContent xmlContent = item.Content as XmlSyndicationContent;
+            if (xmlContent != null)
+            {
+                XElement contentElement = XElement.Load(xmlContent.GetReaderAtContent());
+                return contentElement.Elements().FirstOrDefault(e => e.Name == XName.Get("properties", odataMetaXmlNs));
+            }
+            // If we're here, then we are dealing with a feed that has an MLE
+            // i.e. the m:properties element is a peer of the content element, and shows up
+            // in the elementExtensions instead
+            SyndicationElementExtension propertiesElementExtension = item.ElementExtensions.FirstOrDefault(e => e.OuterName.Equals("properties"));
+            if (propertiesElementExtension != null)
+            {
+                XNode propertiesElement = XNode.ReadFrom(propertiesElementExtension.GetReader());
+                return (XElement)propertiesElement;
+            }
+
+            throw new NotSupportedException("Unsupported feed entry format");
+        }
+
+        /// <summary>
+        /// Gets the inline count within a feed
+        /// </summary>
+        /// <param name="feed">The feed</param>
+        /// <returns>The inline count, or null if none exists</returns>
+        private static long? GetInlineCount(SyndicationFeed feed)
+        {
+            SyndicationElementExtension countElementExtension = feed.ElementExtensions.SingleOrDefault(extension =>
+                extension.OuterName.Equals("count", StringComparison.OrdinalIgnoreCase) &&
+                extension.OuterNamespace.Equals(odataMetaXmlNs));
+
+            if (countElementExtension != null)
+            {
+                XElement countElement = (XElement)XNode.ReadFrom(countElementExtension.GetReader());
+                return XmlConvert.ToInt64(countElement.Value);
+            }
+            else
+            {
+                return null;
+            }
+        }
+
+        /// <summary>
+        /// Gets the link with the specified relationship type
+        /// </summary>
+        /// <param name="rel">Relationship type</param>
+        /// <param name="links">The set of links to search from</param>
+        /// <returns>The link with the specified relationship type, or null if none exists</returns>
+        private static SyndicationLink GetLink(string rel, IEnumerable<SyndicationLink> links)
+        {
+            return links.SingleOrDefault(link => link.RelationshipType.Equals(rel, StringComparison.InvariantCultureIgnoreCase));
+        }
+
+        private static IEnumerable<SyndicationLink> GetLinks(string rel, IEnumerable<SyndicationLink> links)
+        {
+            return links.Where(link => link.RelationshipType.StartsWith(rel, StringComparison.Ordinal));
+        }
+
+        //TODO refactor the extraction of extensions into extension elements and extension attribute methods.
+        private static JsonObject[] GetLinkExtensions(SyndicationLink link)
+        {
+            List<JsonObject> extensions = new List<JsonObject>();
+            //TODO: fix the inclusion of title as extension.  Title attribute is not required in the link element and its
+            //inclusion as an extension should be tested for the precesence of the attribute in the xml element.  Unfortunately,
+            //SyndicationLink doesn't allow for accessing the underlying XML document.. perhaps using an AtomFormatter10?? 
+            extensions.Add(ReaderUtils.CreateExtension("title", null, link.Title));
+            extensions.AddRange(link.AttributeExtensions.Select(pair => ReadExtension(pair)));
+
+            return extensions.ToArray();
+        }
+
+        private static JsonObject[] GetTitleExtensions(TextSyndicationContent title)
+        {
+            List<JsonObject> extensions = new List<JsonObject>();
+            extensions.Add(ReaderUtils.CreateExtension("type", null, title.Type));
+            extensions.AddRange(title.AttributeExtensions.Select(pair => ReadExtension(pair)));
+
+            return extensions.ToArray();
+        }
+
+        /// <summary>
+        /// Gets the "type" value from a property element
+        /// </summary>
+        /// <param name="propertyElement">The property element</param>
+        /// <returns>The "type" value, or default (Edm.String) if none specified</returns>
+        private static string GetTypeAttribute(XElement propertyElement)
+        {
+            XAttribute typeAttribute = propertyElement.Attribute(XName.Get("type", odataMetaXmlNs));
+            if (typeAttribute == null)
+            {
+                if (propertyElement.HasElements)
+                {
+                    return null;
+                }
+                return "Edm.String";
+            }
+            return typeAttribute.Value;
+        }
+
+        private static bool HasTypeAttribute(XElement propertyElement)
+        {
+            return propertyElement.Attribute(XName.Get("type", odataMetaXmlNs)) != null;
+        }
+
+        private static bool IsCollectionProperty(XElement propertyElement)
+        {
+            string type = GetTypeAttribute(propertyElement);
+            if (type != null && type.StartsWith("Collection("))
+            {
+                return true;
+
+            }
+            return propertyElement.Elements().Count(pe => pe.Name == XName.Get("element", odataXmlNs)) > 1;
+        }
+
+        private static JsonObject ReadWorkspaceObject(XElement container, string baseUri)
+        {
+            JsonObject jsonObject = new JsonObject();
+
+            jsonObject["collections"] =
+                container
+                    .Elements()
+                        .Where(element => element.Name.LocalName.Equals("collection"))
+                        .Select(element => ReadWorkspaceCollections(element, baseUri))
+                        .ToArray();
+
+            jsonObject["extensions"] =
+                container
+                    .Elements()
+                        .Where(element =>
+                            !(element.Name.LocalName.Equals("collection") ||
+                              element.Name.LocalName.Equals("title")))
+                        .Select(element => ReadExtensionElement(element))
+                        .ToArray();
+
+            jsonObject["title"] =
+                container
+                    .Elements()
+                    .Where(element => element.Name.LocalName.Equals("title"))
+                    .First()
+                    .Value;
+
+            return jsonObject;
+        }
+
+        private static JsonObject ReadWorkspaceCollections(XElement container, string baseUri)
+        {
+            JsonObject jsonObject = new JsonObject();
+            string title = string.Empty;
+
+            jsonObject["extensions"] =
+                container
+                    .Elements()
+                        .Where(element =>
+                            !(element.Name.LocalName.Equals(collectionElement) ||
+                              element.Name.LocalName.Equals(titleElement)))
+                        .Select(element => ReadExtensionElement(element))
+                        .ToArray();
+
+            jsonObject["title"] =
+                container
+                    .Elements()
+                        .Where(element => element.Name.LocalName.Equals("title"))
+                        .First()
+                        .Value;
+
+            IEnumerable<XAttribute> hrefAttributes =
+                container
+                    .Attributes()
+                        .Where(element => element.Name.LocalName.Equals("href"));
+
+            jsonObject["href"] = baseUri + hrefAttributes.First().Value;
+
+            return jsonObject;
+        }
+
+        private static JsonObject ReadExtensionElement(XElement element)
+        {
+            JsonObject jsonObject = ReaderUtils.CreateExtension(element.Name.LocalName, element.BaseUri, null);
+            jsonObject.Remove("value");
+            jsonObject["attributes"] = ReadExtensionAttributes(element);
+            jsonObject["children"] = element.Elements().Select(child => ReadExtensionElement(element)).ToArray();
+
+            return jsonObject;
+        }
+
+        private static JsonObject ReadExtensionAttribute(XAttribute attribute)
+        {
+            return ReaderUtils.CreateExtension(attribute.Name.LocalName, attribute.BaseUri, attribute.Value);
+        }
+
+        private static JsonObject[] ReadExtensionAttributes(XElement container)
+        {
+            List<JsonObject> attributes = new List<JsonObject>();
+            foreach (XAttribute attribute in container.Attributes())
+            {
+                attributes.Add(ReadExtensionAttribute(attribute));
+            }
+            return attributes.ToArray();
+        }
+
+        private static JsonObject ReadNamedStreamMetadata(SyndicationItem item)
+        {
+            JsonObject propertiesMetadata = new JsonObject();
+            JsonObject streamMetadata;
+            string propertyName;
+
+            foreach (SyndicationLink link in GetLinks(odataEditMediaPrefix, item.Links))
+            {
+                streamMetadata = new JsonObject();
+                streamMetadata["edit_media_extensions"] = GetLinkExtensions(link);
+                streamMetadata["media_src_extensions"] = new JsonObject[0];
+
+                propertyName = link.RelationshipType.Substring(odataEditMediaPrefix.Length + 1);
+                propertiesMetadata[propertyName] = streamMetadata;
+            }
+
+            foreach (SyndicationLink link in GetLinks(odataMediaResourcePrefix, item.Links))
+            {
+                streamMetadata = new JsonObject();
+                streamMetadata["media_src_extensions"] = GetLinkExtensions(link);
+
+                propertyName = link.RelationshipType.Substring(odataMediaResourcePrefix.Length + 1);
+                if (propertiesMetadata.ContainsKey(propertyName))
+                {
+                    streamMetadata = JsonObject.Merge((JsonObject)propertiesMetadata[propertyName], streamMetadata);
+                }
+                propertiesMetadata[propertyName] = streamMetadata;
+            }
+            return propertiesMetadata;
+        }
+
+        private static JsonObject ReadNamedStreams(SyndicationItem item)
+        {
+            // Not very elegant, but quick and easy, do it in two passes.
+            JsonObject streams = new JsonObject();
+            JsonObject streamValue;
+            JsonObject mediaResource;
+            string propertyName;
+
+            foreach (SyndicationLink link in GetLinks(odataEditMediaPrefix, item.Links))
+            {
+                propertyName = link.RelationshipType.Substring(odataEditMediaPrefix.Length + 1);
+                streamValue = new JsonObject();
+                mediaResource = new JsonObject();
+
+                streams[propertyName] = streamValue;
+
+                streamValue["__mediaresource"] = mediaResource;
+
+                mediaResource["edit_media"] = link.GetAbsoluteUri().AbsoluteUri;
+                mediaResource["content_type"] = link.MediaType;
+                mediaResource["media_src"] = link.GetAbsoluteUri().AbsoluteUri;
+
+                var etagAttributeName = new XmlQualifiedName("etag", odataMetaXmlNs);
+                if (link.AttributeExtensions.ContainsKey(etagAttributeName))
+                {
+                    mediaResource["media_etag"] = link.AttributeExtensions[etagAttributeName];
+                    link.AttributeExtensions.Remove(etagAttributeName);
+                }
+            }
+
+            foreach (SyndicationLink link in GetLinks(odataMediaResourcePrefix, item.Links))
+            {
+                propertyName = link.RelationshipType.Substring(odataMediaResourcePrefix.Length + 1);
+                mediaResource = new JsonObject();
+                mediaResource["content_type"] = link.MediaType;
+                mediaResource["media_src"] = link.GetAbsoluteUri().AbsoluteUri;
+
+                if (streams.ContainsKey(propertyName))
+                {
+                    streamValue = streams[propertyName] as JsonObject;
+                    mediaResource = JsonObject.Merge(streamValue["__mediaresource"] as JsonObject, mediaResource);
+                }
+                else
+                {
+                    streamValue = new JsonObject();
+                }
+                streamValue["__mediaresource"] = mediaResource;
+                streams[propertyName] = streamValue;
+            }
+            return streams;
+        }
+
+        private static JsonObject ReadNavigationProperties(SyndicationItem item)
+        {
+            JsonObject navProperties = new JsonObject();
+            SyndicationElementExtension inline;
+
+            string propertyName;
+            JsonObject propertyValue = null;
+
+            foreach (SyndicationLink link in GetLinks(odataRelatedPrefix, item.Links))
+            {
+                propertyName = link.RelationshipType.Substring(odataRelatedPrefix.Length + 1);
+                inline = link.ElementExtensions.SingleOrDefault(e =>
+                    odataMetaXmlNs.Equals(e.OuterNamespace, StringComparison.Ordinal) &&
+                    e.OuterName.Equals("inline", StringComparison.Ordinal));
+
+                if (inline != null)
+                {
+                    XElement inlineElement = (XElement)XNode.ReadFrom(inline.GetReader());
+                    XElement innerElement = inlineElement.Elements().FirstOrDefault();
+
+                    if (innerElement != null)
+                    {
+                        // By default the inner feed/entry does not have the xml:base attribute, so we need to
+                        // add it so that the parsed SyndicationFeed or SyndicationItem retains the baseUri
+                        if (link.BaseUri != null)
+                        {
+                            innerElement.SetAttributeValue(XNamespace.Xml + "base", link.BaseUri.OriginalString);
+                        }
+
+                        // We are converting to a string before creating the reader to strip out extra indenting,
+                        // otherwise the reader creates extra XmlText nodes that SyndicationFeed/SyndicationItem cannot handle
+                        try
+                        {
+                            propertyValue = ReadFeed(new StringReader(innerElement.ToString()));
+                        }
+                        catch (XmlException)
+                        {
+                            // Try with entry instead .. 
+
+                            propertyValue = ReadEntry(new StringReader(innerElement.ToString()));
+                        }
+                    }
+                }
+                else
+                {
+                    JsonObject deferred = new JsonObject();
+                    deferred["uri"] = link.GetAbsoluteUri().AbsoluteUri;
+
+                    propertyValue = new JsonObject();
+                    propertyValue["__deferred"] = deferred;
+                }
+                navProperties[propertyName] = propertyValue;
+            }
+            return navProperties;
+        }
+
+        private static JsonObject ReadNavigationPropertiesMetadata(SyndicationItem item)
+        {
+            JsonObject propertiesMetadata = new JsonObject();
+            JsonObject navMetadata;
+            string propertyName;
+
+            foreach (SyndicationLink link in GetLinks(odataRelatedPrefix, item.Links))
+            {
+                navMetadata = new JsonObject();
+                navMetadata["extensions"] = GetLinkExtensions(link).Where(e =>
+                    !(string.Equals(e["name"] as string, "inline", StringComparison.Ordinal) &&
+                        string.Equals(e["namespaceURI"] as string, odataMetaXmlNs, StringComparison.Ordinal))
+                ).ToArray();
+
+                propertyName = link.RelationshipType.Substring(odataRelatedPrefix.Length + 1);
+                propertiesMetadata[propertyName] = navMetadata;
+            }
+
+            foreach (SyndicationLink link in GetLinks(odataRelatedLinksPrefix, item.Links))
+            {
+                navMetadata = new JsonObject();
+                navMetadata["associationuri"] = link.GetAbsoluteUri().AbsoluteUri;
+                navMetadata["associationuri_extensions"] = link.GetAbsoluteUri().AbsoluteUri;
+
+                propertyName = link.RelationshipType.Substring(odataRelatedLinksPrefix.Length + 1);
+                if (propertiesMetadata.ContainsKey(propertyName))
+                {
+                    navMetadata = JsonObject.Merge(propertiesMetadata[propertyName] as JsonObject, navMetadata);
+                }
+                propertiesMetadata[propertyName] = navMetadata;
+            }
+
+            return propertiesMetadata;
+        }
+
+        private static JsonObject ReadPropertiesMetadata(XElement container)
+        {
+            JsonObject json = null;
+            if (container != null && container.Elements().Any(e => e.Name.NamespaceName == odataXmlNs))
+            {
+                json = new JsonObject();
+                foreach (XElement propertyElement in container.Elements())
+                {
+                    json[propertyElement.Name.LocalName] = ReadPropertyMetadata(propertyElement);
+                }
+            }
+            return json;
+        }
+
+        private static JsonObject ReadPropertyMetadata(XElement property)
+        {
+            var metadata = ReaderUtils.CreateEntryPropertyMetadata(GetTypeAttribute(property));
+
+            if (IsCollectionProperty(property))
+            {
+                string collectionType = GetCollectionType(GetTypeAttribute(property));
+                if (collectionType == null)
+                {
+                    metadata["type"] = "Collection()";
+                }
+
+                List<JsonObject> elements = new List<JsonObject>();
+                foreach (XElement item in property.Elements(XName.Get("element", odataXmlNs)))
+                {
+                    string itemType =
+                        HasTypeAttribute(item) ? GetTypeAttribute(item) :
+                        IsCollectionProperty(item) ? "Collection()" : collectionType;
+
+                    var itemMetadata = ReaderUtils.CreateEntryPropertyMetadata(itemType);
+                    if (item.Elements().Any(e => e.Name.NamespaceName == odataXmlNs))
+                    {
+                        itemMetadata["properties"] = ReadPropertiesMetadata(item);
+                    }
+                    elements.Add(itemMetadata);
+                }
+                metadata["elements"] = elements.ToArray();
+            }
+            else if (property != null && property.Elements().Any(e => e.Name.NamespaceName == odataXmlNs))
+            {
+                metadata["properties"] = ReadPropertiesMetadata(property);
+            }
+
+            return metadata;
+        }
+
+        /// <summary>
+        /// Creates a JsonObject from an XML container element (e.g. the m:properties element) of an OData ATOM feed entry. 
+        /// </summary>
+        /// <param name="container">The XML container</param>
+        /// <param name="buildValue">Function that builds a value from a property element</param>
+        /// <returns>The JsonObject containing the name-value pairs</returns>
+        private static JsonObject ReadObject(XElement container)
+        {
+            if (container == null)
+            {
+                return null;
+            }
+
+            var json = new JsonObject();
+            foreach (XElement propertyElement in container.Elements())
+            {
+                json[propertyElement.Name.LocalName] = ReadDataItem(propertyElement);
+            }
+            return json;
+        }
+
+        private static JsonObject ReadCollectionProperty(XElement property, string typeName)
+        {
+            var collectionType = GetCollectionType(typeName);
+
+            var json = new JsonObject();
+            var results = new List<object>();
+
+            foreach (XElement item in property.Elements())
+            {
+                object resultItem = ReadDataItem(item);
+                results.Add(resultItem);
+
+                JsonObject complexValue = resultItem as JsonObject;
+                if (complexValue != null)
+                {
+                    var metadata = complexValue["__metadata"] as JsonObject;
+                    if (!string.IsNullOrEmpty(collectionType) && metadata["type"] == null)
+                    {
+                        metadata["type"] = collectionType;
+                    }
+                }
+            }
+
+            json["results"] = results;
+            json["__metadata"] = ReaderUtils.CreateEntryPropertyMetadata(typeName, false);
+
+            return json;
+        }
+
+        private static JsonObject ReadComplexProperty(XElement container, string typeName)
+        {
+            JsonObject json = ReadObject(container);
+            json["__metadata"] = ReaderUtils.CreateEntryPropertyMetadata(GetTypeAttribute(container), false);
+            return json;
+        }
+
+        private static JsonObject ReadJsonSpatialProperty(XElement container, XElement gmlValue, bool isGeography)
+        {
+            GmlFormatter gmlFormatter = GmlFormatter.Create();
+            GeoJsonObjectFormatter jsonformatter = GeoJsonObjectFormatter.Create();
+
+            bool ignoreCrc = !gmlValue.Attributes().Any(a => a.Name.LocalName == "srsName");
+
+            ISpatial spatialValue;
+            if (isGeography)
+            {
+                spatialValue = gmlFormatter.Read<Geography>(gmlValue.CreateReader());
+            }
+            else
+            {
+                spatialValue = gmlFormatter.Read<Geometry>(gmlValue.CreateReader());
+            }
+
+            IDictionary<string, object> geoJsonData = jsonformatter.Write(spatialValue);
+            JsonObject json = new JsonObject();
+
+            Queue<object> geoJsonScopes = new Queue<object>();
+            Queue<object> jsonScopes = new Queue<object>();
+
+            geoJsonScopes.Enqueue(geoJsonData);
+            jsonScopes.Enqueue(json);
+
+            Func<object, object> convertScope = (scope) =>
+            {
+                object newScope =
+                        scope is List<object> || scope is object[] ? (object)new List<Object>() :
+                        scope is IDictionary<string, object> ? (object)new JsonObject() :
+                        null;
+
+                if (newScope != null)
+                {
+                    geoJsonScopes.Enqueue(scope);
+                    jsonScopes.Enqueue(newScope);
+                }
+
+                return newScope ?? scope;
+            };
+
+            while (jsonScopes.Count > 0)
+            {
+                if (jsonScopes.Peek() is JsonObject)
+                {
+                    var currentGeoJson = (IDictionary<string, object>)geoJsonScopes.Dequeue();
+                    var currentJson = (JsonObject)jsonScopes.Dequeue();
+
+                    foreach (var item in currentGeoJson)
+                    {
+                        if (!ignoreCrc || item.Key != "crs")
+                        {
+                            currentJson[item.Key] = convertScope(item.Value);
+                        }
+                    }
+                }
+                else
+                {
+                    var currentGeoJson = (IEnumerable<object>)geoJsonScopes.Dequeue();
+                    var currentJson = (List<object>)jsonScopes.Dequeue();
+
+                    foreach (var item in currentGeoJson)
+                    {
+                        currentJson.Add(convertScope(item));
+                    }
+                }
+            }
+            json["__metadata"] = ReaderUtils.CreateEntryPropertyMetadata(GetTypeAttribute(container), false);
+            return json;
+        }
+
+        public static object ReadDataItem(XElement item)
+        {
+            string typeName = GetTypeAttribute(item);
+            XElement gmlRoot = item.Elements().SingleOrDefault(e => e.Name.NamespaceName == gmlXmlNs);
+
+            if (gmlRoot != null)
+            {
+                bool isGeography = typeName.StartsWith("Edm.Geography");
+                return ReadJsonSpatialProperty(item, gmlRoot, isGeography);
+            }
+
+            bool isCollection = IsCollectionProperty(item);
+            if (item.HasElements || isCollection)
+            {
+                // Complex type, Collection Type: parse recursively
+                return isCollection ? ReadCollectionProperty(item, typeName) : ReadComplexProperty(item, typeName);
+            }
+
+            // Primitive type: null value
+            XNamespace mNamespace = item.GetNamespaceOfPrefix("m");
+            XAttribute nullAttribute = mNamespace == null ? null : item.Attribute(mNamespace.GetName("null"));
+            if (nullAttribute != null && nullAttribute.Value.Equals("true", StringComparison.InvariantCultureIgnoreCase))
+            {
+                return null;
+            }
+
+            // Primitive type: check type and parse value accordingly
+            string value = item.Value;
+            switch (typeName)
+            {
+                case "Edm.Byte":
+                    return XmlConvert.ToByte(value);
+                case "Edm.Int16":
+                    return XmlConvert.ToInt16(value);
+                case "Edm.Int32":
+                    return XmlConvert.ToInt32(value);
+                case "Edm.SByte":
+                    return XmlConvert.ToSByte(value);
+                case "Edm.Boolean":
+                    return XmlConvert.ToBoolean(value);
+                case "Edm.Double":
+                    return XmlConvert.ToDouble(value);
+                case "Edm.Single":
+                    return XmlConvert.ToSingle(value);
+                case "Edm.Guid":
+                    return XmlConvert.ToGuid(value);
+                case "Edm.DateTime":
+                    return new JsDate(XmlConvert.ToDateTime(value, XmlDateTimeSerializationMode.Utc));
+                case "Edm.DateTimeOffset":
+                    return new JsDate(XmlConvert.ToDateTimeOffset(value));
+                case "Edm.Time":
+                    throw new NotSupportedException(typeName + " is not supported");
+                // Decimal and Int64 values are sent as strings over the wire.  This is the same behavior as WCF Data Services JSON serializer.
+                case "Edm.Decimal":
+                case "Edm.Int64":
+                case "":
+                default:
+                    return value;
+            }
+        }
+    }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/olingo-odata4-js/blob/e387fc92/JSLib/tests/code/csdlreader.cs
----------------------------------------------------------------------
diff --git a/JSLib/tests/code/csdlreader.cs b/JSLib/tests/code/csdlreader.cs
index 47a331e..e4becbb 100644
--- a/JSLib/tests/code/csdlreader.cs
+++ b/JSLib/tests/code/csdlreader.cs
@@ -1,231 +1,186 @@
-/// <summary>
-/// Class used to parse csdl to create the metatdata object
-/// </summary>
-/// 
-
-namespace DataJS.Tests
-{
-    using System;
-    using System.Collections.Generic;
-    using System.IO;
-    using System.Linq;
-    using System.Xml.Linq;
-
-
-    public static class CsdlReader
-    {
-        static readonly string knownNamespace = "http://schemas.microsoft.com";
-        static readonly string[] repeatingElements = 
-            {
-                "End", 
-                "Property", 
-                "PropertyRef", 
-                "EntitySet", 
-                "AssociationSet", 
-                "FunctionImport", 
-                "NavigationProperty", 
-                "Parameter", 
-                "Using", 
-                "EntityContainer", 
-                "EntityType", 
-                "Association", 
-                "ComplexType", 
-                "Function", 
-                "Schema"
-            };
-
-        public static JsonObject ReadCsdl(TextReader payload)
-        {
-            return BuildElementJsonObject(XElement.Load(payload));
-        }
-
-        /// <summary>
-        /// Builds the extensions element object
-        /// extensions = {
-        /// name: string, // local name of the custom XML element
-        /// namespace: string, // namespace URI of the custom XML element
-        /// value: string, // value of the custom XML element
-        /// attributes: array, // array of attribute extension objects of the custom XML element
-        /// children: array // array of element extension objects of the custom XML element };
-        /// </summary>
-        /// <param name="customElement">The custom element to be made into an extension object</param>
-        /// <returns>the custom element json object</returns>
-        static JsonObject BuildExtensionsElementObject(XElement customElement)
-        {
-            string value;
-            // customElement.Value contains the value of the element's children, but these are already
-            // captured in the children propterty.
-            if (customElement.HasElements)
-            {
-                value = null;
-            }
-            else
-            {
-                if (customElement.Value == "")
-                {
-                    value = null;
-                }
-                else
-                {
-                    value = customElement.Value;
-                }
-            }
-
-            JsonObject jsonObject = BuildBaseExtensionsObject(customElement.Name.LocalName, customElement.Name.Namespace.ToString(), value);
-
-            jsonObject["attributes"] = customElement.Attributes().Select(
-                attribute => BuildBaseExtensionsObject(attribute.Name.LocalName, attribute.Name.Namespace.ToString(), attribute.Value)
-                ).ToArray();
-            jsonObject["children"] = customElement.Elements().Select(element => BuildExtensionsElementObject(element)).ToArray();
-
-            return jsonObject;
-        }
-
-        /// <summary>
-        /// Creates a generic extension object
-        /// extensions = {
-        /// name: string, // local name of the custom XML element or attribute
-        /// namespace: string, // namespace URI of the custom XML element or attribute
-        /// value: string, // value of the custom XML element or attribute }
-        /// </summary>
-        /// <param name="name">name of the object</param>
-        /// <param name="objectNamespace">namespace of the obect</param>
-        /// <param name="value">value of the object</param>
-        /// <returns></returns>
-        static JsonObject BuildBaseExtensionsObject(string name, string objectNamespace, string value)
-        {
-            JsonObject jsonObject = new JsonObject();
-
-            jsonObject["name"] = name;
-            jsonObject["namespace"] = objectNamespace;
-            jsonObject["value"] = value;
-
-            return jsonObject;
-        }
-
-        /// <summary>
-        /// Build the attribute object 
-        /// </summary>
-        /// <param name="xmlAttributes">IEnumberable of XAttributes to build the attribute object</param>
-        /// <returns>The JsonObject containing the name-value pairs for an element's attributes</returns>
-        static JsonObject BuildAttributeJsonObject(IEnumerable<XAttribute> xmlAttributes)
-        {
-            JsonObject jsonObject = new JsonObject();
-            List<JsonObject> extensions = new List<JsonObject>();
-
-            foreach (XAttribute attribute in xmlAttributes)
-            {
-                if (!attribute.IsNamespaceDeclaration)
-                {
-                    string attributeNamespace = attribute.Name.Namespace.ToString();
-                    if (string.IsNullOrEmpty(attributeNamespace) || attributeNamespace.StartsWith(knownNamespace, StringComparison.InvariantCultureIgnoreCase))
-                    {
-                        jsonObject[MakeFirstLetterLowercase(attribute.Name.LocalName)] = attribute.Value;
-                    }
-                    else
-                    {
-                        extensions.Add(BuildBaseExtensionsObject(attribute.Name.LocalName, attribute.Name.Namespace.ToString(), attribute.Value));
-                    }
-                }
-            }
-
-            if (extensions.Count > 0)
-            {
-                jsonObject["extensions"] = extensions.ToArray();
-            }
-
-            return jsonObject;
-        }
-
-        /// <summary>
-        /// Creates a JsonObject from an XML container element with each attribute or subelement as a property
-        /// </summary>
-        /// <param name="container">The XML container</param>
-        /// <param name="buildValue">Function that builds a value from a property element</param>
-        /// <returns>The JsonObject containing the name-value pairs</returns>
-        public static JsonObject BuildElementJsonObject(XElement container)
-        {
-            if (container == null)
-            {
-                return null;
-            }
-
-            JsonObject jsonObject = new JsonObject();
-            List<JsonObject> extensions = new List<JsonObject>();
-
-            if (container.HasAttributes || container.HasElements)
-            {
-                Dictionary<string, List<JsonObject>> repeatingObjectArrays = new Dictionary<string, List<JsonObject>>();
-                JsonObject extensionObject = new JsonObject();
-
-                jsonObject = BuildAttributeJsonObject(container.Attributes());
-
-                foreach (XElement propertyElement in container.Elements())
-                {
-                    string propertyName = MakeFirstLetterLowercase(propertyElement.Name.LocalName);
-                    string properyNamespace = propertyElement.Name.Namespace.ToString();
-
-                    if (string.IsNullOrEmpty(properyNamespace) || properyNamespace.StartsWith(knownNamespace, StringComparison.InvariantCultureIgnoreCase))
-                    {
-                        // Check to see if the element is repeating and needs to be an array
-                        if (repeatingElements.Contains(propertyElement.Name.LocalName))
-                        {
-                            // See if property was already created as an array, if not then create it
-                            if (!repeatingObjectArrays.ContainsKey(propertyName))
-                            {
-                                repeatingObjectArrays.Add(propertyName, new List<JsonObject>());
-                            }
-                            repeatingObjectArrays[propertyName].Add(BuildElementJsonObject(propertyElement));
-                        }
-                        else
-                        {
-                            jsonObject[propertyName] = BuildElementJsonObject(propertyElement);
-                        }
-                    }
-                    else
-                    {
-                        extensions.Add(BuildExtensionsElementObject(propertyElement));
-                    }
-                }
-
-                if (extensions.Count > 0)
-                {
-                    jsonObject["extensions"] = extensions.ToArray();
-                }
-
-                foreach (string key in repeatingObjectArrays.Keys)
-                {
-                    jsonObject[key] = repeatingObjectArrays[key].ToArray();
-                }
-            }
-            else
-            {
-                jsonObject[MakeFirstLetterLowercase(container.Name.LocalName)] = container.Value;
-            }
-
-            return jsonObject;
-        }
-
-        /// <summary>
-        /// Makes the first letter of a string lowercase
-        /// </summary>
-        /// <param name="name">The string to be modified</param>
-        /// <returns>Modified string</returns>
-        private static string MakeFirstLetterLowercase(string str)
-        {
-            if (!string.IsNullOrWhiteSpace(str))
-            {
-                if (str.Length > 1 && !(str[1].ToString() == str[1].ToString().ToUpper()))
-                {
-                    return str[0].ToString().ToLower() + str.Substring(1);
-                }
-                else
-                {
-                    return str;
-                }
-            }
-
-            return str;
-        }
-    }
+/// <summary>
+/// Class used to parse csdl to create the metatdata object
+/// </summary>
+/// 
+
+namespace DataJS.Tests
+{
+    using System;
+    using System.Collections.Generic;
+    using System.IO;
+    using System.Linq;
+    using System.Xml.Linq;
+
+
+    public static class CsdlReader
+    {
+        static readonly string knownNamespace = "http://docs.oasis-open.org";
+        static readonly string[] repeatingElements = 
+            {
+                "Action",
+                "ActionImport",
+                "Annotation",
+                "Annotations",
+                "Apply",
+                "Binary",
+                "Bool",
+                "Cast",
+                "Collection",
+                "ComplexType",
+                "Date",
+                "DateTimeOffset",
+                "Decimal",
+                "Duration",
+                "EntitySet",
+                "EntityType",
+                "EnumMember",
+                "EnumType",
+                "Float",
+                "Function",
+                "FunctionImport",
+                "Guid",
+                "If",
+                "Int",
+                "IsOf",
+                "Key",
+                "LabeledElement",
+                "LabeledElementReference",
+                "Member",
+                "NavigationProperty",
+                "NavigationPropertyBinding",
+                "NavigationPropertyPath",
+                "Null",
+                "OnDelete",
+                "Path",
+                "Parameter",
+                "Property",
+                "PropertyPath",
+                "PropertyRef",
+                "PropertyValue",
+                "Record",
+                "ReferentialConstraint",
+                "String",
+                "Schema",
+                "Singleton",
+                "Term",
+                "TimeOfDay",
+                "TypeDefinition",
+                "UrlRef",
+                "Reference",
+                "Include",
+                "IncludeAnnotations"
+            };
+
+        public static Dictionary<string, object> ReadCsdl(TextReader payload)
+        {
+            return BuildElementJsonObject(XElement.Load(payload));
+        }
+
+        /// <summary>
+        /// Build the attribute object 
+        /// </summary>
+        /// <param name="xmlAttributes">IEnumberable of XAttributes to build the attribute object</param>
+        /// <returns>The JsonObject containing the name-value pairs for an element's attributes</returns>
+        static Dictionary<string, object> BuildAttributeJsonObject(IEnumerable<XAttribute> xmlAttributes)
+        {
+            Dictionary<string, object> jsonObject = new Dictionary<string, object>();
+
+            foreach (XAttribute attribute in xmlAttributes)
+            {
+                if (!attribute.IsNamespaceDeclaration)
+                {
+                    string attributeNamespace = attribute.Name.Namespace.ToString();
+                    if (string.IsNullOrEmpty(attributeNamespace) ||
+                        attributeNamespace.StartsWith(knownNamespace, StringComparison.InvariantCultureIgnoreCase))
+                    {
+                        jsonObject[MakeFirstLetterLowercase(attribute.Name.LocalName)] = attribute.Value;
+                    }
+                }
+            }
+
+            return jsonObject;
+        }
+
+        /// <summary>
+        /// Creates a JsonObject from an XML container element with each attribute or subelement as a property
+        /// </summary>
+        /// <param name="container">The XML container</param>
+        /// <param name="buildValue">Function that builds a value from a property element</param>
+        /// <returns>The JsonObject containing the name-value pairs</returns>
+        public static Dictionary<string, object> BuildElementJsonObject(XElement container)
+        {
+            if (container == null)
+            {
+                return null;
+            }
+
+            Dictionary<string, object> jsonObject = new Dictionary<string, object>();
+            string keyName = MakeFirstLetterLowercase(container.Name.LocalName);
+
+            if (container.HasAttributes || container.HasElements)
+            {
+                Dictionary<string, List<Dictionary<string, object>>> repeatingObjectArrays = new Dictionary<string, List<Dictionary<string, object>>>();
+
+                jsonObject = BuildAttributeJsonObject(container.Attributes());
+
+                foreach (XElement propertyElement in container.Elements())
+                {
+                    string propertyName = MakeFirstLetterLowercase(propertyElement.Name.LocalName);
+                    string properyNamespace = propertyElement.Name.Namespace.ToString();
+
+                    if (string.IsNullOrEmpty(properyNamespace) || properyNamespace.StartsWith(knownNamespace, StringComparison.InvariantCultureIgnoreCase))
+                    {
+                        // Check to see if the element is repeating and needs to be an array
+                        if (repeatingElements.Contains(propertyElement.Name.LocalName))
+                        {
+                            // See if property was already created as an array, if not then create it
+                            if (!repeatingObjectArrays.ContainsKey(propertyName))
+                            {
+                                repeatingObjectArrays.Add(propertyName, new List<Dictionary<string, object>>());
+                            }
+
+                            repeatingObjectArrays[propertyName].Add(BuildElementJsonObject(propertyElement));
+                        }
+                        else
+                        {
+                            jsonObject[propertyName] = BuildElementJsonObject(propertyElement);
+                        }
+                    }
+                }
+
+                foreach (string key in repeatingObjectArrays.Keys)
+                {
+                    jsonObject[key] = repeatingObjectArrays[key].ToArray();
+                }
+            }
+            else
+            {
+                jsonObject[MakeFirstLetterLowercase(container.Name.LocalName)] = container.Value;
+            }
+
+            return jsonObject;
+        }
+
+        /// <summary>
+        /// Makes the first letter of a string lowercase
+        /// </summary>
+        /// <param name="name">The string to be modified</param>
+        /// <returns>Modified string</returns>
+        private static string MakeFirstLetterLowercase(string str)
+        {
+            if (!string.IsNullOrWhiteSpace(str))
+            {
+                if (str.Length > 1 && !(str[1].ToString() == str[1].ToString().ToUpper()))
+                {
+                    return str[0].ToString().ToLower() + str.Substring(1);
+                }
+                else
+                {
+                    return str;
+                }
+            }
+
+            return str;
+        }
+    }
 }
\ No newline at end of file