zoukankan      html  css  js  c++  java
  • [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
    <stringstring> dict = new Dictionary<stringstring>();
                //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 { getset; }
            
    public string Html { getset; }

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

        
    public interface IHtmlTag
        {
            HtmlTag Handle(IDictionary
    <stringstring> 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" /> 等等。

  • 相关阅读:
    C++如何在Dialog和View中显示梯度背景颜色
    C++MFC的关键类(View,Application,Frame,Document等等)之间访问方法列表
    C++深入分析MFC文档视图结构(项目实践)
    C++如何修改SDI程序的默认背景颜色
    BAPI使用HR_INFOTYPE_OPERATION函数批量导入HR信息纪录代码样例(0759信息类型)
    C++在单文档的应用程序增加多个视图
    SD定价过程的16个字段的作用说明
    HR上载信息类型的长文本的样例代码
    C++在工具条中加入组合框控件
    C++如何锁定splitter窗口
  • 原文地址:https://www.cnblogs.com/chenjunbiao/p/1760160.html
Copyright © 2011-2022 走看看