private void SetInnerText(HtmlNode node, string text) { node.ReplaceChild(HtmlTextNode.CreateNode(text), node.FirstChild); }
private static void Plain(StringBuilder builder, ref ToPlainTextState state, IEnumerable <HtmlNode> nodes) { foreach (HtmlNode node in nodes) { if (node is HtmlTextNode) { HtmlTextNode text = (HtmlTextNode)node; char[] chars = HtmlEntity.DeEntitize(text.Text).ToCharArray(); foreach (char ch in chars) { if (char.IsWhiteSpace(ch)) { if (ch == 0xA0 || ch == 0x2007 || ch == 0x202F) { if (state == ToPlainTextState.WhiteSpace) { builder.Append(' '); } builder.Append(' '); state = ToPlainTextState.NotWhiteSpace; } else { if (state == ToPlainTextState.NotWhiteSpace) { state = ToPlainTextState.WhiteSpace; } } } else { if (state == ToPlainTextState.WhiteSpace) { builder.Append(' '); } builder.Append(ch); state = ToPlainTextState.NotWhiteSpace; } } } else { string tag = node.Name.ToLower(); if (tag == "br") { builder.AppendLine(); state = ToPlainTextState.StartLine; } else if (NonVisibleTags.Contains(tag)) { } else if (InlineTags.Contains(tag)) { Plain(builder, ref state, node.ChildNodes); } else { if (state != ToPlainTextState.StartLine) { builder.AppendLine(); state = ToPlainTextState.StartLine; } Plain(builder, ref state, node.ChildNodes); if (state != ToPlainTextState.StartLine) { builder.AppendLine(); state = ToPlainTextState.StartLine; } } } } }
CssBox CreateTextAreaElement(HtmlElement domE, CssBox parentBox, BoxSpec spec, LayoutFarm.RootGraphic rootgfx, HtmlHost host) { //mulitline //TODO: review default size of a textarea... HtmlTextAreaElement htmlTextAreaElem = (HtmlTextAreaElement)domE; var textbox = new LayoutFarm.CustomWidgets.TextBoxContainer(100, 60, true); var subdomExtender = new TextAreaInputSubDomExtender(textbox); CssBox wrapperBox = CreateCssWrapper( host, textbox, textbox.GetPrimaryRenderElement(rootgfx), spec, subdomExtender, true); textbox.KeyDown += (s, e) => { ((LayoutFarm.UI.IUIEventListener)domE).ListenKeyDown(e); }; htmlTextAreaElem.SubDomExtender = subdomExtender;//connect //place holder support DomAttribute placeHolderAttr = domE.FindAttribute("placeholder"); if (placeHolderAttr != null) { textbox.PlaceHolderText = placeHolderAttr.Value; } parentBox.AppendChild(wrapperBox); //content of text area HtmlTextNode textNode = null; foreach (DomNode child in domE.GetChildNodeIterForward()) { switch (child.NodeKind) { case HtmlNodeKind.TextNode: { textNode = (HtmlTextNode)child; } break; } if (textNode != null) { break; } } if (textNode != null) { //if first line is blank line we skip //TODO: review here System.Collections.Generic.List <string> strList = new System.Collections.Generic.List <string>(); int lineCount = 0; using (System.IO.StringReader strReader = new System.IO.StringReader(new string(textNode.GetOriginalBuffer()))) { string line = strReader.ReadLine(); while (line != null) { if (lineCount == 0) { if (line.Trim() != string.Empty) { strList.Add(line); } } else { strList.Add(line); } lineCount++; line = strReader.ReadLine(); } if (strList.Count > 0) { //check last line line = strList[strList.Count - 1]; if (line.Trim() == string.Empty) { strList.RemoveAt(strList.Count - 1); } } } // if (strList.Count > 0) { textbox.SetText(strList); } } return(wrapperBox); }
/// <summary>Sanitizes the node.</summary> /// <param name="node">The node.</param> public void SanitizeNode(HtmlNode node) { HtmlSanitizerTagRule rule; SanitizerOperation operation; using (new RecursionGuard(this)) { // Remove any comment nodes if instructed to do so. if (node.NodeType == HtmlNodeType.Comment && RemoveComments) { node.Remove(); return; } // In theory all text should have HTML entities (ampersand, quotes, lessthan, greaterthan) encoded. // In practice or in case of an attack this may not be the case. Make sure all entities are encoded, but avoid // double encoding correctly encoded entities. Do so by first decoding entities and then encode entities // in the complete text. if (node.NodeType == HtmlNodeType.Text && EncodeHtmlEntities) { var deentitized = WebUtility.HtmlDecode(node.InnerText); // Unfortunately also unicode characters are encoded, which is not really necessary. var entitized = WebUtility.HtmlEncode(deentitized); var replacement = HtmlTextNode.CreateNode(entitized); node.ParentNode.ReplaceChild(replacement, node); return; } // Only further process element nodes (includes the root document). if (node.NodeType != HtmlNodeType.Element && node.NodeType != HtmlNodeType.Document) { return; } // Make sure the tag name is all small caps. HTML5 does not have any // capitalized letters in it's tag names. node.Name = node.Name.ToLowerInvariant(); // Lookup the rule for this node (may be null). If we are in white list mode and no rule is found, // remove the node. Don't remove the document however. if (!Rules.TryGetValue(node.Name, out rule) && WhiteListMode && node.NodeType != HtmlNodeType.Document) { node.Remove(); return; } if (rule != null) { // Apply the global node operation. Quit if it was removed. if (!ApplyNodeOperation(node, rule.Operation)) { return; } // If the tag is empty and the rule instructs the removal of empty tag, remove the node. if (rule.RemoveEmpty && !node.HasAttributes && !node.HasChildNodes) { node.Remove(); return; } // Rename the tag if the rule dictates so. if (!string.IsNullOrEmpty(rule.RenameTag)) { node.Name = rule.RenameTag; } } // Sanitize every attribute of the node in reverse order. for (int i = node.Attributes.Count - 1; i >= 0; i--) { operation = SanitizeAttribute(node.Attributes[i], rule); if (!ApplyNodeOperation(node, operation)) { return; } } if (rule != null) { // Add the css class if specified by the rule. This needs to be done after sanitizing // the attributes as specified class may not be white listed. if (!string.IsNullOrEmpty(rule.SetClass)) { var className = node.GetAttributeValue("class", string.Empty); if (string.IsNullOrEmpty(className)) { className = rule.SetClass; } else { className += " " + rule.SetClass; } node.SetAttributeValue("class", className); } // If the node does not have any attributes, see if we need to do anything with it. if (node.Attributes.Count == 0) { if (!ApplyNodeOperation(node, rule.NoAttributesOperation)) { return; } } // Ensure that all attributes are set according to the rule. foreach (var setAttribute in rule.SetAttributes.Where(r => !node.Attributes.Contains(r.Key))) { node.Attributes.Add(setAttribute.Key, setAttribute.Value); } } // Finally process any child nodes recursively. // Do this in reverse to allow removal of nodes without hassle. for (int i = node.ChildNodes.Count - 1; i >= 0; i--) { SanitizeNode(node.ChildNodes[i]); } // If the tag is empty and the rule instructs the removal of empty tag, remove the node. We are doing // this again because at this point the node may have become empty. if (rule != null) { if (rule.RemoveEmpty && !node.HasAttributes && !node.HasChildNodes) { node.Remove(); return; } } } }
/// <summary> /// Process the node for k-tags and k-expressions and return the processed node. /// </summary> /// <param name="readNode"></param> /// <param name="classNameAlias"></param> /// <param name="classNameAliasDepth"></param> /// <param name="depth"></param> /// <param name="isRepeat"></param> /// <param name="evaluator"></param> /// <returns></returns> private HtmlNode GetProcessedNode(HtmlNode readNode, Dictionary <string, AliasReference> classNameAlias, Dictionary <int, string> classNameAliasDepth, int depth, bool isRepeat, ExpressionEvaluator evaluator, string customerId, KEntity entity, dynamic websiteData, Models.Pagination viewDetails, string queryString, Dictionary <string, long> functionLog, bool isDetailsView, bool isNFSite) { try { HtmlNode returnNode = readNode.CloneNode(false); if (readNode.NodeType == HtmlNodeType.Comment) { return(returnNode); } else if (readNode.NodeType == HtmlNodeType.Text) { returnNode = HtmlTextNode.CreateNode(ReplaceKLanguage(readNode.OuterHtml, classNameAlias, evaluator, entity, viewDetails, websiteData, websiteData?._system?.kresult, queryString, functionLog, isDetailsView, isNFSite)) ?? returnNode; return(returnNode); } else if (readNode.NodeType == HtmlNodeType.Element) { if (isRepeat && (false || readNode.Attributes.Aggregate(false, (acc, x) => acc || x.Name.ToLower().Equals("k-norepeat")))) { returnNode = HtmlCommentNode.CreateNode("<!-- skip -->"); } if (returnNode.Attributes.Count() > 0) { foreach (HtmlAttribute attribute in returnNode.Attributes.ToList()) { if (returnNode.NodeType == HtmlNodeType.Comment) { break; } if (!String.IsNullOrEmpty(attribute.Name) && dynamicTagDescriptors.Contains(attribute.Name.ToLower())) { TagProcessor processor = processorFactory.GetProcessor(attribute.Name); processor.ProcessNode(ref returnNode, attribute, classNameAlias, classNameAliasDepth, depth, customerId, evaluator, entity, websiteData, viewDetails, queryString, functionLog, isDetailsView, isNFSite); if (!(attribute.Name.ToLower().Equals(LanguageAttributes.KPayAmount.GetDescription()) || attribute.Name.ToLower().Equals(LanguageAttributes.KPayPurpose.GetDescription()))) { returnNode.Attributes[attribute.Name.ToLower()]?.Remove(); } } else if (!attribute.Name.Equals("input", StringComparison.InvariantCultureIgnoreCase) && !attribute.Name.Equals("headers", StringComparison.InvariantCultureIgnoreCase) && Kitsune.Helper.Constants.WidgetRegulerExpression.IsMatch(attribute.Value)) { attribute.Value = ReplaceKLanguage(attribute.Value, classNameAlias, evaluator, entity, viewDetails, websiteData, websiteData?._system?.kresult, queryString, functionLog, isDetailsView, isNFSite); //attribute.Value = evaluator.EvaluateExpression(attribute.Value, entity, viewDetails, classNameAlias, websiteData, websiteData?._system?.kresult, queryString, isDetailsView, isNFSite); if (returnNode.Name?.ToLower() == "img" && attribute.Name?.ToLower() == "src") { attribute.Value = attribute.Value?.Trim(); } } } if (requestType == KitsuneRequestUrlType.PRODUCTION && returnNode.Name?.ToLower() == "img") { string source = returnNode.Attributes.Where(x => x.Name.ToLower() == "src")?.FirstOrDefault()?.Value; if (!string.IsNullOrEmpty(source) && !source.StartsWith("/") && !source.StartsWith(".") && !source.StartsWith("data:") && source.ToLower().IndexOf("k-img") < 0) { source = source.Replace(" ", "%20"); string ext = source.Split('?')[0].Split('.').Last().ToLower(); string domain = source.Replace("http://", "").Replace("https://", "").Split('/')[0].ToLower(); if (!BlackListKImgFileExtension.Contains(ext) && !BlackListKImgDomain.Contains(domain) && !domain.Contains("cdn") && !domain.Contains("akamai") && !domain.Contains("cloudflare")) { string rootUrl = websiteData?.rootaliasurl?.url?.Value; if (!source.StartsWith(rootUrl, StringComparison.InvariantCultureIgnoreCase)) { string srcSetValue = ""; foreach (int resolution in KLM_Constants.IMAGE_RESOLUTIONS) { srcSetValue += String.Format(KLM_Constants.K_IMG_FORMAT_STRING, resolution, source); } if (srcSetValue != null) { returnNode.Attributes.Add("srcset", srcSetValue); //returnNode.Attributes.Remove("src"); } } } } } } //if (returnNode.Name?.ToLower() == "img") //{ // string source = returnNode.Attributes.Where(x => x.Name.ToLower() == "src").FirstOrDefault().Value; // if (!string.IsNullOrEmpty(source)) // { // string[] srcParts = source.Split('?')[0].Split('.'); // if (!srcParts[srcParts.Length - 1].Equals("svg", StringComparison.InvariantCultureIgnoreCase)) // { // string rootUrl = websiteData?.rootaliasurl?.url?.Value; // string path = websiteData?._system?.request?.urlpath?.Value; // string srcSetValue = GetSrcSetValue(rootUrl, path, source); // if (srcSetValue != null) // { // returnNode.Attributes.Add("srcset", srcSetValue); // //returnNode.Attributes.Remove("src"); // } // } // } //} if (returnNode.Name?.ToLower() == LanguageAttributes.KScript.GetDescription()?.ToLower()) { TagProcessor processor = processorFactory.GetProcessor(returnNode.Name); processor.ProcessNode(ref returnNode, null, classNameAlias, classNameAliasDepth, depth, customerId, evaluator, entity, websiteData, viewDetails, queryString, functionLog, isDetailsView, isNFSite); } } return(returnNode); } catch (Exception ex) { throw; } }
public void HandleText(HtmlTextNode node) { if (IsTag(node.Text)) { node.Text = ""; } char[] ch = HttpUtility.HtmlDecode(node.Text).ToCharArray(); int start = 0; int length = ch.Length; textElementIdx++; if (flush) { FlushBlock(); flush = false; } if (inIgnorableElement != 0) { return; } char c; bool startWhitespace = false; bool endWhitespace = false; if (length == 0) { return; } int end = start + length; for (int i = start; i < end; i++) { if (IsWhiteSpace(ch [i])) { ch [i] = ' '; } } while (start < end) { c = ch [start]; if (c == ' ') { startWhitespace = true; start++; length--; } else { break; } } while (length > 0) { c = ch [start + length - 1]; if (c == ' ') { endWhitespace = true; length--; } else { break; } } if (length == 0) { if (startWhitespace || endWhitespace) { if (!sbLastWasWhitespace) { textBuilder.Append(' '); tokenBuilder.Append(' '); } sbLastWasWhitespace = true; } else { sbLastWasWhitespace = false; } lastEvent = NBoilerpipeContentHandler.Event.WHITESPACE; return; } if (startWhitespace) { if (!sbLastWasWhitespace) { textBuilder.Append(' '); tokenBuilder.Append(' '); } } if (blockTagLevel == -1) { blockTagLevel = tagLevel; } textBuilder.Append(ch, start, length); tokenBuilder.Append(ch, start, length); if (endWhitespace) { textBuilder.Append(' '); tokenBuilder.Append(' '); } sbLastWasWhitespace = endWhitespace; lastEvent = NBoilerpipeContentHandler.Event.CHARACTERS; currentContainedTextElements.Add(textElementIdx); }
/// update some or generate all cssbox /// </summary> /// <param name="parentElement"></param> /// <param name="fullmode">update all nodes (true) or somenode (false)</param> internal void UpdateChildBoxes(HtmlElement parentElement, bool fullmode) { //recursive *** //first just generate into primary pricipal box //layout process will correct it later switch (parentElement.ChildrenCount) { case 0: { } break; case 1: { CssBox hostBox = HtmlElement.InternalGetPrincipalBox(parentElement); //only one child -- easy DomNode child = parentElement.GetChildNode(0); int newBox = 0; switch (child.NodeType) { case HtmlNodeType.TextNode: { HtmlTextNode singleTextNode = (HtmlTextNode)child; RunListHelper.AddRunList(hostBox, parentElement.Spec, singleTextNode); } break; case HtmlNodeType.ShortElement: case HtmlNodeType.OpenElement: { HtmlElement childElement = (HtmlElement)child; var spec = childElement.Spec; if (spec.CssDisplay == CssDisplay.None) { return; } newBox++; //-------------------------------------------------- if (fullmode) { CssBox newbox = CreateBox(hostBox, childElement, fullmode); childElement.SetPrincipalBox(newbox); } else { CssBox existing = HtmlElement.InternalGetPrincipalBox(childElement); if (existing == null) { CssBox box = CreateBox(hostBox, childElement, fullmode); childElement.SetPrincipalBox(box); } else { //just insert hostBox.AppendChild(existing); if (!childElement.SkipPrincipalBoxEvalulation) { existing.Clear(); UpdateChildBoxes(childElement, fullmode); childElement.SkipPrincipalBoxEvalulation = true; } } } } break; } } break; default: { CssBox hostBox = HtmlElement.InternalGetPrincipalBox(parentElement); CssWhiteSpace ws = parentElement.Spec.WhiteSpace; int childCount = parentElement.ChildrenCount; int newBox = 0; for (int i = 0; i < childCount; ++i) { var childNode = parentElement.GetChildNode(i); switch (childNode.NodeType) { case HtmlNodeType.TextNode: { HtmlTextNode textNode = (HtmlTextNode)childNode; switch (ws) { case CssWhiteSpace.Pre: case CssWhiteSpace.PreWrap: { RunListHelper.AddRunList( CssBox.AddNewAnonInline(hostBox), parentElement.Spec, textNode); } break; case CssWhiteSpace.PreLine: { if (newBox == 0 && textNode.IsWhiteSpace) { continue; //skip } RunListHelper.AddRunList( CssBox.AddNewAnonInline(hostBox), parentElement.Spec, textNode); } break; default: { if (textNode.IsWhiteSpace) { continue; //skip } RunListHelper.AddRunList( CssBox.AddNewAnonInline(hostBox), parentElement.Spec, textNode); } break; } newBox++; } break; case HtmlNodeType.ShortElement: case HtmlNodeType.OpenElement: { HtmlElement childElement = (HtmlElement)childNode; var spec = childElement.Spec; if (spec.CssDisplay == CssDisplay.None) { continue; } if (fullmode) { CssBox box = CreateBox(hostBox, childElement, fullmode); } else { CssBox existingCssBox = HtmlElement.InternalGetPrincipalBox(childElement); if (existingCssBox == null) { CssBox box = CreateBox(hostBox, childElement, fullmode); } else { //just insert hostBox.AppendChild(existingCssBox); if (!childElement.SkipPrincipalBoxEvalulation) { existingCssBox.Clear(); UpdateChildBoxes(childElement, fullmode); childElement.SkipPrincipalBoxEvalulation = true; } } } newBox++; } break; default: { } break; } } } break; } //---------------------------------- //summary formatting context //that will be used on layout process //---------------------------------- }
public static void AddRunList(CssBox toBox, BoxSpec spec, HtmlTextNode textnode) { AddRunList(toBox, spec, textnode.InternalGetRuns(), textnode.GetOriginalBuffer(), textnode.IsWhiteSpace); }
/// <summary> /// 解析单个页面源码 /// </summary> public String BuildPage(String PageCode, Int64 DataID) { #region 替换组件类型的yytag HtmlDocument doc = HtmlDocument(PageCode); var Tags = SelectNodes(doc, "//yytag"); if (Tags == null) { return(doc.DocumentNode.OuterHtml); } for (Int32 i = 0; i < Tags.Count; i++) { if (!Tags[i].HasAttributes) { continue; } if (Tags[i].Attributes["id"] != null) { var ComponentID = long.Parse(Tags[i].Attributes["id"].Value); Tags[i].InnerHtml = GetPageCode(ComponentID); } } #endregion PageCode = ReferenceTagCode(doc.DocumentNode.OuterHtml); doc = HtmlDocument(PageCode); Tags = SelectNodes(doc, "//yytag"); if (Tags == null) { return(doc.DocumentNode.OuterHtml); } for (Int32 i = 0; i < Tags.Count; i++) { if (!Tags[i].HasAttributes || Tags[i].Attributes["modal"] == null) { continue; } #region View String View = String.Empty; #region 如果循环的html标签不在yytag里 if (Tags[i].Attributes["view"] != null) { View = doc.GetElementbyId(Tags[i].Attributes["view"].Value).InnerHtml; } #endregion #region 如果循环的html标签在yytag里 else { View = Tags[i].InnerHtml; } #endregion #endregion if (!String.IsNullOrEmpty(View)) { #region Modal var Modal = new List <Dictionary <String, String> >(); using (var Reader = SqlHelper.ExecuteReader(DB.Database.Connection.ConnectionString, CommandType.Text, String.Format(Tags[i].Attributes["modal"].Value, DataID))) { var Columns = Reader.GetSchemaTable().Rows.Cast <DataRow>().Select(row => row["ColumnName"] as String).ToList(); while (Reader.Read()) { var ModalItem = new Dictionary <String, String>(); for (Int32 j = 0; j < Columns.Count; j++) { ModalItem.Add(Columns[j], Reader[Columns[j]].ToString()); } Modal.Add(ModalItem); } } #endregion #region Content String Content = V8Build(View, new { Modal = Modal }); #endregion #region Render #region 如果模板在指定ID的元素里,就替换InnerHtml if (Tags[i].Attributes["view"] != null) { doc.GetElementbyId(Tags[i].Attributes["view"].Value).InnerHtml = Content; } #endregion #region 如果模板在YYTag标签里,就替换到当前YYTag后面 else { HtmlTextNode nnode = doc.CreateTextNode(Content); Tags[i].ParentNode.InsertAfter(nnode, Tags[i]); } #endregion #endregion } #region ClearTag Tags[i].ParentNode.RemoveChild(Tags[i]); #endregion } String ResultCode = ReferenceTagCode(doc.DocumentNode.OuterHtml); return(ResultCode); }
private void load_DOMInternal(HtmlNode node, TreeViewItem tvi) { TreeViewItem new_tvi = new TreeViewItem(); switch (node.NodeType) { case HtmlNodeType.Comment: HtmlCommentNode commentNode = (HtmlCommentNode)node; string outerHtml = commentNode.OuterHtml; Color foreColor; if (outerHtml.ToUpper().Contains("DOCTYPE")) { foreColor = Colors.Gray; this.tvHTML_DOM.Items.Add(new_tvi); this._DOM_map.Add(node, new_tvi); } else { return; // DOM树不包含注释。 } new_tvi.Header = new Run(outerHtml) { Foreground = getBrush(foreColor) }; return; case HtmlNodeType.Document: case HtmlNodeType.Element: break; case HtmlNodeType.Text: if (tvi == null) { return; // DOM树文档不支持文本。 } HtmlTextNode textNode = (HtmlTextNode)node; string text = textNode.Text.Trim(); if (text == string.Empty) { return; } new_tvi.Header = text; tvi.Items.Add(new_tvi); this._DOM_map.Add(node, new_tvi); return; default: throw new InvalidOperationException(); } if (node.NodeType == HtmlNodeType.Element) { TextBlock tb = new TextBlock(); tb.Inlines.Add(new Run(string.Format("<{0}", node.Name)) { Foreground = getBrush(Colors.Blue) }); HtmlAttributeCollection attributes = node.Attributes; foreach (HtmlAttribute attribute in attributes) { tb.Inlines.Add(" "); tb.Inlines.Add(new Run(attribute.Name) { Foreground = getBrush(Colors.Red) }); tb.Inlines.Add("="); tb.Inlines.Add(new Run(string.Format("\"{0}\"", HttpUtility.HtmlEncode(attribute.Value))) { Foreground = getBrush(Colors.Purple) }); } tb.Inlines.Add(new Run(">") { Foreground = getBrush(Colors.Blue) }); new_tvi.Header = tb; if (tvi == null) { this.tvHTML_DOM.Items.Add(new_tvi); } else { tvi.Items.Add(new_tvi); } this._DOM_map.Add(node, new_tvi); } TreeViewItem childItem = (node.NodeType == HtmlNodeType.Document) ? null : new_tvi; foreach (HtmlNode childNode in node.ChildNodes) { this.load_DOMInternal(childNode, childItem); } if (node.NodeType == HtmlNodeType.Element) { TreeViewItem new_tvi_open = new_tvi; TreeViewItem new_tvi_close = new TreeViewItem() { Visibility = Visibility.Collapsed }; if (tvi == null) { this.tvHTML_DOM.Items.Add(new_tvi_close); } else { tvi.Items.Add(new_tvi_close); } new_tvi_open.Expanded += (sender, e) => { TreeViewItem item = (TreeViewItem)sender; if (item.Items.Count == 0) { return; } new_tvi_close.Visibility = Visibility.Visible; }; new_tvi_open.Collapsed += (sender, e) => { TreeViewItem item = (TreeViewItem)sender; if (item.Items.Count == 0) { return; } new_tvi_close.Visibility = Visibility.Collapsed; }; new_tvi_close.SetBinding( TreeViewItem.BackgroundProperty, new Binding() { Source = new_tvi_open, Path = new PropertyPath(TreeViewItem.BackgroundProperty) } ); new_tvi_close.Header = new Run(string.Format("</{0}>", node.Name)) { Foreground = getBrush(Colors.Blue) }; new_tvi_open.IsExpanded = true; } }
private void load_SORTEDInternal(HtmlNode node, Paragraph p) { switch (node.NodeType) { case HtmlNodeType.Comment: HtmlCommentNode commentNode = (HtmlCommentNode)node; string outerHtml = commentNode.OuterHtml; Color foreColor; if (outerHtml.ToUpper().Contains("DOCTYPE")) { foreColor = Colors.Gray; } else { foreColor = Colors.Green; } p.Inlines.Add(new Run(outerHtml) { Foreground = getBrush(foreColor) }); return; case HtmlNodeType.Document: case HtmlNodeType.Element: break; case HtmlNodeType.Text: HtmlTextNode textNode = (HtmlTextNode)node; string text = textNode.Text; p.Inlines.Add(text); return; default: throw new InvalidOperationException(); } if (node.NodeType == HtmlNodeType.Element) { p.Inlines.Add(new Run(string.Format("<{0}", node.Name)) { Foreground = getBrush(Colors.Blue) }); HtmlAttributeCollection attributes = node.Attributes; foreach (HtmlAttribute attribute in attributes) { p.Inlines.Add(" "); p.Inlines.Add(new Run(attribute.Name) { Foreground = getBrush(Colors.Red) }); p.Inlines.Add("="); p.Inlines.Add(new Run(string.Format("\"{0}\"", HttpUtility.HtmlEncode(attribute.Value))) { Foreground = getBrush(Colors.Purple) }); } if (node.ChildNodes.Count == 0) { if (attributes.Count == 0) { p.Inlines.Add(" "); } p.Inlines.Add(new Run("/>") { Foreground = getBrush(Colors.Blue) }); } else { p.Inlines.Add(new Run(">") { Foreground = getBrush(Colors.Blue) }); } } foreach (HtmlNode childNode in node.ChildNodes) { this.load_SORTEDInternal(childNode, p); } if (node.NodeType == HtmlNodeType.Element && node.ChildNodes.Count != 0) { p.Inlines.Add(new Run(string.Format("</{0}>", node.Name)) { Foreground = getBrush(Colors.Blue) }); } }