使用XML+XSLT实现业务表单
当时XFORM的概念相当热,我也看了一些资料,觉得还是不太成熟,没有敢用。
后来看了微软office2007中的infopath,感觉功能非常强,它可以实现用infopath设计表单,然后用表单控件把表单嵌入到winform中去,并且可以实现表单中的数据加载和保存功能。但是唯一的遗憾就是如果要使用它,就必须要客户机器上安装office2007,这样就不太现实了。
最后来想到的是用xml+xslt是动态生成静态页面,然后把静态页面嵌入在winform的浏览器控件里面,并且屏蔽一些浏览器控件的一些属性,看起来就和winform设计的表单差不多了。这样就方便多了,我可以叫美工帮我设计表单,叫其他的asp.net的程序员帮忙做XML和XSLT以及里面的javascript脚本。后来的项目进展说明了,这种方式真的大大的提高了工作效率,也让我轻松了不少,嘿嘿,又偷懒了。
下面我说说具体的过程吧。
1。首先我在设计表的时候,把整个表单的内容设计成XML类型的字段,当然,其他需要搜索的字段还是要单独建字段,并且保存xslt文件的版本号。
2。设计表单的XML结构,下面是示例。
<!--现场会议记录-->
<meetnote>
<enterprise></enterprise>
<!--会议名称-->
<meets>
<meet>
<name>meet1</name>
<checked>false</checked>
</meet>
<meet>
<name>meet2</name>
<checked>false</checked>
</meet>
<meet>
<name>meet3</name>
<checked>false</checked>
</meet>
</meets>
<compere />
<recorder />
<address />
<meetdate />
<content />
</meetnote>
3.设计表单的XSLT文件,下面是示例。
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
version="1.0" >
<xsl:template match="/">
<html>
<head>
<link href="../css/xmltable.css" rel="stylesheet" type="text/css" />
<script language="javascript">
//使用客户端日期JS脚本初始化
var date = new Date();
var Fun_Year = date.getYear();
var Fun_Month = date.getMonth()+1;
var Fun_Day = date.getDate();
</script>
<script language="javascript" src="../javascript/calendar.js"></script>
<script language="javascript" src="../javascript/check.js"></script>
<script language="javascript" src="../javascript/common.js"></script>
<script language="javascript">
function validate()
{
var errorinfo="";
if(clearSpace(txtcompere.value)=="")
{
errorinfo += "主持人为空\n";
}
if(clearSpace(txtaddress.value)=="")
{
errorinfo+= "会议地点为空\n";
}
if(clearSpace(txtrecorder.value)=="")
{
errorinfo+="记录人为空\n";
}
if(clearSpace(txtmeetdate.value)=="")
{
errorinfo += "会议时间为空\n";
}
if(clearSpace(txtcontent.innerText)=="")
{
errorinfo+= "会议内容为空\n";
}
//会议名称
if(txtmeet1.checked != true && txtmeet2.checked != true && txtmeet3.checked != true)
{
errorinfo+= "请选择会议名称\n";
}
if(errorinfo=="")
{
return true;
}
else
{
window.external.ShowErrorMessage(errorinfo);
return false;
}
}
//数据保存
function savetoxml()
{
var doc = new ActiveXObject("Msxml2.DOMDocument");
doc.async = false;
//调用c#方法获取xml文件路径
var xmlfilepath = window.external.GetXMLPathForJava();
doc.load(xmlfilepath);
//会议名称
doc.selectNodes("meetnote/meets/meet")[0].lastChild.text=(txtmeet1.checked==0)?'false':'true';
doc.selectNodes("meetnote/meets/meet")[1].lastChild.text=(txtmeet2.checked==0)?'false':'true';
doc.selectNodes("meetnote/meets/meet")[2].lastChild.text=(txtmeet3.checked==0)?'false':'true';
doc.selectSingleNode("meetnote/compere").text=txtcompere.value;
doc.selectSingleNode("meetnote/recorder").text=txtrecorder.value;
doc.selectSingleNode("meetnote/address").text=txtaddress.value;
doc.selectSingleNode("meetnote/meetdate").text=txtmeetdate.value;
doc.selectSingleNode("meetnote/content").text=txtcontent.innerText;
//调用c#方法保存xml文件
var examfiletype = window.external.GetExamFileType();
var examfilename = window.external.GetExamFileName();
window.external.Save(doc.xml,examfiletype,examfilename);
return true;
}
</script>
</head>
<body>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<xsl:template match="meetnote">
<table border="1" align="center" cellPadding="0" cellSpacing="0" class="table">
<tr>
<td class="td1" colspan="4">
<div align="center" class="title">现场审核会议记录</div>
</td>
</tr>
<tr>
<td class="td2">
<span>受审核方:</span>
<xsl:value-of select="enterprise" />
</td>
</tr>
<tr>
<td class="td2">
<span>会议名称:</span>
<xsl:apply-templates select="meets/meet"/>
</td>
</tr>
<tr>
<td class="td2">
<span>主 持 人:</span>
<input style="WIDTH: 150px; " type="text" name="txtcompere">
<xsl:attribute name="value">
<xsl:value-of select="compere" />
</xsl:attribute>
</input>
<span>会议地点:</span>
<input style="WIDTH: 200px; " type="text" name="txtaddress">
<xsl:attribute name="value">
<xsl:value-of select="address" />
</xsl:attribute>
</input>
</td>
</tr>
<tr>
<td class="td2">
<span>记 录 人:</span>
<input style="WIDTH: 150px; " type="text" name="txtrecorder">
<xsl:attribute name="value">
<xsl:value-of select="recorder" />
</xsl:attribute>
</input>
<span>会议时间:</span>
<input style="WIDTH: 100px; " type="text" name="txtmeetdate" onfocus="calendar();" id="txtmeetdate">
<xsl:attribute name="value">
<xsl:value-of select="meetdate" />
</xsl:attribute>
</input>
</td>
</tr>
<tr>
<td valign="top" class="td2">
<span>会议内容:</span>
<br/>
<textarea style="WIDTH: 100%;HEIGHT:150px " type="text" name="txtcontent">
<xsl:value-of select="content" />
</textarea>
</td>
</tr>
</table>
</xsl:template>
<!--会议名称-->
<xsl:template match="meets/meet">
<xsl:if test="name='meet1'">
<input type="checkbox" name="txtmeet1" id="txtmeet1" onclick="radiobutton(this,'txtmeet')">
<xsl:if test="checked='true'">
<xsl:attribute name="checked">
checked
</xsl:attribute>
</xsl:if>
</input>
<span>首次会议</span>
</xsl:if>
<xsl:if test="name='meet2'">
<input type="checkbox" name="txtmeet2" id="txtmeet2" onclick="radiobutton(this,'txtmeet')">
<xsl:if test="checked='true'">
<xsl:attribute name="checked">
checked
</xsl:attribute>
</xsl:if>
</input>
<span>沟通会议</span>
</xsl:if>
<xsl:if test="name='meet3'">
<input type="checkbox" name="txtmeet3" id="txtmeet3" onclick="radiobutton(this,'txtmeet')">
<xsl:if test="checked='true'">
<xsl:attribute name="checked">
checked
</xsl:attribute>
</xsl:if>
</input>
<span>末次会议</span>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
4。在XSLT文件中加入JS脚本,用户验证用户输入,收集表单数据,加载表单数据等。(这里涉及到JS代码和浏览器控件所在的winform窗体的代码的相互调用。)
1)首先把winform窗体的类加上这个属性[ComVisible(true)]
2) 在winform窗体里面写上public的方法
//取得xml文件路径(供javascript调用)
public string GetXMLPathForJava()
{
return tempxmlfilepath;
}
3)在XSLT文件里面的JS代码中调用这个方法
//调用c#方法获取xml文件路径
var xmlfilepath = window.external.GetXMLPathForJava();
4)在XSLT文件中定义JS方法
//数据保存
function savetoxml()
{
}
5)在winform窗体中调用JS方法
//调用JS方法
Object result = webBrowser1.Document.InvokeScript("savetoxml");
5.在显示页面的时候,我先使用下面的代码把XSLT和XML转换成HTML文件,存放在临时文件夹中,然后把浏览器控件的URL指向它。
string xsltemplatepath = TemplateHelper.GetFactoryFormXSLTemplatePath(m_FileType, m_DataRow.xsl_version);
try
{
transForm.Load(xsltemplatepath);
transForm.Transform(tempxmlfilepath, temphtmlfilepath);
}
catch(Exception ex)
{
LogError.Write(ex.Message + "\n" + ex.StackTrace);
MessageBox.Show("模板文件加载出错!");
this.Close();
return;
}
webBrowser1.Navigate(temphtmlfilepath);
6。在用户点击保存的时候,我通过XSLT中定义的JS代码,直接把用户保存的数据以XML的方式返回给winform的代码,然后保存到数据库中去。
if (Convert.ToBoolean(validateresult) == true)
{
Object result = webBrowser1.Document.InvokeScript("savetoxml");
if (Convert.ToBoolean(result) == true)
{
this.Close();
}
else
{
MessageBox.Show("保存出错", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
this.DialogResult = DialogResult.None;
}
}
else
{
this.DialogResult = DialogResult.None;
}
7。删除刚才产生的临时文件。