C#实现动态生成静态页面的类详解
作者:且行且思 发布时间:2022-03-25 02:25:29
本文实例讲述了C#实现动态生成静态页面的类。分享给大家供大家参考,具体如下:
动态生成静态页面有许多好处,比如生成html网页有利于被搜索引擎收录。同时,由于减少了数据访问,减轻对数据库访问的压力,提高了网页打开速度。
基本思路:
使用一个字符串作为页面模板,再页面中包含用若干标志(用 {标志名} 表示),生成页面时,将标志替换为对应的值。
实现方法:
在初始化TextTemplate实例时读入模板,以标志为分割点将模板分割成几部分,生成页面时只需简单的将模板内容和标志的值连接起来。例如:
假如有一个模板 ABCD{TAG1}EFG{TAG2}HIJ{TAG3}KMUN
初始化时将模板分割成 "ABCD","EFG","HIJ","KMUN"四个字符串,
假设TAG1=“123”,TAG2=“456”,TAG3=“789”
则生成是相当于执行"ABCD"+"123"+"EFG"+"456"+"HIJ"+"789"+"KMUN"
代码:
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections;
using System.IO;
/// <summary>
/// 表示一个文本模板,该类使用一个字符串作为模板,通过将模板中的标志替换为对应的值(模板中的标志用 {标志名} 表示)生成新的文本
/// </summary>
/// <example>以下代码用文本模板生成IMG标志
/// <code>
/// static class Program
/// {
/// [STAThread]
/// static void Main()
/// {
/// TextTemplate temp = new TextTemplate("<img src='{src}' alt='{alt}' />");
/// Console.WriteLine(temp.Render("pic.bmp","Image"));
/// Hashtable values = new Hashtable();
/// values.Add("src", "pic.bmp");
/// values.Add("alt", "image");
/// Console.WriteLine(temp.Render(values));
/// }
/// }
///
/// 输出为:
/// <img src='pic.bmp' alt='Image' />
/// <img src='pic.bmp' alt='image' />
///
/// </code>
/// </example>
public class TextTemplate
{
TextTemplateTag[] _tags;
String[] _contentParts;
int _tagCount;
private TextTemplate()
{
_tagCount = 0;
_tags = null;
_contentParts = null;
}
/// <summary>
/// 用指定的模板初始化TextTemplate
/// </summary>
/// <param name="content">模板内容</param>
public TextTemplate(String content)
{
FromString(content);
}
/// <summary>
/// 用指定的模板初始化TextTemplate,模板内容重文件读入
/// </summary>
/// <param name="file">模板文件位置</param>
/// <param name="encoding">文件使用的编码</param>
public TextTemplate(string file, Encoding encoding)
{
StreamReader sr = new StreamReader(file, encoding);
try
{
string content = sr.ReadToEnd();
FromString(content);
}
catch (Exception)
{
sr.Close();
throw;
}
sr.Close();
}
/// <summary>
/// 读入模板并以标志为分割点分割模板
/// </summary>
/// <param name="content"></param>
private void FromString(String content)
{
MatchCollection mc = Regex.Matches(content, "{\\w+}");
_tagCount = mc.Count;
_tags = new TextTemplateTag[mc.Count];
_contentParts = new string[mc.Count + 1];
int index = 0;
foreach (Match m in mc)
{
_tags[index++] = new TextTemplateTag(m.Value.Substring(1, m.Value.Length - 2), m.Index, m.Length);
}
int start = 0;
index = 0;
foreach (TextTemplateTag con in _tags)
{
_contentParts[index] = content.Substring(start, con.Position - start);
start = con.Position + con.Length;
index++;
}
if (start < content.Length) _contentParts[index] = content.Substring(start);
}
/// <summary>
/// 用指定的值生成文本
/// </summary>
/// <param name="values">各标志对应的值(用标志名作为key)</param>
/// <returns>生成的文本</returns>
/// <example>以下代码用文本模板生成IMG标志
/// <code>
/// static class Program
/// {
/// [STAThread]
/// static void Main()
/// {
/// TextTemplate temp = new TextTemplate("<img src='{src}' alt='{alt}' />");
/// Console.WriteLine(temp.Render("pic.bmp","Image"));
/// Hashtable values = new Hashtable();
/// values.Add("src", "pic.bmp");
/// values.Add("alt", "image");
/// Console.WriteLine(temp.Render(values));
/// }
/// }
///
/// 输出为:
/// <img src='pic.bmp' alt='Image' />
/// <img src='pic.bmp' alt='image' />
///
/// </code>
/// </example>
public string Render(Hashtable values)
{
StringBuilder result = new StringBuilder(8 * 1024);
int i = 0;
for (i = 0; i < _tagCount; i++)
{
result.Append(_contentParts[i]);
if (values[_tags[i].Name] != null)
result.Append(values[_tags[i].Name]);
else
result.Append("{" + _tags[i].Name + "}");
}
result.Append(_contentParts[i]);
return result.ToString();
}
/// <summary>
/// 用指定的值生成文本
/// </summary>
/// <param name="args">各标志对应的值(忽略标志名,第一个标志对应第一个参数,以此类推)</param>
/// <returns>生成的文本</returns>
/// <example>以下代码用文本模板生成IMG标志
/// <code>
/// static class Program
/// {
/// [STAThread]
/// static void Main()
/// {
/// TextTemplate temp = new TextTemplate("<img src='{src}' alt='{alt}' />");
/// Console.WriteLine(temp.Render("pic.bmp","Image"));
/// Hashtable values = new Hashtable();
/// values.Add("src", "pic.bmp");
/// values.Add("alt", "image");
/// Console.WriteLine(temp.Render(values));
/// }
/// }
///
/// 输出为:
/// <img src='pic.bmp' alt='Image' />
/// <img src='pic.bmp' alt='image' />
///
/// </code>
/// </example>
public string Render(params object[] args)
{
StringBuilder result = new StringBuilder(2 * 1024);
int i = 0;
for (i = 0; i < _tagCount; i++)
{
result.Append(_contentParts[i]);
result.Append(args[i].ToString());
}
result.Append(_contentParts[i]);
return result.ToString();
}
/// <summary>
/// 用指定的值生成文本,并保存到文件中
/// </summary>
/// <param name="file">要保存的文件路径</param>
/// <param name="encoding">文件的编码</param>
/// <param name="values">各标志对应的值(用标志名作为key)</param>
public void SaveAs(string file, Encoding encoding, Hashtable values)
{
StreamWriter sw = new StreamWriter(file, false, encoding);
try
{
String content = Render(values);
sw.Write(content);
}
catch (Exception)
{
sw.Close();
throw;
}
sw.Close();
}
/// <summary>
/// 用指定的值生成文本,并保存到文件中
/// </summary>
/// <param name="file">要保存的文件路径</param>
/// <param name="encoding">文件的编码</param>
/// <param name="args">各标志对应的值(忽略标志名,第一个标志对应第一个参数,以此类推)</param>
public void SaveAs(string file, Encoding encoding, params object[] args)
{
StreamWriter sw = new StreamWriter(file, false, encoding);
try
{
String content = Render(args);
sw.Write(content);
}
catch (Exception)
{
sw.Close();
throw;
}
sw.Close();
}
/// <summary>
/// 将模板以指定的分隔标志分隔成小模板
/// </summary>
/// <param name="splitTag"></param>
/// <returns></returns>
public TextTemplate[] Split(string splitTag)
{
List<TextTemplate> temps = new List<TextTemplate>();
List<string> contentParts = new List<string>();
List<TextTemplateTag> tags = new List<TextTemplateTag>();
int i = 0;
foreach (string content in _contentParts)
{
contentParts.Add(content);
if (i >= _tags.Length || _tags[i].Name == splitTag)
{
TextTemplate newTemp = new TextTemplate();
newTemp._contentParts = contentParts.ToArray();
newTemp._tags = tags.ToArray();
newTemp._tagCount = tags.Count;
temps.Add(newTemp);
contentParts.Clear();
tags.Clear();
}
else
tags.Add(new TextTemplateTag(_tags[i].Name, _tags[i].Position, _tags[i].Length));
i++;
}
return temps.ToArray();
}
}
internal class TextTemplateTag
{
int _position, _length;
string _name;
public TextTemplateTag(string name, int pos, int len)
{
_name = name;
_position = pos;
_length = len;
}
public string Name
{
get { return _name; }
}
public int Position
{
get { return _position; }
}
public int Length
{
get { return _length; }
}
}
实例代码:
static class Program
{
[STAThread]
static void Main()
{
TextTemplate temp = new TextTemplate("<img src='{src}' alt='{alt}' />");
Console.WriteLine(temp.Render("pic.bmp","Image"));
Hashtable values = new Hashtable();
values.Add("src", "pic.bmp");
values.Add("alt", "image");
Console.WriteLine(temp.Render(values));
}
}
输出为:
<img src='pic.bmp' alt='Image' />
<img src='pic.bmp' alt='image' />
其他应用:
TextTemplate还可以用来在安装网站时生成Web.Config文件,只需定义以下模板:
<?xml version="1.0"?>
<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">
<appSettings></appSettings>
<connectionStrings>
<add
name="DJDB.LocalSqlServer"
connectionString="{CONNECTIONSTRING}"
providerName="System.Data.SqlClient"
/>
</connectionStrings>
其他配置
</configuration>
在设置标志 CONNECTIONSTRING 的值即可,这种方法比用XMLDocument类要方便得多。
总结:
TextTemplate的优点有:
1、模板只在初始化时就分析并分割存储,当使用同一模板生成多个页面时,只是简单的件模板内容和标志的值连接起来,不需要每次都去分析模板,如果使用string的Replace方法则每一次都要去分析字符串,而且如果标志值中含有标志,会影响生成的页面。
2、模板可以从文件读入,因此模板文件可以使用各种网页制作工具编辑。
希望本文所述对大家C#程序设计有所帮助。


猜你喜欢
- 本文实例讲述了Android控件之Spinner用法。分享给大家供大家参考。具体如下:以下模拟下拉列表的用法布局文件:<?xml ve
- 本过程是使用Virtual Studio 2019实现的,利用老师给出的框架进行的修改。一、认识NetworkStream(网络流)1、Ne
- Win32 APIWin32 API即为Microsoft 32位平台的应用程序编程接口(Application Programming I
- 一、什么是特性特性(Attribute)是用于在运行时传递程序中各种元素(比如类、方法、结构、枚举、组件等)的行为信息的声明性标签。您可以通
- 通过继承Thread类并实现run方法创建一个线程// 定义一个Thread类,相当于一个线程的模板class MyThread01 ext
- 若要在 C++ 中实现异常处理,你可以使用 try、throw 和 catch 表达式。首先,使用 try 块将可能引发异常的一个或多个语句
- Spring注解AspectJ操作AOP一、被增强类新建一个被增强的类 User,下面有个 add() 方法。package com.pin
- selectById方法根据id,查询记录public void updateRecycleAssayBusinessItemCharge(
- name和url属性的作用定义feign是声明式的web service客户端,它让微服务之间的调用变得更简单了,类似controller调
- 前言相信每位Android开发者都用过Toast,都知道是弹出消息的。类似于js里面的alert,C#里面的MesageBox。当然andr
- 以下内容来自 * ,关于静态类型检查和动态类型检查的解释:•静态类型检查:基于程序的源代码来验证类型安全的过程;•动态类型检查:在程序运行
- 在Android Studio中,你可以很快速的使用Parcelable插件进行实体类的序列化的实现,使用该插件后,你的实体类可以快速的实现
- 定义在类里面的类就叫做内部类。内部类的特点:在内部类中可以直接访问外部类的成员,包括私有的成员在外部类中不能直接访问内部类的成员,必须通过创
- 前言:在Java8支持Lambda表达式以后,为了满足Lambda表达式的一些典型使用场景,JDK为我们提供了大量常用的函数式接口。它们主要
- •readonly和const都是用来标识常量的[1]。•const可用于修饰class的field或者一个局部变量(local varia
- 前言这几天学习谷粒商城又再次的回顾了一次SpringCache,之前在学习谷粒学院的时候其实已经学习了一次了!!!这里就对自己学过来的内容进
- OpenCv提供了函数 findContours()用于对物体轮廓进行检测,该函数实现算法是由S.suzuki K.Abe于1985年发表的
- 从Java 5开始,Java语言对方法参数支持一种新写法,叫 可变长度参数列表,其语法就是类型后跟...,表示此处接受的参数为0到多个Obj
- 本文实例为大家分享了AsyncTask异步类实现网页内容放大缩小的详细代码,供大家参考,具体内容如下WebActivity.java:pac
- 前言本篇文章主要介绍关于我在SpringBoot中使用MyBatis-Plus是如何解决Invalid bound statement (n