小鋪上的一個詢問【多層的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對應的類別就產生好了
當然,相關的資料他會依據貼上的範例內容,去判斷該用什麼樣的資料型態,不過產生的型態不見的合適,這時候可以針對產生的形態稍做調整一下
於是就產生好類別,針對一些欄位的型態,稍微做調整後,類別內容如下:
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
就醬子,測試結果如下:
末記
類似的需求,無論Xml來自哪裡,只要他的內容格式是正確的,就可以透過以上的方式去處理他。JSON 的資料其實也是方式類似的做法。這樣的方式可以應用在政府的公開資料(Open Data)只要是他的格是正確,我們就可以透過以上類似的步驟來進行,而且不只運用在WebForm,用MVC,Windows Form, Windows Phone等,都可以套用。
相關方式記錄一下,提供大家參考
^_^
以下是簽名:
- 歡迎轉貼本站的文章,不過請在貼文主旨上加上【轉貼】,並在文章中附上本篇的超連結與站名【topcat姍舞之間的極度凝聚】,感恩大家的配合。
 - 小喵大部分的文章會以小喵熟悉的語言VB.NET撰寫,如果您需要C#的Code,也許您可以試著用線上的工具進行轉換,這裡提供幾個參考
 
| Microsoft MVP Visual Studio and Development Technologies (2005~2019/6)  | topcat Blog:http://www.dotblogs.com.tw/topcat  |