private string GetString(TextElement[] texts) { StringBuilder builder = new StringBuilder(); foreach (TextElement i in texts) { if (i is TextSpan) { TextSpan s = (TextSpan)i; builder.Append(Escape(s.Text)); } else if (i is CodeSpan) { CodeSpan s = (CodeSpan)i; builder.Append(Escape(s.Text)); } else if (i is HyperlinkSpan) { HyperlinkSpan s = (HyperlinkSpan)i; builder.Append(Escape(s.Text)); } } return(builder.ToString()); }
public void ParsesDocumentWithMultipleNodes() { string documentText = string.Format( @" # {0} {2} ``` {1} ``` ## {0} {2} [{3}]({4}) ", headingText, codeBlockText, paragraphText, hyperlinkText, hyperlinkUri); MarkdownParser markdownParser = new MarkdownParser(); DocumentNode documentNode = markdownParser.ParseString( documentText); HeadingNode headingNode = this.AssertNodeType <HeadingNode>( documentNode.Children.ElementAtOrDefault(0), MarkdownNodeType.Heading); Assert.Equal(headingText, headingNode.Text); Assert.Equal(1, headingNode.HeadingLevel); CodeBlockNode codeBlockNode = this.AssertNodeType <CodeBlockNode>( documentNode.Children.ElementAtOrDefault(2), MarkdownNodeType.CodeBlock); Assert.Equal(codeBlockText, codeBlockNode.Text); headingNode = this.AssertNodeType <HeadingNode>( documentNode.Children.ElementAtOrDefault(3), MarkdownNodeType.Heading); Assert.Equal(headingText, headingNode.Text); Assert.Equal(2, headingNode.HeadingLevel); ParagraphNode paragraphNode = this.AssertNodeType <ParagraphNode>( documentNode.Children.ElementAtOrDefault(4), MarkdownNodeType.Paragraph); Assert.Equal(paragraphText.Replace("\r\n", " "), paragraphNode.Spans.First().Text); HyperlinkSpan hyperlinkSpan = Assert.IsType <HyperlinkSpan>( paragraphNode.Spans.ElementAt(1)); Assert.Equal(hyperlinkText, hyperlinkSpan.Text); Assert.Equal(hyperlinkUri, hyperlinkSpan.Uri); }
public void ParsesHyperlinkWithoutLink() { ParagraphNode paragraphNode = this.ParseAndGetExpectedChild <ParagraphNode>( string.Format( "[{0}]()", hyperlinkText), MarkdownNodeType.Paragraph); HyperlinkSpan hyperlinkSpan = Assert.IsType <HyperlinkSpan>( paragraphNode.Spans.FirstOrDefault()); Assert.Equal(hyperlinkText, hyperlinkSpan.Text); Assert.Equal("", hyperlinkSpan.Uri); }
private string GetTextFromParagraphSpans(IEnumerable <ParagraphSpan> spans) { // in preserve formatting there is only one span all the time if (spans.Count() == 1) { var textSpan = spans.First() as TextSpan; if (textSpan.ParserMode == ParserMode.FormattingPreserve) { return(textSpan.Text); } } StringBuilder sb = new StringBuilder(); bool first = true; bool previousIsHyperLink = false; foreach (var paragraphSpan in spans) { // TODO: make it handle hyperlinks, codesnippets, etc more wisely HyperlinkSpan hyperlink = paragraphSpan as HyperlinkSpan; if (!first && hyperlink != null) { sb.Append(" "); } else if (previousIsHyperLink) { sb.Append(" "); } sb.Append(paragraphSpan.Text); if (hyperlink != null) { if (!string.IsNullOrWhiteSpace(hyperlink.Uri)) { sb.AppendFormat(" ({0})", hyperlink.Uri); } else { previousIsHyperLink = paragraphSpan is HyperlinkSpan; } } first = false; } return(sb.ToString()); }
private void Parse(Status status) { StringBuilder builder = new StringBuilder(); while (index < text.Length) { switch (text[index]) { case '*': if (status == Status.STRONG) { if (Match(text, index + 1, '*')) { if (builder.Length > 0) { elems.Add(new TextSpan(builder.ToString())); builder.Clear(); } elems.Add(new StrongCloseTag()); index += 2; return; } } if (status == Status.EMPHASIS) { if (builder.Length > 0) { elems.Add(new TextSpan(builder.ToString())); builder.Clear(); } elems.Add(new EmphasisCloseTag()); index += 1; return; } if (Match(text, index + 1, '*')) { // ** if (builder.Length > 0) { elems.Add(new TextSpan(builder.ToString())); builder.Clear(); } index += 2; elems.Add(new StrongOpenTag()); Parse(Status.STRONG); } else { // * if (builder.Length > 0) { elems.Add(new TextSpan(builder.ToString())); builder.Clear(); } index += 1; elems.Add(new EmphasisOpenTag()); Parse(Status.EMPHASIS); } break; case '`': if (builder.Length > 0) { elems.Add(new TextSpan(builder.ToString())); builder.Clear(); } // `XXXXXXXXXXXXXXXXXXX` CodeSpan codeSpan = ParseCode(text, ref index); if (codeSpan != null) { elems.Add(codeSpan); } break; case '\\': if (index + 1 < text.Length) { // \? builder.Append(text[index + 1]); index += 2; } else { // \マークは消える index += 1; } break; case '[': if (Match(text, index + 1, '[')) { // [[ if (builder.Length > 0) { elems.Add(new TextSpan(builder.ToString())); builder.Clear(); } HyperlinkSpan tag = ParseUrlHyperlink(text, ref index); if (tag != null) { elems.Add(tag); } continue; } else { // [ if (builder.Length > 0) { elems.Add(new TextSpan(builder.ToString())); builder.Clear(); } HyperlinkSpan tag = ParseHyperlink(text, ref index); if (tag != null) { elems.Add(tag); } } break; case '!': if (Match(text, index + 1, '[')) { // ![ if (builder.Length > 0) { elems.Add(new TextSpan(builder.ToString())); builder.Clear(); } ImageSpan tag = ParseImage(text, ref index); if (tag != null) { elems.Add(tag); } continue; } break; case '<': string element; Dictionary <string, string> attrs; bool closed; if (ParseHtmlTagClose(text, ref index, out element)) { if (builder.Length > 0) { elems.Add(new TextSpan(builder.ToString())); builder.Clear(); } if (status == Status.HTML_EM) { if (element.ToLower() == "em") { elems.Add(new EmphasisCloseTag()); return; } } else if (status == Status.HTML_STRONG) { if (element.ToLower() == "strong") { elems.Add(new StrongCloseTag()); return; } } else if (status == Status.HTML_DEL) { if (element.ToLower() == "del") { elems.Add(new StrikethroughCloseTag()); return; } } else if (status == Status.HTML_SUP) { if (element.ToLower() == "sup") { elems.Add(new SuperscriptCloseTag()); return; } } else if (status == Status.HTML_SUB) { if (element.ToLower() == "sub") { elems.Add(new SubscriptCloseTag()); return; } } else if (status == Status.HTML_SMALL) { if (element.ToLower() == "small") { elems.Add(new SmallCloseTag()); return; } } throw new MdocParseException("予期せぬHTMLタグを検出しました。", line); } else if (ParseHtmlTagOpen(text, ref index, out closed, out element, out attrs)) { if (builder.Length > 0) { elems.Add(new TextSpan(builder.ToString())); builder.Clear(); } element = element.ToLower(); if (element == "em") { elems.Add(new EmphasisOpenTag()); if (closed) { elems.Add(new EmphasisCloseTag()); } else { Parse(Status.HTML_EM); } } else if (element == "strong") { elems.Add(new StrongOpenTag()); if (closed) { elems.Add(new StrongCloseTag()); } else { Parse(Status.HTML_STRONG); } } else if (element == "del") { elems.Add(new StrikethroughOpenTag()); if (closed) { elems.Add(new StrikethroughCloseTag()); } else { Parse(Status.HTML_DEL); } } else if (element == "sup") { elems.Add(new SuperscriptOpenTag()); if (closed) { elems.Add(new SuperscriptCloseTag()); } else { Parse(Status.HTML_SUP); } } else if (element == "sub") { elems.Add(new SubscriptOpenTag()); if (closed) { elems.Add(new SubscriptCloseTag()); } else { Parse(Status.HTML_SUB); } } else if (element == "small") { elems.Add(new SmallOpenTag()); if (closed) { elems.Add(new SmallCloseTag()); } else { Parse(Status.HTML_SMALL); } } else { throw new MdocParseException("予期せぬHTMLタグを検出しました。", line); } } break; default: builder.Append(text[index]); index += 1; break; } } if (builder.Length > 0) { elems.Add(new TextSpan(builder.ToString())); builder.Clear(); } if (status == Status.EMPHASIS) { throw new MdocParseException(MessageResource.EmphasisError, line); } if (status == Status.STRONG) { throw new MdocParseException(MessageResource.BoldError, line); } if (status == Status.HTML_DEL) { throw new MdocParseException(MessageResource.HtmlDelError, line); } if (status == Status.HTML_EM) { throw new MdocParseException(MessageResource.HtmlEmError, line); } if (status == Status.HTML_STRONG) { throw new MdocParseException(MessageResource.HtmlStrongError, line); } if (status == Status.HTML_SUP) { throw new MdocParseException(MessageResource.HtmlSupError, line); } if (status == Status.HTML_SUB) { throw new MdocParseException(MessageResource.HtmlSubError, line); } if (status == Status.HTML_SMALL) { throw new MdocParseException(MessageResource.HtmlSmallError, line); } }
private void WriteText(TextWriter writer, TextElement[] elems) { foreach (TextElement i in elems) { if (i is TextSpan) { TextSpan s = (TextSpan)i; writer.Write(Escape(s.Text)); } else if (i is CodeSpan) { CodeSpan s = (CodeSpan)i; writer.Write(Escape(s.Text)); } else if (i is EmphasisOpenTag) { writer.Write("<em>"); } else if (i is EmphasisCloseTag) { writer.Write("</em>"); } else if (i is StrongOpenTag) { writer.Write("<strong>"); } else if (i is StrongCloseTag) { writer.Write("</strong>"); } else if (i is StrikethroughOpenTag) { writer.Write("<strike>"); } else if (i is StrikethroughCloseTag) { writer.Write("</strike>"); } else if (i is SuperscriptOpenTag) { writer.Write("<sup>"); } else if (i is SuperscriptCloseTag) { writer.Write("</sup>"); } else if (i is SubscriptOpenTag) { writer.Write("<sub>"); } else if (i is SubscriptCloseTag) { writer.Write("</sub>"); } else if (i is SmallOpenTag) { writer.Write("<small>"); } else if (i is SmallCloseTag) { writer.Write("</small>"); } else if (i is HyperlinkSpan) { HyperlinkSpan s = (HyperlinkSpan)i; writer.Write("<a href=\"{1}\">{0}</a>", Escape(s.Text), Escape(s.Href)); } else if (i is ImageSpan) { ImageSpan s = (ImageSpan)i; writer.Write("<img src=\"{1}\" alt=\"{0}\"/>", Escape(s.Text), Escape(s.Source)); } } }