阅读XML文件VB.NET

时间:2012-07-27 07:26:20

标签: vb.net xml-parsing

我正在尝试在VB.NET中阅读以下XML文件

<?xml version="1.0" encoding="UTF-8"?>
<mame build="0.129 (Jan  8 2009)" debug="no">
    <game name="puckman" sourcefile="pacman.c">
        <description>PuckMan (Japan set 1, Probably Bootleg)</description>
        <year>1980</year>
        <manufacturer>Namco</manufacturer>
        <rom name="namcopac.6e" size="4096" crc="fee263b3" sha1="87117ba5082cd7a615b4ec7c02dd819003fbd669" region="main" offset="0"/>
        <rom name="namcopac.6f" size="4096" crc="39d1fc83" sha1="326dbbf94c6fa2e96613dedb53702f8832b47d59" region="main" offset="1000"/>
        <rom name="namcopac.6h" size="4096" crc="02083b03" sha1="7e1945f6eb51f2e51806d0439f975f7a2889b9b8" region="main" offset="2000"/>
        <rom name="namcopac.6j" size="4096" crc="7a36fe55" sha1="01b4c38108d9dc4e48da4f8d685248e1e6821377" region="main" offset="3000"/>
        <rom name="pacman.5e" size="4096" crc="0c944964" sha1="06ef227747a440831c9a3a613b76693d52a2f0a9" region="gfx1" dispose="yes" offset="0"/>
        <rom name="pacman.5f" size="4096" crc="958fedf9" sha1="4a937ac02216ea8c96477d4a15522070507fb599" region="gfx1" dispose="yes" offset="1000"/>
        <rom name="82s123.7f" size="32" crc="2fc650bd" sha1="8d0268dee78e47c712202b0ec4f1f51109b1f2a5" region="proms" offset="0"/>
        <rom name="82s126.4a" size="256" crc="3eb3a8e4" sha1="19097b5f60d1030f8b82d9f1d3a241f93e5c75d6" region="proms" offset="20"/>
        <rom name="82s126.1m" size="256" crc="a9cc86bf" sha1="bbcec0570aeceb582ff8238a4bc8546a23430081" region="namco" offset="0"/>
        <rom name="82s126.3m" size="256" crc="77245b66" sha1="0c4d0bee858b97632411c440bea6948a74759746" region="namco" offset="100"/>
        <chip type="cpu" tag="main" name="Z80" clock="3072000"/>
        <chip type="audio" tag="namco" name="Namco" clock="96000"/>
        <display type="raster" rotate="90" width="288" height="224" refresh="60.606061" pixclock="6144000" htotal="384" hbend="0" hbstart="288" vtotal="264" vbend="0" vbstart="224" />
        <sound channels="1"/>
        <input players="2" buttons="1" coins="2" service="yes">
            <control type="joy4way"/>
        </input>
        <dipswitch name="Rack Test (Cheat)">
            <dipvalue name="Off" default="yes"/>
            <dipvalue name="On"/>
        </dipswitch>
        <dipswitch name="Service Mode">
            <dipvalue name="Off" default="yes"/>
            <dipvalue name="On"/>
        </dipswitch>
        <dipswitch name="Cabinet">
            <dipvalue name="Upright" default="yes"/>
            <dipvalue name="Cocktail"/>
        </dipswitch>
        <dipswitch name="Coinage">
            <dipvalue name="2 Coins/1 Credit"/>
            <dipvalue name="1 Coin/1 Credit" default="yes"/>
            <dipvalue name="1 Coin/2 Credits"/>
            <dipvalue name="Free Play"/>
        </dipswitch>
        <dipswitch name="Lives">
            <dipvalue name="1"/>
            <dipvalue name="2"/>
            <dipvalue name="3" default="yes"/>
            <dipvalue name="5"/>
        </dipswitch>
        <dipswitch name="Bonus Life">
            <dipvalue name="10000" default="yes"/>
            <dipvalue name="15000"/>
            <dipvalue name="20000"/>
            <dipvalue name="None"/>
        </dipswitch>
        <dipswitch name="Difficulty">
            <dipvalue name="Normal" default="yes"/>
            <dipvalue name="Hard"/>
        </dipswitch>
        <dipswitch name="Ghost Names">
            <dipvalue name="Normal" default="yes"/>
            <dipvalue name="Alternate"/>
        </dipswitch>
        <driver status="good" emulation="good" color="good" sound="good" graphic="good" savestate="supported" palettesize="512"/>
    </game>
    <game name="puckmana" sourcefile="pacman.c" cloneof="puckman" romof="puckman">
        <description>PuckMan (Japan set 2)</description>
        <year>1980</year>
        <manufacturer>Namco</manufacturer>
        <rom name="pacman.6e" size="4096" crc="c1e6ab10" sha1="e87e059c5be45753f7e9f33dff851f16d6751181" region="main" offset="0"/>
        <rom name="pacman.6f" size="4096" crc="1a6fb2d4" sha1="674d3a7f00d8be5e38b1fdc208ebef5a92d38329" region="main" offset="1000"/>
        <rom name="pacman.6h" size="4096" crc="bcdd1beb" sha1="8e47e8c2c4d6117d174cdac150392042d3e0a881" region="main" offset="2000"/>
        <rom name="prg7" size="2048" crc="b6289b26" sha1="d249fa9cdde774d5fee7258147cd25fa3f4dc2b3" region="main" offset="3000"/>
        <rom name="prg8" size="2048" crc="17a88c13" sha1="eb462de79f49b7aa8adb0cc6d31535b10550c0ce" region="main" offset="3800"/>
        <rom name="chg1" size="2048" crc="2066a0b7" sha1="6d4ccc27d6be185589e08aa9f18702b679e49a4a" region="gfx1" dispose="yes" offset="0"/>
        <rom name="chg2" size="2048" crc="3591b89d" sha1="79bb456be6c39c1ccd7d077fbe181523131fb300" region="gfx1" dispose="yes" offset="800"/>
        <rom name="pacman.5f" merge="pacman.5f" size="4096" crc="958fedf9" sha1="4a937ac02216ea8c96477d4a15522070507fb599" region="gfx1" dispose="yes" offset="1000"/>
        <rom name="82s123.7f" merge="82s123.7f" size="32" crc="2fc650bd" sha1="8d0268dee78e47c712202b0ec4f1f51109b1f2a5" region="proms" offset="0"/>
        <rom name="82s126.4a" merge="82s126.4a" size="256" crc="3eb3a8e4" sha1="19097b5f60d1030f8b82d9f1d3a241f93e5c75d6" region="proms" offset="20"/>
        <rom name="82s126.1m" merge="82s126.1m" size="256" crc="a9cc86bf" sha1="bbcec0570aeceb582ff8238a4bc8546a23430081" region="namco" offset="0"/>
        <rom name="82s126.3m" merge="82s126.3m" size="256" crc="77245b66" sha1="0c4d0bee858b97632411c440bea6948a74759746" region="namco" offset="100"/>
        <chip type="cpu" tag="main" name="Z80" clock="3072000"/>
        <chip type="audio" tag="namco" name="Namco" clock="96000"/>
        <display type="raster" rotate="90" width="288" height="224" refresh="60.606061" pixclock="6144000" htotal="384" hbend="0" hbstart="288" vtotal="264" vbend="0" vbstart="224" />
        <sound channels="1"/>
        <input players="2" buttons="1" coins="2" service="yes">
            <control type="joy4way"/>
        </input>
        <dipswitch name="Rack Test (Cheat)">
            <dipvalue name="Off" default="yes"/>
            <dipvalue name="On"/>
        </dipswitch>
        <dipswitch name="Service Mode">
            <dipvalue name="Off" default="yes"/>
            <dipvalue name="On"/>
        </dipswitch>
        <dipswitch name="Cabinet">
            <dipvalue name="Upright" default="yes"/>
            <dipvalue name="Cocktail"/>
        </dipswitch>
        <dipswitch name="Coinage">
            <dipvalue name="2 Coins/1 Credit"/>
            <dipvalue name="1 Coin/1 Credit" default="yes"/>
            <dipvalue name="1 Coin/2 Credits"/>
            <dipvalue name="Free Play"/>
        </dipswitch>
        <dipswitch name="Lives">
            <dipvalue name="1"/>
            <dipvalue name="2"/>
            <dipvalue name="3" default="yes"/>
            <dipvalue name="5"/>
        </dipswitch>
        <dipswitch name="Bonus Life">
            <dipvalue name="10000" default="yes"/>
            <dipvalue name="15000"/>
            <dipvalue name="20000"/>
            <dipvalue name="None"/>
        </dipswitch>
        <dipswitch name="Difficulty">
            <dipvalue name="Normal" default="yes"/>
            <dipvalue name="Hard"/>
        </dipswitch>
        <dipswitch name="Ghost Names">
            <dipvalue name="Normal" default="yes"/>
            <dipvalue name="Alternate"/>
        </dipswitch>
        <driver status="good" emulation="good" color="good" sound="good" graphic="good" savestate="supported" palettesize="512"/>
    </game>
</mame>

这是我使用的代码

Imports System.IO
Imports System.Xml
Public Class Form1

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    Try
        Dim m_xmld As XmlDocument
        Dim m_nodelist As XmlNodeList
        Dim m_node As XmlNode

        m_xmld = New XmlDocument()
        m_xmld.Load("C:\mame2.xml")
        m_nodelist = m_xmld.SelectNodes("/mame/game")

        For Each m_node In m_nodelist

            Dim GameAttribute = m_node.Attributes.GetNamedItem("name").Value
            Dim name = m_node.ChildNodes.Item(0).InnerText
            Dim description = m_node.ChildNodes.Item(1).InnerText
            Dim manufacturer = m_node.ChildNodes.Item(2).InnerText
            Dim rotate = m_node.ChildNodes.Item(15).Attributes.GetNamedItem("rotate").Value
            Dim controles = m_node.ChildNodes.Item(17).ChildNodes.Item(0).Attributes.GetNamedItem("type").Value

            MessageBox.Show("ROM: " & GameAttribute _
              & "-- Description: " & name & "-- Year: " _
              & description & "-- Manufacturer: " _
              & manufacturer & "-- Rotate: " _
              & rotate & "-- Control Type: " & controles)

        Next
    Catch errorVariable As Exception

        MessageBox.Show(errorVariable.ToString())
    End Try
    Me.Close()
End Sub
End Class

我正在尝试阅读“名称”,“描述”,“年份”,“制造商”,“旋转”和“输入播放器控件类型”。

使用此代码,我可以阅读第一个游戏,但不能阅读XML文件的其余部分(在本例中我粘贴了2个游戏)。我可以通过childnode编号读取Childnodes和atributes,问题是“rom”中的游戏有不同数量的子节点,程序返回错误。

我想有另一种阅读本文的方法,但我不知道是哪一种。

感谢您提前和抱歉我的英语。

2 个答案:

答案 0 :(得分:1)

您需要使用XPath而不是索引按名称访问子节点。例如:

Dim name As String = m_node.SelectSingleNode("@name").InnerText
Dim description As String = m_node.SelectSingleNode("description").InnerText
Dim manufacturer As String = m_node.SelectSingleNode("manufacturer").InnerText
Dim rotate As String = m_node.SelectSingleNode("display/@rotate").InnerText
Dim controls As String = m_node.SelectSingleNode("input/control/@type").InnerText

答案 1 :(得分:0)

这应该可以解决问题,尽管我确实对你试图反序列化的对象类型采取了一些自由。还有一些工作要做(如'TODO'所述)。我遗漏的唯一代码是将文件路径解析为流以传递给主类的serialize / desreialize方法。我希望这会有所帮助。

#Region "Imports"
'first, import some usefull namespaces
Imports System
Imports System.IO
Imports System.Xml.Serialization
#End Region
#Region "Classes"
'then, start constructing your classes by drilling down in sequence
''' <summary>
''' A class to hold your xml file's data.
''' </summary>
''' <remarks>This class will hold the the data from your file.</remarks>
<XmlRoot("mame")> _
Public Class YourXML_File
#Region "Properties"
    <XmlAttribute(AttributeName:="build")> _
    Public Property Build As String
    <XmlAttribute(AttributeName:="debug")> _
    Public Property Debug As New StrangeBooleanNomenclatureType
    <XmlArray(ElementName:="game")> _
    Public Property Games As New List(Of Game)
#End Region
#Region "Methods"
#Region "Constructors"
    ''' <summary>
    ''' The default constructor.
    ''' </summary>
    ''' <remarks>The xml serializer requires a constructor which takes no arguments.</remarks>
    Public Sub New()
        'do stuff here if you need to, but try to relegate anything important to a constructor that takes a parameter accommodating said important behavior
    End Sub
#End Region
#Region "XML Serialization / Deserialization"
    ''' <summary>
    ''' Strongly typed method to serialize your object.
    ''' </summary>
    Public Shared Function Serialize(ByVal astream As Stream, ByVal axml_fileobj As YourXML_File) As Boolean
        'try to serialize the file stream
        Try
            'first create a xml serializer object
            Dim serializer As New XmlSerializer(GetType(YourXML_File))
            'then serialize the object
            serializer.Serialize(astream, axml_fileobj)
            'return a successful serialization
            Return True
        Catch ex As Exception

            'TODO: handle any exceptions here as you wish

            'let the calling method know the serialization failed
            Return False
        End Try
    End Function
    ''' <summary>
    ''' Strongly typed method to deserialize your object
    ''' </summary>
    Public Shared Function Deserialize(ByVal astream As Stream, ByVal axml_fileobj As YourXML_File) As Boolean
        'try to deserialize the file stream
        Try
            'first create a xml serializer object
            Dim serializer As New XmlSerializer(GetType(YourXML_File))
            'then deserialize the object
            axml_fileobj = serializer.Deserialize(astream)
            'return a successful deserialization
            Return True
        Catch ex As Exception

            'TODO: handle any exceptions here as you wish

            'let the calling method know the deserialization failed
            Return False
        End Try
    End Function
#End Region
#End Region
End Class
''' <summary>
''' A class to represent the "game" element.
''' </summary>
<XmlRoot("game")> _
Public Class Game
#Region "Properties"
    <XmlAttribute("name")> _
    Public Property Game_Name As String
    <XmlAttribute("sourcefile")> _
    Public Property Game_SourceFile As String
    <XmlElement("description")> _
    Public Property Game_Description As String
    <XmlElement("year")> _
    Public Property Game_Year As Integer
    <XmlElement("manufacture")> _
    Public Property Game_Manufacturer As String
    <XmlElement("roms")> _
    Public Property Game_Roms As New List(Of Rom)
    <XmlElement("chips")> _
    Public Property Game_Chips As New List(Of Chip)
    <XmlElement("display")> _
    Public Property Game_Display As New Display
    <XmlElement("sound")> _
    Public Property Game_Sound As New Sound
    <XmlElement("input")> _
    Public Property Game_Input As New Input
    <XmlElement("dipswitches")> _
    Public Property Game_Dipswitches As New List(Of DipSwitch)
    <XmlElement("driver")> _
    Public Property Game_Driver As New Driver
#End Region
#Region "Methods"
#Region "Constructors"
    ''' <summary>
    ''' The default constructor.
    ''' </summary>
    ''' <remarks>The xml serializer requires a constructor which takes no arguments.</remarks>
    Public Sub New()
        'do stuff here if you need to, but try to relegate anything important to a constructor that takes a parameter accommodating said important behavior
    End Sub
#End Region
#End Region
End Class
<XmlRoot("rom")> _
Public Class Rom
#Region "Properties"
    <XmlAttribute("name")> _
    Public Property Rom_Name As String
    <XmlAttribute("size")> _
    Public Property Rom_Size As Integer
    <XmlAttribute("crc")> _
    Public Property Rom_Crc As String
    <XmlAttribute("sha1")> _
    Public Property Rom_Sha1 As String
    <XmlAttribute("region")> _
    Public Property Rom_Region As New RomRegionType
    <XmlAttribute("dispose")> _
    Public Property Rom_Dispose As New StrangeBooleanNomenclatureType
    <XmlAttribute("offset")> _
    Public Property Rom_Offset As Integer
#End Region
#Region "Methods"
#Region "Constructors"
    ''' <summary>
    ''' The default constructor.
    ''' </summary>
    ''' <remarks>The xml serializer requires a constructor which takes no arguments.</remarks>
    Public Sub New()
        'do stuff here if you need to, but try to relegate anything important to a constructor that takes a parameter accommodating said important behavior
    End Sub
#End Region
#End Region
End Class
<XmlRoot("chip")> _
Public Class Chip
#Region "Properties"
    <XmlAttribute("type")> _
    Public Property Chip_Type As New ChipType
    <XmlAttribute("tag")> _
    Public Property Chip_Tag As String
    <XmlAttribute("name")> _
    Public Property Chip_Name As String
    <XmlAttribute("clock")> _
    Public Property Chip_Clock As Integer
#End Region
#Region "Methods"
#Region "Constructors"
    ''' <summary>
    ''' The default constructor.
    ''' </summary>
    ''' <remarks>The xml serializer requires a constructor which takes no arguments.</remarks>
    Public Sub New()
        'do stuff here if you need to, but try to relegate anything important to a constructor that takes a parameter accommodating said important behavior
    End Sub
#End Region
#End Region
End Class
<XmlRoot("display")> _
Public Class Display
#Region "Properties"
    <XmlAttribute("type")> _
    Public Property Display_Type As New DisplayType
    <XmlAttribute("rotate")> _
    Public Property Display_Rotate As Integer
    <XmlAttribute("width")> _
    Public Property Display_Width As Integer
    <XmlAttribute("height")> _
    Public Property Display_Height As Integer
    <XmlAttribute("refresh")> _
    Public Property Display_Refresh As Double
    <XmlAttribute("pixclock")> _
    Public Property Display_PixClock As Integer
    <XmlAttribute("htotal")> _
    Public Property Display_H_Total As Integer
    <XmlAttribute("hbend")> _
    Public Property Display_H_Bend As Integer
    <XmlAttribute("hbstart")> _
    Public Property Display_HbStart As Integer
#End Region
#Region "Methods"
#Region "Constructors"
    ''' <summary>
    ''' The default constructor.
    ''' </summary>
    ''' <remarks>The xml serializer requires a constructor which takes no arguments.</remarks>
    Public Sub New()
        'do stuff here if you need to, but try to relegate anything important to a constructor that takes a parameter accommodating said important behavior
    End Sub
#End Region
#End Region
End Class
<XmlRoot("sound")> _
Public Class Sound
#Region "Properties"
    <XmlAttribute("channels")> _
    Public Property Sound_Channels As Integer
#End Region
#Region "Methods"
#Region "Constructors"
    ''' <summary>
    ''' The default constructor.
    ''' </summary>
    ''' <remarks>The xml serializer requires a constructor which takes no arguments.</remarks>
    Public Sub New()
        'do stuff here if you need to, but try to relegate anything important to a constructor that takes a parameter accommodating said important behavior
    End Sub
#End Region
#End Region
End Class
<XmlRoot("input")> _
Public Class Input
#Region "Properties"
    <XmlAttribute("players")> _
    Public Property Input_Players As Integer
    <XmlAttribute("buttons")> _
    Public Property Input_Buttons As Integer
    <XmlAttribute("coins")> _
    Public Property Input_Coins As Integer
    <XmlAttribute("service")> _
    Public Property Input_Service As New StrangeBooleanNomenclatureType
    <XmlElement("control")> _
    Public Property Input_Controls As New List(Of Control)
#End Region
#Region "Methods"
#Region "Constructors"
    ''' <summary>
    ''' The default constructor.
    ''' </summary>
    ''' <remarks>The xml serializer requires a constructor which takes no arguments.</remarks>
    Public Sub New()
        'do stuff here if you need to, but try to relegate anything important to a constructor that takes a parameter accommodating said important behavior
    End Sub
#End Region
#End Region
End Class
<XmlRoot("control")> _
Public Class Control
#Region "Properties"
    <XmlAttribute("type")> _
    Public Property Control_Type As New ControlType
#End Region
#Region "Methods"
#Region "Constructors"
    ''' <summary>
    ''' The default constructor.
    ''' </summary>
    ''' <remarks>The xml serializer requires a constructor which takes no arguments.</remarks>
    Public Sub New()
        'do stuff here if you need to, but try to relegate anything important to a constructor that takes a parameter accommodating said important behavior
    End Sub
#End Region
#End Region
End Class
<XmlRoot("dipswitch")> _
Public Class DipSwitch
#Region "Properties"
    <XmlAttribute("name")> _
    Public Property DipSwitch_Name As String
    <XmlElement("dipvalue")> _
    Public Property DipSwitch_DipValues As New List(Of DipValue)
#End Region
#Region "Methods"
#Region "Constructors"
    ''' <summary>
    ''' The default constructor.
    ''' </summary>
    ''' <remarks>The xml serializer requires a constructor which takes no arguments.</remarks>
    Public Sub New()
        'do stuff here if you need to, but try to relegate anything important to a constructor that takes a parameter accommodating said important behavior
    End Sub
#End Region
#End Region
End Class
<XmlRoot("dipvalue")> _
Public Class DipValue
#Region "Properties"
    <XmlAttribute("name")> _
    Public Property DipValue_Name As String
    <XmlAttribute("default")> _
    Public Property DipValue_Default As New StrangeBooleanNomenclatureType
#End Region
#Region "Methods"
#Region "Constructors"
    ''' <summary>
    ''' The default constructor.
    ''' </summary>
    ''' <remarks>The xml serializer requires a constructor which takes no arguments.</remarks>
    Public Sub New()
        'do stuff here if you need to, but try to relegate anything important to a constructor that takes a parameter accommodating said important behavior
    End Sub
#End Region
#End Region
End Class
<XmlRoot("driver")> _
Public Class Driver
#Region "Properties"
    <XmlAttribute("status")> _
    Public Property Driver_Status As New StatusState
    <XmlAttribute("emulation")> _
    Public Property Driver_Emulation As New StatusState
    <XmlAttribute("color")> _
    Public Property Driver_Color As New StatusState
    <XmlAttribute("sound")> _
    Public Property Driver_Sound As New StatusState
    <XmlAttribute("graphic")> _
    Public Property Driver_Graphic As New StatusState
    <XmlAttribute("savestate")> _
    Public Property Driver_SaveState As New SaveStateType
    <XmlAttribute("palettesize")> _
    Public Property Driver_PaletteSize As Integer
#End Region
#Region "Methods"
#Region "Constructors"
    ''' <summary>
    ''' The default constructor.
    ''' </summary>
    ''' <remarks>The xml serializer requires a constructor which takes no arguments.</remarks>
    Public Sub New()
        'do stuff here if you need to, but try to relegate anything important to a constructor that takes a parameter accommodating said important behavior
    End Sub
#End Region
#End Region
End Class
#End Region
#Region "Enums"
'finally, introduce some enumerations to strongly define the exact range of the more loosely defined attributes used
Public Enum StatusState
    <XmlEnum("bad")> Bad = 0
    <XmlEnum("good")> Good = 1
End Enum
Public Enum StrangeBooleanNomenclatureType
    <XmlEnum("no")> No = 0
    <XmlEnum("yes")> Yes = 1
End Enum
Public Enum ChipType
    <XmlEnum("cpu")> CPU = 0
    <XmlEnum("audio")> Audio = 1

    'TODO: add other chip types here

End Enum
Public Enum RomRegionType
    <XmlEnum("main")> Main = 0
    <XmlEnum("gfx1")> GFX1 = 1
    <XmlEnum("proms")> Proms = 2
    <XmlEnum("namco")> Namco = 3

    'TODO: add more region types here

End Enum
Public Enum DisplayType
    <XmlEnum("raster")> Raster = 0

    'TODO: add more display types here

End Enum
Public Enum ControlType
    <XmlEnum("joy4way")> joy4way = 0

    'TODO: add more control types here

End Enum
Public Enum SaveStateType
    <XmlEnum("supported")> Supported = 0

    'TODO: add more save state types here

End Enum
#End Region