/// <summary> /// Main function for parsing process /// </summary> /// <param name="text">text to parse</param> /// <param name="baseForeColor">base Font color</param> /// <param name="baseFont">base font</param> /// <param name="fontSize">base font size</param> /// <param name="aligment">base textaligment</param> /// <param name="fontStyle"> base font style etc. Regular, Bold</param> /// <returns>Formatted text block that contains the whole structure</returns> public static FormattedTextBlock Parse(string text, Color baseForeColor, string baseFont, float fontSize, FontStyle fontStyle, ContentAlignment aligment) { if (string.IsNullOrEmpty(text)) { return(new FormattedTextBlock()); } Stack <FormattedText.HTMLLikeListType> lastListType = new Stack <FormattedText.HTMLLikeListType>(); lastListType.Push(FormattedText.HTMLLikeListType.None); text = text.Replace("\\<", "<").Replace("\\>", ">").Replace("\r\n", "<br>").Replace("\n", "<br>"); //prepare initially block FormattedTextBlock textBlock = new FormattedTextBlock(); FormattedText previousFormattedText = new FormattedText();//this is a base item for creating HTML previousFormattedText.FontColor = baseForeColor; previousFormattedText.FontName = baseFont; previousFormattedText.FontSize = fontSize; previousFormattedText.ContentAlignment = aligment; previousFormattedText.FontStyle = fontStyle; //create tokens StringTokenizer tokenizer = new StringTokenizer(text, "<"); int count = tokenizer.Count(); bool hasOpenTag = text.IndexOf("<") > -1; TextLine currentLine = new TextLine(); textBlock.Lines.Add(currentLine); bool shouldProduceNewLine = false; TinyHTMLParsersData parsersData = new TinyHTMLParsersData(); //enumerate tokens for (int i = 0; i < count; ++i) { FormattedText currentItem = ProcessToken(ref previousFormattedText, tokenizer, hasOpenTag, parsersData, ref shouldProduceNewLine); if (!string.IsNullOrEmpty(currentItem.HtmlTag) && currentItem.HtmlTag.Length >= 1 && shouldProduceNewLine) { currentLine = new TextLine(); textBlock.Lines.Add(currentLine); if (currentItem.HtmlTag.Length >= 2) { currentItem.HtmlTag = currentItem.HtmlTag.TrimEnd(' ').Trim('/'); } shouldProduceNewLine = (!string.IsNullOrEmpty(currentItem.text) && currentItem.text.Trim().Length == 0); } currentLine.List.Add(currentItem); previousFormattedText = new FormattedText(currentItem); } return(textBlock); }
private static void ProcessSpan(ref FormattedText currentFormattedText, string lowerHtmlTag, string htmlTag, bool isClosingTag, TinyHTMLParsersData parserData) { if (isClosingTag) { if (parserData.lastFormattedText.Count > 0) { currentFormattedText = parserData.lastFormattedText.Pop(); currentFormattedText.ShouldDisplayBullet = false; } return; } parserData.lastFormattedText.Push(new FormattedText(currentFormattedText)); string style = ParseAttribute(htmlTag, lowerHtmlTag, "style"); string value = ProcessStyle(style, "color"); if (!string.IsNullOrEmpty(value)) { currentFormattedText.FontColor = ParseColor(value, currentFormattedText.FontColor); } value = ProcessStyle(style, "background-color"); if (!string.IsNullOrEmpty(value)) { currentFormattedText.BgColor = ParseColor(value, currentFormattedText.BgColor); } value = ProcessStyle(style, "font-family"); if (!string.IsNullOrEmpty(value)) { currentFormattedText.FontName = ParseFont(value); } value = ProcessStyle(style, "font-size"); if (!string.IsNullOrEmpty(value)) { currentFormattedText.FontSize = ParseNumber(value, currentFormattedText.FontSize); } }
/// <summary> /// process single token from Html string /// </summary> /// <param name="prevItem"></param> /// <param name="tokenizer"></param> /// <param name="hasOpenTag"></param> /// <param name="parserData"></param> /// <param name="shouldProduceNewLine"></param> /// <returns>a FormattedText object</returns> private static FormattedText ProcessToken(ref FormattedText prevItem, StringTokenizer tokenizer, bool hasOpenTag, TinyHTMLParsersData parserData, ref bool shouldProduceNewLine) { string currentToken = tokenizer.NextToken(); //text block StringTokenizer currentCommand = new StringTokenizer(currentToken, ">"); bool hasCloseTag = currentToken.IndexOf(">") > -1; string htmlTag = currentCommand.NextToken(); string text = currentCommand.NextToken(); FormattedText item = new FormattedText(prevItem); if (!hasOpenTag || !hasCloseTag) { item.text = htmlTag; //only text without htmlTag item.HtmlTag = string.Empty; } else { bool isKnowCommand = ApplyHTMLSettingsFromTag(ref item, prevItem, htmlTag, parserData, ref shouldProduceNewLine, ref text); if (isKnowCommand) { item.text = text; } else { item.text = htmlTag + text; } item.HtmlTag = htmlTag; } if (!string.IsNullOrEmpty(item.text)) { item.text = item.text.Replace("<", "<").Replace(">", ">"); } item.StartNewLine = shouldProduceNewLine; return(item); }
private static void ProcessSingleListEntry(bool isCloseTag, ref int numberCount, FormattedText currentFormattedText, TinyHTMLParsersData parserData) { FormattedText.HTMLLikeListType listType = parserData.lastListType.Peek(); currentFormattedText.ShouldDisplayBullet = !isCloseTag; if (listType != FormattedText.HTMLLikeListType.OrderedList) { return; } if (!isCloseTag) { ++numberCount; } currentFormattedText.Number = numberCount; }
/// <summary> /// Parse single HTML tag and apply settings /// </summary> /// <param name="currentFormattedText"></param> /// <param name="prevText"></param> /// <param name="htmlTag"></param> /// <param name="parserData"></param> /// <param name="shouldProduceNewLine"></param> /// <param name="text"></param> public static bool ApplyHTMLSettingsFromTag(ref FormattedText currentFormattedText, FormattedText prevText, string htmlTag, TinyHTMLParsersData parserData, ref bool shouldProduceNewLine, ref string text) { if (string.IsNullOrEmpty(htmlTag)) { return(true); } htmlTag = htmlTag.Trim('<', '>'); bool isClosingTag = htmlTag.StartsWith("/"); currentFormattedText.IsClosingTag = isClosingTag; if (isClosingTag) { htmlTag = htmlTag.TrimStart('/'); } string lowerHtmlTag = htmlTag.ToLower(); bool isKnowCommand = true; if (lowerHtmlTag == "i" || lowerHtmlTag == "em") { currentFormattedText.FontStyle = ProcessFontStyle(currentFormattedText.FontStyle, FontStyle.Italic, isClosingTag); } else if (lowerHtmlTag == "b" || lowerHtmlTag == "strong") { currentFormattedText.FontStyle = ProcessFontStyle(currentFormattedText.FontStyle, FontStyle.Bold, isClosingTag); } else if (lowerHtmlTag == "u") { currentFormattedText.FontStyle = ProcessFontStyle(currentFormattedText.FontStyle, FontStyle.Underline, isClosingTag); } else if (lowerHtmlTag.StartsWith("color") && htmlTag.Length > 6) { currentFormattedText.FontColor = ParseColor(htmlTag.Substring(6), currentFormattedText.FontColor); } else if (lowerHtmlTag.StartsWith("size=") || lowerHtmlTag.StartsWith("size =")) { currentFormattedText.FontSize = ParseSize(htmlTag, prevText.FontSize); } else if ((lowerHtmlTag.StartsWith("font=") || lowerHtmlTag.StartsWith("font =")) && htmlTag.Length > 5) { currentFormattedText.FontName = ParseFont(htmlTag.Substring(5)); } else if (lowerHtmlTag == "strike") { currentFormattedText.FontStyle = ProcessFontStyle(currentFormattedText.FontStyle, FontStyle.Strikeout, isClosingTag); } else if (lowerHtmlTag.StartsWith("bgcolor")) { currentFormattedText.BgColor = ProcessBgColor(lowerHtmlTag, currentFormattedText.BgColor, isClosingTag); } //lists else if (lowerHtmlTag == "ul") { ProcessListEntry(isClosingTag, FormattedText.HTMLLikeListType.List, parserData.lastListType, parserData.lastListNumberCount, currentFormattedText); } else if (lowerHtmlTag == "ol") { ProcessListEntry(isClosingTag, FormattedText.HTMLLikeListType.OrderedList, parserData.lastListType, parserData.lastListNumberCount, currentFormattedText); } else if (lowerHtmlTag == "li") { int lastNumber = 0; shouldProduceNewLine = !shouldProduceNewLine && !isClosingTag; if (parserData.lastListNumberCount.Count > 0) { lastNumber = parserData.lastListNumberCount.Pop(); } if (parserData.lastListType.Count > 0) { ProcessSingleListEntry(isClosingTag, ref lastNumber, currentFormattedText, parserData); } parserData.lastListNumberCount.Push(lastNumber); } //end lists else if (lowerHtmlTag == "html") { } else if (lowerHtmlTag == "br" || lowerHtmlTag == "br /" || lowerHtmlTag == "br/") { shouldProduceNewLine = !isClosingTag; } else if (lowerHtmlTag == "p") { if (isClosingTag) { shouldProduceNewLine = false; } else { if (!prevText.IsClosingTag && !prevText.StartNewLine) { shouldProduceNewLine = !shouldProduceNewLine; } } } else if (lowerHtmlTag.StartsWith("img ")) { string imageName = ParseAttribute(htmlTag, lowerHtmlTag, "src"); string width = ParseAttribute(htmlTag, lowerHtmlTag, "width"); string height = ParseAttribute(htmlTag, lowerHtmlTag, "height"); SetImage(imageName, width, height, currentFormattedText); } else if (lowerHtmlTag.StartsWith("a")) { ProcessLink(currentFormattedText, htmlTag, lowerHtmlTag, isClosingTag, ref text); } else if (lowerHtmlTag.StartsWith("span")) { ProcessSpan(ref currentFormattedText, lowerHtmlTag, htmlTag, isClosingTag, parserData); } else { isKnowCommand = false; } //if (parserData.shouldClearProduceBullets) //{ // currentFormattedText.ShouldDisplayBullet = false; // parserData.shouldClearProduceBullets = false; //} return(isKnowCommand); }