You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

遍历XML时触发System.NullReferenceException问题求助

XML遍历空引用异常的修复方案

问题场景

给定如下XML结构:

<Tournament TeamPlayers="1">
    <Teams>
        <Team>
            <TeamID>0</TeamID>
            <TeamName>Sample</TeamName>
            <Status>10</Status>
            <Memo>Sample Team</Memo>
            <ByeRounds>0</ByeRounds>
            <Players>
                <Player>
                    <MemberNumber>1</MemberNumber>
                    <MemberName>Dummy</MemberName>
                    <PlayerFirstName>Test</PlayerFirstName>
                    <PlayerLastName>User</PlayerLastName>
                    <SeatOrder>A</SeatOrder>
                </Player>
                <Player>
                    <MemberNumber></MemberNumber>
                    <MemberName></MemberName>
                    <PlayerFirstName></PlayerFirstName>
                    <PlayerLastName></PlayerLastName>
                    <SeatOrder>B</SeatOrder>
                </Player>
                <Player>
                    <MemberNumber></MemberNumber>
                    <MemberName></MemberName>
                    <PlayerFirstName></PlayerFirstName>
                    <PlayerLastName></PlayerLastName>
                    <SeatOrder>C</SeatOrder>
                </Player>
            </Players>
        </Team>
    </Teams>
</Tournament>

遍历<Players>节点并映射到自定义类集合时,运行以下代码触发System.NullReferenceException,断点指向Dim tpPlayer As PlayerInfo行:

Dim teamNodes As XmlNodeList = xmlDoc.DocumentElement.SelectNodes("/Tournament/Teams/Team")
Dim lstOutputTeams As New List(Of TournamentTeam)

' Check the atrribute of "TeamPlayers" in the root. 
'Dim intExpectedPlayers As Integer = xmlDoc.Attributes("/").Value
Dim intExpectedPlayers As Integer = xmlDoc.SelectSingleNode("/Tournament").Attributes("TeamPlayers").Value

For Each node As XmlNode In teamNodes

    Dim tpPlayerA As New PlayerInfo
    Dim tpPlayerB As New PlayerInfo
    Dim tpPlayerC As New PlayerInfo

    Dim playerNodes As XmlNodeList = node.SelectNodes("Players")

    For Each innerNode As XmlNode In playerNodes
        Dim tpPlayer As PlayerInfo = New PlayerInfo With {
            .strMembershipName = innerNode.SelectSingleNode("MemberName").InnerText,
            .strMembershipNo = innerNode.SelectSingleNode("MemberNumber").InnerText,
            .strPlayerFirstName = innerNode.SelectSingleNode("PlayerFirstName").InnerText,
            .strPlayerLastName = innerNode.SelectSingleNode("PlayerLastName").InnerText,
            .strSeatOrder = innerNode.SelectSingleNode("SeatOrder").InnerText
        }

        Select Case tpPlayer.strSeatOrder
            Case "A"
                tpPlayerA = tpPlayer
            Case "B"
                tpPlayerB = tpPlayerB
            Case "C"
                tpPlayerC = tpPlayerC
        End Select
    Next

    lstOutputTeams.Add(New TournamentTeam() With {
                       .strTeamName = node.SelectSingleNode("TeamName").InnerText,
                       .intTeamID = node.SelectSingleNode("TeamID").InnerText,
                       .intByeRounds = node.SelectSingleNode("ByeRounds").InnerText,
                       .intStatus = node.SelectSingleNode("Status").InnerText,
                       .strMemo = node.SelectSingleNode("Memo").InnerText,
                       .tpPlayerA = tpPlayerA,
                       .tpPlayerB = tpPlayerB,
                       .tpPlayerC = tpPlayerC}
                       )
Next

问题原因

  1. XPath节点选择错误:node.SelectNodes("Players")获取的是<Players>父节点,而非其下的<Player>子节点。尝试在<Players>节点上查找MemberName会返回null,访问InnerText时触发空引用。
  2. 赋值逻辑错误:SelectCase中Case B和C的赋值语句是tpPlayerB = tpPlayerB,未将当前遍历的Player对象赋值给对应的变量。
  3. 类型转换隐患:XML节点的InnerText是字符串类型,直接赋值给Integer类型的属性(如intTeamID)可能引发类型转换异常。

修复后的代码

Dim teamNodes As XmlNodeList = xmlDoc.DocumentElement.SelectNodes("/Tournament/Teams/Team")
Dim lstOutputTeams As New List(Of TournamentTeam)

' 正确获取根节点属性并转换为Integer
Dim intExpectedPlayers As Integer = Convert.ToInt32(xmlDoc.SelectSingleNode("/Tournament").Attributes("TeamPlayers").Value)

For Each node As XmlNode In teamNodes

    Dim tpPlayerA As New PlayerInfo
    Dim tpPlayerB As New PlayerInfo
    Dim tpPlayerC As New PlayerInfo

    ' 修改XPath,获取Players下的所有Player子节点
    Dim playerNodes As XmlNodeList = node.SelectNodes("Players/Player")

    For Each innerNode As XmlNode In playerNodes
        ' 安全获取节点文本,避免空引用
        Dim getNodeText = Function(nodeName As String) 
                              Dim childNode = innerNode.SelectSingleNode(nodeName)
                              Return If(childNode IsNot Nothing, childNode.InnerText, String.Empty)
                          End Function

        Dim tpPlayer As PlayerInfo = New PlayerInfo With {
            .strMembershipName = getNodeText("MemberName"),
            .strMembershipNo = getNodeText("MemberNumber"),
            .strPlayerFirstName = getNodeText("PlayerFirstName"),
            .strPlayerLastName = getNodeText("PlayerLastName"),
            .strSeatOrder = getNodeText("SeatOrder")
        }

        Select Case tpPlayer.strSeatOrder
            Case "A"
                tpPlayerA = tpPlayer
            Case "B"
                tpPlayerB = tpPlayer ' 修正赋值逻辑
            Case "C"
                tpPlayerC = tpPlayer ' 修正赋值逻辑
        End Select
    Next

    ' 显式转换字符串为Integer类型
    lstOutputTeams.Add(New TournamentTeam() With {
                       .strTeamName = node.SelectSingleNode("TeamName").InnerText,
                       .intTeamID = Convert.ToInt32(node.SelectSingleNode("TeamID").InnerText),
                       .intByeRounds = Convert.ToInt32(node.SelectSingleNode("ByeRounds").InnerText),
                       .intStatus = Convert.ToInt32(node.SelectSingleNode("Status").InnerText),
                       .strMemo = node.SelectSingleNode("Memo").InnerText,
                       .tpPlayerA = tpPlayerA,
                       .tpPlayerB = tpPlayerB,
                       .tpPlayerC = tpPlayerC}
                       )
Next

关键修改点

  • 将node.SelectNodes("Players")改为node.SelectNodes("Players/Player"),直接遍历每个<Player>节点。
  • 新增getNodeText函数,安全获取节点文本,避免因节点不存在导致的空引用。
  • 修正SelectCase中的赋值逻辑,将tpPlayerB = tpPlayerB改为tpPlayerB = tpPlayer。
  • 对Integer类型的属性使用Convert.ToInt32进行显式类型转换,避免隐式转换错误。

内容的提问来源于stack exchange,提问作者Paul Williams

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 20:39:20