惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
P
Palo Alto Networks Blog
S
Securelist
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
NISL@THU
NISL@THU
L
Lohrmann on Cybersecurity
有赞技术团队
有赞技术团队
The GitHub Blog
The GitHub Blog
C
Cisco Blogs
B
Blog
Microsoft Azure Blog
Microsoft Azure Blog
Recent Announcements
Recent Announcements
Simon Willison's Weblog
Simon Willison's Weblog
T
Tenable Blog
Know Your Adversary
Know Your Adversary
Spread Privacy
Spread Privacy
WordPress大学
WordPress大学
月光博客
月光博客
Latest news
Latest news
C
CXSECURITY Database RSS Feed - CXSecurity.com
T
Threat Research - Cisco Blogs
Cisco Talos Blog
Cisco Talos Blog
I
InfoQ
D
Darknet – Hacking Tools, Hacker News & Cyber Security
W
WeLiveSecurity
Hacker News - Newest:
Hacker News - Newest: "LLM"
酷 壳 – CoolShell
酷 壳 – CoolShell
U
Unit 42
C
Cybersecurity and Infrastructure Security Agency CISA
博客园 - 聂微东
人人都是产品经理
人人都是产品经理
Google DeepMind News
Google DeepMind News
Apple Machine Learning Research
Apple Machine Learning Research
Attack and Defense Labs
Attack and Defense Labs
罗磊的独立博客
T
The Exploit Database - CXSecurity.com
I
Intezer
GbyAI
GbyAI
Jina AI
Jina AI
www.infosecurity-magazine.com
www.infosecurity-magazine.com
Blog — PlanetScale
Blog — PlanetScale
博客园 - 司徒正美
Google Online Security Blog
Google Online Security Blog
Engineering at Meta
Engineering at Meta
D
Docker
Recent Commits to openclaw:main
Recent Commits to openclaw:main
小众软件
小众软件
云风的 BLOG
云风的 BLOG
爱范儿
爱范儿
Project Zero
Project Zero

博客园 - songsoft

Js表单验证控件-02 Ajax验证 Js表单验证控件(使用方便,无需编码)-01使用说明 字符串对比 KindEditor编辑器For DotNet控件 Flash AS实现时钟效果(全脚本实现) 模板引擎开发(二)-值标签的处理 Jquery插件-浮动广告 模板引擎开发(一) 软件开发模型之一 万祖归宗是瀑布 关于制度化管理 关于加薪的策略 关于文档编写 蓝海与红海--有感于软件创新 李广难封--有感于团队建设 哪里是乐土?--关于团队良性循环 从酒桌上看团队建设 创造一切条件让大家“混” 百万富翁成长路线 绿有四季--关于需求沟通
模板引擎开发(三)-自定义标签的处理
songsoft · 2013-06-26 · via 博客园 - songsoft

自定义标签大致可以理解为一个HTML代码块,也可以指向一个HTML文件。

在模板页中,很多地方需要相同的内容,例如页面的头部、尾部等,这个时候,可以利用自定义标签来定义HTML代码,然后在模板页中引用就可以了。

自定义标签的格式如下:
{%@ pageTop%} 页面顶部的顶部的自定义标签;

自定义标签中的HTML代码,我用了XML来记录,当然也有可视化的编辑界面来操作,在这里就不再缀述,只是说明一下原理即可,XML如下:

  <Tag Uid="5895643">
      <Name>PageTop</Name>
      <Type>page</Type>
      <Intro><![CDATA[所有页面的顶部]]></Intro>
      <Page>PageTop.html</Page>
      <Context><![CDATA[<div id="pagetop">logo 信息化动力核心 </div>
<div></div>]]></Context>
    </Tag>

上述代码,标明了自定义标签的唯一标识、名称、类型(指定某个页面)、介绍、html文件名、html代码块;

说到这里就简单了,我们只需要把自定义标签从模板页中检索出来,替换成HTML代码就行了。代码如下:

/// <summary>
        /// 将模板内容中的所有自定义标签,替换为实际的值
        /// </summary>
        /// <param name="html">要处理的模板对象</param>
        /// <returns></returns>
        public string Transact(TemplateBuider.PageTransact.Html html)
        {
            string patt = @"{%@\s*(\S[^\s%]+)\s*%}";
            Regex rex = new Regex(patt, RegexOptions.Singleline);
            MatchCollection mc = rex.Matches(html.HtmlContext);
            for (int i = 0; i < mc.Count; i++)
            {
                Match ma = mc[i];
                string key = ma.Groups[1].Value;
                //获取当前标签对象
                Song.TemplateManager.Tags.CustomTag custom = _tags.Find(delegate(TemplateManager.Tags.CustomTag p) { return p.Name.ToLower() == key.ToLower(); });
                if (custom == null) continue;
                //转换自定义标签中的路径,使之与当前模板页为相对路径
                string context =_replacePath(html, custom);
                //将自定义标签合并到的模板
                html.HtmlContext = Microsoft.VisualBasic.Strings.Replace(html.HtmlContext, ma.Value, context, 1, -1, Microsoft.VisualBasic.CompareMethod.Text);
            }
            return html.HtmlContext;
        }

上述代码有一些是我系统中相关方法,大家不必关注,关键是正则表达式。

可这个时候,有个问题。各个模板页并不在一个文件夹下,路径各不相同,自定义标签中的HTML如果有超链接,在模板页引用后,如果只是简单的替换,这些超链接就有可能出错,找不到指定的内容。所以,我们必须将自定义标签中的链接对象转换成当前模板的路径名。

思路是这样的,首先找出自定义标签的路径,如果自定义标签是指向HTML文件的,则按Html路径;如果是纯HTML代码,则以当前模板库的路径为路径;自定义标签中的所有链接,包括超链接、CSS引用、Js引用、iframe等,转换为相对于自定义标签路径的路径;然后找当前模板页的路径;将所有的链接转换为当前模板页的路径。

这中间牵涉到一个算法,从A文件到B文件的相对路径。举例说:A文件在/3/4/5/q/w/a.html,B文件在/3/4/6/s/b.html,如果A文件中写一个超链接引用B文件,这个超链接怎么写?
我这里写了一个方法。计算两个文件的相对路径,代码如下:

       /// <summary>
        /// 计算两个文件的相对路径
        /// </summary>
        /// <param name="baseFile">用于参照的文件,就从当前文件开始查找另一个文件</param>
        /// <param name="targetFile">目标文件,就是求它的相对路径</param>
        /// <returns>返回targetFile相对于baseFile的相对路径</returns>
        private string _getRelativePath(string baseFile, string targetFile)
        {
            baseFile = baseFile.Replace("\\", "/");
            baseFile = baseFile.ToLower();
            targetFile = targetFile.ToLower();
            //
            while (baseFile.IndexOf("/") > -1 && targetFile.IndexOf("/") > -1)
            {
                string b = baseFile.Substring(0, baseFile.IndexOf("/"));
                string t = targetFile.Substring(0, targetFile.IndexOf("/"));
                if (b != t) break;                
                baseFile = baseFile.Substring(baseFile.IndexOf("/") + 1);
                targetFile = targetFile.Substring(targetFile.IndexOf("/") + 1);               
            }
            string path = "";
            while (baseFile.IndexOf("/") > -1)
            {
                baseFile = baseFile.Substring(baseFile.IndexOf("/") + 1);
                path += "../";
            }
            return path + targetFile;
        }

有了上面的方法,就好处理了,真正的超链接转换,就是正则匹配处理了。方法如下:

        /// <summary>
        /// 将模板页中的路径处理成相对于当前模板页的路径
        /// </summary>
        /// <param name="html"></param>
        /// <param name="tag"></param>
        /// <returns></returns>
        private string _replacePath(TemplateBuider.PageTransact.Html html, TemplateManager.Tags.CustomTag tag)
        {
            string context = tag.Context;
            //处理自定义标签中的超链接,使其相对于当前文件路径            
            string cutomPath = _cutomPath(tag);
            //将超链接处理为相对于模板页的路径
            string linkExpr = @"(?<=\s+)(?<key>href|src|action|background[^=""']*)=([""'])?(?<value>[^'"">]*)\1?";
            Regex regex = new Regex(linkExpr, RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace | RegexOptions.IgnoreCase);
            MatchCollection mc = regex.Matches(tag.Context);
            foreach (Match m in mc)
            {
                string link = m.Groups["value"].Value.Trim();
                if (link == "") continue;
                //外网链接不处理,如Http://开头的超链接
                if (new Regex(@"[a-zA-z]+://[^\s]*", RegexOptions.Singleline).IsMatch(link))
                    continue;
                //根路径不处理,如/manage/index.aspx,第一个字符是/
                if (new Regex(@"^\/\w+.").IsMatch(link))
                    continue;
                //如果是参数标签,则不处理
                if (new Regex(@"^{.+").IsMatch(link))
                    continue;
                //将超链接转换为相对于静态化目录的路径
                link = _getCutomLinkPath(cutomPath, link);
                //将超链接转换为基于当前模板页的相对路径
                link = _getRelativePath(html.TagetFile, link);
                link = m.Groups[2].Value + "=\"" + link + "\"";
                context = context.Replace(m.Value, link);
            }
            return context;
        }        

在上述代码中,根路径不处理、站外链接不处理、以{开头的链接不处理。

总结

我的这个自定义标签功能并不强,虽然自定义标签中也可以有其它组件,但其本质未变,只是HTML代码块的替换。本来想写带参数的自定义标签呢,这样就更类似于asp.net的用户控件,精力有限,暂时先这样吧。