/// <summary> /// Create a new comment from another. /// </summary> public HComment(HComment other) { if (other == null) { throw new ArgumentNullException("other"); } this.value = other.value; }
/// <summary> /// Deserialize as a list of nodes /// </summary> public IEnumerable <HNode> Deserialize(TextReader reader, Func <Exception, bool> errorHandler = null) { if (reader == null) { throw new ArgumentNullException("reader"); } // Create the parser var parser = new HParser(reader); parser.RemoveUnknownOrInvalidEntities = this.RemoveUnknownOrInvalidEntities; var token = ParseNext(parser, errorHandler); Stack <HElement> opened = new Stack <HElement>(); HXmlDeclaration currentXDecl = null; String tag; HNode tokenToReturns = null; while (token != null) { switch (token.TokenType) { case ParsedTokenType.Text: var htxt = new HText(HEntity.HtmlDecode(((ParsedText)token).Text, RemoveUnknownOrInvalidEntities)); if (opened.Count > 0) { ProtectAddOnPeek(opened, htxt, errorHandler); } else { tokenToReturns = htxt; } break; case ParsedTokenType.CData: var hcd = new HCData(((ParsedCData)token).Text); if (opened.Count > 0) { ProtectAddOnPeek(opened, hcd, errorHandler); } else { tokenToReturns = hcd; } break; case ParsedTokenType.Comment: var hcom = new HComment(HEntity.HtmlDecode(((ParsedComment)token).Text, RemoveUnknownOrInvalidEntities)); if (opened.Count > 0) { ProtectAddOnPeek(opened, hcom, errorHandler); } else { tokenToReturns = hcom; } break; case ParsedTokenType.OpenTag: opened.Push(new HElement(((ParsedTag)token).TagName)); break; case ParsedTokenType.AutoClosedTag: System.Diagnostics.Debug.Assert(opened.Count > 0, "Opened tags are empty when receiving AutoClosedTag."); System.Diagnostics.Debug.Assert(opened.Peek().Name == ((ParsedTag)token).TagName, "AutoClosedTag and opened element are not same tag name."); var actag = opened.Pop(); if (opened.Count > 0) { ProtectAddOnPeek(opened, actag, errorHandler); } else { tokenToReturns = actag; } break; case ParsedTokenType.CloseTag: System.Diagnostics.Debug.Assert(opened.Count > 0, "Opened tags are empty when receiving CloseTag."); System.Diagnostics.Debug.Assert(opened.Peek().Name == ((ParsedTag)token).TagName, "CloseTag and opened element are not same tag name."); // Tag with text content String tagName = opened.Peek().Name; if (IsRawElement(tagName) || IsEscapableRawElement(tagName)) { token = ParseContentTextNext(tagName, parser, errorHandler); continue; } break; case ParsedTokenType.EndTag: tag = ((ParsedTag)token).TagName; HElement helm; // Close all elements that not matching the tag while (opened.Count > 0 && !String.Equals(opened.Peek().Name, tag, StringComparison.OrdinalIgnoreCase)) { helm = opened.Pop(); if (opened.Count > 0) { ProtectAddOnPeek(opened, helm, errorHandler); } else { yield return(helm); } } // If we are opened tag, then close it because we find our element if (opened.Count > 0) { helm = opened.Pop(); if (opened.Count > 0) { ProtectAddOnPeek(opened, helm, errorHandler); } else { yield return(helm); } } break; case ParsedTokenType.OpenProcessInstruction: if (currentXDecl != null) { while ((token = ParseNext(parser, errorHandler)) != null && token.TokenType != ParsedTokenType.CloseProcessInstruction) { ; } ProcessError(new ParseError("XML declaration already opened."), errorHandler); } tag = ((ParsedTag)token).TagName; if (!String.Equals("xml", tag, StringComparison.OrdinalIgnoreCase)) { while ((token = ParseNext(parser, errorHandler)) != null && token.TokenType != ParsedTokenType.CloseProcessInstruction) { ; } ProcessError(new ParseError(String.Format("Unexpected '{0}' process instruction.", tag)), errorHandler); } currentXDecl = new HXmlDeclaration(null, null, null); break; case ParsedTokenType.CloseProcessInstruction: if (currentXDecl == null) { ProcessError(new ParseError("No XML declaration opened."), errorHandler); } else { if (opened.Count > 0) { ProtectAddOnPeek(opened, currentXDecl, errorHandler); } else { tokenToReturns = currentXDecl; } } currentXDecl = null; break; case ParsedTokenType.Doctype: var vs = ((ParsedDoctype)token).Values ?? new String[0]; var hdt = new HDocumentType( vs.Length > 0 ? vs[0] : null, vs.Length > 1 ? vs[1] : null, vs.Length > 2 ? vs[2] : null, vs.Length > 3 ? vs[3] : null ); if (opened.Count > 0) { ProtectAddOnPeek(opened, hdt, errorHandler); } else { tokenToReturns = hdt; } break; case ParsedTokenType.Attribute: var attr = (ParsedAttribute)token; // Xml declaration ? if (currentXDecl != null) { if (String.Equals("version", attr.Name, StringComparison.OrdinalIgnoreCase)) { currentXDecl.Version = attr.Value; } else if (String.Equals("encoding", attr.Name, StringComparison.OrdinalIgnoreCase)) { currentXDecl.Encoding = attr.Value; } else if (String.Equals("standalone", attr.Name, StringComparison.OrdinalIgnoreCase)) { currentXDecl.Standalone = attr.Value; } else { ProcessError(new ParseError(String.Format("Invalid XML declaration attribute : ''", attr.Name)), errorHandler); } } System.Diagnostics.Debug.Assert(opened.Count > 0, "No element opened for the attribtue."); ProtectAddOnPeek(opened, new HAttribute(attr.Name, attr.Value), errorHandler); break; //default: // break; } // Returns a token if we have one if (tokenToReturns != null) { yield return(tokenToReturns); tokenToReturns = null; } // Next token token = ParseNext(parser, errorHandler); } // Close all opened elements while (opened.Count > 0) { yield return(opened.Pop()); } }
/// <summary> /// Serialize a comment /// </summary> protected virtual void SerializeComment(HComment comment, TextWriter writer) { writer.Write("<!-- "); writer.Write(HEntity.HtmlEncode(comment.Value)); writer.Write(" -->"); }