使用XML+XSLT实现业务表单

文/lijun4017  出处/博客园

其实这是我的一个两年前的项目中用到的东西,今天刚好翻以前的代码,看到,觉得也是自己想出来的东西,写写也无妨,哪怕是为了填充我空虚的blog。这个是一个智能客户端,但是里面涉及的表单非常之多,统计一下,有200个张。本来也不是问题,用FORM一个一个画也能够画出来,但是这样有几个缺点,一方面导致智能客户端的dll变的比较大,每次更新的时候,都要下载整个dll;一方面分工不好分,原来那个公司那时候只有我用过winform,老板就把这个任务分配给我了。但是我一个人,要做那么多的表单,而且在比较短的时间内,也不是说不可能,太累了。我想想看能不能有其他方法。

当时XFORM的概念相当热,我也看了一些资料,觉得还是不太成熟,没有敢用。

后来看了微软office2007中的infopath,感觉功能非常强,它可以实现用infopath设计表单,然后用表单控件把表单嵌入到winform中去,并且可以实现表单中的数据加载和保存功能。但是唯一的遗憾就是如果要使用它,就必须要客户机器上安装office2007,这样就不太现实了。

最后来想到的是用xml+xslt是动态生成静态页面,然后把静态页面嵌入在winform的浏览器控件里面,并且屏蔽一些浏览器控件的一些属性,看起来就和winform设计的表单差不多了。这样就方便多了,我可以叫美工帮我设计表单,叫其他的asp.net的程序员帮忙做XML和XSLT以及里面的javascript脚本。后来的项目进展说明了,这种方式真的大大的提高了工作效率,也让我轻松了不少,嘿嘿,又偷懒了。

下面我说说具体的过程吧。
1.首先我在设计表的时候,把整个表单的内容设计成XML类型的字段,当然,其他需要搜索的字段还是要单独建字段,并且保存xslt文件的版本号。
2.设计表单的XML结构,下面是示例。

<?xml version="1.0" encoding="utf-8" ?>
<!--现场会议记录-->
<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文件,下面是示例。

<?xml version="1.0" encoding="utf-8"?>
<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指向它。

  XslCompiledTransform transForm = new XslCompiledTransform();
            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的代码,然后保存到数据库中去。

Object validateresult = webBrowser1.Document.InvokeScript("validate");
            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.删除刚才产生的临时文件。

友情提示:此文并不表示本站肯定持有相同观点,转载请注明出处。
 您可能对 [XML] 的这些文章也感兴趣:

XML--INTERNET的“世界语”  XML基础入门
XML的四种解析器原理及性能比较  用ASP.NET结合XML制作广告管理程序
XML在语音中的应用  XHTML基础问答
XML常见问题  GML、SVG、VML的比较
XMLHTTP对象应用开发初体验  W3C有意推广XML新标准 为兼容性吵翻了天
XML技术2007年度回顾和前景展望  一个在客户端生成并使用XML的例子
亲密接触XML(6)-元素的内容  XML卷之实战锦囊(1):动态排序
使用模板执行SQL查询  XML介绍系列(1)
利用XMLHTTP检测URL及探测服务器信息  论Asp与XML的关系
XML技术系列讲座(2)XML技术预览  XML方言一箩筐 是好是坏