/// <summary> /// Emits valid XML 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 ('>'). /// /// Rather than detect "]]>", this simply encodes all '>'. /// From XML 1.0, 5th ed. http://www.w3.org/TR/xml/#sec-line-ends /// "the XML processor must behave as if it normalized all line breaks in external parsed entities (including the document entity) on input, before parsing" /// Therefore, this encodes all CR ('\r') chars to preserve them in the final output. /// </remarks> public static void HtmlEncode(TextWriter writer, string value) { HtmlFormatter.HtmlEncode(writer, value, false, false); }
/// <summary> /// Emits valid XML character data /// </summary> /// <param name="writer"></param> /// <param name="value"></param> /// <param name="encodeNonAscii">encodes all non-ASCII chars</param> public static void HtmlEncode(TextWriter writer, string value, bool encodeNonAscii) { HtmlFormatter.HtmlEncode(writer, value, encodeNonAscii, 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)); } } } }