public void Format_PrefixWithoutNamespace_ReturnsPrefix() { var input = new[] { MarkupGrammar.TokenElementBegin(new DataName("div")), MarkupGrammar.TokenAttribute(new DataName("visible", "jbst", null)), MarkupGrammar.TokenPrimitive(false), MarkupGrammar.TokenElementEnd, }; const string expected = @"<div jbst:visible=""false""></div>"; var formatter = new HtmlFormatter(new DataWriterSettings()); var actual = formatter.Format(input); Assert.Equal(expected, actual); }
public void Format_HtmlEntityEuroEncodeNonAscii_ReturnsMarkup() { var input = new[] { MarkupGrammar.TokenPrimitive("€") }; const string expected = @"€"; var formatter = new HtmlFormatter(new DataWriterSettings()) { EncodeNonAscii = true }; var actual = formatter.Format(input); Assert.Equal(expected, actual); }
public void Format_SingleAttributeWhitespace_ReturnsMarkup() { var input = new[] { MarkupGrammar.TokenElementBegin(new DataName("root")), MarkupGrammar.TokenAttribute(new DataName("whitespace")), MarkupGrammar.TokenPrimitive(" this contains whitespace "), MarkupGrammar.TokenElementEnd }; const string expected = @"<root whitespace="" this contains whitespace ""></root>"; var formatter = new HtmlFormatter(new DataWriterSettings()); var actual = formatter.Format(input); Assert.Equal(expected, actual); }
public void Format_XmlEntityHex_ReturnsMarkup() { var input = new[] { MarkupGrammar.TokenPrimitive("\uABCD") }; const string expected = "\uABCD"; var formatter = new HtmlFormatter(new DataWriterSettings()) { EncodeNonAscii = false }; var actual = formatter.Format(input); Assert.Equal(expected, actual); }
public void Format_MathML_ReturnsMarkup() { var input = new[] { MarkupGrammar.TokenElementBegin(new DataName("p")), MarkupGrammar.TokenPrimitive(@"You can add a string to a number, but this stringifies the number:"), MarkupGrammar.TokenElementEnd, MarkupGrammar.TokenPrimitive("\r\n"), MarkupGrammar.TokenElementBegin(new DataName("math")), MarkupGrammar.TokenPrimitive("\r\n\t"), MarkupGrammar.TokenElementBegin(new DataName("ms")), MarkupGrammar.TokenPrimitive(@"x<y"), MarkupGrammar.TokenElementEnd, MarkupGrammar.TokenPrimitive("\r\n\t"), MarkupGrammar.TokenElementBegin(new DataName("mo")), MarkupGrammar.TokenPrimitive(@"+"), MarkupGrammar.TokenElementEnd, MarkupGrammar.TokenPrimitive("\r\n\t"), MarkupGrammar.TokenElementBegin(new DataName("mn")), MarkupGrammar.TokenPrimitive(@"3"), MarkupGrammar.TokenElementEnd, MarkupGrammar.TokenPrimitive("\r\n\t"), MarkupGrammar.TokenElementBegin(new DataName("mo")), MarkupGrammar.TokenPrimitive(@"="), MarkupGrammar.TokenElementEnd, MarkupGrammar.TokenPrimitive("\r\n\t"), MarkupGrammar.TokenElementBegin(new DataName("ms")), MarkupGrammar.TokenPrimitive(@"x<y3"), MarkupGrammar.TokenElementEnd, MarkupGrammar.TokenPrimitive("\r\n"), MarkupGrammar.TokenElementEnd, }; const string expected = @"<p>You can add a string to a number, but this stringifies the number:</p> <math> <ms>x<y</ms> <mo>+</mo> <mn>3</mn> <mo>=</mo> <ms>x<y3</ms> </math>"; var formatter = new HtmlFormatter(new DataWriterSettings()); var actual = formatter.Format(input); Assert.Equal(expected, actual); }
public void Format_ParentAndChildDifferentDefaultNamespaces_ReturnsMarkup() { var input = new[] { MarkupGrammar.TokenElementBegin(new DataName("foo", String.Empty, "http://json.org")), MarkupGrammar.TokenElementBegin(new DataName("child", String.Empty, "http://jsonfx.net")), MarkupGrammar.TokenPrimitive("text value"), MarkupGrammar.TokenElementEnd, MarkupGrammar.TokenElementEnd, }; const string expected = @"<foo xmlns=""http://json.org""><child xmlns=""http://jsonfx.net"">text value</child></foo>"; var formatter = new HtmlFormatter(new DataWriterSettings()); var actual = formatter.Format(input); Assert.Equal(expected, actual); }
public void Format_NamespacedChildTag_ReturnsMarkup() { var input = new[] { MarkupGrammar.TokenElementBegin(new DataName("foo")), MarkupGrammar.TokenElementBegin(new DataName("child", String.Empty, "http://example.com/schema")), MarkupGrammar.TokenPrimitive("value"), MarkupGrammar.TokenElementEnd, MarkupGrammar.TokenElementEnd }; const string expected = @"<foo><child xmlns=""http://example.com/schema"">value</child></foo>"; var formatter = new HtmlFormatter(new DataWriterSettings()); var actual = formatter.Format(input); Assert.Equal(expected, actual); }
public void Format_ParentAndChildSharePrefixedNamespace_ReturnsMarkup() { var input = new[] { MarkupGrammar.TokenElementBegin(new DataName("foo", "bar", "http://example.org")), MarkupGrammar.TokenElementBegin(new DataName("child", "bar", "http://example.org")), MarkupGrammar.TokenPrimitive("value"), MarkupGrammar.TokenElementEnd, MarkupGrammar.TokenElementEnd, }; const string expected = @"<bar:foo xmlns:bar=""http://example.org""><bar:child>value</bar:child></bar:foo>"; var formatter = new HtmlFormatter(new DataWriterSettings()); var actual = formatter.Format(input); Assert.Equal(expected, actual); }
public void Format_OverlappingNamespacedTagsErrorRecovery_ReturnsAutoBalanced() { var input = new[] { MarkupGrammar.TokenElementBegin(new DataName("odd", "a", "http://example.com/odd/a")), MarkupGrammar.TokenElementBegin(new DataName("auto-closed", "b", "http://example.com/auto-closed/b")), MarkupGrammar.TokenElementBegin(new DataName("even", "c", "http://example.com/even/c")), MarkupGrammar.TokenElementEnd, MarkupGrammar.TokenElementEnd, MarkupGrammar.TokenElementEnd, }; const string expected = @"<a:odd xmlns:a=""http://example.com/odd/a""><b:auto-closed xmlns:b=""http://example.com/auto-closed/b""><c:even xmlns:c=""http://example.com/even/c""></c:even></b:auto-closed></a:odd>"; var formatter = new HtmlFormatter(new DataWriterSettings()); var actual = formatter.Format(input); Assert.Equal(expected, actual); }
public void Format_OverlappingTagsAutoBalanced_ReturnsMarkupAsIs() { var input = new[] { MarkupGrammar.TokenElementBegin(new DataName("odd")), MarkupGrammar.TokenElementBegin(new DataName("auto-closed")), MarkupGrammar.TokenElementBegin(new DataName("even")), MarkupGrammar.TokenElementEnd, MarkupGrammar.TokenElementEnd, MarkupGrammar.TokenElementEnd }; const string expected = @"<odd><auto-closed><even></even></auto-closed></odd>"; var formatter = new HtmlFormatter(new DataWriterSettings()); var actual = formatter.Format(input); Assert.Equal(expected, actual); }
public void Format_XmlDocTypeExternal_ReturnsUnparsed() { var input = new[] { MarkupGrammar.TokenUnparsed("!", "", @"DOCTYPE html PUBLIC ""-//W3C//DTD XHTML 1.1//EN"" ""http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd""" ) }; const string expected = @"<!DOCTYPE html PUBLIC ""-//W3C//DTD XHTML 1.1//EN"" ""http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"">" ; var formatter = new HtmlFormatter(new DataWriterSettings()); var actual = formatter.Format(input); Assert.Equal(expected, actual); }
private void WriteXmlns(TextWriter writer, string prefix, string namespaceUri) { // " xmlns" writer.Write(MarkupGrammar.OperatorValueDelim); this.WriteLocalName(writer, "xmlns"); if (!String.IsNullOrEmpty(prefix)) { // ":prefix" writer.Write(MarkupGrammar.OperatorPrefixDelim); this.WriteLocalName(writer, prefix); } // ="value" writer.Write(MarkupGrammar.OperatorPairDelim); writer.Write(MarkupGrammar.OperatorStringDelim); HtmlFormatter.HtmlAttributeEncode(writer, namespaceUri, this.encodeNonAscii, this.canonicalForm); writer.Write(MarkupGrammar.OperatorStringDelim); }
public void Format_SingleEmptyAttributeHtmlStyle_ReturnsMarkup() { var input = new[] { MarkupGrammar.TokenElementBegin(new DataName("root")), MarkupGrammar.TokenAttribute(new DataName("noValue")), MarkupGrammar.TokenPrimitive(String.Empty), MarkupGrammar.TokenElementEnd }; const string expected = @"<root noValue></root>"; var formatter = new HtmlFormatter(new DataWriterSettings()) { EmptyAttributes = HtmlFormatter.EmptyAttributeType.Html }; var actual = formatter.Format(input); Assert.Equal(expected, actual); }
//[Fact(Skip="Embedded DOCTYPE not supported")] public void Format_XmlDocTypeLocal_ReturnsUnparsed() { var input = new[] { MarkupGrammar.TokenUnparsed("!", "", @"DOCTYPE doc [ <!ATTLIST normId id ID #IMPLIED> <!ATTLIST normNames attr NMTOKENS #IMPLIED> ]") }; const string expected = @"<!DOCTYPE doc [ <!ATTLIST normId id ID #IMPLIED> <!ATTLIST normNames attr NMTOKENS #IMPLIED> ]>"; var formatter = new HtmlFormatter(new DataWriterSettings()); var actual = formatter.Format(input); Assert.Equal(expected, actual); }
public void Format_DifferentPrefixSameNamespace_ReturnsMarkup() { // Not sure if this is correct: http://stackoverflow.com/questions/3312390 // "The namespace name for an unprefixed attribute name always has no value" // "The attribute value in a default namespace declaration MAY be empty. // This has the same effect, within the scope of the declaration, of there being no default namespace." // http://www.w3.org/TR/xml-names/#defaulting var input = new[] { MarkupGrammar.TokenElementBegin(new DataName("foo", String.Empty, "http://example.org")), MarkupGrammar.TokenAttribute(new DataName("key", "blah", "http://example.org")), MarkupGrammar.TokenPrimitive("value"), MarkupGrammar.TokenElementEnd, }; const string expected = @"<foo xmlns=""http://example.org"" key=""value""></foo>"; var formatter = new HtmlFormatter(new DataWriterSettings()); var actual = formatter.Format(input); Assert.Equal(expected, actual); }
public void Format_NestedDefaultNamespaces_ReturnsMarkup() { var input = new[] { MarkupGrammar.TokenElementBegin(new DataName("outer", String.Empty, "http://example.org/outer")), MarkupGrammar.TokenElementBegin(new DataName("middle-1", String.Empty, "http://example.org/inner")), MarkupGrammar.TokenElementBegin(new DataName("inner", String.Empty, "http://example.org/inner")), MarkupGrammar.TokenPrimitive("this should be inner"), MarkupGrammar.TokenElementEnd, MarkupGrammar.TokenElementEnd, MarkupGrammar.TokenElementBegin(new DataName("middle-2", String.Empty, "http://example.org/outer")), MarkupGrammar.TokenPrimitive("this should be outer"), MarkupGrammar.TokenElementEnd, MarkupGrammar.TokenElementEnd, }; const string expected = @"<outer xmlns=""http://example.org/outer""><middle-1 xmlns=""http://example.org/inner""><inner>this should be inner</inner></middle-1><middle-2>this should be outer</middle-2></outer>"; var formatter = new HtmlFormatter(new DataWriterSettings()); var actual = formatter.Format(input); Assert.Equal(expected, actual); }
public void Format_MultipleAttributesCanonicalForm_ReturnsCanonicalMarkup() { var input = new[] { MarkupGrammar.TokenElementVoid(new DataName("root")), MarkupGrammar.TokenAttribute(new DataName("whitespace")), MarkupGrammar.TokenPrimitive(" this contains whitespace "), MarkupGrammar.TokenAttribute(new DataName("no-value")), MarkupGrammar.TokenPrimitive(String.Empty), MarkupGrammar.TokenAttribute(new DataName("anyQuotedText")), MarkupGrammar.TokenPrimitive("/\\\uCAFE\uBABE\uAB98\uFCDE\ubcda\uef4A\b\f\n\r\t`1~!@#$%^&*()_+-=[]{}|;:',./<>?") }; const string expected = @"<root anyQuotedText=""/\" + "\uCAFE\uBABE\uAB98\uFCDE\uBCDA\uEF4A" + @"

	`1~!@#$%^&*()_+-=[]{}|;:',./<>?"" no-value whitespace="" this contains whitespace ""></root>"; var formatter = new HtmlFormatter(new DataWriterSettings()) { CanonicalForm = true }; var actual = formatter.Format(input); Assert.Equal(expected, actual); }
public void Format_PhpHelloWorld_ReturnsMarkup() { var input = new[] { MarkupGrammar.TokenElementBegin(new DataName("html")), MarkupGrammar.TokenPrimitive("\r\n\t"), MarkupGrammar.TokenElementBegin(new DataName("head")), MarkupGrammar.TokenPrimitive("\r\n\t\t"), MarkupGrammar.TokenElementBegin(new DataName("title")), MarkupGrammar.TokenPrimitive("PHP Test"), MarkupGrammar.TokenElementEnd, MarkupGrammar.TokenPrimitive("\r\n\t"), MarkupGrammar.TokenElementEnd, MarkupGrammar.TokenPrimitive("\r\n\t"), MarkupGrammar.TokenElementBegin(new DataName("body")), MarkupGrammar.TokenPrimitive("\r\n\t\t"), MarkupGrammar.TokenUnparsed("?", "?", @"php echo '<p>Hello World</p>'; "), MarkupGrammar.TokenPrimitive("\r\n\t"), MarkupGrammar.TokenElementEnd, MarkupGrammar.TokenPrimitive("\r\n"), MarkupGrammar.TokenElementEnd, }; const string expected = @"<html> <head> <title>PHP Test</title> </head> <body> <?php echo '<p>Hello World</p>'; ?> </body> </html>"; var formatter = new HtmlFormatter(new DataWriterSettings()); var actual = formatter.Format(input); Assert.Equal(expected, actual); }
public void Format_HtmlContentPrettyPrinted_ReturnsMarkup() { var input = new[] { MarkupGrammar.TokenElementBegin(new DataName("div")), MarkupGrammar.TokenAttribute(new DataName("class")), MarkupGrammar.TokenPrimitive("content"), MarkupGrammar.TokenPrimitive("\r\n\t"), MarkupGrammar.TokenElementBegin(new DataName("p")), MarkupGrammar.TokenAttribute(new DataName("style")), MarkupGrammar.TokenPrimitive("color:red"), MarkupGrammar.TokenPrimitive("\r\n\t\t"), MarkupGrammar.TokenElementBegin(new DataName("strong")), MarkupGrammar.TokenPrimitive("Lorem ipsum"), MarkupGrammar.TokenElementEnd, MarkupGrammar.TokenPrimitive(" dolor sit amet, "), MarkupGrammar.TokenElementBegin(new DataName("i")), MarkupGrammar.TokenPrimitive("consectetur"), MarkupGrammar.TokenElementEnd, MarkupGrammar.TokenPrimitive(" adipiscing elit.\r\n\t"), MarkupGrammar.TokenElementEnd, MarkupGrammar.TokenPrimitive("\r\n"), MarkupGrammar.TokenElementEnd, }; const string expected = @"<div class=""content""> <p style=""color:red""> <strong>Lorem ipsum</strong> dolor sit amet, <i>consectetur</i> adipiscing elit. </p> </div>"; var formatter = new HtmlFormatter(new DataWriterSettings()); var actual = formatter.Format(input); Assert.Equal(expected, actual); }
/// <summary> /// Emits valid XML attribute character data /// </summary> /// <param name="writer"></param> /// <param name="value"></param> /// <param name="encodeNonAscii">encodes all non-ASCII chars</param> public static void HtmlAttributeEncode(TextWriter writer, string value, bool encodeNonAscii) { HtmlFormatter.HtmlAttributeEncode(writer, value, encodeNonAscii, false); }
private void WriteAttribute(TextWriter writer, string prefix, string localName, Token <MarkupTokenType> value) { // " " writer.Write(MarkupGrammar.OperatorValueDelim); if (!String.IsNullOrEmpty(prefix)) { // "prefix:" this.WriteLocalName(writer, prefix); writer.Write(MarkupGrammar.OperatorPrefixDelim); } // local-name this.WriteLocalName(writer, localName); ITextFormattable <MarkupTokenType> formattable = value.Value as ITextFormattable <MarkupTokenType>; string attrValue = (formattable == null) ? value.ValueAsString() : null; if ((formattable == null) && String.IsNullOrEmpty(attrValue)) { switch (this.EmptyAttributes) { case EmptyAttributeType.Html: { return; } case EmptyAttributeType.Xhtml: { attrValue = localName; break; } case EmptyAttributeType.Xml: { break; } } } // ="value" writer.Write(MarkupGrammar.OperatorPairDelim); writer.Write(MarkupGrammar.OperatorStringDelim); switch (value.TokenType) { case MarkupTokenType.Primitive: { if (formattable != null) { formattable.Format(this, writer); } else { HtmlFormatter.HtmlAttributeEncode(writer, attrValue, this.encodeNonAscii, this.canonicalForm); } break; } default: { throw new TokenException <MarkupTokenType>( value, String.Format(HtmlFormatter.ErrorUnexpectedToken, value)); } } writer.Write(MarkupGrammar.OperatorStringDelim); }
/// <summary> /// Emits valid XML attribute character data /// </summary> /// <param name="writer"></param> /// <param name="value"></param> /// <remarks> /// From XML 1.0, 5th ed. http://www.w3.org/TR/xml/#syntax /// CharData is defined as all chars except less-than ('<'), ampersand ('&'), the sequence "]]>", optionally encoding greater-than ('>'). /// Attributes should additionally encode double-quote ('"') and single-quote ('\'') /// Rather than detect "]]>", this simply encodes all '>'. /// </remarks> public static void HtmlAttributeEncode(TextWriter writer, string value) { HtmlFormatter.HtmlAttributeEncode(writer, value, false, false); }
/// <summary> /// Formats the token sequence to the writer /// </summary> /// <param name="writer"></param> /// <param name="tokens"></param> public void Format(IEnumerable <Token <MarkupTokenType> > tokens, TextWriter writer) { if (tokens == null) { throw new ArgumentNullException("tokens"); } IStream <Token <MarkupTokenType> > stream = Stream <Token <MarkupTokenType> > .Create(tokens); PrefixScopeChain.Scope scope = null; while (!stream.IsCompleted) { Token <MarkupTokenType> token = stream.Peek(); switch (token.TokenType) { case MarkupTokenType.ElementBegin: case MarkupTokenType.ElementVoid: { DataName tagName = token.Name; MarkupTokenType tagType = token.TokenType; stream.Pop(); token = stream.Peek(); scope = new PrefixScopeChain.Scope(); if (this.ScopeChain.ContainsNamespace(tagName.NamespaceUri) || (String.IsNullOrEmpty(tagName.NamespaceUri) && !this.ScopeChain.ContainsPrefix(String.Empty))) { string prefix = this.ScopeChain.GetPrefix(tagName.NamespaceUri, false); scope.TagName = new DataName(tagName.LocalName, prefix, tagName.NamespaceUri); } else { scope[tagName.Prefix] = tagName.NamespaceUri; scope.TagName = tagName; } this.ScopeChain.Push(scope); IDictionary <DataName, Token <MarkupTokenType> > attributes = null; while (!stream.IsCompleted && token.TokenType == MarkupTokenType.Attribute) { if (attributes == null) { attributes = this.canonicalForm ? (IDictionary <DataName, Token <MarkupTokenType> >) new CanonicalList() : (IDictionary <DataName, Token <MarkupTokenType> >) new Dictionary <DataName, Token <MarkupTokenType> >(); } DataName attrName = token.Name; string prefix = this.ScopeChain.EnsurePrefix(attrName.Prefix, attrName.NamespaceUri); if (prefix != null) { if (prefix != attrName.Prefix) { attrName = new DataName(attrName.LocalName, prefix, attrName.NamespaceUri, true); } if (!this.ScopeChain.ContainsNamespace(attrName.NamespaceUri) && (!String.IsNullOrEmpty(attrName.NamespaceUri) || this.ScopeChain.ContainsPrefix(String.Empty))) { scope[prefix] = attrName.NamespaceUri; } } stream.Pop(); token = stream.Peek(); attributes[attrName] = token ?? MarkupGrammar.TokenNone; stream.Pop(); token = stream.Peek(); } this.WriteTag(writer, tagType, tagName, attributes, scope); scope = null; break; } case MarkupTokenType.ElementEnd: { if (this.ScopeChain.HasScope) { this.WriteTag(writer, MarkupTokenType.ElementEnd, this.ScopeChain.Peek().TagName, null, null); this.ScopeChain.Pop(); } else { // TODO: decide if this is should throw an exception } stream.Pop(); token = stream.Peek(); break; } case MarkupTokenType.Primitive: { ITextFormattable <MarkupTokenType> formattable = token.Value as ITextFormattable <MarkupTokenType>; if (formattable != null) { formattable.Format(this, writer); } else { HtmlFormatter.HtmlEncode(writer, token.ValueAsString(), this.encodeNonAscii, this.canonicalForm); } stream.Pop(); token = stream.Peek(); break; } default: { throw new TokenException <MarkupTokenType>( token, String.Format(ErrorUnexpectedToken, token.TokenType)); } } } }