通过 LINQ 从 XML 反序列化

Posted

技术标签:

【中文标题】通过 LINQ 从 XML 反序列化【英文标题】:DeSerialize From XML By LINQ 【发布时间】:2021-12-12 06:39:11 【问题描述】:

所以,我有 XML 文件:

<?xml version="1.0" encoding="utf-8"?>
<RailwayStations>
  <RailwayStation />
  <RailwayStationName>Verdansk</RailwayStationName>
  <RailwayStationCountOfWays>10</RailwayStationCountOfWays>
  <RailwayStationCountOfLuggageRooms>3</RailwayStationCountOfLuggageRooms>
  <RailwayStationLuggageRoomHeight>10</RailwayStationLuggageRoomHeight>
  <RailwayStationLuggageRoomWidth>20</RailwayStationLuggageRoomWidth>
  <RailwayStationLuggageRoomDepth>30</RailwayStationLuggageRoomDepth>
  <RailwayStationLuggageRoomHeight>11</RailwayStationLuggageRoomHeight>
  <RailwayStationLuggageRoomWidth>21</RailwayStationLuggageRoomWidth>
  <RailwayStationLuggageRoomDepth>31</RailwayStationLuggageRoomDepth>
  <RailwayStationLuggageRoomHeight>12</RailwayStationLuggageRoomHeight>
  <RailwayStationLuggageRoomWidth>22</RailwayStationLuggageRoomWidth>
  <RailwayStationLuggageRoomDepth>32</RailwayStationLuggageRoomDepth>
</RailwayStations>

而且,我想从中读取。我下面的代码将 null 返回到所有字段

var xDoc = XDocument.Load(fileName);

            var obj = from xElement in xDoc.Element("RailwayStations")?.Elements("RailwayStation")
                select new RailwayStation()
                
                    RailwayStationName = xElement.Element("RailwayStationName")?.Value,
                    RailwayStationCountOfWays = Convert.ToInt32(xElement.Element("RailwayStationCountOfWays")?.Value),
                    RailwayStationCountOfLuggageRooms =
                        Convert.ToInt32(xElement.Element("RailwayStationCountOfLuggageRooms")?.Value),
                    
                    LuggageRooms = (from element in xDoc.Element("RailwayStations")?.Elements("RailwayStation")
                        select new LuggageRoom()
                        
                            _luggageRoomHeight = Convert.ToInt32(element.Element("RailwayStationLuggageRoomHeight")?.Value),
                            _luggageRoomWidth = Convert.ToInt32(element.Element("RailwayStationLuggageRoomHeight")?.Value),
                            _luggageRoomDepth = Convert.ToInt32(element.Element("RailwayStationLuggageRoomHeight")?.Value),
                        ).ToList()
                ;
            return obj;

有什么建议吗?关于 XML 文件 - 用自制的方法创建,我将XElements 添加到XDocument 并保存。

【问题讨论】:

为什么要搜索RailwayStationinside 元素?该元素没有任何子元素,只有兄弟姐妹。 更好的问题,为什么RailwayStation 没有孩子?选择了节点名,为什么除了RailwayStation之外还有来自RailwayStations的其他子节点? @gunr2171,序列化新手。在我发现的示例中,类似的结构。 @gunr2171,我想我明白了。 xml 看起来格式不正确,修复您的 XML,代码将更有可能工作 【参考方案1】:

根据您代码中的预期,您的 XML 格式似乎不正确,这就是您的代码所期望的:

<?xml version="1.0" encoding="utf-8"?>
<RailwayStations>
  <RailwayStation>
    <RailwayStationName>Verdansk</RailwayStationName>
    <RailwayStationCountOfWays>10</RailwayStationCountOfWays>
    <RailwayStationCountOfLuggageRooms>3</RailwayStationCountOfLuggageRooms>
    <LuggageRooms>
      <LuggageRoom>
        <RailwayStationLuggageRoomHeight>10</RailwayStationLuggageRoomHeight>
        <RailwayStationLuggageRoomWidth>20</RailwayStationLuggageRoomWidth>
        <RailwayStationLuggageRoomDepth>30</RailwayStationLuggageRoomDepth>          
      </LuggageRoom>
      <LuggageRoom>
        <RailwayStationLuggageRoomHeight>11</RailwayStationLuggageRoomHeight>
        <RailwayStationLuggageRoomWidth>21</RailwayStationLuggageRoomWidth>
        <RailwayStationLuggageRoomDepth>31</RailwayStationLuggageRoomDepth>         
      </LuggageRoom>
      <LuggageRoom>
        <RailwayStationLuggageRoomHeight>12</RailwayStationLuggageRoomHeight>
        <RailwayStationLuggageRoomWidth>22</RailwayStationLuggageRoomWidth>
        <RailwayStationLuggageRoomDepth>32</RailwayStationLuggageRoomDepth>       
      </LuggageRoom>
    </LuggageRooms>
  </RailwayStation>
  <RailwayStation>
    <RailwayStationName>Number 2</RailwayStationName>
    <RailwayStationCountOfWays>8</RailwayStationCountOfWays>
    <RailwayStationCountOfLuggageRooms>1</RailwayStationCountOfLuggageRooms>
    <LuggageRooms>
      <LuggageRoom>
        <RailwayStationLuggageRoomHeight>12</RailwayStationLuggageRoomHeight>
        <RailwayStationLuggageRoomWidth>22</RailwayStationLuggageRoomWidth>
        <RailwayStationLuggageRoomDepth>32</RailwayStationLuggageRoomDepth>          
      </LuggageRoom>
    </LuggageRooms>
  </RailwayStation>
</RailwayStations>

现在请注意,RailwayStations(复数)现在有多个名为 RailwayStation 的子元素。行李室也是如此,代码实际上对这些做出了错误的假设,但数据的结构应该使每个行李室都包含在一个外部元素中,在这个例子中我称之为LuggageRooms

var xDoc = XDocument.Load(fileName);
var obj = from xElement in xDoc.Element("RailwayStations")?.Elements("RailwayStation")
          select new RailwayStation()
          
              RailwayStationName = xElement.Element("RailwayStationName")?.Value,
              RailwayStationCountOfWays = Convert.ToInt32(xElement.Element("RailwayStationCountOfWays")?.Value),
              RailwayStationCountOfLuggageRooms =
                Convert.ToInt32(xElement.Element("RailwayStationCountOfLuggageRooms")?.Value),
            
              LuggageRooms = (from element in xElement.Elements("LuggageRooms")
                select new LuggageRoom()
                
                    _luggageRoomHeight = Convert.ToInt32(element.Element("RailwayStationLuggageRoomHeight")?.Value),
                    _luggageRoomWidth = Convert.ToInt32(element.Element("RailwayStationLuggageRoomWidth")?.Value),
                    _luggageRoomDepth = Convert.ToInt32(element.Element("RailwayStationLuggageRoomDepth")?.Value),
                ).ToList()
          ;
return obj;

看起来你这里有一个XY problem,如果你也在构造 XML,请检查那里的逻辑以确保它有意义。

如果您正在构建这个 XML,那么请考虑使用更简单的命名元素的模式:

 <RailwayStation>
   <Name>Number 2</Name>
   <CountOfWays>8</CountOfWays>
   <CountOfLuggageRooms>1</CountOfLuggageRooms>
   <LuggageRooms>
     <LuggageRoom>
       <Height>12</Height>
       <Width>22</Width>
       <Depth>32</Depth>          
     </LuggageRoom>
   </LuggageRooms>
 </RailwayStation>

那么你的代码可能是这样的:

 var xDoc = XDocument.Load(fileName);
 var obj = from xElement in xDoc.Element("RailwayStations")?.Elements("RailwayStation")
           select new RailwayStation()
           
               Name = xElement.Element("Name")?.Value,
               CountOfWays = Convert.ToInt32(xElement.Element("CountOfWays")?.Value),
               CountOfLuggageRooms = Convert.ToInt32(xElement.Element("CountOfLuggageRooms")?.Value),
             
               LuggageRooms = (from element in xElement.Elements("LuggageRooms")
                 select new LuggageRoom()
                 
                     Height = Convert.ToInt32(element.Element("Height")?.Value),
                     Width = Convert.ToInt32(element.Element("Width")?.Value),
                     Depth = Convert.ToInt32(element.Element("Depth")?.Value),
                 ).ToList()
           ;
 return obj;

我意识到这是一个重大的结构变化,但它将简化所有未来的处理并减少通过网络传输的字节数。

【讨论】:

以上是关于通过 LINQ 从 XML 反序列化的主要内容,如果未能解决你的问题,请参考以下文章

如何反序列化 System.Xml.Linq.XElement?

xml序列化与反序列化工具

Code-Serialization:Xml序列化与Xml反序列化

如何从 nusoap 服务返回的 XML 反序列化对象?

C# 中的 Jaxb 等效项

C# 中的 Jaxb 等效项