使用 XML 呈现树型结构
周融,2007 年 1 月
(C) 2007 All Rights Reserved.
在用户界面设计上,往往会遇到一种树型结构的数据源,在使用传统方法对这种被划分了父子关系的层次型数据源做呈现时,发现很难入手,甚至因为必须使用递归调用而造成整个应用程序的崩溃。本文介绍一种利用 XML 呈现树型结构数据源的方法和一个实例程序,供开发人员参考。
本文适用于:Web 用户界面;SQL Server 2005;ASP.NET 2.0;AJAX 1.0。
在本文中:
· 理解 XML
· 第一步:构建数据库存储结构
· 第二步:在数据库中使用 XML
· 第三步:构建用户界面
· 第四步:完成数据绑定
· 结论
理解 XML
XML 是一种 SGML 扩展,全称为可扩展标记语言,它是一种声明性语言,可用来表示如数据、配置信息、数据结构或当作呈现引擎使用。XML 被广泛的应用到各种数据存储和呈现上,如 HTML、Office 文档、程序配置,甚至存储在数据库中的数据,都含有 XML 的原形。事实上,人们可以利用 XML 做任何与数据打交道的事情。鉴于其与数据的紧密程度,人们也将 XML 称为 XML 数据库。
呈放 XML 数据的文档称为 XML 文档。XML 文档必须包含一个 <? ?> 标记,用来说明此 XML 文档的性质(如版本和编码),如果是类型化的 XML 文档,则每一个 XML 文档只能拥有一个顶层元素,XML 元素之间可以被嵌套;每一个 XML 元素节点可以拥有属性(Attribute)和数据区域(#InnerText 和 CDATA)。如下为一个规范的 XML 文档中的部分数据。
<Items>
<Item Name=”Console Root” Url=”~/admin/default.aspx” Description=”Console root” />
<Item Name=”Admins”>
<Item Name=”Home Page” Url=”~/admin/homepage.aspx” />
</Item>
</Items>
从 XML 本身的数据组织形式看,它有着天然的层次结构,这给树型结构的呈现带来了方便。
第一步:构建数据库存储结构
假设我们现在的场景是,在站点后台管理页面上的左边管理节点实现动态构建,即每一个管理单元都有父子关系并可以被自定义。这些数据从数据库中获取。效果请参见 http://zhourong/admin/,用户名和密码请使用 zhourong 和 orochi。
注意:您必须安装 Windows Internet Explorer 7 才能正常浏览此站点。
我们需要做的第一件事情就是构建这些管理单元在数据库中的存储结构。考虑到这些功能都属于系统设置部分,所以建立一张 SystemSetting 表,存放所有系统设置信息;又考虑到有些系统设置是 XML 数据,因此需要扩展一个 XML 格式的存储列。数据库表构建方法如下。
(
[Key] nvarchar(max) NOT NULL,
[Value] nvarchar(max) NULL,
[XmlData] xml NULL
PRIMARY KEY ([Key])
);
这样,就可以通过如下语句得到我们需要的 XML 数据。
第二步:在数据库中使用 XML
有了存储载体,下一步就应该向 SystemSetting 表插入数据了,注意,在插入 XML 数据时,不能使用 SQL Server Management Studio 直接插入,而需要利用脚本。下面是插入 XML 数据的方法:
VALUES (N’AdministrationItems’, NULL, ‘<?xml version=”1.0” <Items>…</Items>’);
这是直接对 XML 数据列插入的方法,如果您需要在 XML 数据中新增、删除或修改某一个元素节点,则需要利用更为复杂的 XML 查询语言(XQuery)。XQuery 支持这些常用操作:
· modify()
· query()
更多 XQuery 的信息,请参见 MSDN。
Modify() 方法用来修改 XML 数据列中的数据,如下面的实例可以向 SystemSetting 表的 XmlData 数据列中添加一个新的 <Item>。
SET XmlData.modify
(
‘
Insert <Item Name=”New Item” Url=”~/admin/demo.aspx” Description=”” />
Into (/Items/Item{Name=”Console Root”})
’
)
WHERE [Key] = N’AdministrationItems’;
该语句可以在名称为“Console Root”的节点下面增加新的节点。如果需要查询 <Items> 节点下的所有信息,则可以使用如下 XQuery 语句:
WHERE [Key] = N’AdministrationItems’;
XQuery 还能实现删除和更复杂的 XML 操作,这里不再详细概述;请参考 MSDN 的 Microsoft SQL Server 2005 联机丛书以便获得更多信息。
第三步:构建用户界面
在数据库中有了数据之后,我们开始构建用户界面。这里使用的是很简单的页面布局,主模板界面(default.master)的源代码如下所示。
MasterPageFile="~/Default.master" %>
<asp:Content ContentPlaceHolderID="MainMenuContent" runat="server">
<asp:TreeView ID="MenuTreeView" runat="server" Width="100%" OnSelectedNodeChanged="MenuTreeView_NodeChanged">
<DataBindings>
<asp:TreeNodeBinding TextField="Name" NavigateUrlField="Url" ToolTipField="Name"
DataMember="Item" />
</DataBindings>
</asp:TreeView>
</asp:Content>
<asp:Content ID="MainContent" ContentPlaceHolderID="MainContent" runat="server">
<asp:Panel ID="ItemsPanel" runat="server">
<asp:Literal ID="HeaderLiteral" runat="server" Text="开始管理任务"></asp:Literal>
<hr style="height: 1px; color: Gray" />
<asp:Repeater ID="ItemsRepeater" runat="server">
<ItemTemplate>
<div style="width: 320px; height: 76px; float: left; margin: 2px 2px 2px 2px;" class="Hilight">
<div style="float: left;">
<asp:Image ID="LogoImage" ImageUrl='<%# Eval("ImageUrl") %>' Height="64" Width="64"
runat="server" />
</div>
<div style="float: left;">
<asp:HyperLink ID="Link" runat="server" NavigateUrl='<%# Eval("Url") %>'><%...# Eval("Name") %></asp:HyperLink>
<br />
<asp:Literal ID="Description" runat="server" Text='<%# Eval("Description") %>' />
</div>
</div>
</ItemTemplate>
</asp:Repeater>
</asp:Panel>
<asp:ContentPlaceHolder ID="MainContentPlaceHolder" runat="server">
</asp:ContentPlaceHolder>
</asp:Content>
界面上有一个 TreeView 和一个Repeater 数据控件,TreeView 用来展示管理节点,Repeater 用来展示 TreeView 控件选中节点的子管理项目。效果参见 http://zhourong/admin。
在界面上,单击左边树型结构的任何一个节点,都可以在右侧展现该节点下子节点的信息。下面我们分析这个界面是如何做到这个功能的。
第四步:完成数据绑定
(1)构建 XML 数据源的数据邦定
我们首先要做的是,在整个模板页面加载时,先将 XML 数据源绑定到 TreeView 和 Repeater 上。这需要通过如下代码实现。
protected void Page_Load(object sender, EventArgs e)
...{
_ds1 = new XmlDataSource();
_ds2 = new XmlDataSource();
SqlDataReader dr = Utities.GetAdministrationItems();
if (dr.Read())
_ds1.Data = dr.GetSqlXml(0).Value;
dr.Close();
_ds2.Data = _ds1.Data;
MenuTreeView.DataSource = _ds1;
ItemsRepeater.DataSource = _ds2;
if (IsPostBack) return;
MenuTreeView.DataBind();
ItemsRepeater.DataBind();
}
Utities.GetAdministrationItems 函数返回一个包含管理项目 XML 数据的 string。它正是通过 XQuery 来实现的。
这段代码能将 XML 数据源绑定到控件上,然后通过在界面上增加 DataBinding 来实现数据源呈现。下面的代码非常关键。
DataMember="Item" />
</DataBindings>
它指示编译器每一个树型节点的文本、超级链接和工具提示用 XML 节点“Item”中的“Name”属性、“Url”属性和“Name”属性代替;
(2)响应SelectedNodeChanged 事件
再来看我们如何实现 Repeater 控件的智能呈现子节点功能。通过指定 Eval() 函数的数据抱定,将 XML 数据源绑定到了每一个 Repeater 的 Item 上,要实现动态显示 TreeView 选中节点的子节点,则需要响应 TreeView 的 OnSelectedNodeChanged 事件,代码如下:
...{
if (MenuTreeView.SelectedNode != null)
...{
_ds2.XPath = GetXPathString(MenuTreeView.SelectedNode);
ItemsRepeater.DataBind();
}
ItemsPanel.Visible = (ItemsRepeater.Items.Count == 0) ? false : true;
HeaderLiteral.Text = string.Format("{0} 的管理选项 ({1} 个项目)", MenuTreeView.SelectedNode.Text, ItemsRepeater.Items.Count);
}
上述代码中使用了 XQuery,即通过设置 XmlDataSource 对象的 XPath 属性来指定哪些数据需要被邦定。GetXPathString() 函数返回一个包含正确查询的 string,它的数据集正好是 MenuTreeView.SelectedNode 的所有一级子节点。这个函数代码如下:
...{
if (node.Depth == 0)
...{
return string.Format("/Item[@Name="{0}"]/Item", node.Text);
}
else
...{
return GetXPathString(node.Parent) + string.Format("[@Name="{0}"]/Item", node.Text);
}
}
这个递归函数返回类似如下 string 的结果。
这个XPath 表示的 XML 数据集包含所有 Items 下,第一级节点名称为“Console Root”,第二级节点名称为“Admin”的所有第三级节点。这样,一个完全动态的树型结构的展示全部完成。
后续工作还可以利用 AJAX 将这个结构做成类似于 Windows 资源管理器的样式并包含拖放、异步刷新等 AJAX 特有的功能,这部分功能将在针对管理项目节点的管理页面(对这个树型结构的更新和维护页面)中实现。
结论
XML 为多种数据的呈现提供了有效方法。通过使用 Microsoft SQL Server 2005 中的 XML 数据类型和 XQuery 以及在 Web 应用程序中的数据绑定功能,使得 XML 在呈现树型结构上非常具备优势。请继续关注我们的管理页面,它将在本文发表后一个星期具备更强大的树型结构操作功能。