public static XhtmlDocument GetRenderingLayout(string formName) { if (HasCustomRenderingLayout(formName)) { var key = GetKey(formName); var layout = Localization.T(key); return(XhtmlDocument.Parse(layout)); } var model = ModelsFacade.GetModel(formName); if (model == null) { throw new ArgumentException($"Form '{formName}' not loaded"); } var doc = new XhtmlDocument(); foreach (var field in model.Fields.Where(f => f.Label != null)) { doc.Body.Add(new XElement(Namespaces.Xhtml + "p", $"%{field.Name}%")); } return(doc); }
/// <exclude /> public static void NormalizeXhtmlDocument(XhtmlDocument rootDocument) { using (TimerProfilerFacade.CreateTimerProfiler()) { while (true) { XElement nestedDocument = rootDocument.Root.Descendants(XhtmlDocument.XName_html).FirstOrDefault(); if (nestedDocument == null) { break; } var nestedHead = nestedDocument.Element(XhtmlDocument.XName_head); var nestedBody = nestedDocument.Element(XhtmlDocument.XName_body); Verify.IsNotNull(nestedHead, "XHTML document is missing <head /> element"); Verify.IsNotNull(nestedBody, "XHTML document is missing <body /> element"); rootDocument.Root.Add(nestedDocument.Attributes().Except(rootDocument.Root.Attributes(), _nameBasedAttributeComparer)); // making <meta property="..." /> from nested documents appear first. We will not filter them later and this ensure desired precedence bool IsMetaProperty(XElement e) => e.Name.LocalName == "meta" && e.Attribute("property") != null; rootDocument.Head.AddFirst(nestedHead.Elements().Where(IsMetaProperty)); rootDocument.Head.Add(nestedHead.Nodes().Where(f => !(f is XElement e && IsMetaProperty(e)))); rootDocument.Head.Add(nestedHead.Attributes().Except(rootDocument.Head.Attributes(), _nameBasedAttributeComparer)); rootDocument.Body.Add(nestedBody.Attributes().Except(rootDocument.Body.Attributes(), _nameBasedAttributeComparer)); nestedDocument.ReplaceWith(nestedBody.Nodes()); } } }
/// <exclude /> public static void NormalizeXhtmlDocument(XhtmlDocument rootDocument) { using (TimerProfilerFacade.CreateTimerProfiler()) { while (true) { XElement nestedDocument = rootDocument.Root.Descendants(XhtmlDocument.XName_html).FirstOrDefault(); if (nestedDocument == null) { break; } var nestedHead = nestedDocument.Element(XhtmlDocument.XName_head); var nestedBody = nestedDocument.Element(XhtmlDocument.XName_body); Verify.IsNotNull(nestedHead, "XHTML document is missing <head /> element"); Verify.IsNotNull(nestedBody, "XHTML document is missing <body /> element"); rootDocument.Root.Add(nestedDocument.Attributes().Except(rootDocument.Root.Attributes(), _nameBasedAttributeComparer)); rootDocument.Head.Add(nestedHead.Nodes()); rootDocument.Head.Add(nestedHead.Attributes().Except(rootDocument.Head.Attributes(), _nameBasedAttributeComparer)); rootDocument.Body.Add(nestedBody.Attributes().Except(rootDocument.Body.Attributes(), _nameBasedAttributeComparer)); nestedDocument.ReplaceWith(nestedBody.Nodes()); } } }
internal static void ProcessXhtmlDocument(XhtmlDocument xhtmlDocument, IPage page) { using (Profiler.Measure("Normalizing XHTML document")) { NormalizeXhtmlDocument(xhtmlDocument); } using (Profiler.Measure("Resolving relative paths")) { ResolveRelativePaths(xhtmlDocument); } using (Profiler.Measure("Sorting <head> elements")) { PrioritizeHeadNodes(xhtmlDocument); } using (Profiler.Measure("Appending C1 meta tags")) { AppendC1MetaTags(page, xhtmlDocument); } using (Profiler.Measure("Parsing localization strings")) { LocalizationParser.Parse(xhtmlDocument); } }
/// <exclude /> public static Control Render(XDocument document, FunctionContextContainer contextContainer, IXElementToControlMapper mapper, IPage page) { using (TimerProfilerFacade.CreateTimerProfiler()) { ExecuteEmbeddedFunctions(document.Root, contextContainer); ResolvePageFields(document, page); NormalizeAspNetForms(document); if (document.Root.Name != Namespaces.Xhtml + "html") { return(new LiteralControl(document.ToString())); } XhtmlDocument xhtmlDocument = new XhtmlDocument(document); NormalizeXhtmlDocument(xhtmlDocument); ResolveRelativePaths(xhtmlDocument); PrioritizeHeadNodex(xhtmlDocument); AppendC1MetaTags(page, xhtmlDocument); LocalizationParser.Parse(xhtmlDocument); return(xhtmlDocument.AsAspNetControl(mapper)); } }
/// <summary> /// Appends the c1 meta tags to the head section. Those tag are used later on by SEO assistant. /// </summary> /// <param name="page">The page.</param> /// <param name="xhtmlDocument">The XHTML document.</param> public static void AppendC1MetaTags(IPage page, XhtmlDocument xhtmlDocument) { if (UserValidationFacade.IsLoggedIn()) { bool emitMenuTitleMetaTag = string.IsNullOrEmpty(page.MenuTitle) == false; bool emitUrlTitleMetaTag = string.IsNullOrEmpty(page.UrlTitle) == false; if (emitMenuTitleMetaTag || emitUrlTitleMetaTag) { xhtmlDocument.Head.Add( new XComment("The C1.* meta tags are only emitted when you are logged in"), new XElement(Namespaces.Xhtml + "link", new XAttribute("rel", "schema.C1"), new XAttribute("href", "http://www.composite.net/ns/c1/seoassistant"))); if (emitMenuTitleMetaTag) { xhtmlDocument.Head.Add( new XElement(Namespaces.Xhtml + "meta", new XAttribute("name", "C1.menutitle"), new XAttribute("content", page.MenuTitle))); } if (emitUrlTitleMetaTag) { xhtmlDocument.Head.Add( new XElement(Namespaces.Xhtml + "meta", new XAttribute("name", "C1.urltitle"), new XAttribute("content", page.UrlTitle))); } } } }
private void NormalizeAspNetForms(XhtmlDocument xhtmlDocument) { // If current control is inside <form id="" runat="server"> tag all <asp:forms> tags will be removed from placeholder bool isInsideAspNetForm = false; var ansestor = this.Parent; while (ansestor != null) { if (ansestor is HtmlForm) { isInsideAspNetForm = true; break; } ansestor = ansestor.Parent; } if (!isInsideAspNetForm) { return; } List <XElement> aspNetFormElements = xhtmlDocument.Descendants(Namespaces.AspNetControls + "form").Reverse().ToList(); foreach (XElement aspNetFormElement in aspNetFormElements) { aspNetFormElement.ReplaceWith(aspNetFormElement.Nodes()); } }
/// <exclude /> public static XhtmlDocument RenderDataList <T>(IVisualFunction function, XhtmlDocument xhtmlDocument, DataTypeDescriptor typeDescriptor, FunctionContextContainer functionContextContainer, Expression <Func <T, bool> > filter) where T : class, IData { if (function == null) { throw new ArgumentNullException("function"); } if (xhtmlDocument == null) { throw new ArgumentNullException("xhtmlDocument"); } if (typeDescriptor == null) { throw new ArgumentNullException("typeDescriptor"); } if (functionContextContainer == null) { throw new ArgumentNullException("functionContextContainer"); } Type dataType = typeDescriptor.GetInterfaceType(); if (dataType == null) { throw new InvalidOperationException(string.Format("'{0}' is not a known type manager type.", typeDescriptor.TypeManagerTypeName)); } List <T> allData = DataFacade.GetData <T>(filter).ToList(); List <T> itemsToList; if (function.OrderbyFieldName == "(random)") { int itemsInList = allData.Count(); int itemsToFetch = Math.Min(itemsInList, function.MaximumItemsToList); itemsToList = new List <T>(); while (itemsToFetch > 0) { int itemToGet = (Math.Abs(Guid.NewGuid().GetHashCode()) % itemsInList); // (new Random()).Next(0, itemsInList); itemsToList.Add(allData[itemToGet]); allData.RemoveAt(itemToGet); itemsToFetch--; itemsInList--; } } else { IComparer <T> comparer = GenericComparer <T> .Build(typeDescriptor.GetInterfaceType(), function.OrderbyFieldName, function.OrderbyAscending); allData.Sort(comparer); itemsToList = allData.Take(function.MaximumItemsToList).ToList(); } return(RenderDataListImpl <T>(xhtmlDocument, typeDescriptor, itemsToList, functionContextContainer)); }
/// <summary> /// Gets a Page Template Feature based on name. /// </summary> /// <param name="featureName">Name of the Page Template Feature to return.</param> /// <returns></returns> public static XhtmlDocument GetPageTemplateFeature(string featureName) { EnsureWatcher(); string featureKey = featureName.ToLowerInvariant(); XhtmlDocument cachedFeatureDocument = _featureCache.Get(featureKey); if (cachedFeatureDocument == null) { lock (_lock) { cachedFeatureDocument = _featureCache.Get(featureKey); if (cachedFeatureDocument == null) { cachedFeatureDocument = LoadPageTemplateFeature(featureName); _featureCache.Add(featureKey, cachedFeatureDocument); } } } return(new XhtmlDocument(cachedFeatureDocument)); }
/// <exclude /> public static Control AsAspNetControl(this XhtmlDocument xhtmlDocument, IXElementToControlMapper controlMapper) { using (TimerProfilerFacade.CreateTimerProfiler()) { var htmlControl = new HtmlGenericControl("html"); CopyAttributes(xhtmlDocument.Root, htmlControl); HtmlHead headControl = xhtmlDocument.BuildHtmlHeadControl(controlMapper); Control bodyControl = xhtmlDocument.Body.AsAspNetControl(controlMapper); htmlControl.Controls.Add(headControl); htmlControl.Controls.Add(bodyControl); PlaceHolder pageHolder = new PlaceHolder(); if (xhtmlDocument.DocumentType != null) { string docType = xhtmlDocument.DocumentType.ToString(); var offset = docType.IndexOf("[]", StringComparison.Ordinal); if (offset >= 0) { docType = docType.Remove(offset, 2); } pageHolder.Controls.Add(new LiteralControl(docType)); } pageHolder.Controls.Add(htmlControl); return(pageHolder); } }
private static void ResolvePlaceholders(XDocument document, IEnumerable <IPagePlaceholderContent> placeholderContents) { using (TimerProfilerFacade.CreateTimerProfiler()) { var placeHolders = (from placeholder in document.Descendants(RenderingElementNames.PlaceHolder) let idAttribute = placeholder.Attribute(RenderingElementNames.PlaceHolderIdAttribute) where idAttribute != null select new { Element = placeholder, IdAttribute = idAttribute }).ToList(); foreach (var placeholder in placeHolders) { string placeHolderId = placeholder.IdAttribute.Value; placeholder.IdAttribute.Remove(); IPagePlaceholderContent placeHolderContent = placeholderContents.FirstOrDefault(f => f.PlaceHolderId == placeHolderId); XhtmlDocument xhtmlDocument = ParsePlaceholderContent(placeHolderContent); placeholder.Element.ReplaceWith(xhtmlDocument.Root); //try //{ // placeholder.Element.Add(new XAttribute(RenderingElementNames.PlaceHolderIdAttribute, placeHolderId)); //} //catch (Exception ex) //{ // throw new InvalidOperationException($"Failed to set id '{placeHolderId}' on element", ex); //} } } }
private static XhtmlDocument BuildDefaultDocument(IVisualFunction newFunction) { XElement htmlTable = new XElement(Namespaces.Xhtml + "table"); Type interfaceType = TypeManager.GetType(newFunction.TypeManagerName); DataTypeDescriptor typeDescriptor = DynamicTypeManager.GetDataTypeDescriptor(interfaceType); foreach (DataFieldDescriptor dataField in typeDescriptor.Fields.OrderBy(f => f.Position)) { if (!typeDescriptor.KeyPropertyNames.Contains(dataField.Name) && dataField.FormRenderingProfile != null && !string.IsNullOrEmpty(dataField.FormRenderingProfile.Label)) { string fieldMarkup = string.Format("<data:fieldreference fieldname=\"{0}\" typemanagername=\"{1}\" xmlns:data=\"{2}\" />", dataField.Name, newFunction.TypeManagerName, Namespaces.DynamicData10); htmlTable.Add(new XElement(Namespaces.Xhtml + "tr", new XElement(Namespaces.Xhtml + "td", dataField.FormRenderingProfile.Label), new XElement(Namespaces.Xhtml + "td", XElement.Parse(fieldMarkup)))); } } XhtmlDocument defaultDocument = new XhtmlDocument(); defaultDocument.Body.Add(htmlTable); return(defaultDocument); }
/// <summary> /// Loads the document. /// </summary> /// <param name="document">The XML document.</param> /// <param name="webPath">The public web path.</param> /// <param name="useXhtmlNamespace">if set to <c>true</c> use XHTML namespace (<c>true</c> by default).</param> public static XhtmlDocument GetDocument(XDocument document, string webPath, bool useXhtmlNamespace) { if (document == null) { return(null); } var heading = useXhtmlNamespace ? document.Root .Element(xhtml + "body") .Element(xhtml + "h1") : document.Root .Element("body") .Element("h1"); var title = useXhtmlNamespace ? document.Root .Element(xhtml + "head") .Element(xhtml + "title") .Value : document.Root .Element("head") .Element("title") .Value; var d = new XhtmlDocument { Header = (heading == null) ? null : heading.Value, Location = webPath, Title = title }; return(d); }
public override void ExecutePageHierarchy() { if (RequestContext.IsSuccess) { HandleSubmit(); } if (IntroText == null) { var value = Localization.EvaluateT(Form.Model, "IntroText", null); if (value != null) { try { IntroText = XhtmlDocument.Parse(value); } catch { } } } if (SuccessResponse == null) { var value = Localization.EvaluateT(Form.Model, "SuccessResponse", null); if (value != null) { try { SuccessResponse = XhtmlDocument.Parse(value); } catch { } } } base.ExecutePageHierarchy(); }
/// <exclude /> public static void ResolveRelativePaths(XhtmlDocument xhtmlDocument) { IEnumerable <XElement> xhtmlElements = xhtmlDocument.Descendants().Where(f => f.Name.Namespace == Namespaces.Xhtml); IEnumerable <XAttribute> pathAttributes = xhtmlElements.Attributes().Where(f => f.Name.LocalName == "src" || f.Name.LocalName == "href" || f.Name.LocalName == "action"); string applicationVirtualPath = UrlUtils.PublicRootPath; List <XAttribute> relativePathAttributes = pathAttributes.Where(f => f.Value.StartsWith("~/") || f.Value.StartsWith("%7E/")).ToList(); foreach (XAttribute relativePathAttribute in relativePathAttributes) { int tildePrefixLength = (relativePathAttribute.Value.StartsWith("~") ? 1 : 3); relativePathAttribute.Value = applicationVirtualPath + relativePathAttribute.Value.Substring(tildePrefixLength); } if (applicationVirtualPath.Length > 1) { List <XAttribute> hardRootedPathAttributes = pathAttributes.Where(f => f.Value.StartsWith("/Renderers/")).ToList(); foreach (XAttribute hardRootedPathAttribute in hardRootedPathAttributes) { hardRootedPathAttribute.Value = applicationVirtualPath + hardRootedPathAttribute.Value; } } }
private void initializeCodeActivity_ExecuteCode(object sender, EventArgs e) { string markup; if (C1File.Exists(this.FilePath)) { markup = C1File.ReadAllText(this.FilePath); } else { // someone deleted the feature file, but that won't stop us! XhtmlDocument template = new XhtmlDocument(); template.Head.Add(""); template.Body.Add(""); markup = template.ToString(); } this.Bindings.Add("FeatureName", this.FeatureName); this.Bindings.Add("Markup", markup); if (Path.GetExtension(this.FilePath) == ".html") { this.documentFormActivity1.FormDefinitionFileName = @"\Administrative\PageTemplateFeature\EditVisual.xml"; } else { this.documentFormActivity1.FormDefinitionFileName = @"\Administrative\PageTemplateFeature\EditMarkup.xml"; } }
/// <exclude /> public static Control Render(XDocument document, FunctionContextContainer contextContainer, IXElementToControlMapper mapper, IPage page) { using (TimerProfilerFacade.CreateTimerProfiler()) { using (Profiler.Measure("Executing embedded functions")) { ExecuteEmbeddedFunctions(document.Root, contextContainer); } using (Profiler.Measure("Resolving page fields")) { ResolvePageFields(document, page); } using (Profiler.Measure("Normalizing ASP.NET forms")) { NormalizeAspNetForms(document); } if (document.Root.Name != RenderingElementNames.Html) { return(new LiteralControl(document.ToString())); } var xhtmlDocument = new XhtmlDocument(document); ProcessXhtmlDocument(xhtmlDocument, page); using (Profiler.Measure("Converting XHTML document into an ASP.NET control")) { return(xhtmlDocument.AsAspNetControl(mapper)); } } }
private static HtmlHead BuildHtmlHeadControl(this XhtmlDocument xhtmlDocument, IXElementToControlMapper controlMapper) { var headControl = new HtmlHead(); xhtmlDocument.MergeToHeadControl(headControl, controlMapper); return(headControl); }
public void MovePageNumbers() { foreach (var span in XhtmlDocument.Descendants(XhtmlNs + "span").Where(IsPageNumberElement)) { Utils.TrimWhiteSpace(span); Utils.AddPageName(span); MovePageNumber(span); } }
public override void OnFinish(object sender, EventArgs e) { var formToken = (IModelReference)((DataEntityToken)EntityToken).Data; var renderingMarkup = GetBinding <string>("RenderingMarkup"); RenderingLayoutFacade.SaveRenderingLayout(formToken.Name, XhtmlDocument.Parse(renderingMarkup)); SetSaveStatus(true); }
public static void SaveRenderingLayout(string formName, XhtmlDocument layout) { using (var writer = ResourceFacade.GetResourceWriter()) { var key = GetKey(formName); writer.AddResource(key, layout.ToString()); } }
public override object Execute(ParameterList parameters, FunctionContextContainer context) { var doc = new XhtmlDocument(); var useRenderingLayout = parameters.GetParameter <bool>("UseRenderingLayout"); var instance = (Form)context.GetParameterValue(BaseFormFunction.InstanceKey, typeof(Form)); DumpModelValues(instance, doc, useRenderingLayout); return(doc); }
private object ExecuteChildAction(Dictionary <string, object> routeValues, ViewContext viewContext) { routeValues.Add("PageModel", viewContext.ViewData.Model); var htmlHelper = (viewContext.TempData["HtmlHelper"] as HtmlHelper) ?? new HtmlHelper(viewContext, new ViewPage()); var functionParameters = new RouteValueDictionary(routeValues); var html = htmlHelper.Action("Index", _controllerDescriptor.ControllerName, functionParameters); return(XhtmlDocument.Parse(html.ToString())); }
/// <exclude /> protected override void OnInit(System.EventArgs e) { XhtmlDocument feature = PageTemplateFeatureFacade.GetPageTemplateFeature(this.Name); FunctionContextContainer functionContextContainer = PageRenderer.GetPageRenderFunctionContextContainer(); var markup = new Markup(feature.Root, functionContextContainer); Controls.Add(markup); base.OnInit(e); }
internal static void MergeToHeadControl(this XhtmlDocument xhtmlDocument, HtmlHead headControl, IXElementToControlMapper controlMapper) { XElement headSource = xhtmlDocument.Head; if (headSource == null) { return; } CopyAttributes(headSource, headControl); XElement titleElement = headSource.Elements(XName_Title).LastOrDefault(); if (titleElement != null) { HtmlTitle existingControl = headControl.Controls.OfType <HtmlTitle>().FirstOrDefault(); if (existingControl != null) { headControl.Controls.Remove(existingControl); } // NOTE: we aren't using headControl.Title property since it adds "<title>" tag as the last one headControl.Controls.AddAt(0, new HtmlTitle { Text = HttpUtility.HtmlEncode(titleElement.Value) }); } var metaTags = headSource.Elements().Where(f => f.Name == XName_Meta); int metaTagPosition = Math.Min(1, headControl.Controls.Count); foreach (var metaTag in metaTags) { var metaControl = new HtmlMeta(); foreach (var attribute in metaTag.Attributes()) { if (attribute.Name.LocalName == "id") { metaControl.ID = attribute.Value; } else { metaControl.Attributes.Add(attribute.Name.LocalName, attribute.Value); } } headControl.Controls.AddAt(metaTagPosition++, metaControl); } ExportChildNodes(headSource.Nodes().Where(f => !(f is XElement element) || (element.Name != XName_Title && element.Name != XName_Meta)), headControl, controlMapper); headControl.RemoveDuplicates(); }
private static void PrioritizeHeadNodes(XhtmlDocument xhtmlDocument) { var prioritizedHeadNodes = new List <Tuple <int, XNode> >(); foreach (var node in xhtmlDocument.Head.Nodes().ToList()) { int p = GetHeadNodePriority(node); prioritizedHeadNodes.Add(new Tuple <int, XNode>(p, node)); node.Remove(); } xhtmlDocument.Head.Add(prioritizedHeadNodes.OrderBy(f => f.Item1).Select(f => f.Item2)); }
/// <exclude /> public static Control Render(XDocument document, FunctionContextContainer contextContainer, IXElementToControlMapper mapper, IPage page) { using (TimerProfilerFacade.CreateTimerProfiler()) { bool disableCaching = false; using (Profiler.Measure("Executing embedded functions")) { ExecuteFunctionsRec(document.Root, contextContainer, func => { if (!disableCaching && !FunctionAllowsCaching(func)) { disableCaching = true; } return(true); }); } if (disableCaching) { using (Profiler.Measure("PageRenderer: Disabling HTTP caching as at least one of the functions is not cacheable")) { HttpContext.Current?.Response.Cache.SetCacheability(HttpCacheability.NoCache); } } using (Profiler.Measure("Resolving page fields")) { ResolvePageFields(document, page); } using (Profiler.Measure("Normalizing ASP.NET forms")) { NormalizeAspNetForms(document); } if (document.Root.Name != RenderingElementNames.Html) { return(new LiteralControl(document.ToString())); } var xhtmlDocument = new XhtmlDocument(document); ProcessXhtmlDocument(xhtmlDocument, page); using (Profiler.Measure("Converting XHTML document into an ASP.NET control")) { return(xhtmlDocument.AsAspNetControl(mapper)); } } }
/// <summary> /// Binds placeholders' content to the related properties on a template definition /// </summary> /// <param name="template">The template.</param> /// <param name="pageContentToRender">The page rendering job.</param> /// <param name="placeholderProperties">The placeholder properties.</param> /// <param name="functionContextContainer">The function context container, if not null, nested functions fill be evaluated.</param> public static void BindPlaceholders(IPageTemplate template, PageContentToRender pageContentToRender, IDictionary <string, PropertyInfo> placeholderProperties, FunctionContextContainer functionContextContainer) { Verify.ArgumentNotNull(template, "template"); Verify.ArgumentNotNull(pageContentToRender, "pageContentToRender"); Verify.ArgumentNotNull(placeholderProperties, "placeholderProperties"); foreach (var placeholderContent in pageContentToRender.Contents) { string placeholderId = placeholderContent.PlaceHolderId; if (!placeholderProperties.ContainsKey(placeholderId)) { continue; } XhtmlDocument placeholderXhtml = PageRenderer.ParsePlaceholderContent(placeholderContent); if (functionContextContainer != null) { bool allFunctionsExecuted; using (Profiler.Measure($"Evaluating placeholder '{placeholderId}'")) { allFunctionsExecuted = PageRenderer.ExecuteCacheableFunctions(placeholderXhtml.Root, functionContextContainer); } if (allFunctionsExecuted) { using (Profiler.Measure("Normalizing XHTML document")) { PageRenderer.NormalizeXhtmlDocument(placeholderXhtml); } } } PageRenderer.ResolveRelativePaths(placeholderXhtml); PropertyInfo property = placeholderProperties[placeholderId]; if (!property.ReflectedType.IsInstanceOfType(template)) { string propertyName = property.Name; property = template.GetType().GetProperty(property.Name); Verify.IsNotNull(property, "Failed to find placeholder property '{0}'", propertyName); } property.SetValue(template, placeholderXhtml); } }
public static void ConvertActionLinks(XhtmlDocument document, RequestContext requestContext, RouteCollection routeCollection) { var actionLinks = GetLinkContainingAttributes(document).Where(a => IsRawActionLink((string)a)); foreach (var linkAttr in actionLinks) { string url = ConvertActionLink((string)linkAttr, requestContext, routeCollection); if (url != null && !url.StartsWith("/?")) { linkAttr.Value = url; } } }
/// <summary> /// Cleans HTML documents or fragments into XHTML conformant markup /// </summary> /// <param name="xmlMarkup">The html to clean</param> /// <returns></returns> public static XDocument TidyXml(string xmlMarkup) { try { return(XhtmlDocument.Parse(xmlMarkup)); } catch (Exception) { // take the slow road below... } byte[] xmlByteArray = Encoding.UTF8.GetBytes(xmlMarkup); Tidy tidy = GetXmlConfiguredTidy(); List <string> namespacePrefixedElementNames = LocateNamespacePrefixedElementNames(xmlMarkup); AllowNamespacePrefixedElementNames(tidy, namespacePrefixedElementNames); AllowHtml5ElementNames(tidy); TidyMessageCollection tidyMessages = new TidyMessageCollection(); string xml = ""; using (MemoryStream inputStream = new MemoryStream(xmlByteArray)) { using (MemoryStream outputStream = new MemoryStream()) { tidy.Parse(inputStream, outputStream, tidyMessages); outputStream.Position = 0; C1StreamReader sr = new C1StreamReader(outputStream); xml = sr.ReadToEnd(); } } if (tidyMessages.Errors > 0) { StringBuilder errorMessageBuilder = new StringBuilder(); foreach (TidyMessage message in tidyMessages) { if (message.Level == MessageLevel.Error) { errorMessageBuilder.AppendLine(message.ToString()); } } throw new InvalidOperationException(string.Format("Failed to parse html:\n\n{0}", errorMessageBuilder.ToString())); } xml = RemoveDuplicateAttributes(xml); return(XDocument.Parse(xml)); }