[转载]C#生成CHM文件(入门篇)

mikel阅读(1238)

[转载]C#生成CHM文件(入门篇) – Alexis – 博客园.

HTML Help Workshop介绍:微软出品的HTML Help WorkShop制作chm文件的最佳工具。

本文,我们将用编程的方法来实现将html文件编译成CHM文件。在开始编程之前,我们有必要了解下HTML Help Workshop是怎么生成CHM的。

HTML Help Workshop编译成CHM文件需要如下三个文件,分别以hhp,hhc,hhk为文件后缀名。

hhp:CHM工程文件,CHM目标文件属性95%的参数都在这里被确定.
hhc,列表文件,确定目标文件中左侧树形列表中”目录”选项卡下的内容.
hhk,索引文件,确定目标文件中左侧树形列表中”索引”选项卡下的内容.
hhp几乎就是一个标准的ini文件.分为三个小节Option,Windows,Files.

典型的配置文件(hhp)结构如下:

[OPTIONS]
Compatibility=1.1 Or later
Default window=Main
Default font=宋体,9,1
Contents file=test.hhc
Index file=test.hhk
Display compile progress=Yes
Full-text search=Yes
Language=0X804 中文(中国)

[WINDOWS]
Main=,”test.hhc”,”test.hhk”,,,,,,,0x20,0xB4,0x104E,[80,60,720,540],0x0,0x0,,,,,0

[FILES]
NewTopic.html

稍微解释下:

Default window=Main:默认的显示模式,这里是主页面

Default font=宋体,9,1:默认的字体

Contents file=test.hhc:内容文件

Index file=test.hhk:索引文件

Display compile progress=Yes:是否显示编译过程

Full-text search=Yes:是否全文搜索

Language=0X804 中文(中国):默认语言

索引文件(hhk)也是一个HTML文件,它包含若干个关键词,当用户打开chm文件后,单击索引标签并输入一个关键词后,chm文件将显示与这个关键词有关的主题的列表,使大家非常方便地找到相关主题。 典型的文件结构如下:

代码
DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> <HTML> <HEAD> <meta name="GENERATOR" content="Microsoft® HTML Help Workshop 4.1">   HEAD> <BODY> <UL>  <LI> <OBJECT type="text/sitemap">  <param name="Name" value="NewTopic">  <param name="Local" value="NewTopic.html">  OBJECT> UL> BODY> HTML>
 
内容页项目资源hhc)文件结构如下:
代码
DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> <HTML> <HEAD> <meta name="GENERATOR" content="Microsoft® HTML Help Workshop 4.1"> HEAD> <BODY> <OBJECT type="text/site properties">  <param name="Window Styles" value="0x237"> OBJECT> <UL>  <LI> <OBJECT type="text/sitemap">  <param name="Name" value="NewTopic">  OBJECT> <UL>  <LI> <OBJECT type="text/sitemap">  <param name="Name" value="NewTopic">  <param name="Local" value="NewTopic.html">  OBJECT> UL> UL> BODY> HTML>
 

用C#编程实现编译,其实是利用Process类来调用exe实现的。
代码
Process helpCompileProcess = new Process(); //创建新的进程,用Process启动HHC.EXE来Compile一个CHM文件  try  {  //判断文件是否存在并不被占用  try  {  string path = _chmFile; //chm生成路径  if (File.Exists(path))  {  File.Delete(path);  }  }  catch  {  throw new Exception("文件被打开!");  }  ProcessStartInfo processStartInfo = new ProcessStartInfo();  processStartInfo.WindowStyle = ProcessWindowStyle.Hidden;  processStartInfo.FileName = hhcFile; //调入HHC.EXE文件  processStartInfo.Arguments = "\"" + Path.GetFullPath(GetPathToProjectFile()) + "\"";//获取空的HHP文件  processStartInfo.UseShellExecute = false;  helpCompileProcess.StartInfo = processStartInfo;  helpCompileProcess.Start();  helpCompileProcess.WaitForExit(); //组件无限期地等待关联进程退出  if (helpCompileProcess.ExitCode == 0)  {  MessageBox.Show(new Exception().Message);  return false;  }  }  finally  {  helpCompileProcess.Close();  }  return true;
 

附件是项目,.Net4.0的,有兴趣的可以在其他版本上也实现下,只要将文件拷过去即可。

如果是vs2010,直接运行项目即可,在运行项目之前可以先把CreateChm\bin\Debug目录下的hhp、hhc、hhk、chm文件全部删掉,运行程序后后生成这些文件。

PS:我尝试将一些引用js文件和图片的html文件,将他们编译为chm文件时,这些js文件和图片能够自动被包含到chm文件中,呵呵,这样就可以创建丰富多彩的chm文件了,如我给的demo中,指针就是一个漂亮的时钟,关于更复杂的CHM编程,稍后带来。

PS:如果觉得的好的话,请点推荐,如果值得收藏的话,请点收藏,3Q

C#创建简易CHM文件Demo

[原创]ASP.NET MVC 使用模板引擎AderTemplateEngine进行视图解析

mikel阅读(1143)

ASP.NET MVC 使用AderTemplateEngine模板引擎进行视图显示

1. 创建ArtTemplateViewLocator视图文件定位类,代码如下:

namespace ArtLib

{

class ArtTemplateViewLocator : ViewLocator

{

public ArtTemplateViewLocator()

{

base.ViewLocationFormats = new string[] { “~/Views/{1}/{0}.htm”,

“~/Views/{1}/{0}.html”,

“~/Views/Shared/{0}.htm”,

“~/Views/Shared/{0}.html”

};

base.MasterLocationFormats = new string[] { “” };

}

}

}

2. 创建VariableResolver类用于ArtTemplate模板视图解析,并注册自定义组件TagList,代码如下:

namespace ArtLib

{

public static class VariableResolver

{

public static object ArtTemplateResolve(string filePath,IDictionary viewData)

{

//初始化模板引擎

TemplateManager template1 = TemplateManager.FromFile(filePath);

//设置模板数据

template1.SetValue(“ViewData”, viewData);

//注册自定义的标签

template1.RegisterCustomTag(“list”, new TagList());

return template1.Process();

}

}

}

3. 创建ArtTemplateViewEngine类用于处理视图请求,并赋予ViewData给模板引擎,代码如下:

IViewLocator _viewLocator = null;

public IViewLocator ViewLocator

{

get

{

if (this._viewLocator == null)

{

this._viewLocator = new ArtTemplateViewLocator();

}

return this._viewLocator;

}

set

{

this._viewLocator = value;

}

}

public string TemplatePath { get; set; }

#region IViewEngine 成员

public void RenderView(ViewContext viewContext)

{

string viewLocation = ViewLocator.GetViewLocation(viewContext, viewContext.ViewName);

if (string.IsNullOrEmpty(viewLocation))

{

throw new InvalidOperationException(string.Format(“View {0} could not be found.”, viewContext.ViewName));

}

string viewPath = HttpContext.Current.Request.MapPath(viewLocation);

//以下为模板解析

string viewTemplate = VariableResolver.ArtTemplateResolve(viewPath, viewContext.ViewData) as string;

HttpContext.Current.Response.Write(viewTemplate);

}

#endregion

4. 创建ArtTemplateControllerFactory类,用于Golbal.asax进行视图绑定,代码如下:

namespace ArtLib

{

public class ArtTemplateControllerFactory : DefaultControllerFactory

{

protected override IController CreateController(RequestContext requestContext, string controllerName)

{

Controller controller = (Controller)base.CreateController(requestContext, controllerName);

controller.ViewEngine = new ArtTemplateViewEngine();//修改默认的视图引擎为我们刚才创建的视图引擎

return controller;

}

}

}

5. 创建自定义的模板标签类:TagList.cs用于显示数据列表,代码如下:

namespace ArtLib

{

public class TagList : ITagHandler

{

#region ITagHandler 成员

public void TagBeginProcess(TemplateManager manager, Ader.TemplateEngine.Parser.AST.Tag tag, ref bool processInnerElements, ref bool captureInnerContent)

{

processInnerElements = true;

captureInnerContent = true;

}

public void TagEndProcess(TemplateManager manager, Ader.TemplateEngine.Parser.AST.Tag tag, string innerContent)

{

Expression exp;

exp = tag.AttributeValue(“pageSize”);

if (exp == null)

throw new Exception(“Missing attribute: pageSize”);

string pageSize = manager.EvalExpression(exp).ToString();

exp = tag.AttributeValue(“currentPage”);

if (exp == null)

throw new Exception(“Missing attribute: currentPage”);

string currentPage = manager.EvalExpression(exp).ToString();

Business business = new BusinessLogic();

List<InformationSimple> list = new List<InformationSimple>();

if (string.IsNullOrEmpty(pageSize))

{

list = business.Select<InformationSimple>();

}

else

{

Page page = new Page();

page.PageSize = Convert.ToInt32(pageSize);

page.CurrentPage = Convert.ToInt32(currentPage);

list = business.SelectByPage<InformationSimple>(ref page);

}

String html = “”;

foreach (InformationSimple info in list)

{

html = html + “<tr><td>” + info.InfoTitle + “</td></tr>”;

}

html = “<table>” + html + “</table>”;

manager.WriteValue(html);

}

#endregion

}

6. 修改ASP.NET MVC的测试项目的Global.asax文件的Application_Start()方法,加入自定义控制器工厂类:ArtTemplateControllerFactory,代码如下:

protected void Application_Start()

{

ControllerBuilder.Current.SetControllerFactory(typeof(ArtTemplateControllerFactory));

RegisterRoutes(RouteTable.Routes);

}

7. 创建模板文件Views/Home/Index.htm,代码如下:

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>

<html xmlns=”http://www.w3.org/1999/xhtml” >

<head>

<title></title>

</head>

<body>

<ad:list pageSize=”10″ currentPage=”1″></ad:list>

#ViewData[“Title”]#

</body>

</html>

8.

[转载].NET模板引擎 EFPlatform.CodeGenerator (代码生成器 静态页生成 生成HTML 模板)

mikel阅读(872)

[转载].NET模板引擎 EFPlatform.CodeGenerator (代码生成器 静态页生成 生成HTML 模板) – Eric’s Bloggy – 博客园.

这个东东是去年我看着ASP:标记突发奇想花4天 时间设计编写的类库, 原名叫 HtmlGenerator, 最近发现PHP和JAVA有很多类似的项目, 但是都设计的很渣(不同意的表打我@_@), 于是把 HtmlGenerator 重构了一下, 改叫 CodeGenerator. 配合我的数据库迁移工具和数据库实体类生成品….. 好像跑题了 -____-

CodeGenerator 的特点:
1. 标记简结实用, 所有网页美工都能在一分钟内掌握. 而且不与HTML标准冲突, 模板页可用任何WYSIWYG工具编辑, 和编辑普通HTML网完全相同.
2. 标记只与表示层相关, 不包括任何业务逻辑, 丝毫不影响你应用多层结构.
3. 标记到后台被解析成了生成器对象, 完全面向对象, 不像绝大多数生成器要死嗑字符串.
4. 生成器对象使用DataSource属性取得数据, DataSource可以为  简单值类型(如 int, DateTIme), 也可以为简单数组(如 decimal[], string[]), 还可以为ADO.NET数据集(如DataTable), 甚至单个对象实体或对象集合或列表(如 SomeClassCollection, List<SomeClass>), 所有数据源类型通吃! 哈哈, 比ASP.NET带的数据控件支持的类型还多.
5. 标记的Name直接与数据源的列名ColumnName或属性名PropertyName, 好处不言而喻了吧.
6. 说到这里好了, 留一手先. 呵呵

演示程序下载地址: http://files.cnblogs.com/ericfine/Demo.rar
EFPlatform.CodeGenerator 源代码下载地址: http://files.cnblogs.com/ericfine/EFPlatform.CodeGenerator.rar (过时了)
EFPlatform.TemplateEngine 源代码下载地址: http://files.cnblogs.com/ericfine/EFPlatform.TemplateEngine.rar (其实就是CodeGenerator的优化版:))

应用项目:
http://portray.mz99.com/
http://music.mz99.com/
http://joke.mz99.com/
http://www.mcuol.com/

应用流程:

Default.aspx.cs:

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.Common;
using System.IO;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using EFPlatform.TemplateEngine;

public partial class _Default : Page
{
private string outputPath;
private string categoryFileName;
private string productFileName;
private static DbProviderFactory dbFactory;
private DbConnection connection;

protected void Page_Load(object sender, EventArgs e)
{
outputPath
= Server.MapPath(./);
categoryFileName
= string.Format(@”{0}\Template\Category.html, outputPath);
productFileName
= string.Format(@”{0}\Template\Product.html, outputPath);
string currentConnection = ConfigurationManager.AppSettings[Connection];
ConnectionStringSettings css
= ConfigurationManager.ConnectionStrings[currentConnection];
this.GetConnection(css);
}


private void GenerateCategory()
{
string template = Helper.ReadTextFile(categoryFileName);
Generator gen
= new Generator(template);
gen.ParseTemplate();
Region rgnTitle
= gen.GetRegion(Title);
Region rgnCategory
= gen.GetRegion(Category);
Region rgnProducts
= gen.GetRegion(Products);
Region rgnNavigator
= gen.GetRegion(Navigator);

if(rgnTitle == null || rgnCategory == null || rgnProducts == null || rgnNavigator == null)
{
Response.Write(
Missing region.);
return;
}


int categoryId;
string outputFileName;
DataView dvCategory
= this.GetCategoryTable().DefaultView;
Pager pgrCategory
= new Pager(1, dvCategory.Count);

for(int i = 0; i < pgrCategory.PageCount; i++)
{
rgnTitle.DataSource
= (string)dvCategory[i][CategoryName]; //Use a string as data source
rgnCategory.DataSource = dvCategory[i]; //Use a DataRowView object as data source
pgrCategory.CurrentPage = i + 1;
rgnNavigator.DataSource
= pgrCategory; //Use a Pager object as data source
categoryId = (int)dvCategory[i][CategoryID];
rgnProducts.DataSource
= this.GetProductTable(categoryId); //Use a DataTable object as data souce
outputFileName = string.Format(@”{0}\Html\Category{1}.html, outputPath, categoryId);
Helper.WriteTextFile(outputFileName, gen.Generate());
}

}


private void GenerateProduct()
{
string template = Helper.ReadTextFile(productFileName);
Generator gen
= new Generator(template);
gen.ParseTemplate();
Region rgnTitle
= gen.GetRegion(Title);
Region rgnProduct
= gen.GetRegion(Product);
Region rgnNavigator
= gen.GetRegion(Navigator);

if(rgnTitle == null || rgnProduct == null || rgnNavigator == null)
{
Response.Write(
Missing region.);
return;
}


string outputFileName;
List
<Product> productList = this.GetProductList();
Pager pgrProduct
= new Pager(1, productList.Count);

for(int i = 0; i < pgrProduct.PageCount; i++)
{
rgnTitle.DataSource
= productList[i].CategoryName; //Use a string as data source
rgnProduct.DataSource = productList[i]; //Use a Product object as data source
pgrProduct.CurrentPage = i + 1;
rgnNavigator.DataSource
= pgrProduct; //Use a Pager object as data source
outputFileName = string.Format(@”{0}\Html\Product{1}.html, outputPath, productList[i].ProductID);
Helper.WriteTextFile(outputFileName, gen.Generate());
}

}


DataSourcePreparing

protected void Button1_Click(object sender, EventArgs e)
{
this.GenerateCategory();
}


protected void Button2_Click(object sender, EventArgs e)
{
this.GenerateProduct();
}

}

Web.config:

<?xml version=”1.0″?>
<configuration>
<system.web>
<compilation Debug=”true” />
<authentication mode=”Windows” />
<customErrors mode=”Off” defaultRedirect=”GenericErrorPage.htm”>
<error statusCode=”403″ redirect=”NoAccess.htm” />
<error statusCode=”404″ redirect=”FileNotFound.htm” />
</customErrors>
</system.web>
<connectionStrings>
<add name=”Access” providerName=”System.Data.OleDb” connectionString=”Provider=Microsoft.Jet.OLEDB.4.0;Data Source=|DataDirectory|Northwind.mdb”/>
<add name=”SQLExpress” providerName=”System.Data.SQLClient” connectionString=”Data Source=.\SQLExpress;Integrated Security=True;User Instance=True;Database=Northwind;AttachDBFilename=|DataDirectory|Northwind.mdf”/>
</connectionStrings>
<appSettings>
<add key=”Connection” value=”Access”/>
</appSettings>
</configuration>

[转载]模版引擎AderTemplate源代码分析笔记

mikel阅读(1126)

[转载]模版引擎AderTemplate源代码分析笔记 – kwklover – 博客园.

概述

AderTemplate是一个小型的模板引擎。无论是拿来直接使用还是用来研究模板引擎实现方式,都是一个不错的选择。本文尝试对其源代码做一些分析。

数据流程

AderTemplate的数据处理流程可以总结为:
模版文件 -> 模版分析 -> Template对象 -> 分析处理TemplateElement集合 -> 输出目标文本

模版语法

简化描述如下

1,变量替换 :如#variable#

2,循环语句 <ad:foreach var=”x” collection=”#values#” index=”i”></ad:foreach>

3,判断语句 <ad:if test=”#value#”> </ad:if>

详细请参看AderTemplate的相关说明.

模版分析

模版分析的过程可以分成两步:
1
,把模版文件分析成Token

2,对Token流进行分析,形成Element集合

所以,首先要了解TokenElement的结构与异同。

Token的类结构:

AderTemplateToken.JPG

TokenKind(Token的类型)的详细说明:

TokenKind

说明

EOF

结束符

Comment

注释,但在AderTemplate没看到具体实现

ID

这个比较难描述,下面会通过输出Token流来直官了解下ID

TextData

文本数据,不包含模版语法的独立文本区

TagStart

Tag的开始标记,<ad: 注:Tag是一个Element,后面详述

TagEnd

Tag的结束符, > ,注意与TagClose的区别

TagEndClose

Tag的自闭结束符 ,即 />

TagClose

Tag的结束标记 </ad: <ad:对应,所以与TagEnd很容易区别

TagEquals

Tag=符号。与Tag无关的=属于TextData,TagEquals

ExpStart

AderTemplate中,语法#v#被定义为Expression.#ExpStart

ExpEnd

AderTemplate中,语法#v#被定义为Expression.#ExpEnd

LParent

左括号 (

RParent

右括号 )

Dot

即一个点 .

Comma

逗号 ,

Integer

数字

StringStart

文本的开始符,即

StringEnd

文本的结束符,即

StringText

How to description ?

为了获得更直观的认识。下面尝试把一个简单的模版文件分析的Token流输出。
模版文件,我们暂且命名为templateFile

<ad:foreach collection=”#GetBookList(3)#” var=”book” index=”i”>

<tr>

<td>#i#</td>

<td>#book.BookName#</td>

<td>#book.BookCount#</td>

</tr>

</ad:foreach>

分析的代码:

static void Main(string[] args)

{

string data = string.Empty;

using (System.IO.StreamReader reader = new System.IO.StreamReader(templateFile))

{

data = reader.ReadToEnd();

}

//模版分析,形成Token

TemplateLexer lexer = new TemplateLexer(data);

Console.WriteLine(“=======开始输出TemplateLexer分析出Token=======”);

do

{

Token token = lexer.Next();

Console.WriteLine(“\tToken类型:{0}\t行列:({1}, {2})\t数据:{3}”, token.TokenKind.ToString(), token.Line, token.Col

, token.Data.Replace(“\r\n”, “”));

if (token.TokenKind == TokenKind.EOF)

break;

} while (true);

Console.WriteLine(“=======结束输出TemplateLexer分析出Token=======\r\n”);

}

输出结果:

输出结果

对照表格的说明和输出结果。可以把Token理解为特定类型的文本区,即把模版文件按照TokenKind定义的类型分解成多个文本区(Token),所以分析模版文件形成的Token(集合)是一种相对线性的结构。是对模版文件的初步分析与处理。

下面继续说说Element的类体系:

AderTemplateElement.JPG

上述类关系图中可以看到Element主要有四个继承体系。

但每个类表达的意义是什么呢?

下面用一个表格做一个简单的说明。

类名

指代及其含义

Element

各种Element的基类

Text

文本类的Element , TokenKindTextDataToken相似的概念

TagClose

Tag结束符号

Tag

Tag是一个比较广的概念。上述的模版可以表示一个foreach tag

Expression

AderTemplate把语法类似#values#定义为一个Expression

FCall

Expression子类之一,表示该Expression是一个外部函数(Function)

FieldAccess

Expression子类之一,可以近似的理解成字段访问”,#book.BookName#

Name

Expression子类之一,可以近似的理解成外部变量”,#i#

StringLiteral

Expression子类之一,可以近似的理解成非数字型变量

IntLiteral

Expression子类之一,可以近似的理解成数字型变量

StringExpression

Expression子类之一,但其表示的是Expression的集合封装类

为了获得更直观的了解。我们可以通过分析上述的模版文件输出的Element来理解。因为此部分代码比较多。所以不列出了。后面会提供包含本文提到的所有代码的example.

这里需要说明的是Tag ElementTag是一个复合结构.Tag在不同的分析阶段,会些许不同。

如下面代码的(1)(2)分析出的Element是不同的。可通过输出结果来跟踪异同。

TemplateLexer lexer = new TemplateLexer(templateData);

TemplateParser parser = new TemplateParser(lexer);

List<Element> elems = parser.Parse(); –(1)

TagParser tagParser = new TagParser(elems);

elems = tagParser.CreateHierarchy(); –(2)

TokenElement异同分析:

在上面已经提到,Token是对模版文件的一种初步分析和分解。AderTemplate对模版文件的分析处理目标是把模版文件表达为一个Template对象。而Template对象的本质其实就是Element集合的封装类,也就是AderTemplate的对模版文件的分析其实是希望把模版文件在程序结构层面表达为一个Element的集合,从上面的ElementToken类关系图可以看出。Element远比Token复杂的多。如果直接从模版文件直接分析成Element集合结构的话,可以预见分析过程会变的相当复杂。所以AderTemplate引入了Token数据结构作为一种辅助分析手段。使得AderTemplate的对模版文件的分析过程变得更流畅和清晰了。程序的架构也变得相对优雅。所以我认为阅读AderTemplate的源代码,关键是理解TokenElement的结构和作用。特别是Element结构。因为它是AderTemplate的基础结构。即解决了在程序层面用什么结构来表达模版文件的问题。

模版分析涉及到的处理类:

TemplateLexer : 从模版文件中分析成Token流。

TemplateParser: 基于Token流分析成初步的Element集合结构。

TagParser : 把TemplateParser分析出的Element集合做最后的优化处理。

Template(模版)对象:

AderTemplate中。我们可以简单地认为一个Template就是经过模版分析后形成的最终的Element集合的封装体。

Template(模版)处理:

TemplateElement集合进行分析。生成目标文本。

此过程涉及到的技术其实不复杂,就是反射和委托,所以本文不打算详细分析此过程。否则篇幅过大。而且没什么意义。在后面我会提供一个模拟AderTemplateElement分析处理到生成目标文本过程的例字。

相关例子

为了辅助理解AderTemplate的整个处理过程。我写了几个例子。
1
,输出Token的结构信息。对比模版文件辅助理解Token的结构

2,输出从Token流中分析出的Element集合的结构信息。以辅助理解Element的结构。

3,模拟从Element集合中生成目标文本的过程。辅助理解从Element集合到生成目标文本的整个处理流程和过程。这个过程是相对简单的。从这个角度来看,AderTemplateElement集合来表达模版文件是一个比较优秀的设计。

至于如何从模版文件分析成Element集合(Template对象)则是一个相对复杂的过程了。最好的解释还是源代码本身了。所以就不在此不做更多的分析了。

总结

AderTemplate是一个小型的模版引擎。功能并不算强大。但基本功能已经具备。从应用的角度来说,可能未必是一个最好的选择。但想学习模版引擎的开发。确是一个很不错的选择。我个人认为其架构还是比较优秀的。而且数据处理流程也很清晰。

当写作本文的时候,我阅读AderTemplate的源代码已有好些天了。依然感觉似懂非懂。到是写本文让我把思路给理清了。所以有时候。我觉得。写笔记也是一种学习。:)


AderTemplate与相关例子代码下载

[转载]推荐一个模板引擎templateengine

mikel阅读(1064)

[转载]推荐一个模板引擎 – templateengine – 流浪的风(专注于.NET2.0技术) – 博客园.

一直都在使用StringTemplate模板引擎,虽然使用方便,但是功能实在太弱太弱,准备放弃使用StringTemplate。刚好碰巧发现了另外一个开源的模板引擎,就是今天要介绍的TemplateEngine 2,功能非常强大。

先看看他的语法吧

Thank You for your order #order.billFirstName# #order.billLastName#.
<br>
Your Order Total is: #format(order.total, “C”)#
<br>
<ad:if test=”#order.shipcountry isnot “US”#”>
Your order will arrive in 2-3 weeks
<ad:else>
Your order will arrive in 5-7 days
</ad:if>

TemplateEngine2.0 主要功能

Template Engine主要是两个类在使用:Template 和TemplateManager,Template 是一个基本模板, TemplateManager是扩展的模板

用Template或TemplateManager 是非常容易创建模板的

Template template = Template.FromString(string name, string data)
Template template
= Template.FromFile(string name, string filename)

用TemplateManager

TemplateManager mngr = new TemplateManager(Template template);

或者

TemplateManager mngr = TemplateManager.FromFile(string filename);
TemplateManager mngr
= TemplateManager.FromString(string template);

当调用FromString 方法时,string是模板的代码。这个方法能动态的加载文本到template中。FormFile是指调用的模板文件。

TemplateManager有个属性SetValue可以用来设置模板的变量和变量的内容

mngr.SetValue(xx, xxxxxxxxxxxxxx);

输出模板

Response.Write(mngr.Process());

这一切都非常的简单。

函数列表

equals(obj1.obj2) 比较两个变量是否一样,返回bool型
notequals(obj1,obj2)比较两个变量是否不一样,返回 bool型 也可以 not(equals(obj1,obj2))
iseven(num) 测试是否是偶数
isodd(num)测试是否奇数
isempty(string) 测试字符串是否为0
isnotempty(string) 测试字符串是否大于0
isnumber(num) 测试是否为整型
toupper(string) 转化成大写
tolower(string) 转化成小写
isdefined(varname) 测试变量是否有定义
ifdefined(varname, value) 返回 value 如果varname 是有定义的,
特别有用:#ifdefined(“name”, name)# 将输出value 如果varname没有定义,其它情况不输出
len(string)返回字符串长度
tolist(collection, property, delim) 简单的输出列表

例1:

ArrayList list = new ArrayList();
list.Add(
one);
list.Add(
two);
list.Add(
three);
template.SetValue(
mylist, list);

你的模板内容:
#toList(mylist, ” & “)#
输出:one & two & three

例2:

list.Add(new Customer(Tom, Whatever));
list.Add(
new Customer(Henry, III));
list.Add(
new Customer(Tom, Jackson));
template.SetValue(
mylist, list);

模板内容:
#toList(mylist, “firstName”, “,”)#
输出:Tom,Henry,Tom

函数列表

snull(obj)
测试是否为空
not(boolvalue) 返回not(!)的bool型
iif(booleanExpression, iftruevalue, iffalsevalue) 如果booleanExpression为真,输出iftruevalue,否则输出iffalsevalue
format(object, formatstring)格式化字符串,相当于ToString(formatstring)

例子:

#format(total, “C”)#
will output: $1,208.45

函数列表

trim(string)
去除前后空格
filter(collection, booleanproperty) 返回一个新的组所有符合booleanproperty要求的
gt(obj1,obj2) 如果 obj1 > obj2 返回为真,否则为false
lt(obj1,obj2) 如果 obj1 < obj2 返回为真,否则为false
compare(obj1, obj2) 如果 obj1<obj2 返回-1 obj1=obj2 返回0 如果obj1>obj2 返回1
or(bool1,bool2) 有一个为真返回就是true
and(bool1, bool2) 两个都为真时返回true
comparenocase(string1, string2) 相等时返回为true 否则为false
stripnewlines(string) 返回 所有\r\n 用space 代替的字符串
typeof(object) 返回object 类型,如typeof(“abcd234”) 返回 “string” typeof(3) 返回 int
cint(value) 返回整数 等同于Convert.toInt32()
cdouble(value) 返回双精度
cdate(value) 返回一个datetime 型
createtypereference(type) 引用一个静态的类型,但格式必须是<ad:set tag

例:
#createtypereference(“System.Math”).Round(3.39789)#
#createtypereference(“System.Math”).PI#
or
<ad:set name=”MyMath” value=”#createtypereference(“System.Math”)#” />
#MyMath.Round(3.3)#
#MyMath.PI#

还支持C#内置的一些方法,如还可以这样使用
#xx.Length#

还有很多你意想不到的效果,赶紧来试用吧。

官方地址:http://www.adersoftware.com/index.cfm?page=templateEngine2

[转载]使用vbs借助mspaint.exe实现图片无损压缩

mikel阅读(1054)

[转载]使用vbs借助mspaint.exe实现图片无损压缩_勇敢的心_百度空间.

有的时候四处寻觅的好东西可能就在眼前!由于想要换一个网站的Banner,为了能把图片压缩到极致,于是四处寻找好用的图片压缩工具,试用了一些软件后 才发现,原来最好的图片压缩工具其实就是微软winXP系统下自带的MSpaint.exe(画图程序)。

美中不足的是Mspaint无批量处理功能,只能逐个压缩,这给我们需要处理大量图片的朋友带来了不小困难。笔者就此问题,在网上也找了若干的解决方案,发现借助vbs可以很好地解决此问题;参照其他网友的实现,笔者又做了少许加工,完成了如下vbs脚本:

‘**********************************************
‘*使用说明,选择源文件夹和目标文件夹
‘*不支持中文路径和文件名
‘**********************************************

Dim FileName,fs,srcFolder,disFolder
Const PICTURE_TYPE = “.jpg.gif.jpeg”
Const MY_COMPUTER = &H11&
Const WINDOW_HANDLE = 0
Const OPTIONS = 0
Set objShell = CreateObject(“Shell.Application”)
Set objFolder = objShell.Namespace(My_Computer)
Set objFolderItem = objFolder.Self
srcFolder = objFolderItem.Path

‘**********************************************
‘*选择源文件夹
‘**********************************************
Set objFolder = objShell.BrowseForFolder(WINDOW_HANDLE, “选择源文件夹:”, OPTIONS, “”)
If objFolder Is Nothing Then
msgbox “您没有选择任何有效目录!”
wscript.quit
End If

Set objFolderItem = objFolder.Self
srcFolder = objFolderItem.Path

If HasChinese(srcFolder) Then
msgbox “不支持中文路径,请重新选择!”
wscript.quit
End If

‘**********************************************
‘*选择输出文件夹
‘**********************************************
Set objFolder = objShell.BrowseForFolder(WINDOW_HANDLE, “选择输出文件夹:”, OPTIONS, “”)
If objFolder Is Nothing Then
msgbox “您没有选择任何有效目录!”
wscript.quit
End If

Set objFolderItem = objFolder.Self
disFolder = objFolderItem.Path

If HasChinese(disFolder) Then
msgbox “不支持中文路径,请重新选择!”
wscript.quit
End If
Call main

Sub main
On Error Resume Next
set WshShell = WScript.CreateObject(“WScript.Shell”)
WshShell.Run “C:\WINDOWS\system32\mspaint.exe”
WScript.Sleep 1000
WshShell.AppActivate “paint”
WScript.Sleep 1000

Dim objfso,objfolder1
Set objfso = CreateObject(“scripting.filesystemobject”)
Set objfolder1 = objfso.getfolder(srcFolder)

For Each objfile In objfolder1.files
If AllowExtension(LCase(objfso.GetExtensionName(objfile))) =true Then

WshShell.Sendkeys “^o”
WScript.Sleep 100
path=TrimLast(srcFolder,”\”) +”\”+ objfile.name
WshShell.SendKeys path
WScript.Sleep 100
WshShell.SendKeys “~”
WScript.Sleep 200
‘另存为
WshShell.Sendkeys “%f”
WshShell.Sendkeys “a”
WScript.Sleep 100
WshShell.Sendkeys “{BS}”
path=TrimLast(disFolder,”\”) +”\”+ objfile.name
WshShell.SendKeys path
WScript.Sleep 100
WshShell.Sendkeys “~”
WScript.Sleep 200

End If
Next

End Sub
‘**********************************************
‘*检查是否含有中文
‘**********************************************
Function HasChinese(sFileName)
Set regEx = New RegExp
regEx.Pattern = “^[\x00-\xff]*$”
regEx.IgnoreCase = True
HasChinese = Not regEx.test(sFileName)
End Function

‘**********************************************
‘*检查是否允许的扩展名
‘**********************************************
Function AllowExtension(sFileName)
If IsNull(sFileName) Or sFileName = “” Then
AllowExtension = False
else
AllowExtension = InStr(PICTURE_TYPE,sFileName)>0
End If
End Function

‘****
‘* Remove “chr” (if it exists) from end of “str”.
‘****
Function TrimLast(str,chr)
TrimLast = str
If Right(str,1) = chr Then
TrimLast = Left(str,Len(str)-1)
End If
End Function

直接下载:批量压缩图片.vbs

[转载].net c# 一个简单但是功能强大动态模板引擎

mikel阅读(997)

[转载].net c# 一个简单但是功能强大动态模板引擎 – DotNet Software Project – 博客园.

net C# 一个简单但是功能强大动态模板引擎(一) 收藏
注意:欢迎转载,但是请注明出处.

流行的模板引擎有很多,譬如Velocity.但是他的模板语言比较简,复杂的功能比较难实现,而且编辑模板比较麻烦容易出错.

但是利用UserControl就可以实现功能强大的一个动态模板引擎,编辑的模板的时候跟编辑一个用户控件没有区别,并且支持任何.net语言譬如C#.

下面就是代码:

view plaincopy to clipboardprint?
using System;
using System.Collections.Generic;
using System.Text;

namespace Template
{
public class TemplateBody : System.Web.UI.UserControl
{
private IDictionary<string, object> _context = new Dictionary<string, object>();
protected void Page_Load(object sender, EventArgs e)
{

}

public IDictionary<string, object> ViewData
{
get { return _context; }
}
}
}
using System;
using System.Collections.Generic;
using System.Text;

namespace Template
{
public class TemplateBody : System.Web.UI.UserControl
{
private IDictionary<string, object> _context = new Dictionary<string, object>();
protected void Page_Load(object sender, EventArgs e)
{

}

public IDictionary<string, object> ViewData
{
get { return _context; }
}
}
}

TemplateBody类基本没什么代码只是声明了一个ViewData属性,该属性用于向模板添加数据由模板来获取并展示.

view plaincopy to clipboardprint?
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Web.UI;

namespace Template
{
public class TemplateEngine:IDisposable
{
private UserControl _uc;
private TemplateBody _tpl;

public TemplateEngine()
{
_uc = new UserControl();
}
/// <summary>
/// 加载一个模板
/// </summary>
/// <param name=”path”>这个路径为相对路径</param>
public void Load(string path)
{
_tpl = _uc.LoadControl(path) as TemplateBody;
if (_tpl == null)
{
throw (new ArgumentException(path));
}
}
/// <summary>
/// 控制展示
/// </summary>
/// <returns>返回生成的字符串</returns>
public string Render()
{
TextWriter tw = new StringWriter();
Render(tw);
return tw.ToString();
}
/// <summary>
/// 展示模板
/// </summary>
/// <param name=”writer”>TextWriter对象,可以传Response.Output</param>
public void Render(TextWriter writer)
{
HtmlTextWriter htw = new HtmlTextWriter(writer);
_tpl.RenderControl(htw);
}
/// <summary>
/// 增加一个显示数据的上下文
/// </summary>
/// <param name=”key”></param>
/// <param name=”obj”></param>
public void AddContext(string key, object obj)
{
_tpl.ViewData.Add(key, obj);
}

public object this[string key]
{
get{
object ret;
_tpl.ViewData.TryGetValue(key, out ret);
return ret;
}
set { AddContext(key, value); }
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected void Dispose(bool disposing)
{
if (disposing)
{
_uc.Dispose();
}

}
~TemplateEngine()
{
Dispose(false);
}
}
}
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Web.UI;

namespace Template
{
public class TemplateEngine:IDisposable
{
private UserControl _uc;
private TemplateBody _tpl;

public TemplateEngine()
{
_uc = new UserControl();
}
/// <summary>
/// 加载一个模板
/// </summary>
/// <param name=”path”>这个路径为相对路径</param>
public void Load(string path)
{
_tpl = _uc.LoadControl(path) as TemplateBody;
if (_tpl == null)
{
throw (new ArgumentException(path));
}
}
/// <summary>
/// 控制展示
/// </summary>
/// <returns>返回生成的字符串</returns>
public string Render()
{
TextWriter tw = new StringWriter();
Render(tw);
return tw.ToString();
}
/// <summary>
/// 展示模板
/// </summary>
/// <param name=”writer”>TextWriter对象,可以传Response.Output</param>
public void Render(TextWriter writer)
{
HtmlTextWriter htw = new HtmlTextWriter(writer);
_tpl.RenderControl(htw);
}
/// <summary>
/// 增加一个显示数据的上下文
/// </summary>
/// <param name=”key”></param>
/// <param name=”obj”></param>
public void AddContext(string key, object obj)
{
_tpl.ViewData.Add(key, obj);
}

public object this[string key]
{
get{
object ret;
_tpl.ViewData.TryGetValue(key, out ret);
return ret;
}
set { AddContext(key, value); }
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected void Dispose(bool disposing)
{
if (disposing)
{
_uc.Dispose();
}

}
~TemplateEngine()
{
Dispose(false);
}
}
}

TemplateEngine 是负责显示的类,核心代码也就是调用了RenderControl函数.

下面是具体使用:

1.创建一个web工程,注意其他工程可能不支持.

2.添加默认页面Default.aspx

3.根目录添加一个TemplateTest.ascx的模板文件 扩展名默认是ascx,如果需要更改别的扩展名的话需要在web.config里在compilation节点增加下列代码:

view plaincopy to clipboardprint?
<buildProviders>
<add extension=”.view” type=”System.Web.Compilation.UserControlBuildProvider”/>
</buildProviders>
<buildProviders>
<add extension=”.view” type=”System.Web.Compilation.UserControlBuildProvider”/>
</buildProviders>

4.直接运行就可以.

Default.aspx代码:

view plaincopy to clipboardprint?
using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;

using Template;

namespace TemplateDemo
{
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
TemplateEngine te = new TemplateEngine();
te.Load(“TemplateTest.ascx”);
te.AddContext(“Text”, “Super Man”);
te.Render(Response.Output);
}
}
}
using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;

using Template;

namespace TemplateDemo
{
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
TemplateEngine te = new TemplateEngine();
te.Load(“TemplateTest.ascx”);
te.AddContext(“Text”, “Super Man”);
te.Render(Response.Output);
}
}
}
TemplateTest.ascx代码:

view plaincopy to clipboardprint?
<%@ Control Language=”C#” AutoEventWireup=”true” CodeBehind=”TemplateBody.cs” Inherits=”Template.TemplateBody” %>

<% for (int i = 0; i < 10; i++){
%>
<%=ViewData[“Text”]%>
<% }%>
<%@ Control Language=”C#” AutoEventWireup=”true” CodeBehind=”TemplateBody.cs” Inherits=”Template.TemplateBody” %>
<% for (int i = 0; i < 10; i++){
%>
<%=ViewData[“Text”]%>
<% }%>

记住,模板必须要加这个头:

<%@ Control Language=”C#” AutoEventWireup=”true” CodeBehind=”TemplateBody.cs” Inherits=”Template.TemplateBody” %>

下面是显示结果:

Super Man Super Man Super Man Super Man Super Man Super Man Super Man Super Man Super Man Super Man

需要改进的地方:

目前模板只支持相对路径,因为.net他对文件进行缓存处理,这样运行一次模板后即编译模板并进行缓存,如果文件被更改将重新编译,提高效率.

如果您需要从数据库或者从一个Stream里加载模板的话,需要重写VirtualPathProvide,并且重写判断模板被更改的函数 CacheDependency,还有获取虚拟文件的函数GetFile, 这样很容易实现从任何地方获取模板.如果您有兴趣可以进行改进,完善.

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/baoaya/archive/2009/07/27/4384178.aspx

[转载]jtemplates jquery模板引擎使用

mikel阅读(1031)

[转载]jtemplates jquery模板引擎使用 – 蛰穴灵异 技术博客 – 博客园.

工作中需要在前端将json数据源绑定到页面html代码中,之前一直用组合html代码的形式编写,不太容易维护。Ms ajax4.0据说有一套模板引擎,只有预览版,而且看来比较复杂,不太能马上用。在网上找到一个jtemplates的js模板引擎,感觉还可以,适合 用来在页面上动态绑定数据。

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
<html xmlns=”http://www.w3.org/1999/xhtml”>
<head runat=”server”>
<title>Index</title>
<script src=”/Scripts/JQuery-1.3.2.js” type=”text/JavaScript></script>
<script src=”/Scripts/plugins/JQuery-jtemplates.js” type=”text/JavaScript></script>

<script type=”text/JavaScript>
$(document).ready(
function() {
var data = [{ name1: 测试信息,id:12 },{ name1: 测试信息,id:12 }];
$(
#result).setTemplateElement(template1);
$(
#result).processTemplate(data);
});
</script>
</head>
<body>
<div>
<textarea id=”template1″ style=”display: none;”>
<table>
<thead>
<tr>
<td colspan=”2″>
fdaasfd
</td>
</tr>
</thead>
<tbody>
{#foreach $T as r}
<tr>
<td>
name:{$T.r.name1}
</td>
<td>
id:{$T.r.id}
</td>
</tr>
{#/for}
</tbody>
<tfoot>
</tfoot>
</table>
</textarea>
</div>

<div id=”result”></div>
</body>
</html>

[转载]从模板引擎到模板引擎-使用aspx页面作为模板引擎的一种实现

mikel阅读(942)

[转载]从模板引擎到模板引擎-使用aspx页面作为模板引擎的一种实现 – 懒人居 – Coding for fun – 博客园.

此文完全有感而发,在网上看到很多介绍各类模板引擎的文章,但是我却越来越感觉到很多时候我们所做的事
情是在舍近求远。
什么是模板引擎?说白了就是能够自动替换占位符的替换引擎。原理上也就是两个步骤,找到-》替换。但是替换不是简单的替换,包括:

  • 简单变量替换();
  • 复杂变量替换();
  • 对象变量替换();
  • 键值类型替换();
  • 自定义集合替换();
  • 同时显示多个变量();
  • 模板调用();
  • 给调用模板传参数();
  • 值模板();
  • 简单循环();
  • 交差循环显示();
  • 通过模板交差循环();
  • 条件判断();
  • 从文件中创建模板();

常用的模板引擎,StringTemplate和Velocity差不多都是按照这种模式来设计的。但是这样子真的就是我们需要的吗?我们拿一段典型的StringTemplate的模板代码来看看:

首先是在模板文件中:

姓名:$User.Name$ 年龄:$User.Value$

然后是在代码里:

User us = new User();
us.Name
= xxsssx;
us.Value
=80;
StringTemplate st
= new StringTemplate($User.Name$,$User.Value$);
st.SetAttribute(
User, us);
Console.WriteLine(st.ToString());

那么我们来和ASP.NET本身的代码做一个比较
aspx页面
<asp:Label id=”Name” runat=”Server” /><asp:Label id=”Mail” runat=”Server” />
aspx.cs文件

User us = new User();
us.Name
= xxsssx;
us.Value
=80;
Name.Text
=us.Name;
Mail.Text
=us.Value

是不是有点感觉用了模板引擎跟脱了裤子放屁没有什么区别?
那么我们为什么要用模板引擎?是真的需要还是赶时髦?
就我个人来看,模板引擎是需要的。视图和控制的分离是必要的,但是我们要分清楚什么是视图,什么是控制。是不是视图就不能包含代码和逻辑?肯定答案是否定 的,因为就算用了StringTemplate,你还是需要给它填充数据,而给它填充数据的代码仍然是属于视图而不是控制或者有人干脆就当作了模型。那么 既然这样,为什么我们就不能用aspx页面本身来作为模板呢?它可以判断,可以循环,可以分支,可以使用现成的控件。比如

<%
if(Helper.IsLogin()){
User u=Helper.GetLoginedUser();
%>
你的姓名是:<%=u.Name%>
<%}%>

我们把这种方法和StringTemplate的方法来比较一下。

aspx模板    StringTemplate
ASP.NET控件    支持           不支持
复杂显示逻辑    支持          支持(未经测试所有可能性)
编辑器支持       支持          不支持
编译检测          支持           不支持

现在可能有个疑问了,aspx的页面怎么作为模板来被调用呢?以访问就直接看到了没办法生成静态页面啊?
其实解决的方法很简单,只需要Server.Execute()就可以将执行的aspx页面运行的结果以一个TextWriter返回。这样子要怎么处理还不是看我们怎么高兴啦。哈哈

记得之前有人提过类似方法,不过有人可能会质疑:那不是还有美工也会asp.net?其实回过头一想,如果你告诉美工<%=u.Name%> 就是代表用户的姓名,那么也不会需要美工学习全套的asp.net,而其实就美工来说,如果学习简单实用asp.net都有困难,那么学习 StringTemplate的全套模板语法和灵活掌握使用方法可能更加让人郁闷。如果这些工作都给程序员来完成的话,那么已经是程序员熟练掌握的C#语 法是不是更加的平易近人呢?况且还可以智能感知菜单和编译检测支持。所以我觉得在大多数情况下这种方法是比较爽的一种方式。