/// <summary> /// 检查元素是否为自结束标签 /// </summary> /// <param name="tag">元素开始标签</param> /// <returns>是否为自结束标签</returns> protected virtual bool IsSelfCloseElement( HtmlBeginTag tag ) { return HtmlSpecification.IsForbiddenEndTag( tag.TagName ); }
/// <summary> /// 检查元素是否为CDATA标签 /// </summary> /// <param name="tag">元素开始标签</param> /// <returns>是否为CDATA标签</returns> protected virtual bool IsCDataElement( HtmlBeginTag tag ) { return HtmlSpecification.IsCDataElement( tag.TagName ); }
/// <summary> /// 处理元素开始标签 /// </summary> /// <param name="beginTag">开始标签信息</param> /// <returns>处理过程中所创建的元素对象,若不支持则返回 null</returns> protected virtual IHtmlElement ProcessBeginTag( HtmlBeginTag beginTag ) { if ( HtmlSpecification == null )//当解析第一个开始标签时还没有找到 DTD 声明,则强行使用默认的 HTML 规范。 SetHtmlSpecification( (HtmlDoctypeDeclaration) null ); string tagName = beginTag.TagName; bool selfClosed = beginTag.SelfClosed; //检查是否为自结束标签,并作相应处理 if ( IsSelfCloseElement( beginTag ) ) selfClosed = true; //检查是否为CData标签,并作相应处理 if ( IsCDataElement( beginTag ) ) Reader.EnterCDataMode( tagName.ToLowerInvariant() ); //检查父级是否可选结束标记,并作相应处理 { var element = CurrentContainer as IHtmlElement; if ( element != null && HtmlSpecification.IsOptionalEndTag( element.Name ) ) { if ( ImmediatelyClose( tagName, element ) ) ContainerStack.Pop(); } } //处理所有属性 var attributes = new Dictionary<string, string>( StringComparer.OrdinalIgnoreCase ); foreach ( var a in beginTag.Attributes ) { string name = a.Name; string value = a.Value; if ( value != null ) value = HtmlEncoding.HtmlDecode( value ); if ( attributes.ContainsKey( name ) )//重复的属性名,只取第一个 continue; attributes.Add( name, value ); } //创建元素 { var element = CreateElement( tagName, attributes ); //加入容器堆栈 if ( !selfClosed ) ContainerStack.Push( element ); return element; } }