---------续

发表于:2007-06-30来源:作者:点击数: 标签:
现在我们可以改变XML块并且通过这个改变过的XML创建一个新的对象了。比如我们通过改变XML中Name元素的值来给新的对象一个不同的Name属性值。 为了显示新的对象的细节,我们要使用一个ASP.NET 服务器 端控件。这个控件将有一个叫做Book的属性,用它来告诉控件
现在我们可以改变XML块并且通过这个改变过的XML创建一个新的对象了。比如我们通过改变XML中Name元素的值来给新的对象一个不同的Name属性值。
为了显示新的对象的细节,我们要使用一个ASP.NET服务器端控件。这个控件将有一个叫做Book的属性,用它来告诉控件把哪个book来做输出处理(Render)。在代码中创建一个新的类叫BookView。
Imports System
Imports System.Web
Imports System.Web.UI

Namespace Controls

Public Class BookView
Inherits Control

@# need somewhere to store the book...
Dim m_Book As Book

Public Property Book() As Book
Get
Return m_Book
End Get
Set
m_Book = Value
End Set
End Property

End Class

End Namespace


    Inherits指示符告诉VB从System.Web.UI.Control对象中继承类,这样就给ASPX页面上的控件提供了所需的几种方法。同样的如果我们想使用一个控件,它必须在一个名字空间里。我们使用了Controls这个名字空间,因此从技术上讲,我们把这类表示为Serialization.Controls.Bookview。

    为了让这个控件能工作,我们需要重载Render方法。如果没有得到一个需要输出处理得Book对象,我们需要告诉用户我们什么都没做:
Protected Overrides Sub Render(ByVal writer As System.Web.UI.HtmlTextWriter)

@# do we have a book?
If m_Book Is Nothing Then

@# render something...
writer.Write("Nothing to do!")
Else
如果我们得到了一个Book对象,那我们就可以象下面这样做了:
@# draw the name of the book...
writer.Write("Type: " & book.GetType().ToString & "<br>")
writer.Write("Name: " & book.Name & "<br>")
writer.Write("ISBN: " & book.ISBN & "<br>")
End If

End Sub


把控件加入到ASPX页面

    把控件加入到页面之前,我们需要在页面中加入对控件所在的名字空间的引用。这是通过在页面顶部加一个Register指示符来实现的。
<%@ Page Language="vb" AutoEventWireup="false" Codebehind="WebForm1.vb" Inherits="Serialization.WebForm1"%>
<%@ Register TagPrefix="mycontrols" Namespace="Serialization.Controls" %>

    TagPrefix属性告诉ASP.NET特定的服务器端控件在什么名字空间里。为了把我们的控件加入到我们的form中,我们要使用这个前缀和相应的控件类的联合。
<form id="WebForm1" method="post" runat="server">
<textarea runat="server" id="xmlarea" cols="60" rows="15"></textarea>
<br>
<input runat="server" type="submit" value="Turn XML into an object!">
</form>
<mycontrols:bookview runat="server" id="bookview"></mycontrols:bookview>


    请注意我们已经用ID属性给了控件一个名字叫bookview。这将允许我们在VB代码中引用该控件,就像用xmlarea一样。
VS.NET开发环境可能已经在WebForm1中添加了一个对bookview的定义。确认下面的代码行已经在类里存在了,如果没有,那么手动添加进来。
Public Class WebForm1
Inherits System.Web.UI.Page
Protected WithEvents xmlarea As System.Web.UI.HtmlControls.HtmlTextArea
Protected WithEvents bookview As Controls.BookView

处理XML

    只要点击Turn XML into an object按钮,页面就会被重新载入,我们的WebForm1_Load事件也会因此而被调用。我们可以用xmlarea的value属性来接收XML。通过XmlSerializer把它传进来并且设置我们的BookView控件的Book属性。
然后我们先要看一下页面是否是posted back的。如果是我们就可以进行处理了。首先我们创建一个新的StringReader并且告诉他使用xmlarea的值作为源数据。
Protected Sub WebForm1_Load(ByVal Sender As System.Object, _
ByVal e As System.EventArgs)
If Not IsPostback Then @# Evals true first time browser hits the page

Else

@# try and turn the xml back into an object...
Dim reader As New StringReader(xmlarea.Value)

    然后和前面一样,我们创建一个XmlSerializer的实例,并且告诉它我们需要什么样的对象类型。(在这,为了得到类型,我们已经创建了一个Book对象的实例并使用它的GetType方法。XmlSerializer不会在这个特定的对象中设置属性,这个对象将单独存在,仅用来提供类型信息。
@# create a serializer...
Dim MyBook As New Book()
Dim serializer As New XmlSerializer(MyBook.GetType())

最后我们用Try…Catch块来做Deserialize。因为我们不能保证用户一定会给我们一个正确的xml块,所以我们需要确保不会出错。

@# try and read it...
Try

@# turn it into a book...
bookview.Book = CType(serializer.Deserialize(reader), Book)

Catch

End Try

End If
End Sub

    为了测试结果,我们运行这个项目并且改变被默认创建的XML。当我们点击Turn XML Into an object按钮时,新的Book对象将包含已经改变的值。




使用数组

    经常会遇到包含了对象数组的对象。比如我们的Book对象中,应该包含一个“作者”(authors)数组。XML序列化为你提供一种特殊的方式来处理数组。不过这也说明了XML序列化的一个大缺点---有很多东西是不能够被处理的。也就是说XML序列化只能处理最基本的数据类型。比如numbers, strings和其他一些最基本的可以读写的的对象。

    ASP程序员常用的办法是使用一些如字典对象或集合对象来保存和移动这样的数据块。XML序列化不能处理这些,但是它可以处理数组。矛盾的是,ASP程序员并不十分习惯于传递数组,因为以前版本的VB并不擅长做这些。
我们还是可以按照我们的想法去保存数据的,.NET提供了很多有用的对象来处理数据列表。为了把数据从XML中序列化进/出,我们需要把数据列表转换为数组。

“Authors”对象

    为了抓住一个特定的作者的信息,我们需要创建一个新的Author对象。创建它并加入以下代码:
Imports System

Public Class Author

Private m_Name As String

Public Property Name () As String
Get
Return m_name
End Get
Set
m_name = value
End Set
End Property
End Class

    为了在Book对象中抓到作者的列表,我们需要创建一个列表模板。我们用一个Hashtable,然后把下面的代码加到Book类的定义中:
Private m_Name As String
Private m_ISBN As String
Private m_Authors As New Hashtable()

     为了向列表中加入一个新的作者,我们要创建一个AddAuthor方法,这个方法将创建一个新的Author对象,把它加入到我们的hash表中。
@# a method to add an author...
Public Function AddAuthor(ByVal Name As String) As Author

@# create a new author...
Dim NewAuthor As New Author()
NewAuthor.Name = Name

@# add it to the collection...
m_Authors.Add(Name, NewAuthor)

End Function

    现在当我们创建我们的默认对象,我们需要添加一个作者。我们可以通过改变WebForm1_PreRender事件来着这些。
@# create an instance of a book...
Dim MyBook As New Book()
MyBook.Name = "Beginning E-commerce"
MyBook.ISBN = "1861003986"
MyBook.AddAuthor("Matthew Reynolds")

    如同我们说过的,为了序列化hash表,我们需要把它转换到一个数组中去。下面是如何把Authors属性从hash表转化到Author数组中去的方法,反之亦然。
Public Property Authors() As Author()
Get

@# create a new author array...
Dim AuthorArray(m_authors.Count) As Author
Dim Author As Author, n As Integer
For Each author In m_Authors.Values
AuthorArray(n) = Author
n += 1
Next

@# return the array...
Return AuthorArray

End Get
Set

@# reset the authors we@#ve already got (i.e. what
@# we are given is the definitive list.)
m_Authors.Clear()

@# go through the authors we have...
Dim Author As Author
For Each Author In Value
m_Authors.Add(Author.Name, Author)
Next

End Set
End Property

    现在如果运行这个项目,我们会注意到作者的列表已经被加入到XML块中了。




    想看一下XML是否已经被序列化成一个对象的话,我们需要改变一下我们的BookView控件来输出作者列表。把下面的代码加入到Render事件中处理:
@# draw the name of the book...
writer.Write("Type: " & book.GetType().ToString & "<br>")
writer.Write("Name: " & book.Name & "<br>")
writer.Write("ISBN: " & book.ISBN & "<br>")

@# loop through the authors...
Dim Author As Author
For Each Author In m_Book.Authors
writer.Write("Author: " & Author.Name & "<br>")
Next

    现在我们改变了XML,让它包含一个新的author,点击Turn XML into an object按钮,我们得到如下的结果:




总结

    本文中我们看到了在.NET Framework中XmlSerializer对象是如何用来把一个对象转换成一个XML块并且把它传递给stream对象的。在这个例子中,我们使用了StringStream对象,但是FileStream和NetworkStream不用什么变化就可以使用的,这是.NET中一个很cool的特性。尽管本文里我们没有看到一个XmlSerialization实际应用中的例子,但你可以在IBuySpy.com中看到如何利用它来得到站点的配置信息。我们会在ASPToday以后的案例分析中详细讲述XmlSerializer和序列化的。

[/TD][/TR][/TABLE]

原文转自:http://www.ltesting.net