257 lines
10 KiB
C#

using System;
using System.Text;
using System.IO;
using System.Xml;
using System.Collections;
using System.Text.RegularExpressions;
#if AdvTree
namespace DevComponents.Tree.TextMarkup
#elif DOTNETBAR
namespace DevComponents.DotNetBar.TextMarkup
#elif SUPERGRID
namespace DevComponents.SuperGrid.TextMarkup
#elif LAYOUT
namespace DevComponents.DotNetBar.Layout.TextMarkup
#endif
{
internal class MarkupParser
{
#region Private Variables
private static string TextElementName = "text";
private static string BodyTag = "body";
#endregion
#region Internal Implementation
public static BodyElement Parse(string text)
{
StringBuilder plainText = new StringBuilder(text.Length);
BodyElement root = new BodyElement();
root.HasExpandElement = false;
MarkupElement currentParent = root;
Stack openTags = new Stack();
openTags.Push(root);
// Input text is not wrapped into the container tag so we wrap it here
text = text.Replace(" ", "{ent_nbsp}");
text = text.Replace("&zwsp;", "{ent_zwsp}");
text = text.Replace("<", "{ent_lt}");
text = text.Replace(">", "{ent_gt}");
text = text.Replace("&", "{ent_amp}");
text = text.Replace("|", "{ent_l}");
text = text.Replace("&", "|");
text = text.Replace("{ent_nbsp}", " ");
text = text.Replace("{ent_zwsp}", "&zwsp;");
text = text.Replace("{ent_lt}", "<");
text = text.Replace("{ent_gt}", ">");
StringReader sr = new StringReader("<"+BodyTag+">" + text + "</"+BodyTag+">");
#if !DEBUG
try
#endif
{
XmlTextReader reader = new XmlTextReader(sr);
//reader.EntityHandling = EntityHandling.ExpandCharEntities;
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element)
{
if (reader.Name == BodyTag)
continue;
MarkupElement el = CreateMarkupElement(reader.Name);
if (el == null)
{
reader.Skip();
continue;
}
else if (el is ExpandElement)
root.HasExpandElement = true;
if (el is IActiveMarkupElement)
root.ActiveElements.Add(el);
// Parse any attributes here
if (reader.AttributeCount > 0)
{
el.ReadAttributes(reader);
reader.MoveToElement();
}
currentParent.Elements.Add(el);
if (el is ContainerElement)
currentParent = el;
if (!reader.IsEmptyElement)
openTags.Push(el);
}
else if (reader.NodeType == XmlNodeType.Text)
{
if (reader.Value.Length == 1)
{
TextElement el = CreateMarkupElement(TextElementName) as TextElement;
if (reader.Value == " ")
{
el.TrailingSpace = true;
plainText.Append(' ');
}
else
{
el.Text = reader.Value;
el.Text = el.Text.Replace("|", "&");
el.Text = el.Text.Replace("{ent_l}", "|");
el.Text = el.Text.Replace("{ent_amp}", "&&");
plainText.Append(el.Text+" ");
}
currentParent.Elements.Add(el);
}
else
{
string s = reader.Value;
if (s.StartsWith("\r\n"))
s = s.TrimStart(new char[] { '\r', '\n' });
s = s.Replace("\r\n", " ");
string[] words = s.Split(' ');
bool space = false;
if (currentParent.Elements.Count > 0 && currentParent.Elements[currentParent.Elements.Count - 1] is NewLine)
space = true;
for (int i = 0; i < words.Length; i++)
{
if (words[i].Length == 0)
{
if (space)
continue;
space = true;
}
else
space = false;
TextElement el = CreateMarkupElement(TextElementName) as TextElement;
el.Text = words[i].Replace("|","&");
el.Text = el.Text.Replace("{ent_l}", "|");
el.Text = el.Text.Replace("{ent_amp}", "&&");
plainText.Append(el.Text + " ");
if (i < words.Length - 1)
{
el.TrailingSpace = true;
space = true;
}
currentParent.Elements.Add(el);
}
}
}
else if (reader.NodeType == XmlNodeType.Whitespace)
{
if (reader.Value.IndexOf(' ') >= 0)
{
TextElement el = CreateMarkupElement(TextElementName) as TextElement;
el.TrailingSpace = true;
currentParent.Elements.Add(el);
}
}
else if (reader.NodeType == XmlNodeType.EntityReference)
{
TextElement el = CreateMarkupElement(TextElementName) as TextElement;
if (reader.Name == "nbsp")
{
el.TrailingSpace = true;
}
else if (reader.Name == "zwsp")
{
el.TrailingSpace = false;
}
else
el.Text = reader.Name;
el.EnablePrefixHandling = false;
currentParent.Elements.Add(el);
}
else if (reader.NodeType == XmlNodeType.EndElement)
{
MarkupElement el = openTags.Pop() as MarkupElement;
if (el != currentParent)
{
currentParent.Elements.Add(new EndMarkupElement(el));
}
else
{
if (currentParent != root)
currentParent = currentParent.Parent;
}
}
}
}
#if !DEBUG
catch
{
return null;
}
#endif
root.PlainText = plainText.ToString();
return root;
}
public static MarkupElement CreateMarkupElement(string elementName)
{
if (elementName == "b" || elementName == "strong")
return new Strong();
else if (elementName == "i" || elementName == "em")
return new Italic();
else if (elementName == "u")
return new Underline();
else if (elementName == "br")
return new NewLine();
else if (elementName == "expand")
return new ExpandElement();
else if (elementName == "a")
return new HyperLink();
else if (elementName == "p")
return new Paragraph();
else if (elementName == "div")
return new Div();
else if (elementName == "span")
return new Span();
else if (elementName == "img")
return new ImageElement();
else if (elementName == "h1")
return new Heading();
else if (elementName == "h2")
return new Heading(2);
else if (elementName == "h3")
return new Heading(3);
else if (elementName == "h4")
return new Heading(4);
else if (elementName == "h5")
return new Heading(5);
else if (elementName == "h6")
return new Heading(6);
else if (elementName == "font")
return new FontElement();
else if (elementName == "s" || elementName == "strike")
return new Strike();
else if (elementName == TextElementName)
return new TextElement();
else if (elementName == "symbol")
return new SymbolElement();
return null;
}
/// <summary>
/// Tests whether input text could be markup text.
/// </summary>
/// <param name="text">Text to test.</param>
/// <returns>true if text could be markup, otherwise false</returns>
public static bool IsMarkup(ref string text)
{
if (text == null || text.IndexOf("</") < 0 && text.IndexOf("/>") < 0)
return false;
return true;
}
internal static string RemoveExpand(string text)
{
return Regex.Replace(text, "<expand.*?>", "", RegexOptions.IgnoreCase);
}
#endregion
}
}