internal static async Task <IEnumerable <Common.IDocument> > ProcessElementsAsync( Common.IDocument input, IExecutionContext context, string querySelector, bool first, Action <Common.IDocument, IExecutionContext, IElement, Dictionary <string, object> > processElement) { // Parse the HTML content IHtmlDocument htmlDocument = await input.ParseHtmlAsync(context, HtmlParser); if (htmlDocument == null) { return(input.Yield()); } // Evaluate the query selector try { if (!string.IsNullOrWhiteSpace(querySelector)) { IElement[] elements = first ? new[] { htmlDocument.QuerySelector(querySelector) } : htmlDocument.QuerySelectorAll(querySelector).ToArray(); if (elements.Length > 0 && elements[0] != null) { INode clone = htmlDocument.Clone(true); // Clone the document so we know if it changed Dictionary <string, object> metadata = new Dictionary <string, object>(); foreach (IElement element in elements) { processElement(input, context, element, metadata); } if (htmlDocument.Equals(clone)) { // Elements were not edited so return the original document or clone it with new metadata return(metadata.Count == 0 ? input.Yield() : input.Clone(metadata).Yield()); } // Elements were edited so get the new content using (Stream contentStream = await context.GetContentStreamAsync()) { using (StreamWriter writer = contentStream.GetWriter()) { htmlDocument.ToHtml(writer, ProcessingInstructionFormatter.Instance); writer.Flush(); IContentProvider contentProvider = context.GetContentProvider(contentStream, MediaTypes.Html); return(metadata.Count == 0 ? input.Clone(contentProvider).Yield() : input.Clone(metadata, contentProvider).Yield()); } } } } return(input.Yield()); } catch (Exception ex) { context.LogWarning("Exception while processing HTML for {0}: {1}", input.ToSafeDisplayString(), ex.Message); return(input.Yield()); } }