使用 XML 和 XSLT 生成动态 ASP.NET 页面






3.16/5 (55投票s)
2004年10月15日
2分钟阅读

544203

9006
通过转换 XML 为 XSL 文件生成动态表单。
引言
有时您需要创建动态页面。您可能允许用户通过选择他们需要的字段来构建自己的应用程序。 在本文中,我将展示如何使用 ASP.NET 和 XML 构建动态应用程序。 在此示例中,我使用 XML 进行元编程或生成编程。 我将 XML 与 XSLT 结合使用来生成 ASP.NET PRE,利用 XSLT 输出的 ASP.NET 内置解析方法。 我们需要执行的步骤:
- 创建 XML 文件(页面的模式)。
- 创建 XSLT 样式,将 XML 转换为 ASP.NET PRE。
- 转换 XML,并在运行时创建由生成的 ASP.NET PRE 定义的服务器控件。
- 将实例化的控件插入到页面的控件集合中。
- 处理来自服务器控件的 postback 事件。
首先,我们需要在 XML 文件中设计出良好的页面结构。 下面定义了一个基本的页面结构。 该示例结构由字段元素组成,具有属性、属性和列表项。
<FORM>
<PAGES>
<PAGE title="Page Title" id="page_1">
<FIELDS>
<!-- create regular TextBox -->
<FIELD type="TextBox" label="Last Name:" required="true">
<PROPERTIES>
<PROPERTY name="ID">LAST_NAME</PROPERTY>
</PROPERTIES>
</FIELD>
<!-- create multiline TextBox (textarea) -->
<FIELD type="TextBox" label="Description:">
<PROPERTIES>
<PROPERTY name="ID">DESCRIPTION</PROPERTY>
<PROPERTY name="TextMode">MultiLine</PROPERTY>
<PROPERTY name="Cols">30</PROPERTY>
<PROPERTY name="Rows">2</PROPERTY>
</PROPERTIES>
</FIELD>
<!-- regular textbox prefilled with text -->
<FIELD type="TextBox" label="Prefilled Contrl:">
<PROPERTIES>
<PROPERTY name="ID">PREFILLED_CONTROL</PROPERTY>
<PROPERTY name="Text">Some Text</PROPERTY>
</PROPERTIES>
</FIELD>
<!-- regular text box which must filled
and allowed Date datata type -->
<FIELD type="TextBox" label="Start Date:"
required="true" validation="Date">
<PROPERTIES>
<PROPERTY name="ID">START_DATE</PROPERTY>
</PROPERTIES>
</FIELD>
<!-- create select box -->
<FIELD type="DropDownList" label="Title:">
<PROPERTIES>
<PROPERTY name="ID">TITLE</PROPERTY>
</PROPERTIES>
<LISTITEMS>
<LISTITEM value="">Select One</LISTITEM>
<LISTITEM value="1">Architector</LISTITEM>
<LISTITEM value="2">Sr. Developer</LISTITEM>
<LISTITEM value="3">Programmer</LISTITEM>
<LISTITEM value="4">Web Designer</LISTITEM>
</LISTITEMS>
</FIELD>
<!-- radio buttons list -->
<FIELD type="RadioButtonList" label="Are you US citizen?">
<PROPERTIES>
<PROPERTY name="ID">IS_US_CITIZEN</PROPERTY>
<PROPERTY name="RepeatColumns">1</PROPERTY>
<PROPERTY name="RepeatDirection">Vertical</PROPERTY>
<PROPERTY name="RepeatLayout">Table</PROPERTY>
<PROPERTY name="TextAlign">Right</PROPERTY>
</PROPERTIES>
<LISTITEMS>
<LISTITEM value="1">Yes</LISTITEM>
<LISTITEM value="0">No</LISTITEM>
</LISTITEMS>
</FIELD>
<!-- check box list -->
<FIELD type="CheckBoxList" label="Languages:">
<PROPERTIES>
<PROPERTY name="ID">LANGUAGES</PROPERTY>
<PROPERTY name="RepeatColumns">1</PROPERTY>
<PROPERTY name="RepeatDirection">Vertical</PROPERTY>
<PROPERTY name="RepeatLayout">Table</PROPERTY>
<PROPERTY name="TextAlign">Right</PROPERTY>
</PROPERTIES>
<LISTITEMS>
<LISTITEM value="C#">C#</LISTITEM>
<LISTITEM value="Java">Java</LISTITEM>
<LISTITEM value="VB">Visual Basic</LISTITEM>
</LISTITEMS>
</FIELD>
<!-- here is a hyperlink (a) -->
<FIELD type="HyperLink">
<PROPERTIES>
<PROPERTY name="ID">LINK</PROPERTY>
<PROPERTY name="NavigateUrl">javascript:void(alert('Hello ooo'));
</PROPERTY>
<PROPERTY name="Text">Say Hello</PROPERTY>
</PROPERTIES>
</FIELD>
<FIELD type="html" src="file path"/>
<!-- you can place here any other asp controls -->
</FIELDS>
</PAGE>
...
</PAGES>
</FORM>
下一步是创建 XSLT 样式来转换我们的 XML 模式。 XSLT 遍历每个字段,首先为该字段输出一个标签作为纯文本。 样式表还检查该字段是否是必需的,并在需要时添加一个 RequiredFieldValidator
。 然后,样式表创建一个 Web 控件(它可以是任何有效的 Web 控件,例如 TextBox
、RadioButtonList
、DropDownList
等)。 为每个 ListControls 创建 ListItem
。
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:asp="remove">
<xsl:output method="xml" indent="yes" encoding="utf-8" omit-xml-declaration="yes">
</xsl:output>
<xsl:template match="/">
<!-- page id parameter if we have more than 1 page in our XML file -->
<xsl:param name="pageid"/>
<!-- start form page -->
<table cellpadding="0" cellspacing="5">
<!-- set title of the current page -->
<tr>
<td colspan="3" align="center" style="font-size:25px">
<xsl:value-of select="FORM/PAGES/PAGE[@id=$pageid]/@title" />
</td>
</tr>
<tr><td colspan="3" style="height:20px"></td></tr>
<!-- iterate through page fields -->
<xsl:for-each select="FORM/PAGES/PAGE[@id=$pageid]/FIELDS/FIELD">
<!-- create row -->
<xsl:element name="tr">
<xsl:attribute name="id">
TR_<xsl:value-of select="PROPERTIES/PROPERTY[@name='ID']"></xsl:value-of>
</xsl:attribute>
<!-- hide the row -->
<xsl:if test="@display='none'">
<xsl:attribute name="style">display:none;</xsl:attribute>
</xsl:if>
<xsl:choose>
<!-- this is the way to place "include" files into your PRE -->
<xsl:when test="@type='HTML'">
<td colspan="3">
<!-- #include file="<xsl:value-of select="@src"></xsl:value-of>" -->
</td>
</xsl:when>
<!-- other controls -->
<xsl:otherwise>
<!-- field label column -->
<td valign="top">
<xsl:value-of select="@label" />
</td>
<!-- field column -->
<td>
<!-- field element -->
<xsl:element name="asp:{@type}">
<xsl:attribute name="runat">server</xsl:attribute>
<xsl:for-each select="./PROPERTIES/PROPERTY">
<xsl:attribute name="{@name}">
<xsl:value-of select="current()"></xsl:value-of>
</xsl:attribute>
</xsl:for-each>
<xsl:for-each select="./LISTITEMS/LISTITEM">
<asp:ListItem value="{@value}">
<xsl:value-of select="current()"></xsl:value-of>
</asp:ListItem>
</xsl:for-each>
</xsl:element>
</td>
<!-- validation message column -->
<td>
<xsl:if test="@required='true'">
<asp:RequiredFieldValidator ErrorMessage="Required" runat="server"
ControlToValidate="{PROPERTIES/PROPERTY[@name='ID']}" />
</xsl:if>
<xsl:if test="@validation='Date'">
<asp:CompareValidator ErrorMessage="Dates Only" runat="server"
Operator="DataTypeCheck" Type="Date"
ControlToValidate="{PROPERTIES/PROPERTY[@name='ID']}" />
</xsl:if>
<xsl:if test="@validation='Number'">
<asp:CompareValidator ErrorMessage="Numbers Only" runat="server"
Operator="DataTypeCheck" Type="Integer"
ControlToValidate="{PROPERTIES/PROPERTY[@name='ID']}" />
</xsl:if>
<xsl:if test="@validation='Currency'">
<asp:CompareValidator ErrorMessage="Currency Only" runat="server"
Operator="DataTypeCheck" Type="Currency"
ControlToValidate="{PROPERTIES/PROPERTY[@name='ID']}" />
</xsl:if>
</td>
</xsl:otherwise>
</xsl:choose>
</xsl:element>
</xsl:for-each>
</table>
</xsl:template>
</xsl:stylesheet>
我们的 XSLT 文件为 XSL 命名空间定义了一个前缀(xmlns:asp="remove"
)。 这用于生成纯 HTML。 现在我们准备编写我们的页面转换器了。
...
private readonly string XslFile = @"...\default.xslt";
private readonly string XmlFile = @"...\default.config";
...
private void Page_Load(object sender, System.EventArgs e)
{
string pageId = "page_1";
if (!Page.IsPostBack)
{
/**
* Transform aspx page with fields from xml file
* Get transform result as a string
* Parse controls into a parent control holder
*/
XmlDocument xdoc = new XmlDocument();
xdoc.Load(XmlFile);
// load xslt to do transformation
XslTransform xsl = new XslTransform();
xsl.Load(XslFile);
// load xslt arguments to load specific page from xml file
// this can be used if you have multiple pages
// in your xml file and you loading them one at a time
XsltArgumentList xslarg = new XsltArgumentList();
xslarg.AddParam("pageid", "", pageId);
// get transformed results
StringWriter sw = new StringWriter();
xsl.Transform(xdoc, xslarg, sw);
string result = sw.ToString().Replace("xmlns:asp=\"remove\"",
"").Replace("<","<").Replace(">",">");
// free up the memory of objects that are not used anymore
sw.Close();
// parse the controls and add it to the page
Control ctrl = Page.ParseControl(result);
Page.Controls.Add(ctrl);
}
}
private void BtnSave_Click(object sender, System.EventArgs e)
{
// save data into a data container
// ...
Response.Write (Request.Form["LAST_NAME"]);
}
结论
在本文中,我们将数据与内容分离,以实现更简洁的设计和更好的可维护性。 当 XML 与 XSLT 结合使用时,ASP.NET 服务器控件变得更加强大。 这为动态和强大的系统打开了无数的可能性。