[練習]將多層的xml轉為物件,處理並顯示到GridView上

小鋪上的一個詢問【多層的xml 如何解析】,對方傳來一個多層的xml,要如何解析他並將他轉換成GridView顯示出來,小喵順便把過程整理成文章,以便未來有類似需求的朋友可以參考。

緣起

小鋪上的一個詢問【多層的xml 如何解析】,對方傳來一個多層的xml,要如何解析他並將他轉換成GridView顯示出來,小喵順便把過程整理成文章,以便未來有類似需求的朋友可以參考。

 

XML格式務必正確

其實解析XML的方式很多,透過XmlDocument,Linq to Xml, Xml轉物件,都是可行的方式。不過,很重要的一點

Xml的格式一定要正確
Xml的格式一定要正確
Xml的格式一定要正確

(因為很重要,所以講三次)

Xml的格式一旦有問題,那麼不管哪種Xml衍生出來的方式都無效,只能當作純文字去處理他

 

該篇的11樓,樓主提供的格式有問題,MedlineCitation 這個標籤有頭無尾,無法收尾就無法處理,所以小喵先行整理Xml,讓Xml格是正確變成可以去解析的內容。

<?xml version="1.0"?>
<!DOCTYPE PDArticleSet PUBLIC "-//NLM//DTD PDArticle, 1st January 2014//EN" "http://www.ncbi.nlm.nih.gov/corehtml/query/DTD/PD_140101.dtd">
<PDArticleSet>

	<PDArticle>
		<MedlineCitation Owner="NLM" Status="PD-not-MEDLINE">
			<PMID Version="1">1</PMID>
			<DateCreated>
				<Year>2014</Year>
				<Month>08</Month>
				<Day>11</Day>
			</DateCreated>
			<DateCompleted>
				<Year>2014</Year>
				<Month>08</Month>
				<Day>11</Day>
			</DateCompleted>
		</MedlineCitation>
	</PDArticle>

	<PDArticle>
		<MedlineCitation Owner="NLM" Status="PD-not-MEDLINE">
			<PMID Version="1">2</PMID>
			<DateCreated>
				<Year>2014</Year>
				<Month>08</Month>
				<Day>11</Day>
			</DateCreated>
			<DateCompleted>
				<Year>2014</Year>
				<Month>08</Month>
				<Day>11</Day>
			</DateCompleted>
		</MedlineCitation>
	</PDArticle>
</PDArticleSet>

有了正確的Xml,剩下的就挑一種解決的方式。

剛好前幾天友分享一篇【[筆記] Object 物件(集合) XML 互轉 公用程式】,就利用這篇的方式將Xml轉為物件,之後再進行處理

 

選擇性貼上→貼上 XML 做為類別

Visual Studio不愧是地表最強的開發工具,提供將xml轉為物件類別的方式,使用方式很簡單,只需要新增一個類別檔,別管一開始的內容,將正確格式的Xml複製下來,接著,到類別編輯區的空白處,點選【功能表】的【編輯】→【選擇性貼上】→【貼上XML做為類別】,神奇的,XML對應的類別就產生好了

當然,相關的資料他會依據貼上的範例內容,去判斷該用什麼樣的資料型態,不過產生的型態不見的合適,這時候可以針對產生的形態稍做調整一下

xml2obj0001

xml2obj0002

於是就產生好類別,針對一些欄位的型態,稍微做調整後,類別內容如下:

Imports Microsoft.VisualBasic

'''<remarks/>
<System.Xml.Serialization.XmlTypeAttribute(AnonymousType:=True), _
 System.Xml.Serialization.XmlRootAttribute([Namespace]:="", IsNullable:=False)> _
Partial Public Class PDArticleSet

    Private pDArticleField() As PDArticleSetPDArticle

    '''<remarks/>
    <System.Xml.Serialization.XmlElementAttribute("PDArticle")> _
    Public Property PDArticle() As PDArticleSetPDArticle()
        Get
            Return Me.pDArticleField
        End Get
        Set(value As PDArticleSetPDArticle())
            Me.pDArticleField = Value
        End Set
    End Property
End Class

'''<remarks/>
<System.Xml.Serialization.XmlTypeAttribute(AnonymousType:=True)> _
Partial Public Class PDArticleSetPDArticle

    Private medlineCitationField As PDArticleSetPDArticleMedlineCitation

    '''<remarks/>
    Public Property MedlineCitation() As PDArticleSetPDArticleMedlineCitation
        Get
            Return Me.medlineCitationField
        End Get
        Set(value As PDArticleSetPDArticleMedlineCitation)
            Me.medlineCitationField = Value
        End Set
    End Property
End Class

'''<remarks/>
<System.Xml.Serialization.XmlTypeAttribute(AnonymousType:=True)> _
Partial Public Class PDArticleSetPDArticleMedlineCitation

    Private pMIDField As PDArticleSetPDArticleMedlineCitationPMID

    Private dateCreatedField As PDArticleSetPDArticleMedlineCitationDateCreated

    Private dateCompletedField As PDArticleSetPDArticleMedlineCitationDateCompleted

    Private ownerField As String

    Private statusField As String

    '''<remarks/>
    Public Property PMID() As PDArticleSetPDArticleMedlineCitationPMID
        Get
            Return Me.pMIDField
        End Get
        Set(value As PDArticleSetPDArticleMedlineCitationPMID)
            Me.pMIDField = Value
        End Set
    End Property

    '''<remarks/>
    Public Property DateCreated() As PDArticleSetPDArticleMedlineCitationDateCreated
        Get
            Return Me.dateCreatedField
        End Get
        Set(value As PDArticleSetPDArticleMedlineCitationDateCreated)
            Me.dateCreatedField = Value
        End Set
    End Property

    '''<remarks/>
    Public Property DateCompleted() As PDArticleSetPDArticleMedlineCitationDateCompleted
        Get
            Return Me.dateCompletedField
        End Get
        Set(value As PDArticleSetPDArticleMedlineCitationDateCompleted)
            Me.dateCompletedField = Value
        End Set
    End Property

    '''<remarks/>
    <System.Xml.Serialization.XmlAttributeAttribute()> _
    Public Property Owner() As String
        Get
            Return Me.ownerField
        End Get
        Set(value As String)
            Me.ownerField = Value
        End Set
    End Property

    '''<remarks/>
    <System.Xml.Serialization.XmlAttributeAttribute()> _
    Public Property Status() As String
        Get
            Return Me.statusField
        End Get
        Set(value As String)
            Me.statusField = Value
        End Set
    End Property
End Class

'''<remarks/>
<System.Xml.Serialization.XmlTypeAttribute(AnonymousType:=True)> _
Partial Public Class PDArticleSetPDArticleMedlineCitationPMID

    Private versionField As Integer

    Private valueField As Integer

    '''<remarks/>
    <System.Xml.Serialization.XmlAttributeAttribute()> _
    Public Property Version() As Integer
        Get
            Return Me.versionField
        End Get
        Set(value As Integer)
            Me.versionField = value
        End Set
    End Property

    '''<remarks/>
    <System.Xml.Serialization.XmlTextAttribute()> _
    Public Property Value() As Integer
        Get
            Return Me.valueField
        End Get
        Set(value As Integer)
            Me.valueField = value
        End Set
    End Property
End Class

'''<remarks/>
<System.Xml.Serialization.XmlTypeAttribute(AnonymousType:=True)> _
Partial Public Class PDArticleSetPDArticleMedlineCitationDateCreated

    Private yearField As String

    Private monthField As String

    Private dayField As String

    '''<remarks/>
    Public Property Year() As String
        Get
            Return Me.yearField
        End Get
        Set(value As String)
            Me.yearField = value
        End Set
    End Property

    '''<remarks/>
    Public Property Month() As String
        Get
            Return Me.monthField
        End Get
        Set(value As String)
            Me.monthField = value
        End Set
    End Property

    '''<remarks/>
    Public Property Day() As String
        Get
            Return Me.dayField
        End Get
        Set(value As String)
            Me.dayField = value
        End Set
    End Property
End Class

'''<remarks/>
<System.Xml.Serialization.XmlTypeAttribute(AnonymousType:=True)> _
Partial Public Class PDArticleSetPDArticleMedlineCitationDateCompleted

    Private yearField As String

    Private monthField As String

    Private dayField As String

    '''<remarks/>
    Public Property Year() As String
        Get
            Return Me.yearField
        End Get
        Set(value As String)
            Me.yearField = value
        End Set
    End Property

    '''<remarks/>
    Public Property Month() As String
        Get
            Return Me.monthField
        End Get
        Set(value As String)
            Me.monthField = value
        End Set
    End Property

    '''<remarks/>
    Public Property Day() As String
        Get
            Return Me.dayField
        End Get
        Set(value As String)
            Me.dayField = value
        End Set
    End Property
End Class

 

建立GridView顯示要使用的類別

由於最後希望藉由 GridView 來顯示資料,所以另外定一個類別,用來搭配GridView顯示資料用,相關的內容如下:

Public Class PDArticleInfo
    Public Property PMID As Integer = 0
    Public Property DateCreate As Date = Nothing
    Public Property DateCCompleted As Date = Nothing
End Class

 

到此,準備工作差不多完成了,接著就是來實際的使用測試看看

 

測試

小喵準備一個TextBox,用來貼上Xml,這樣可以反覆的來進行測試,一個按鈕來啟動轉換,一個GridView來顯示最後的結果

於是安排畫面如下:

<asp:TextBox ID="txtXml" runat="server" TextMode="MultiLine" Rows="20" Columns="50"></asp:TextBox>
<br />
<asp:Button ID="Button1" runat="server" Text="Button" />
<br />
<asp:GridView ID="GridView1" runat="server">
</asp:GridView>

接著,撰寫按鈕按下後的相關動作

Protected Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    '如果內容不是空的
    If Me.txtXml.Text <> "" Then
        '轉換公用程式的物件初始化
        Dim oUtilO2X As New UtilObj2Xml

        '宣告轉換完成的物件
        Dim oPDASet As PDArticleSet
        '透過公用程式進行物件轉換
        oPDASet = oUtilO2X.Xml2Obj(GetType(PDArticleSet), Me.txtXml.Text)

        '宣告給GridView顯示的物件集合
        Dim oPDAs As New List(Of PDArticleInfo)
        '物件集合中的單一物件宣告
        Dim tPDA As PDArticleInfo

        '迴圈將xml轉換的物件取出,放入GridView要顯示的物件集合中
        For Each m As PDArticleSetPDArticle In oPDASet.PDArticle
            tPDA = New PDArticleInfo
            tPDA.PMID = m.MedlineCitation.PMID.Value
            tPDA.DateCreate = CDate(m.MedlineCitation.DateCreated.Year & "/" & m.MedlineCitation.DateCreated.Month & "/" & m.MedlineCitation.DateCreated.Day)
            tPDA.DateCCompleted = CDate(m.MedlineCitation.DateCompleted.Year & "/" & m.MedlineCitation.DateCompleted.Month & "/" & m.MedlineCitation.DateCompleted.Day)
            oPDAs.Add(tPDA)
        Next

        '將物件集合設定為GridView的DataSource並綁定
        Me.GridView1.DataSource = oPDAs
        Me.GridView1.DataBind()
    End If
End Sub

就醬子,測試結果如下:

xml2obj0003

 

末記

類似的需求,無論Xml來自哪裡,只要他的內容格式是正確的,就可以透過以上的方式去處理他。JSON 的資料其實也是方式類似的做法。這樣的方式可以應用在政府的公開資料(Open Data)只要是他的格是正確,我們就可以透過以上類似的步驟來進行,而且不只運用在WebForm,用MVC,Windows Form, Windows Phone等,都可以套用。

相關方式記錄一下,提供大家參考

^_^

 


以下是簽名:


Microsoft MVP
Visual Studio and Development Technologies
(2005~2019/6)