我正在努力想出一个良好的类结构来简化XML文件的使用。我有个好的开始,但还不够。
这是一个XML文件
<?xml version="1.0" encoding="utf-8"?>
<Records>
<Band>Black Sabbath
<Album>
Paranoid
<Date>1977</Date>
</Album>
</Band>
<Band>Iron Maiden
<Album>
Killers
<Date>1981</Date>
</Album>
<Album>
PeiceOfMind
<Date>1983</Date>
</Album>
</Band>
</Records>
这是我的基类
Public Class XmlClassBase
Friend _list As LinkedList(Of XmlClassListItem)
Friend _current As LinkedListNode(Of XmlClassListItem)
Public IncludeIfEmpty As Boolean
Public ReadOnly Property Attributes() As Dictionary(Of String, String)
Get
If _current Is Nothing Then
_current = _list.AddLast(New XmlClassListItem)
End If
Return _current.Value.Attributes
End Get
End Property
Public Property Text As String
Get
If _current IsNot Nothing Then
Return _current.Value.Text
Else
Return String.Empty
End If
End Get
Set(value As String)
If _current Is Nothing Then
_current = _list.AddLast(New XmlClassListItem)
End If
_current.Value.Text = value
End Set
End Property
Friend Sub New()
_list = New LinkedList(Of XmlClassListItem)
_current = _list.AddLast(New XmlClassListItem)
End Sub
Public Overridable Sub Add()
Throw New System.Exception("Add called on base " + Me.GetType.ToString + ".")
End Sub
Friend Function AddInternal(NewElement As XmlClassListItem) As Boolean
Dim NewNode As LinkedListNode(Of XmlClassListItem)
Dim rc As Boolean
NewNode = _list.AddLast(NewElement)
If NewNode IsNot Nothing Then
_current = NewNode
rc =True
End If
Return rc
End Function
End Class
Public Class XmlClassListItem
Private _text As String
Public Attributes As Dictionary(Of String, String)
Public Sub New()
Attributes = New Dictionary(Of String, String)
End Sub
Public Property Text As String
Get
Return _text
End Get
Set(value As String)
_text = value
End Set
End Property
End Class
我通过例程运行xml,这就是我的结果:
public class RecordsNode
inherits XmlClassBase
public class BandNode
inherits XmlClassBase
public class AlbumNode
inherits XmlClassBase
public class DateNode
inherits XmlClassBase
public Overrides sub Add()
dim NewDate as new xmlclasslistitem
addinternal(newDate)
end sub
public function HasChildren() as boolean
return false
end function
End class
private _Date as DateNode
public sub new()
_Date = new DateNode
end Sub
Public ReadOnly Property [Date] As DateNode
Get
Return _Date
End Get
End Property
Public Overrides sub Add()
dim NewAlbum as new xmlclasslistitem
addinternal(newAlbum)
end sub
public function HasChildren() as boolean
return false
end function
End class
private _Album as AlbumNode
public sub new()
_Album = new AlbumNode
end sub
public readonly property Album as AlbumNode
get
return _Album
end get
end property
public Overrides sub Add()
dim NewBand as new xmlclasslistitem
addinternal(newBand)
end sub
public function HasChildren() as boolean
dim Children as boolean
return Children
end function
End class
private _Band as BandNode
private _FilePath as string
public sub new()
_Band = new BandNode
end sub
public readonly property Band as BandNode
get
return _Band
end get
end property
public property FilePath as string
get
return _FilePath
end get
set
_FilePath = value
end set
end property
private sub AddElement(Doc As XmlDocument, ByRef Parent As XmlElement, ParentName As String, Child As XmlElement)
if Parent is nothing then
Parent = Doc.CreateElement(ParentName)
end if
Parent.AppendChild(Child)
end sub
private function CreateElement(Item as XmlClassBase) as boolean
if Item.IncludeIfEmpty or Item.Text <> string.empty or Item.Attributes.Count > 0 then
return true
else
return false
end if
end Function
private function SaveElement(Doc as Xmldocument, Item as xmlclassbase, Parent as xmlelement, strParentName as string, strText as string) as xmlelement
Dim Attribute As XmlAttribute
dim Element As XmlElement = nothing
dim ElementName As string
Dim KeyValue As KeyValuePair(Of String, String)
'if CreateElement(Item)
ElementName = Item.gettype.name
ElementName = ElementName.substring(0, ElementName.length - 4)
Element = Doc.CreateElement(ElementName)
Element.InnerText = strText
AddElement(Doc, Parent, strParentName, Element)
For Each KeyValue In Item.Attributes
Attribute = Doc.CreateAttribute(KeyValue.Key)
Attribute.Value = KeyValue.Value
Element.Attributes.Append(Attribute)
next
'end if
return Element
end Function
public function Load() as boolean
dim Doc as xmldocument
Doc = New XmlDocument()
Doc.Load(_FilePath)
LoadHelper(Doc, "Band", me)
LoadHelper(Doc, "Band", me.Band)
LoadHelper(Doc, "Album", me.Band.Album)
LoadHelper(Doc, "Date", me.Band.Album.Date)
return true
end function
public sub LoadHelper(Doc As XmlDocument, Source As String, Target As XmlClassBase)
dim bFirstNode as boolean
dim lisNodes as XmlNodeList
dim r as Integer
dim strText as string = string.empty
bFirstNode = True
lisNodes = Doc.GetElementsByTagName(Source)
For Each Node As XmlNode In lisNodes
If bFirstNode Then
bFirstNode = False
else
Target.Add()
end if
strText = String.Empty
For Each child As XmlNode In Node.ChildNodes
If child.NodeType = XmlNodeType.Text Or child.NodeType = XmlNodeType.CDATA Then
strText &= child.Value.Trim
end if
next
If strText <> String.Empty Then
Target.Text = strText
end if
For r = 0 To Node.Attributes.Count - 1
Target.Attributes.Add(Node.Attributes(r).Name, Node.Attributes(r).InnerText)
next
next
end sub
public function Save() as boolean
dim Records0 as xmlelement = nothing
dim Band1 as xmlelement = nothing
dim Album2 as xmlelement = nothing
dim Date3 as xmlelement = nothing
dim Dec as xmldeclaration
dim Doc as xmldocument
Doc = New XmlDocument()
Dec = Doc.CreateXmlDeclaration("1.0", "utf-8", String.Empty)
Doc.AppendChild(Dec)
Records0 = SaveElement(Doc, me, nothing, "Records", Text)
For Each Item As XmlClassListItem In me.Band._list
Band1 = SaveElement(Doc, me.Band, Records0, "Band", Item.Text)
Records0.appendchild(Band1)
next
For Each Item As XmlClassListItem In me.Band.Album._list
Album2 = SaveElement(Doc, me.Band.Album, Band1, "Album", Item.Text)
Band1.appendchild(Album2)
next
For Each Item As XmlClassListItem In me.Band.Album.Date._list
Date3 = SaveElement(Doc, me.Band.Album.Date, Album2, "Date", Item.Text)
Album2.appendchild(Date3)
next
If Band1 IsNot Nothing Then
Records0.AppendChild(Band1)
end If
If Album2 IsNot Nothing Then
Band1.AppendChild(Album2)
end If
If Date3 IsNot Nothing Then
Album2.AppendChild(Date3)
end If
Doc.AppendChild(Records0)
Doc.Save(_FilePath)
return true
end Function
public Overrides sub Add()
dim NewRecords as new xmlclasslistitem
addinternal(newRecords)
end sub
public function HasChildren() as boolean
dim Children as boolean
return Children
end function
End class
工作得相当好。简单地获取一些数据:
r = New RecordsNode
r.FilePath = "C:\Test.xml"
r.Load()
TextBox1.Text = r.Band.Text
TextBox2.Text = r.Band.Album.Text
TextBox3.Text = r.Band.Album.Date.Text
注意:要测试创建项目,请添加三个文本框并将代码添加到Form_Load事件中。现在将类RecordsNode和Base类添加到一个单独的文件中。最后将XML复制到文件中。
关于这一点的好处是它对开发人员来说很容易,并使代码具有可读性。
添加节点并填充列表框(请注意,新节点仅存在于内存中,但如果调用Save方法,则该节点将保持不变。)
r = New RecordsNode
r.FilePath = "C:\Test.xml"
r.Load()
r.Band.Add()
r.Band.Text = "Metallica"
For Each band As XmlClassListItem In r.Band._list
ListBox1.Items.Add(band.Text)
Next
一个主要缺陷是无法访问循环中的子成员。如果我想要循环中的乐队的专辑或专辑,则无法获得。我没有看到解决这个问题的简单方法。
在我从零开始并重新设计整个事情之前,我想知道是否有人能够找到解决方法。
如果有人需要,我可以提供C#版本。
请不要告诉我使用XSD。我试过这个,它使得丑陋的课程变得丑陋。我不认为有人认为有一个名为 BatchPatientDataRequisitionDataOptionalDataUserField 的类使代码可读。
答案 0 :(得分:0)
我喜欢使用xml的方式:
http://www.codeproject.com/Articles/483055/XML-Serialization-and-Deserialization-Part
非常简单,直接且干净。它基本上为你完成了所有的工作。