XML(数据绑定)

       和 SqlDataSource 以及 ObjectDataSource 相似,XmlDataSource 控件以声明性的方式工作,不过也有两个主要的不同点:

  • XmlDataSource 不是从数据库或数据访问类而是从 XML 文件获取信息,它为其他控件的数据绑定提供一个 XmlDocument 对象。
  • XML 内容是分层的且可有无限多层。而 SqlDataSource 和 ObjectDataSource 返回的是平面数据表。

非层次化绑定

       处理 XML 数据固有的层次化的最简单的办法就是忽略它,直接把 XML 数据源绑定到普通的网格控件上:

<asp:GridView ID="GridView1" runat="server" DataSourceID="sourceDVD">
</asp:GridView>
<asp:XmlDataSource ID="sourceDVD" runat="server" DataFile="DvdList.xml"></asp:XmlDataSource>

image

       XmaDataSource 从 DvdList.xml 文件抓取数据并作为 XmlDocument 对象提供给 GridView,然后调用 DataBind()。因为 XmlDocument 实现了 IEnumable 接口,因此 GridView 可以像遍历 DataView 相似的方式来遍历它的结构。GridView 遍历了 XmlDocument.Nodes 集合并获取了每个 XmlNode 的所有特性。

       (调用 XmlDataSource.GetXmlDocument()可让它把内容返回为 XmlDocument 对象。)

       这里的缺陷非常明显。XmlDocument 使用的 IEnumerable 实现没考虑齐全,它只遍历上层的 XmlNode 对象,这样你只能见到最上层的节点。也就是说,如果你不定制 XML 数据绑定的过程,就只能绑定到最顶层的节点,并且只能显示那个节点的特性。如果顶层节点有多种类型,绑定控件将使用第一个节点的架构。

      

       那么,如何显示 XML 文档中更深层次的内容?你有以下几个选择:

  • 可以用 XPath 过滤出重要的元素
  • 可以用 XSL 把 XML 转换为你希望的扁平化结构
  • 可以把一个数据控件嵌套到另一个数据控件中
  • 可以使用支持层次数据的控件(.NET 唯一满足这一需求的现成控件是 TreeView)

01. 使用 XPath

       绑定到 XmlNode 时,通常只会显示特性值。不过,你可以使用 XPath 数据绑定表达式获得嵌套元素的文本。实现这一目的最灵活的办法是使用一个定义了 XPath 数据绑定表达式的模版。

       XPath 数据绑定表达式和 Eval()表达式基本类似,不过要基于当前节点提供 XPath 而不是再提供要显示的字段名字。

<asp:GridView ID="GridView1" runat="server" DataSourceID="sourceDVD" AutoGenerateColumns="false">
    <Columns>
        <asp:TemplateField HeaderText="DVD">
            <ItemTemplate>
                <b><%# XPath("Title") %></b><br />
                <%# XPath("Director") %><br />
            </ItemTemplate>
        </asp:TemplateField>
    </Columns>
</asp:GridView>

image

       遗憾的是,需要借助模版才能获得编写 XPath()表达式的能力。这限制了 XML 数据绑定场景中其他控件(如下拉列表框)的使用。

       还可以使用 XPath 过滤出初始的匹配集,例如,要显示所有的演员名单:

<asp:XmlDataSource ID="sourceDVD" runat="server" DataFile="DvdList.xml" 
    XPath="/DvdList/DVD/Starring/Star">
</asp:XmlDataSource>
<asp:TemplateField HeaderText="DVD">
    <ItemTemplate>
        <%
   1: #XPath(".") 
%>
    </ItemTemplate>
</asp:TemplateField>

image

       还可以用 XPath 属性创建一个简单的记录浏览器,只要让用户从另一个控件(如下拉列表框)选择 ID,然后相应的设置 XPath 属性即可:

<asp:DropDownList ID="DropDownList1" runat="server" OnSelectedIndexChanged="DropDownList1_SelectedIndexChanged"
    AutoPostBack="True" Width="119px">
    <asp:ListItem Value="1">a</asp:ListItem>
    <asp:ListItem Value="2">b</asp:ListItem>
    <asp:ListItem Value="3">c</asp:ListItem>
    <asp:ListItem Value="4">d</asp:ListItem>
    <asp:ListItem Value="5">e</asp:ListItem>
</asp:DropDownList>
<asp:GridView ID="GridView1" runat="server" DataSourceID="sourceDVD" AutoGenerateColumns="false">
    <Columns>
        <asp:TemplateField HeaderText="DVD">
            <ItemTemplate>
                <%
   1: #XPath("Price") 
%>
            </ItemTemplate>
        </asp:TemplateField>
    </Columns>
</asp:GridView>
<asp:XmlDataSource ID="sourceDVD" runat="server" DataFile="DvdList.xml" XPath="/DvdList/DVD">
</asp:XmlDataSource>
protected void DropDownList1_SelectedIndexChanged(object sender, EventArgs e)
{
    sourceDVD.XPath = "/DvdList/DVD[@ID=" + DropDownList1.SelectedValue + "]";
}

       这个记录浏览器可以工作,是因为数据绑定只在页面生命周期块结束时才执行。

02. 嵌套的网格

       网格的嵌套可以让你处理更加复杂的 XML 结构。ASP.NET 可以提供这一实现而不需要你编写任何的代码。

       首先,定义外层的网格,使用模版就可以显示标题和导演的信息,在第一个 GridView 的模版内部定义第二个 GridView,技巧在于 DataSource 属性,你可以用一个新的 XPathSelect()数据绑定语句来设置它。

<asp:GridView ID="GridView1" runat="server" DataSourceID="sourceDVD" AutoGenerateColumns="false">
    <Columns>
        <asp:TemplateField HeaderText="DVD">
            <ItemTemplate>
                <b>
                    <%
   1: # XPath("Title") 
%></b><br />
                <%
   1: # XPath("Director") 
%><br />
                <br />
                <i>Starring...</i><br />
 
                <asp:GridView ID="GridView2" runat="server" AutoGenerateColumns="false" GridLines="None"
                    ShowHeader="false" DataSource='<%# XPathSelect("Starring/Star") %>'>
                    <Columns>
                        <asp:TemplateField>
                            <ItemTemplate>
                                <%
   1: # XPath(".") 
%><br />
                            </ItemTemplate>
                        </asp:TemplateField>
                    </Columns>
                </asp:GridView>
            </ItemTemplate>
        </asp:TemplateField>
    </Columns>
</asp:GridView>
<asp:XmlDataSource ID="sourceDVD" runat="server" DataFile="DvdList.xml"></asp:XmlDataSource>

image

03. 使用 TreeView 的层次绑定

       某些控件有内建的智能,可以直接显示层次化的数据。最典型的就是 TreeView。把 TreeView 绑定到 XmlDataSource 时,它调用 XmlDataSource.GetHierarchicalView()方法并显示 XML 文档的完整结构

       这个默认显示离我们所期望的还太远,只显示文档结构(元素名称),而不显示文档内容(元素文本),还忽略了特性。

       为了改善这一状况必须进行调整。首先,把 TreeView.AutoGenerateDataBindings 设为 false,然后显式地把 XML 文档的不同部分映射到各节点。创建映射时,需要在<DataBindings>节内加入<asp:TreeNodeBinding />元素,必须从根元素开始,为你希望绑定的每一层添加绑定,不能跳过任何一层。每个<asp:TreeNodeBinding />必须明确它要绑定的节点名称(DataMember)、它应显式的文本(TextField),节点的隐藏值(ValueField)。遗憾的是,TextField 和 ValueField 都是设计用于绑定特性的,如果你要绑定到元素的内容,就只能通过比较笨的方式指定 #InnerText 代码。

<asp:TreeView ID="TreeView1" runat="server" AutoGenerateDataBindings="false" DataSourceID="sourceDVD">
    <DataBindings>
        <asp:TreeNodeBinding DataMember="DvdList" Text="Root" Value="Root" />
        <asp:TreeNodeBinding DataMember="DVD" TextField="ID" />
        <asp:TreeNodeBinding DataMember="Title" TextField="#InnerText" />
        <asp:TreeNodeBinding DataMember="Director" TextField="#InnerText" />
        <asp:TreeNodeBinding DataMember="Price" TextField="#InnerText" />
        <asp:TreeNodeBinding DataMember="Starring" Text="Starring" />
        <asp:TreeNodeBinding DataMember="Star" TextField="#InnerText" />
    </DataBindings>
</asp:TreeView>
<asp:XmlDataSource ID="sourceDVD" runat="server" DataFile="DvdList.xml"></asp:XmlDataSource>

image

04. 使用 XSLT 转换结构后绑定

        XmlDataSource 为 XSL 转换提供了内建的支持。不同的是,你不是用样式表把 XML 转换为 HTML ,而是用它把源 XML 文档转换为便于数据绑定使用的 XML 结构。例如,可以生成一个恰好含有你需要的结果的 XML 文档,并且生成为扁平化结构(把元素转换为特性)以方便数据绑定。

       要指定样式表,你可以把 XmlDataSource.TransformFile 指向一个含有 XSL 转换的文件,或者使用 XmlDataSource.Transform 属性把样式表作为单个长字符串。还可以同时使用样式表和XPath表达式,但总是优先使用样式表。

       使用 XmlDataSource XSLT 功能的一个充分理由是,你必须把 XML 数据准备好供层次控件(TreeView)使用。

       例如,要创建一个按电影分组的演员列表,你也可以把所有的内容放到特性里,这样便于绑定。以下是你需要的最终的 XML:

<Movies>
  <DVD ID="1" Title="The Matrix">
    <Star Name="Keanu Reeves" />
    <Star Name="Laurence Fishburne" />
  </DVD>
 
  <DVD ID="2" Title="Forrest Gump">
    <Star Name="Tom Hanks" />
    <Star Name="Robin Wright" />
  </DVD>
  ......
</Movies>

       可以用下面的 XSL 样式表把原始的 XML 转换成为这种标记:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes"/>
 
  <xsl:template match="/">
    <!-- Rename the root element -->
    <xsl:element name="Movies">
      <xsl:apply-templates select="DvdList/DVD"></xsl:apply-templates>
    </xsl:element>
  </xsl:template>
 
  <xsl:template match="DVD">
    <!-- Transform the <DVD> element into a new element with a different structure. -->
    <xsl:element name="DVD">
      <xsl:attribute name="ID">
        <xsl:value-of select="@ID"/>
      </xsl:attribute>
      <!-- Put the nested <Title> into an attribute. -->
      <xsl:attribute name="Title">
        <xsl:value-of select="Title/text()"/>
      </xsl:attribute>
      <xsl:apply-templates select="Starring/Star" />
    </xsl:element>
  </xsl:template>
 
  <xsl:template match="Star">
    <xsl:element name="Star">
      <xsl:attribute name="Name">
        <xsl:value-of select="text()"/>
      </xsl:attribute>
    </xsl:element>
  </xsl:template>
 
 
</xsl:stylesheet>

       现在就可以帮顶到 TreeView 上进行显示了:

<asp:TreeView ID="TreeView1" runat="server" DataSourceID="sourceDVD" AutoGenerateDataBindings="false">
    <DataBindings>
        <asp:TreeNodeBinding DataMember="Movies" Text="Movies" />
        <asp:TreeNodeBinding DataMember="DVD" TextField="Title" />
        <asp:TreeNodeBinding DataMember="Star" TextField="Name" />
    </DataBindings>
</asp:TreeView>
<asp:XmlDataSource ID="sourceDVD" runat="server" DataFile="DvdList.xml" TransformFile="DvdList2.xslt">
</asp:XmlDataSource>

image

05. 绑定到来自其他源的 XML 内容

       到目前为止,所有示例都是帮顶到文件中的 XML,不过这并不是唯一可能遇到的情况。你还可以通过 XmlDataSource.Data 属性提供一个 XML 字符串:

private void XmlDataBinding(string xmlContent)
{
    sourceDVD.Data = xmlContent;
}

      

通过 XmlDataSource 更新 XML

       XmlDataSource 不支持可编辑的绑定(绑定GridView,选择编辑,视图提交更新时会得到一个错误)。然而 XmlDataSource 确实提供了 Save()方法。这个方法调用当前的 XML 内容替代 DataFile 属性指定的文件。虽然需要加入代码才能调用 Save()方法,但有些开发人员已经用这项技术提供了可编辑的 XML 数据绑定。

       基本思路是这样的:

  1. 用户提交控件中的更新时,代码调用 XmlDataSource.GetXmlDocument()方法以 XmlDocument 对象的形式获得当前 XML 的内容
  2. 代码找到相应的节点并用 XmlDocument 的功能实现变更(查找和编辑给定的节点、删除节点和添加节点)
  3. 最后,代码必须调用 XmlDataSource.Save()方法提交更新。

       虽然代码这个方法可以工作的很出色,但它并不是设计网站的好办法。如果确实需要修改 XML 的内容,那么用前面描述过的 XML 类在一个单独的组件内实现逻辑通常会更好一些。

原文地址:https://www.cnblogs.com/SkySoot/p/2660602.html