Ejemplo n.º 1
0
        /// <summary>
        /// Reads messages asynchronously.
        /// </summary>
        /// <param name="reader">
        /// The reader.
        /// </param>
        /// <returns>
        /// The messages.
        /// </returns>
        internal static async Task <ReadOnlyCollection <Message> > ReadMessagesAsync(XmlReader reader)
        {
            var messages = new List <Message>();

            if (await reader.MoveToDocumentElementAsync("response").ConfigureAwait(false))
            {
                await reader.ReadAsync().ConfigureAwait(false);

                reader.EnsureMarkup(XmlNodeType.Element, "messages");
                await reader.ReadAsync().ConfigureAwait(false);

                while (reader.NodeType == XmlNodeType.Element && reader.Name == "msg")
                {
                    var name = reader.GetRequiredAttribute("type");
                    var type = EnumConverter <MessageType> .Instance.Convert(name);

                    var text = await reader.ReadElementContentAsStringAsync().ConfigureAwait(false);

                    messages.Add(new Message(type, text));
                }

                reader.EnsureMarkup(XmlNodeType.EndElement, "messages");
            }

            return(new ReadOnlyCollection <Message>(messages));
        }
        /// <summary>
        /// Asynchronously reads data into the current
        /// <see cref="SearchResultStream"/>.
        /// </summary>
        /// <param name="reader">
        /// The <see cref="XmlReader"/> from which to read.
        /// </param>
        /// <returns>
        /// A <see cref="Task"/> representing the operation.
        /// </returns>
        public async Task ReadXmlAsync(XmlReader reader)
        {
            var fieldNames = new List <string>();

            this.FieldNames = new ReadOnlyCollection <string>(fieldNames);
            this.IsFinal    = true;

            if (!await reader.MoveToDocumentElementAsync("results").ConfigureAwait(false))
            {
                return;
            }

            string preview = reader.GetRequiredAttribute("preview");

            this.IsFinal = !BooleanConverter.Instance.Convert(preview);

            if (!await reader.ReadAsync().ConfigureAwait(false))
            {
                return;
            }

            reader.EnsureMarkup(XmlNodeType.Element, "meta");
            await reader.ReadAsync().ConfigureAwait(false);

            reader.EnsureMarkup(XmlNodeType.Element, "fieldOrder");

            if (reader.IsEmptyElement)
            {
                await reader.ReadAsync().ConfigureAwait(false);

                reader.EnsureMarkup(XmlNodeType.EndElement, "meta");
                await reader.ReadAsync().ConfigureAwait(false);
            }
            else
            {
                await reader.ReadEachDescendantAsync("field", async (r) =>
                {
                    await r.ReadAsync().ConfigureAwait(false);
                    var fieldName = await r.ReadContentAsStringAsync().ConfigureAwait(false);
                    fieldNames.Add(fieldName);
                }).ConfigureAwait(false);

                await reader.ReadEndElementSequenceAsync("fieldOrder", "meta").ConfigureAwait(false);
            }

            if (reader.NodeType == XmlNodeType.Element && reader.Name == "messages")
            {
                //// Skip messages

                await reader.ReadEachDescendantAsync("msg", (r) =>
                {
                    return(Task.FromResult(true));
                }).ConfigureAwait(false);

                reader.EnsureMarkup(XmlNodeType.EndElement, "messages");
                await reader.ReadAsync().ConfigureAwait(false);
            }
        }
Ejemplo n.º 3
0
        static async Task <dynamic> ParsePropertyValueAsync(XmlReader reader, int level)
        {
            if (reader.IsEmptyElement)
            {
                await reader.ReadAsync().ConfigureAwait(false);

                return(null);
            }

            string  name = reader.Name;
            dynamic value;

            await reader.ReadAsync().ConfigureAwait(false);

            switch (reader.NodeType)
            {
            default:

                value = await reader.ReadContentAsStringAsync().ConfigureAwait(false);

                break;

            case XmlNodeType.Element:

                // TODO: rewrite

                switch (reader.Name)
                {
                case "s:dict":

                    value = await ParseDictionaryAsync(reader, level).ConfigureAwait(false);

                    break;

                case "s:list":

                    value = await ParseListAsync(reader, level).ConfigureAwait(false);

                    break;

                default: throw new InvalidDataException();         // TODO: Diagnostics : unexpected start tag
                }

                break;

            case XmlNodeType.EndElement:

                reader.EnsureMarkup(XmlNodeType.EndElement, name);
                value = null;
                break;
            }

            reader.EnsureMarkup(XmlNodeType.EndElement, name);
            await reader.ReadAsync().ConfigureAwait(false);

            return(value);
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Asynchronously positions the source <see cref="XmlReader"/> to the start-
        /// tag following an <see cref="XmlNodeType"/>.XmlDeclaration.
        /// </summary>
        /// <exception cref="XmlException">
        /// Thrown when an XML error condition occurs.
        /// </exception>
        /// <param name="reader">
        /// The source <see cref="XmlReader"/>.
        /// </param>
        /// <param name="names">
        /// Optional list of permitted document element names.
        /// </param>
        /// <returns>
        /// <c>true</c> if the source <see cref="XmlReader"/> is successfully
        /// positioned at one of the permitted document element
        /// <paramref name= "names"/>; otherwise, if the end of file is reached,
        /// <c>false</c>.
        /// </returns>
        ///
        /// ### <exception cref="ArgumentNullException">
        /// <paramref name="reader"/> is <c>null</c>.
        /// </exception>
        /// ### <exception cref="InvalidDataException">
        /// There is no start-tag following the
        /// <see cref="XmlNodeType"/>.XmlDeclaration or the start-tag is not in the
        /// list of permitted document element names.
        /// </exception>
        public static async Task <bool> MoveToDocumentElementAsync(this XmlReader reader, params string[] names)
        {
            Contract.Requires <ArgumentNullException>(reader != null);

            if (reader.ReadState == ReadState.Initial)
            {
                await reader.ReadAsync().ConfigureAwait(false);

                if (reader.NodeType == XmlNodeType.XmlDeclaration)
                {
                    try
                    {
                        await reader.ReadAsync().ConfigureAwait(false);
                    }
                    catch (XmlException)
                    {
                        //// WORKAROUND:
                        //// Issue: Some searches return no results and in
                        //// these cases Splunk writes nothing but an XML
                        //// Declaration. When nothing follows the declaration
                        //// the XmlReader fails to detect EOF, does not update
                        //// the current XmlNode, and then throws an XmlException
                        //// because it thinks the XmlNode appears on a line
                        //// other than the first.
                        ////
                        //// We catch the issue here, dispose the reader to
                        //// ensure that EOF is true, and then return.
                        ////
                        //// Verified against Microsoft .NET 4.5 and Splunk
                        //// 5.0.4, 6.0.3, and 6.1.1.

                        if (reader.NodeType == XmlNodeType.XmlDeclaration)
                        {
                            reader.Dispose();
                            return(false);
                        }

                        throw;
                    }
                }
            }
            else
            {
                reader.MoveToElement(); // ensures we're on an element, not an attribute
            }

            if (reader.ReadState != ReadState.Interactive)
            {
                return(false);
            }

            reader.EnsureMarkup(XmlNodeType.Element, names);
            return(true);
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Reads a sequence of element end tags.
        /// </summary>
        /// <remarks>
        /// The <paramref name="reader"/> should be positioned on the first end tag
        /// in the sequence of <paramref name="names"/> when this method is called.
        /// The <paramref name="reader"/> will be positioned on the node following
        /// the last end tag in the sequence of <paramref name="names "/> when this
        /// method returns.
        /// </remarks>
        /// <param name="reader">
        /// The source <see cref="XmlReader"/>.
        /// </param>
        /// <param name="names">
        /// The sequence of element end tag names to match.
        /// </param>
        /// <returns>
        /// A <see cref="Task"/> representing the operation.
        /// </returns>
        ///
        /// ### <exception cref="ArgumentNullException">
        /// <paramref name="reader"/> or <paramref name="names"/> is <c>null</c>.
        /// </exception>
        /// ### <exception cref="InvalidDataException">
        /// If the sequence of nodes read from <paramref name="reader"/> does not
        /// match the sequence of end tag <paramref name="names"/>.
        /// </exception>
        public static async Task ReadEndElementSequenceAsync(this XmlReader reader, params string[] names)
        {
            Contract.Requires <ArgumentNullException>(reader != null);
            Contract.Requires <ArgumentNullException>(names != null);

            foreach (var name in names)
            {
                reader.EnsureMarkup(XmlNodeType.EndElement, name);
                await reader.ReadAsync().ConfigureAwait(false);
            }
        }
Ejemplo n.º 6
0
        static async Task <ReadOnlyCollection <dynamic> > ParseListAsync(XmlReader reader, int level)
        {
            List <dynamic> value = new List <dynamic>();

            if (!reader.IsEmptyElement)
            {
                await reader.ReadAsync().ConfigureAwait(false);

                while (reader.NodeType == XmlNodeType.Element && reader.Name == "s:item")
                {
                    value.Add(await ParsePropertyValueAsync(reader, level + 1).ConfigureAwait(false));
                }

                reader.EnsureMarkup(XmlNodeType.EndElement, "s:list");
            }

            await reader.ReadAsync().ConfigureAwait(false);

            return(new ReadOnlyCollection <dynamic>(value));
        }
        /// <summary>
        /// Asynchronously reads data into the current <see cref="SearchResult"/>.
        /// </summary>
        /// <param name="reader">
        /// The <see cref="XmlReader"/> from which to read.
        /// </param>
        /// <returns>
        /// A <see cref="Task"/> representing the operation.
        /// </returns>
        public async Task ReadXmlAsync(XmlReader reader)
        {
            Contract.Requires <ArgumentNullException>(reader != null, "reader");

            reader.MoveToElement();
            reader.EnsureMarkup(XmlNodeType.Element, "result");

            this.Object = new ExpandoObject();
            var dictionary = (IDictionary <string, object>) this.Object;

            this.SegmentedRaw = null;

            await reader.ReadEachDescendantAsync("field", async (r) =>
            {
                var key        = r.GetRequiredAttribute("k");
                var values     = new List <string>();
                var fieldDepth = r.Depth;

                while (await r.ReadAsync().ConfigureAwait(false))
                {
                    if (r.Depth == fieldDepth)
                    {
                        break;
                    }

                    Debug.Assert(r.Depth > fieldDepth, "This loop should have exited earlier.");
                    r.EnsureMarkup(XmlNodeType.Element, "value", "v");

                    if (r.Name == "value")
                    {
                        if (await r.ReadToDescendantAsync("text").ConfigureAwait(false))
                        {
                            values.Add(await r.ReadElementContentAsStringAsync().ConfigureAwait(false));
                        }
                    }
                    else if (r.Name == "v")
                    {
                        Debug.Assert(this.SegmentedRaw == null);
                        Debug.Assert(key == "_raw");

                        string value      = await r.ReadOuterXmlAsync().ConfigureAwait(false);
                        this.SegmentedRaw = XElement.Parse(value);
                        values.Add(this.SegmentedRaw.Value);
                    }
                }

                switch (values.Count)
                {
                case 0:
                    dictionary.Add(key, null);
                    break;

                case 1:
                    dictionary.Add(key, values[0]);
                    break;

                default:
                    dictionary.Add(key, new ReadOnlyCollection <string>(values));
                    break;
                }
            }).ConfigureAwait(false);
        }
Ejemplo n.º 8
0
        static async Task<dynamic> ParsePropertyValueAsync(XmlReader reader, int level)
        {
            if (reader.IsEmptyElement)
            {
                await reader.ReadAsync();
                return null;
            }

            string name = reader.Name;
            dynamic value;

            await reader.ReadAsync();

            switch (reader.NodeType)
            {
                default:

                    value = await reader.ReadContentAsStringAsync();
                    break;

                case XmlNodeType.Element:

                    // TODO: rewrite

                    switch (reader.Name)
                    {
                        case "s:dict":

                            value = await ParseDictionaryAsync(reader, level);
                            break;

                        case "s:list":

                            value = await ParseListAsync(reader, level);
                            break;

                        default: throw new InvalidDataException(); // TODO: Diagnostics : unexpected start tag
                    }

                    break;

                case XmlNodeType.EndElement:

                    reader.EnsureMarkup(XmlNodeType.EndElement, name);
                    value = null;
                    break;
            }

            reader.EnsureMarkup(XmlNodeType.EndElement, name);
            await reader.ReadAsync();

            return value;
        }
Ejemplo n.º 9
0
        static async Task<ReadOnlyCollection<dynamic>> ParseListAsync(XmlReader reader, int level)
        {
            List<dynamic> value = new List<dynamic>();

            if (!reader.IsEmptyElement)
            {
                await reader.ReadAsync();

                while (reader.NodeType == XmlNodeType.Element && reader.Name == "s:item")
                {
                    value.Add(await ParsePropertyValueAsync(reader, level + 1));
                }
                
                reader.EnsureMarkup(XmlNodeType.EndElement, "s:list");
            }

            await reader.ReadAsync();
            return new ReadOnlyCollection<dynamic>(value);
        }
Ejemplo n.º 10
0
        static async Task<dynamic> ParseDictionaryAsync(XmlReader reader, int level)
        {
            var value = (IDictionary<string, dynamic>)new ExpandoObject();

            if (!reader.IsEmptyElement)
            {
                await reader.ReadAsync();

                while (reader.NodeType == XmlNodeType.Element && reader.Name == "s:key")
                {
                    string name = reader.GetAttribute("name");

                    // TODO: Include a domain-specific name translation capability (?)

                    if (level == 0)
                    {
                        switch (name)
                        {
                            case "action.email.subject.alert":
                                name = "action.email.subject_alert";
                                break;
                            case "action.email.subject.report":
                                name = "action.email.subject_report";
                                break;
                            case "action.email":
                            case "action.populate_lookup":
                            case "action.rss":
                            case "action.script":
                            case "action.summary_index":
                            case "alert.suppress":
                            case "auto_summarize":
                                name += ".IsEnabled";
                                break;
                            case "alert_comparator":
                                name = "alert.comparator";
                                break;
                            case "alert_condition":
                                name = "alert.condition";
                                break;
                            case "alert_threshold":
                                name = "alert.threshold";
                                break;
                            case "alert_type":
                                name = "alert.type";
                                break;
                            case "coldPath.maxDataSizeMB":
                                name = "coldPath_maxDataSizeMB";
                                break;
                            case "display.visualizations.charting.chart":
                                name += ".Type";
                                break;
                            case "homePath.maxDataSizeMB":
                                name = "homePath_maxDataSizeMB";
                                break;
                            case "update.checksum.type":
                                name = "update.checksum_type";
                                break;
                        }
                    }

                    string[] names = name.Split(':', '.');
                    var dictionary = value;
                    string propertyName;
                    dynamic propertyValue;

                    for (int i = 0; i < names.Length - 1; i++)
                    {
                        propertyName = NormalizePropertyName(names[i]);

                        if (dictionary.TryGetValue(propertyName, out propertyValue))
                        {
                            if (!(propertyValue is ExpandoObject))
                            {
                                throw new InvalidDataException(); // TODO: Diagnostics : conversion error
                            }
                        }
                        else
                        {
                            propertyValue = new ExpandoObject();
                            dictionary.Add(propertyName, propertyValue);
                        }

                        dictionary = (IDictionary<string, object>)propertyValue;
                    }

                    propertyName = NormalizePropertyName(names[names.Length - 1]);
                    propertyValue = await ParsePropertyValueAsync(reader, level + 1);
                    dictionary.Add(propertyName, propertyValue);
                }

                reader.EnsureMarkup(XmlNodeType.EndElement, "s:dict");
            }

            await reader.ReadAsync();
            return value;  // TODO: what's the type seen by dynamic?
        }
Ejemplo n.º 11
0
        /// <summary>
        /// Asynchronously reads XML data into the current <see cref="AtomEntry"/>.
        /// </summary>
        /// <exception cref="InvalidDataException">
        /// Thrown when an Invalid Data error condition occurs.
        /// </exception>
        /// <param name="reader">
        /// The reader from which to read.
        /// </param>
        /// <returns>
        /// A <see cref="Task"/> representing the operation.
        /// </returns>
        public async Task ReadXmlAsync(XmlReader reader)
        {
            Contract.Requires<ArgumentNullException>(reader != null, "reader");

            this.Author = null;
            this.Content = null;
            this.Id = null;
            this.Links = null;
            this.Published = DateTime.MinValue;
            this.Title = null;
            this.Updated = DateTime.MinValue;

            reader.Requires(await reader.MoveToDocumentElementAsync("entry"));

            Dictionary<string, Uri> links = null;
            await reader.ReadAsync();

            while (reader.NodeType == XmlNodeType.Element)
            {
                string name = reader.Name;

                switch (name)
                {
                    case "title":

                        this.Title = await reader.ReadElementContentAsync(StringConverter.Instance);
                        break;

                    case "id":

                        this.Id = await reader.ReadElementContentAsync(UriConverter.Instance);
                        break;

                    case "author":
                        
                        await reader.ReadAsync();
                        reader.EnsureMarkup(XmlNodeType.Element, "name");
                        this.Author = await reader.ReadElementContentAsync(StringConverter.Instance);
                        reader.EnsureMarkup(XmlNodeType.EndElement, "author");
                        await reader.ReadAsync();
                        break;

                    case "published":

                        this.Published = await reader.ReadElementContentAsync(DateTimeConverter.Instance);
                        break;

                    case "updated":

                        this.Updated = await reader.ReadElementContentAsync(DateTimeConverter.Instance);
                        break;

                    case "link":

                        if (links == null)
                        {
                            links = new Dictionary<string, Uri>();
                        }

                        var href = reader.GetRequiredAttribute("href");
                        var rel = reader.GetRequiredAttribute("rel");
                        links[rel] = UriConverter.Instance.Convert(href);
                        await reader.ReadAsync();
                        break;

                    case "content":

                        this.Content = await ParsePropertyValueAsync(reader, 0);
                        break;

                    default: throw new InvalidDataException(); // TODO: Diagnostics : unexpected start tag
                }
            }

            reader.EnsureMarkup(XmlNodeType.EndElement, "entry");
            await reader.ReadAsync();

            if (links != null)
            {
                this.Links = new ReadOnlyDictionary<string, Uri>(links);
            }
        }
Ejemplo n.º 12
0
        /// <summary>
        /// Asynchronously reads XML data into the current <see cref="AtomFeed"/>.
        /// </summary>
        /// <exception cref="InvalidDataException">
        /// Thrown when an Invalid Data error condition occurs.
        /// </exception>
        /// <param name="reader">
        /// The reader from which to read.
        /// </param>
        /// <returns>
        /// A <see cref="Task"/> representing the operation.
        /// </returns>
        public async Task ReadXmlAsync(XmlReader reader)
        {
            Contract.Requires <ArgumentNullException>(reader != null, "reader");

            this.Author           = null;
            this.Entries          = null;
            this.GeneratorVersion = null;
            this.Id         = null;
            this.Links      = null;
            this.Messages   = null;
            this.Pagination = Pagination.None;
            this.Title      = null;
            this.Updated    = DateTime.MinValue;

            reader.Requires(await reader.MoveToDocumentElementAsync("feed").ConfigureAwait(false));
            var documentElementName = reader.Name;

            List <AtomEntry>         entries  = null;
            Dictionary <string, Uri> links    = null;
            List <Message>           messages = null;


            await reader.ReadAsync().ConfigureAwait(false);

            while (reader.NodeType == XmlNodeType.Element)
            {
                string name = reader.Name;

                switch (name)
                {
                case "title":

                    this.Title = await reader.ReadElementContentAsync(StringConverter.Instance).ConfigureAwait(false);

                    break;

                case "id":

                    this.Id = await reader.ReadElementContentAsync(UriConverter.Instance).ConfigureAwait(false);

                    break;

                case "author":

                    await reader.ReadAsync().ConfigureAwait(false);

                    reader.EnsureMarkup(XmlNodeType.Element, "name");
                    this.Author = await reader.ReadElementContentAsync(StringConverter.Instance).ConfigureAwait(false);

                    reader.EnsureMarkup(XmlNodeType.EndElement, "author");
                    await reader.ReadAsync().ConfigureAwait(false);

                    break;

                case "generator":

                    // string build = reader.GetRequiredAttribute("build"); // TODO: Incorporate build number? Build number sometimes adds a fifth digit.
                    string version = reader.GetRequiredAttribute("version");
                    this.GeneratorVersion = VersionConverter.Instance.Convert(string.Join(".", version));
                    await reader.ReadAsync().ConfigureAwait(false);

                    break;

                case "updated":

                    this.Updated = await reader.ReadElementContentAsync(DateTimeConverter.Instance).ConfigureAwait(false);

                    break;

                case "entry":

                    var entry = new AtomEntry();

                    if (entries == null)
                    {
                        entries = new List <AtomEntry>();
                    }

                    entries.Add(entry);

                    await entry.ReadXmlAsync(reader).ConfigureAwait(false);

                    break;

                case "link":

                    var href = reader.GetRequiredAttribute("href");
                    var rel  = reader.GetRequiredAttribute("rel");

                    if (links == null)
                    {
                        links = new Dictionary <string, Uri>();
                    }

                    links[rel] = UriConverter.Instance.Convert(href);
                    await reader.ReadAsync().ConfigureAwait(false);

                    break;

                case "s:messages":

                    bool isEmptyElement = reader.IsEmptyElement;
                    await reader.ReadAsync().ConfigureAwait(false);

                    if (messages == null)
                    {
                        messages = new List <Message>();
                    }

                    if (isEmptyElement)
                    {
                        continue;
                    }

                    while (reader.NodeType == XmlNodeType.Element && reader.Name == "s:msg")
                    {
                        var value = reader.GetRequiredAttribute("type");
                        var type  = EnumConverter <MessageType> .Instance.Convert(value);

                        var text = await reader.ReadElementContentAsStringAsync().ConfigureAwait(false);

                        messages.Add(new Message(type, text));
                    }

                    if (reader.NodeType == XmlNodeType.EndElement)
                    {
                        reader.EnsureMarkup(XmlNodeType.EndElement, "s:messages");
                        await reader.ReadAsync().ConfigureAwait(false);
                    }

                    break;

                case "opensearch:itemsPerPage":

                    int itemsPerPage = await reader.ReadElementContentAsync(Int32Converter.Instance).ConfigureAwait(false);

                    this.Pagination = new Pagination(itemsPerPage, this.Pagination.StartIndex, this.Pagination.TotalResults);
                    break;

                case "opensearch:startIndex":

                    int startIndex = await reader.ReadElementContentAsync(Int32Converter.Instance).ConfigureAwait(false);

                    this.Pagination = new Pagination(this.Pagination.ItemsPerPage, startIndex, this.Pagination.TotalResults);
                    break;

                case "opensearch:totalResults":

                    int totalResults = await reader.ReadElementContentAsync(Int32Converter.Instance).ConfigureAwait(false);

                    this.Pagination = new Pagination(this.Pagination.ItemsPerPage, this.Pagination.StartIndex, totalResults);
                    break;

                default: throw new InvalidDataException(string.Format("Unexpected start tag: {0}", reader.Name));     // TODO: Improved diagnostics
                }
            }

            reader.EnsureMarkup(XmlNodeType.EndElement, documentElementName);
            await reader.ReadAsync().ConfigureAwait(false);

            this.Entries  = entries == null ? emptyAtomEntryCollection : new ReadOnlyCollection <AtomEntry>(entries);
            this.Links    = links == null ? emptyLinksDictionary : new ReadOnlyDictionary <string, Uri>(links);
            this.Messages = messages == null ? emptyMessageCollection : new ReadOnlyCollection <Message>(messages);
        }
Ejemplo n.º 13
0
        /// <summary>
        /// Asynchronously reads XML data into the current <see cref="AtomFeed"/>.
        /// </summary>
        /// <exception cref="InvalidDataException">
        /// Thrown when an Invalid Data error condition occurs.
        /// </exception>
        /// <param name="reader">
        /// The reader from which to read.
        /// </param>
        /// <returns>
        /// A <see cref="Task"/> representing the operation.
        /// </returns>
        public async Task ReadXmlAsync(XmlReader reader)
        {
            Contract.Requires<ArgumentNullException>(reader != null, "reader");

            this.Author = null;
            this.Entries = null;
            this.GeneratorVersion = null;
            this.Id = null;
            this.Links = null;
            this.Messages = null;
            this.Pagination = Pagination.None;
            this.Title = null;
            this.Updated = DateTime.MinValue;

            reader.Requires(await reader.MoveToDocumentElementAsync("feed"));
            var documentElementName = reader.Name;

            List<AtomEntry> entries = null;
            Dictionary<string, Uri> links = null;
            List<Message> messages = null;

            await reader.ReadAsync();

            while (reader.NodeType == XmlNodeType.Element)
            {
                string name = reader.Name;

                switch (name)
                {
                    case "title":

                        this.Title = await reader.ReadElementContentAsync(StringConverter.Instance);
                        break;

                    case "id":

                        this.Id = await reader.ReadElementContentAsync(UriConverter.Instance);
                        break;

                    case "author":

                        await reader.ReadAsync();
                        reader.EnsureMarkup(XmlNodeType.Element, "name");
                        this.Author = await reader.ReadElementContentAsync(StringConverter.Instance);
                        reader.EnsureMarkup(XmlNodeType.EndElement, "author");
                        await reader.ReadAsync();
                        break;

                    case "generator":

                        // string build = reader.GetRequiredAttribute("build"); // TODO: Incorporate build number? Build number sometimes adds a fifth digit.
                        string version = reader.GetRequiredAttribute("version");
                        this.GeneratorVersion = VersionConverter.Instance.Convert(string.Join(".", version));
                        await reader.ReadAsync();
                        break;

                    case "updated":

                        this.Updated = await reader.ReadElementContentAsync(DateTimeConverter.Instance);
                        break;

                    case "entry":

                        var entry = new AtomEntry();

                        if (entries == null)
                        {
                            entries = new List<AtomEntry>();
                        }

                        entries.Add(entry);

                        await entry.ReadXmlAsync(reader);
                        break;

                    case "link":

                        var href = reader.GetRequiredAttribute("href");
                        var rel = reader.GetRequiredAttribute("rel");

                        if (links == null)
                        {
                            links = new Dictionary<string, Uri>();
                        }

                        links[rel] = UriConverter.Instance.Convert(href);
                        await reader.ReadAsync();
                        break;

                    case "s:messages":

                        bool isEmptyElement = reader.IsEmptyElement;
                        await reader.ReadAsync();

                        if (messages == null)
                        {
                            messages = new List<Message>();
                        }

                        if (isEmptyElement)
                        {
                            continue;
                        }

                        while (reader.NodeType == XmlNodeType.Element && reader.Name == "s:msg")
                        {
                            var value = reader.GetRequiredAttribute("type");
                            var type = EnumConverter<MessageType>.Instance.Convert(value);
                            var text = await reader.ReadElementContentAsStringAsync();
                            
                            messages.Add(new Message(type, text));
                        }

                        if (reader.NodeType == XmlNodeType.EndElement)
                        {
                            reader.EnsureMarkup(XmlNodeType.EndElement, "s:messages");
                            await reader.ReadAsync();
                        }

                        break;

                    case "opensearch:itemsPerPage":

                        int itemsPerPage = await reader.ReadElementContentAsync(Int32Converter.Instance);
                        this.Pagination = new Pagination(itemsPerPage, this.Pagination.StartIndex, this.Pagination.TotalResults);
                        break;

                    case "opensearch:startIndex":

                        int startIndex = await reader.ReadElementContentAsync(Int32Converter.Instance);
                        this.Pagination = new Pagination(this.Pagination.ItemsPerPage, startIndex, this.Pagination.TotalResults);
                        break;

                    case "opensearch:totalResults":

                        int totalResults = await reader.ReadElementContentAsync(Int32Converter.Instance);
                        this.Pagination = new Pagination(this.Pagination.ItemsPerPage, this.Pagination.StartIndex, totalResults);
                        break;

                    default: throw new InvalidDataException(string.Format("Unexpected start tag: {0}", reader.Name)); // TODO: Improved diagnostics
                }
            }

            reader.EnsureMarkup(XmlNodeType.EndElement, documentElementName);
            await reader.ReadAsync();

            if (entries != null)
            {
                this.Entries = new ReadOnlyCollection<AtomEntry>(entries);
            }

            if (links != null)
            {
                this.Links = new ReadOnlyDictionary<string, Uri>(links);
            }

            if (messages != null)
            {
                this.Messages = new ReadOnlyCollection<Message>(messages);
            }
        }
Ejemplo n.º 14
0
        static async Task <dynamic> ParseDictionaryAsync(XmlReader reader, int level)
        {
            var value = (IDictionary <string, dynamic>) new ExpandoObject();

            if (!reader.IsEmptyElement)
            {
                await reader.ReadAsync().ConfigureAwait(false);

                while (reader.NodeType == XmlNodeType.Element && reader.Name == "s:key")
                {
                    string name = reader.GetAttribute("name");

                    // TODO: Include a domain-specific name translation capability (?)

                    if (level == 0)
                    {
                        switch (name)
                        {
                        case "action.email.subject.alert":
                            name = "action.email.subject_alert";
                            break;

                        case "action.email.subject.report":
                            name = "action.email.subject_report";
                            break;

                        case "action.email":
                        case "action.populate_lookup":
                        case "action.rss":
                        case "action.script":
                        case "action.summary_index":
                        case "alert.suppress":
                        case "auto_summarize":
                            name += ".IsEnabled";
                            break;

                        case "alert_comparator":
                            name = "alert.comparator";
                            break;

                        case "alert_condition":
                            name = "alert.condition";
                            break;

                        case "alert_threshold":
                            name = "alert.threshold";
                            break;

                        case "alert_type":
                            name = "alert.type";
                            break;

                        case "coldPath.maxDataSizeMB":
                            name = "coldPath_maxDataSizeMB";
                            break;

                        case "display.visualizations.charting.chart":
                            name += ".Type";
                            break;

                        case "homePath.maxDataSizeMB":
                            name = "homePath_maxDataSizeMB";
                            break;

                        case "update.checksum.type":
                            name = "update.checksum_type";
                            break;
                        }
                    }

                    string[] names      = name.Split(':', '.');
                    var      dictionary = value;
                    string   propertyName;
                    dynamic  propertyValue;

                    for (int i = 0; i < names.Length - 1; i++)
                    {
                        propertyName = NormalizePropertyName(names[i]);

                        if (dictionary.TryGetValue(propertyName, out propertyValue))
                        {
                            if (!(propertyValue is ExpandoObject))
                            {
                                throw new InvalidDataException(); // TODO: Diagnostics : conversion error
                            }
                        }
                        else
                        {
                            propertyValue = new ExpandoObject();
                            dictionary.Add(propertyName, propertyValue);
                        }

                        dictionary = (IDictionary <string, object>)propertyValue;
                    }

                    propertyName  = NormalizePropertyName(names[names.Length - 1]);
                    propertyValue = await ParsePropertyValueAsync(reader, level + 1).ConfigureAwait(false);

                    dictionary.Add(propertyName, propertyValue);
                }

                reader.EnsureMarkup(XmlNodeType.EndElement, "s:dict");
            }

            await reader.ReadAsync().ConfigureAwait(false);

            return(value);  // TODO: what's the type seen by dynamic?
        }
Ejemplo n.º 15
0
        /// <summary>
        /// Asynchronously reads XML data into the current <see cref="AtomEntry"/>.
        /// </summary>
        /// <exception cref="InvalidDataException">
        /// Thrown when an Invalid Data error condition occurs.
        /// </exception>
        /// <param name="reader">
        /// The reader from which to read.
        /// </param>
        /// <returns>
        /// A <see cref="Task"/> representing the operation.
        /// </returns>
        public async Task ReadXmlAsync(XmlReader reader)
        {
            Contract.Requires <ArgumentNullException>(reader != null, "reader");

            this.Author    = null;
            this.Content   = null;
            this.Id        = null;
            this.Links     = null;
            this.Published = DateTime.MinValue;
            this.Title     = null;
            this.Updated   = DateTime.MinValue;

            reader.Requires(await reader.MoveToDocumentElementAsync("entry").ConfigureAwait(false));

            Dictionary <string, Uri> links = null;
            await reader.ReadAsync().ConfigureAwait(false);

            while (reader.NodeType == XmlNodeType.Element)
            {
                string name = reader.Name;

                switch (name)
                {
                case "title":

                    this.Title = await reader.ReadElementContentAsync(StringConverter.Instance).ConfigureAwait(false);

                    break;

                case "id":

                    this.Id = await reader.ReadElementContentAsync(UriConverter.Instance).ConfigureAwait(false);

                    break;

                case "author":

                    await reader.ReadAsync().ConfigureAwait(false);

                    reader.EnsureMarkup(XmlNodeType.Element, "name");
                    this.Author = await reader.ReadElementContentAsync(StringConverter.Instance).ConfigureAwait(false);

                    reader.EnsureMarkup(XmlNodeType.EndElement, "author");
                    await reader.ReadAsync().ConfigureAwait(false);

                    break;

                case "published":

                    this.Published = await reader.ReadElementContentAsync(DateTimeConverter.Instance).ConfigureAwait(false);

                    break;

                case "updated":

                    this.Updated = await reader.ReadElementContentAsync(DateTimeConverter.Instance).ConfigureAwait(false);

                    break;

                case "link":

                    if (links == null)
                    {
                        links = new Dictionary <string, Uri>();
                    }

                    var href = reader.GetRequiredAttribute("href");
                    var rel  = reader.GetRequiredAttribute("rel");
                    links[rel] = UriConverter.Instance.Convert(href);
                    await reader.ReadAsync().ConfigureAwait(false);

                    break;

                case "content":

                    this.Content = await ParsePropertyValueAsync(reader, 0).ConfigureAwait(false);

                    break;

                default: throw new InvalidDataException();     // TODO: Diagnostics : unexpected start tag
                }
            }

            reader.EnsureMarkup(XmlNodeType.EndElement, "entry");
            await reader.ReadAsync().ConfigureAwait(false);

            if (links != null)
            {
                this.Links = new ReadOnlyDictionary <string, Uri>(links);
            }
        }
Ejemplo n.º 16
0
        /// <summary>
        /// Asynchronously reads data into the current <see cref="SearchResult"/>.
        /// </summary>
        /// <param name="reader">
        /// The <see cref="XmlReader"/> from which to read.
        /// </param>
        /// <returns>
        /// A <see cref="Task"/> representing the operation.
        /// </returns>
        public async Task ReadXmlAsync(XmlReader reader)
        {
            Contract.Requires <ArgumentNullException>(reader != null, "reader");

            reader.MoveToElement();
            reader.EnsureMarkup(XmlNodeType.Element, "result");

            this.Object = new Dictionary <string, object>();
            var dictionary = (IDictionary <string, object>) this.Object;

            this.tagsObject = new Dictionary <string, object>();
            var tagsDictionary = (IDictionary <string, object>) this.tagsObject;

            this.SegmentedRaw = null;

            await reader.ReadEachDescendantAsync("field", async (r) =>
            {
                ImmutableSortedSet <string> .Builder tags = null;

                var key    = r.GetRequiredAttribute("k");
                var values = new List <object>();

                var fieldDepth = r.Depth;

                while (await r.ReadAsync().ConfigureAwait(false))
                {
                    if (r.Depth == fieldDepth)
                    {
                        break;
                    }

                    Debug.Assert(r.Depth > fieldDepth, "This loop should have exited earlier.");
                    r.EnsureMarkup(XmlNodeType.Element, "value", "v");

                    if (r.IsEmptyElement)
                    {
                        continue;
                    }

                    if (r.Name == "value")
                    {
                        await r.ReadAsync().ConfigureAwait(false);
                        string value = null;

                        while (r.NodeType == XmlNodeType.Element)
                        {
                            r.EnsureMarkup(XmlNodeType.Element, "text", "tag");
                            var elementName = r.Name;

                            string content = await r.ReadElementContentAsStringAsync().ConfigureAwait(false);

                            switch (elementName)
                            {
                            case "text":
                                value = content;
                                break;

                            case "tag":
                                if (tags == null)
                                {
                                    tags = ImmutableSortedSet.CreateBuilder <string>();
                                }
                                tags.Add(content);
                                break;
                            }
                        }

                        r.EnsureMarkup(XmlNodeType.EndElement, "value");

                        if (tags != null && tags.Count > 0)
                        {
                            values.Add(new TaggedFieldValue(value ?? string.Empty, tags.ToImmutable()));
                            tags.Clear();
                        }
                        else
                        {
                            values.Add(value ?? string.Empty);
                        }
                    }
                    else
                    {
                        Debug.Assert(this.SegmentedRaw == null);
                        Debug.Assert(key == "_raw");

                        string value      = await r.ReadOuterXmlAsync().ConfigureAwait(false);
                        this.SegmentedRaw = XElement.Parse(value);
                        values.Add(this.SegmentedRaw.Value);
                    }
                }

                if (key.StartsWith("tag::"))
                {
                    var valueSet = ImmutableSortedSet.ToImmutableSortedSet <string>(values.Cast <string>());
                    tagsDictionary.Add(key.Substring("tag::".Length), valueSet);
                    dictionary.Add(key, valueSet);
                }
                else
                {
                    switch (values.Count)
                    {
                    case 0:
                        dictionary.Add(key, string.Empty);
                        break;

                    case 1:
                        dictionary.Add(key, values[0]);
                        break;

                    default:
                        dictionary.Add(key, new ReadOnlyCollection <object>(values));
                        break;
                    }
                }
            }).ConfigureAwait(false);
        }
Ejemplo n.º 17
0
        static async Task <dynamic> ParseDictionaryAsync(XmlReader reader, int level)
        {
            var value = (IDictionary <string, dynamic>) new ExpandoObject();

            if (!reader.IsEmptyElement)
            {
                await reader.ReadAsync().ConfigureAwait(false);

                while (reader.NodeType == XmlNodeType.Element && reader.Name == "s:key")
                {
                    string name = reader.GetAttribute("name");

                    // TODO: Include a domain-specific name translation capability (?)

                    if (level == 0)
                    {
                        switch (name)
                        {
                        case "action.email.subject.alert":
                            name = "action.email.subject_alert";
                            break;

                        case "action.email.subject.report":
                            name = "action.email.subject_report";
                            break;

                        case "action.email":
                        case "action.populate_lookup":
                        case "action.rss":
                        case "action.script":
                        case "action.summary_index":
                        case "action.webhook":
                        case "alert.suppress":
                        case "auto_summarize":
                            name += ".IsEnabled";
                            break;

                        case "alert_comparator":
                            name = "alert.comparator";
                            break;

                        case "alert_condition":
                            name = "alert.condition";
                            break;

                        case "alert_threshold":
                            name = "alert.threshold";
                            break;

                        case "alert_type":
                            name = "alert.type";
                            break;

                        case "coldPath.maxDataSizeMB":
                            name = "coldPath_maxDataSizeMB";
                            break;

                        case "display.visualizations.charting.chart":
                            name += ".Type";
                            break;

                        case "display.visualizations.charting.layout.splitSeries.allowIndependentYRanges":
                            name = "display.visualizations.charting.layout.splitSeries_allowIndependentYRanges";
                            break;

                        case "homePath.maxDataSizeMB":
                            name = "homePath_maxDataSizeMB";
                            break;

                        case "update.checksum.type":
                            name = "update.checksum_type";
                            break;
                        }
                    }

                    string[] names      = name.Split(':', '.');
                    var      dictionary = value;
                    string   propertyName;
                    dynamic  propertyValue;

                    // There are cases where the server sends us bad values for "s:key", namely
                    // the empty string. This happens for example when we get back the metadata for
                    // a search job which contains an "eval". In these cases, we simply replace the
                    // empty string with a literal string called "empty", so that we know where it came
                    // from.
                    //
                    // The risk with this fix is that we will have multiple empty keys at the same
                    // level, and thus using "empty" would clash. However, this would be an even more
                    // serious error on the part of the API, as it would mean we have no way to disambiguate
                    // those two entries. As such, we feel it is safe.
                    if (names[names.Length - 1] == "")
                    {
                        names[names.Length - 1] = "empty";
                    }

                    for (int i = 0; i < names.Length - 1; i++)
                    {
                        propertyName = NormalizePropertyName(names[i]);

                        if (dictionary.TryGetValue(propertyName, out propertyValue))
                        {
                            if (!(propertyValue is ExpandoObject))
                            {
                                throw new InvalidDataException(name); // TODO: Diagnostics : conversion error
                            }
                        }
                        else
                        {
                            propertyValue = new ExpandoObject();
                            dictionary.Add(propertyName, propertyValue);
                        }

                        dictionary = (IDictionary <string, object>)propertyValue;
                    }

                    propertyName  = NormalizePropertyName(names[names.Length - 1]);
                    propertyValue = await ParsePropertyValueAsync(reader, level + 1).ConfigureAwait(false);

                    dictionary.Add(propertyName, propertyValue);
                }

                reader.EnsureMarkup(XmlNodeType.EndElement, "s:dict");
            }

            await reader.ReadAsync().ConfigureAwait(false);

            return(value);  // TODO: what's the type seen by dynamic?
        }