嵌套LINQ to XML检索报错:输入字符串格式不正确问题排查
XML数据解析问题排查与修正
原始XML结构
<Tournament TeamPlayers="1"> <Teams> <Team> <TeamID></TeamID> <Name></Name> <Status></Status> <Memo></Memo> <ByeRounds></ByeRounds> <Players> <Player Seat="A"> <MemberNo></MemberNo> <MemberName></MemberName> <PlayerFirstName></PlayerFirstName> <PlayerLastName></PlayerLastName> </Player> </Players> </Team> </Teams> <Staff> <Player> <MembershipNo></MembershipNo> <PlayerFirstName></PlayerFirstName> <PlayerLastName></PlayerLastName> <MembershipName></MembershipName> <Position></Position> </Player> </Staff> <Penalties> <Penalty> <Judge></Judge> <Player></Player> <InfractionType></InfractionType> <PenaltyType></PenaltyType> <Notes></Notes> </Penalty> </Penalties> </Tournament>
问题场景与错误代码
需求是遍历<Teams>、<Staff>、<Penalty>节点并存入列表,但编写的VB.NET代码无法正确嵌套访问<Players>元素,运行时提示**"Input string was not in a correct format"**错误,原始代码如下:
Dim TeamsNodes = xDoc.Descendants("Teams") lstOutputTeams = team.Descendants("Team").[Select](Function(t) New TournamentTeam With { .intTeamID = t.Element("TeamID"), .intByeRounds = t.Element("ByeRounds"), .strTeamName = t.Element("Name"), .strMemo = t.Element("Memo"), .intStatus = t.Element("Status"), .tpPlayerA = (From p In team.Descendants("Players") Select New PlayerInfo With { .strMembershipNo = p.Element("MemberNo").Value, .strPlayerFirstName = p.Element("PlayerFirstName").Value, .strPlayerLastName = p.Element("PlayerLastName").Value, .strMembershipName = p.Element("MemberName")}) }).ToList() Next lstFinalOutput.Add(lstOutputTeams)
错误原因分析
- 数值类型转换错误:
intTeamID、intByeRounds、intStatus是数值类型,但代码直接将XElement对象赋值给它们,且XML中这些元素可能为空,直接取Value转数值时会因空字符串抛出格式错误。 - Players节点层级访问错误:
- 应该从当前
Team节点t下查找Players,而非外层的team变量; MemberNo等字段属于<Player>节点,而非<Players>节点,原代码层级定位错误。
- 应该从当前
- 集合类型不匹配:
tpPlayerA应为单个PlayerInfo对象,但原代码用Select返回了IEnumerable(Of PlayerInfo),类型不匹配。 - 空值未处理:XML元素可能为空,直接访问
.Value会引发空引用异常或格式转换错误。
修正后的代码
' 假设xDoc是已加载的XDocument对象 Dim TeamsNodes = xDoc.Descendants("Teams") ' 遍历每个Teams节点下的Team For Each teamNode In TeamsNodes lstOutputTeams = teamNode.Descendants("Team").Select(Function(t) New TournamentTeam With { ' 处理数值类型的空值转换,空值时设默认值0 .intTeamID = If(String.IsNullOrEmpty(t.Element("TeamID")?.Value), 0, Integer.Parse(t.Element("TeamID").Value)), .intByeRounds = If(String.IsNullOrEmpty(t.Element("ByeRounds")?.Value), 0, Integer.Parse(t.Element("ByeRounds").Value)), .intStatus = If(String.IsNullOrEmpty(t.Element("Status")?.Value), 0, Integer.Parse(t.Element("Status").Value)), ' 字符串类型处理空元素,转为空字符串 .strTeamName = t.Element("Name")?.Value ?? "", .strMemo = t.Element("Memo")?.Value ?? "", ' 定位当前Team下Seat="A"的Player,转为单个PlayerInfo对象 .tpPlayerA = t.Descendants("Player").FirstOrDefault(Function(p) p.Attribute("Seat")?.Value = "A")?. Let(playerNode = New PlayerInfo With { .strMembershipNo = playerNode.Element("MemberNo")?.Value ?? "", .strPlayerFirstName = playerNode.Element("PlayerFirstName")?.Value ?? "", .strPlayerLastName = playerNode.Element("PlayerLastName")?.Value ?? "", .strMembershipName = playerNode.Element("MemberName")?.Value ?? "" }) }).ToList() lstFinalOutput.Add(lstOutputTeams) Next
关键修正点说明
- 数值类型字段增加空值判断,用
If和Integer.Parse安全转换,空值时设默认值; - 字符串字段用空合并运算符
??处理空元素,避免空引用; - 调整
Players节点的查找层级,从当前Team节点t下找Player,并通过FirstOrDefault获取单个匹配Seat="A"的对象; - 用
?.空传播运算符避免空元素访问时的异常。
内容的提问来源于stack exchange,提问作者Paul Williams
相关产品推荐
相关产品推荐

