[OpenAPI] html标签分析

     个人空间的OpenAPI与facebook非常接近(从需要求上就要做成一样),所以我们在hi中也将会使用类拟于fbml这样的自定义标签(himl)。在对notifications.send接口的开发中需要传入notification参数,这个参数是通知的内容,其实就是一些html和himl标签混合在一起的字符串,其中有一个需求:用户传进一个UserName参数要求我们把它变成这个用户的真实姓名,例如:<hi:name id="billok" />。这里就是一个himl自定义标签了。我们要做的工作就是要解析类拟的自定标签把它转换成真实姓名。

     框架还是有点复杂,为了表达清楚点,这里不谈很多细节,只列一下这个subject相关的内容。

     首先,应用程序把notification参数传入notifications.send接口后,会经过一点的流程把参数html传进如下一个处理请求的基类的方法:

string ParseContent(string html){}  这个方法是用户分析html参数把其中的himl标签进行特殊处理。

         protected   virtual   string  ParseContent( string  html)
        {
            
// 加载html到HtmlDocument
            HtmlDocument doc  =   new  HtmlDocument();
            doc.LoadHtml(HttpUtility.HtmlDecode(html));

            
// 遍历第一层节点
             foreach  (HtmlNode node  in  doc.DocumentNode.ChildNodes)
            {
                HtmlUtil.ForEach(node);
            }

            
return  doc.DocumentNode.OuterHtml;
        }

这里我们使用了HtmlAgilityPack对html分析组件,首先把html字符串加裁成HtmlDocument对象,这样就会自动分析出文档的dom树结构,然后把我们通过遍历第一层节点,使用HtmlUtil.ForEach处理第一层根节点,处理完后就把所有的html进行输出。使用HtmlAgilityPack的好处是可以方便的对dom进行操作,可以删除节点和替换节点,不过相信还有更好的类库可以使用或者以后改为LINQ to xml进行处理。

     我们还是详细看一下ForEach方法的实现吧。

         public   static   void  ForEach(HtmlNode node)
        {
            
if  (node.NodeType  !=  HtmlNodeType.Element)
            {
                
return ;
            }
            
else
            {
                
if  ( ! node.HasChildNodes)
                {
                    
// 叶节点
                    HandleNode(node);
                }
                
else
                {
                    
foreach  (HtmlNode childNode  in  node.ChildNodes)
                    {
                        ForEach(childNode);
                    }
                    
// 子节点:有子与有父节点
                    HandleNode(node);
                }
            }
        }

这里实际上是一个递归操作,如果传进的节点不是一个Element元素(例如:不带标签的纯文件,注解等),这样的node我们是不需要处理的,所以就直接return终结循环就好了。对于Element节点的处理,就只分为有子节点和没有子节点的情况就行,如果有子节点的话就再遍历子节点并递归调用ForEach方法,目的就是把有Element处理一遍。你也发现了我们对节点的处理又被封装到另一个方法中了HandleNode:

         private   static   void  HandleNode(HtmlNode node)
        {
            
// 分析节点
            IHtmlTag iHtmlTag  =  ObjectFactory.CreateIHtmlTag(node.Name);
            Dictionary
< string string >  dict  =   new  Dictionary < string string > ();
            //dict.Add("HtmlNode_OuterHtml", node.OuterHtml);//可以传入节点的全部html,以作进一步处理
             foreach  (HtmlAttribute attr  in  node.Attributes)
            {
                
if  ( ! dict.ContainsKey(attr.Name))
                {
                    dict.Add(attr.Name, attr.Value);
                }
            }
            HtmlTag htmlTag 
=  iHtmlTag.Handle(dict);

            
// 处理节点
             switch  (htmlTag.HandleType)
            {
                
case  HtmlTagHandleType.Remove:
                    
if  (node.ParentNode  !=   null )
                        node.ParentNode.RemoveChild(node);
                    
break ;
                
case  HtmlTagHandleType.Replace:
                    
if  (node.ParentNode  !=   null )
                    {
                        HtmlNode newNode 
=  HtmlNode.CreateNode(htmlTag.Html);
                        node.ParentNode.ReplaceChild(newNode, node);
                    }
                    
break ;
                
case  HtmlTagHandleType.Unknown:
                
default :
                    
// 不做任务处理
                     break ;

            }
        }

这个方法分为两个步聚:分析节点和处理节点,并且利用了IOC模式。

IOC模式是系统框架的一部分,这里就不详细谈了,你只要知道从ObjectFactory.CreateIHtmlTag方法可以得到标签名(如:hi:name)所以指定的关于IHtmlTag接口的一个实现,如果没有合符处理的实现就会使用一个默认实现(就是告诉"处理节点"步聚什么都不用做)。对于IHtmlTag接口我们看一下定义:

     public   enum  HtmlTagHandleType
    {
        Unknown,
        Remove,
        Replace,
    }

    
public   class  HtmlTag
    {
        
public  HtmlTagHandleType HandleType {  get set ; }
        
public   string  Html {  get set ; }

        
public  HtmlTag()
        {
            HandleType 
=  HtmlTagHandleType.Unknown;
            Html 
=   string .Empty;
        }
    }

    
public   interface  IHtmlTag
    {
        HtmlTag Handle(IDictionary
< string string >  attributes);
    }

IHtmlTag接口只有一个方法

HtmlTag Handle(IDictionary<string, string> attributes); 接受一个节点属性的键值对字典,返回对这些键值对进行处理的结果。

返回的HtmlTag可以指示出需要后续进行怎么样的操作(HtmlTagHandleType),以及处理完后的html

Okay! 对节点进行分析后得到HtmlTag,现在就可以进行节点处理的工作了。节点的处理方式以HtmlTagHandleType的返回为准,分别是Remove删除节点,Replace替换节点,不作处理。


经过这些处理后,返加doc.DocumentNode.OuterHtml就可以得到处理后的html内容了。通过实现IHtmlTag接口,可以很方便的添加新的himl标签对内容时行特殊处理了。并用标签还可以任竟扩展属性,例如:<hi:name id="billok,junbiaochen" target="abc" /> 等等。

 

 

 

你可能感兴趣的:(html标签)