ASP.NET中自动生成XML文件并通过XSLT显示在网页中的方法
XML是一种很方便的描述数据的方法,其格式也比较接近HTML,因此就有了想把XML直接通过网页的形式显示在浏览器中的想法。但是直接打开XML文件,浏览器是无法解析的,只是把文档的结构原封不动地呈现出来而已。例如,我们有一个学生课程表的文档schedule.xml,用浏览器直接打开是这个样子的。(不过不知道为什么只能在IE中打开,在chrome中打开后无法显示,求教)
那么如何将XML文档能够以比较容易看懂的方式显示在网页上呢?通过查找资料以后得知有一种XML文档叫做XSLT(EXtensible Stylesheet Language Transform,可扩展样式表语言转换)。详见http://www.w3school.com.cn/xsl/index.asp。
接着就是要选择我们比较容易看懂的形式了。由于是课程表,我们当然首选采用表格的形式展现。但是在确定展现的具体手段时却遇到了瓶颈。究竟是采用课程驱动、还是时间驱动的形式?经过反复试验和调试,终于确定以时间为驱动,采用逐单元格填充的方式进行转换。最终生成的XSLT代码如下(部分):
- <?xml version="1.0" encoding="gb2312"?>
- <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
- <xsl:template match="/">
- <html>
- <body>
- <h2>我的课程表</h2>
- <table border="1">
- <tr bgcolor="#9acd32">
- <th></th>
- <th align="center">1</th>
- <th align="center">2</th>
- <th align="center">3</th>
- <th align="center">4</th>
- <th align="center">5</th>
- <th align="center">6</th>
- <th align="center">7</th>
- <th align="center">8</th>
- <th align="center">9</th>
- <th align="center">10</th>
- <th align="center">11</th>
- </tr>
- <tr>
- <td>周一</td>
- <xsl:for-each select="schedule/day">
- <xsl:if test="week = '周一'">
- <td>
- <xsl:for-each select="course">
- <xsl:choose>
- <xsl:when test="time = 1">
- <xsl:value-of select="name"></xsl:value-of>
- </xsl:when>
- <xsl:otherwise>
- </xsl:otherwise>
- </xsl:choose>
- </xsl:for-each>
- </td>
- ...
- </xsl:if>
- </xsl:for-each>
- </tr>
- ....
- </table>
- </body>
- </html>
- </xsl:template>
- </xsl:stylesheet>
接下来就是要将XML和XSLT结合起来了。
XML输出有两种方式,一种是流的形式,另一种是文件的形式。采用流的方式其实并不适用,因为文档流默认是填充在一个文件的前面的,如果是采用HTML或者ASPX等文件,会影响整个文档的结构。因此采用文件的方法,即将所有XML节点写入一个文件,并保存在服务器上。当然,随着用户数量的增多,生成的XML文件必然会越来越多,所以还得增加一个定期删除的机制,这个不在我们讨论范围之内因此不再赘述。
之前从数据库中读出数据并写入一个List的方法如下:
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Web;
- using System.Configuration;
- using System.Xml;
- using System.Web.UI;
- using System.Web.UI.WebControls;
- namespace CampusSystem
- {
- public enum Weekday { 周一, 周二, 周三, 周四, 周五 };
- public struct CourseToXML
- {
- public string course_id;
- public string name;
- public Weekday week;
- public string[] times;
- }
- public static class ScheduleMaker
- {
- static string connString = ConfigurationManager.ConnectionStrings["CampusConnectionString"].ConnectionString;
- static CampusDBDataContext db = new CampusDBDataContext(connString);
- public static List<CourseToXML> MakeScheduleList(string uid)
- {
- string course_id = string.Empty;
- string name = string.Empty;
- string allTime = string.Empty;
- CourseToXML ctx = new CourseToXML();
- List<CourseToXML> ctxl = new List<CourseToXML>();
- var mySchedule = from ms in db.Schedule where ms.student_id == uid select ms.course_id;
- foreach (string cid in mySchedule)
- {
- var courseInfo = from ci in db.Course where ci.course_id == cid select new { ci.course_id, ci.name, ci.time };
- foreach (var c in courseInfo)
- {
- course_id = c.course_id;
- name = c.name;
- allTime = c.time;
- string[] oneTimes = allTime.Split(';');
- foreach (string oneTime in oneTimes)
- {
- string[] weekAndTime = oneTime.Split(',');
- string week = weekAndTime[0];
- string[] times = weekAndTime[1].Split('.');
- ctx.course_id = course_id;
- ctx.name = name;
- ctx.times = times;
- switch (week)
- {
- case "周一":
- ctx.week = Weekday.周一;
- break;
- case "周二":
- ctx.week = Weekday.周二;
- break;
- case "周三":
- ctx.week = Weekday.周三;
- break;
- case "周四":
- ctx.week = Weekday.周四;
- break;
- case "周五":
- ctx.week = Weekday.周五;
- break;
- default:
- break;
- }
- ctxl.Add(ctx);
- }
- }
- }
- ctxl.Sort((CourseToXML ctxA, CourseToXML ctxB) =>
- {
- if (ctxA.week == ctxB.week)
- return ctxA.times[0].CompareTo(ctxB.times[0]);
- else
- return ctxA.week.CompareTo(ctxB.week);
- });
- return ctxl;
- }
- }
- }
需要查询的页面schedule.aspx如下:(前提是需要有一个存放生成后的html文档的html文件。)
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Web;
- using System.Web.UI;
- using System.Web.UI.WebControls;
- using System.Xml;
- using System.Xml.Xsl;
- namespace CampusSystem
- {
- public partial class schedule : System.Web.UI.Page
- {
- string uid;
- protected void Page_Load(object sender, EventArgs e)
- {
- uid = GetUID();
- List<CourseToXML> list = ScheduleMaker.MakeScheduleList(uid); //读出数据库中数据
- MakeScheduleXML(list, uid); //生成XML文档
- XslCompiledTransform xslt = new XslCompiledTransform();
- xslt.Load(Server.MapPath("schedule.xsl"));
- xslt.Transform(Server.MapPath("Schedule/schedule_" + uid + ".xml"), Server.MapPath("schedule.html"));
- //这个方法就是将指定的XML文件通过指定的XSL文件转换以后生成到一个指定的html文件中。
- Response.Redirect("schedule.html");
- }
- private string GetUID()
- {
- string uid = string.Empty;
- HttpCookie cookie = Request.Cookies["LOGIN"];
- if (cookie != null) // 若Cookie不为空,则采用cookie
- {
- uid = cookie["uid"];
- }
- else // 否则采用Session
- {
- uid = (string)Session["uid"];
- }
- return uid;
- }
- protected void MakeScheduleXML(List<CourseToXML> list, string uid)
- {
- XmlDocument xmlDoc = new XmlDocument();
- XmlDeclaration decl = xmlDoc.CreateXmlDeclaration("1.0", "utf-8", null);
- xmlDoc.AppendChild(decl);
- XmlElement root = xmlDoc.CreateElement("schedule");
- xmlDoc.AppendChild(root);
- for (int weekday = 0; weekday < 5; weekday++)
- {
- XmlNode nodeDay = xmlDoc.CreateElement("day");
- root.AppendChild(nodeDay);
- XmlNode week = null;
- switch (weekday)
- {
- case 0:
- week = xmlDoc.CreateElement("week");
- week.InnerText = Weekday.周一.ToString();
- break;
- case 1:
- week = xmlDoc.CreateElement("week");
- week.InnerText = Weekday.周二.ToString();
- break;
- case 2:
- week = xmlDoc.CreateElement("week");
- week.InnerText = Weekday.周三.ToString();
- break;
- case 3:
- week = xmlDoc.CreateElement("week");
- week.InnerText = Weekday.周四.ToString();
- break;
- case 4:
- week = xmlDoc.CreateElement("week");
- week.InnerText = Weekday.周五.ToString();
- break;
- default:
- break;
- }
- nodeDay.AppendChild(week);
- foreach (CourseToXML ctx in list)
- {
- XmlNode course = null;
- if (weekday == (int)(ctx.week))
- {
- course = xmlDoc.CreateElement("course");
- foreach (string t in ctx.times)
- {
- XmlNode time = xmlDoc.CreateElement("time");
- time.InnerText = t;
- course.AppendChild(time);
- }
- XmlNode name = xmlDoc.CreateElement("name");
- name.InnerText = ctx.name;
- course.AppendChild(name);
- nodeDay.AppendChild(course);
- }
- }
- }
- xmlDoc.Save(Server.MapPath("Schedule/schedule_" + uid + ".xml"));
- }
- }
- }
运行以后自动返回所生成的html文档,就能看到结果了。
虽然还略显简陋就是了,当然,这个可以通过css来控制,这里也不再赘述。
总结
为了完成这个任务,采取了一切能想到的方法。包括XMLDocument,XSLT转换,LINQ,泛型,Lambda表达式,还有XML本身的设计等等,很多知识的大综合。也是对自己学习能力和综合应用能力一个提高。真正的成就感就是在这样不断解决问题的过程中产生的,也是给了我继续把项目做好的动力。