Home > Back-end >  DeSerialize From XML By LINQ
DeSerialize From XML By LINQ

Time:10-27

So, I have XML file:

<?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>

And, I want to read from it. My code below returns null to all fields

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;

Any suggestions? About XML File - it created by self-made method, where I add XElements to XDocument and save it.

CodePudding user response:

Based on the expectation in your code, it looks like your XML is not well-formed, this is what your code is expecting:

<?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>

Notice now that RailwayStations (plural) now has multiple child elements called RailwayStation. The same then goes for the Luggage rooms, the code is actually making the wrong assumption for these anyway, but the data should be structured so that each luggage room is contained within an outer element, in this example I called it 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;

It looks like you have an XY problem here, if you are constructing the XML as well, please check the logic in there to make sure that it makes sense.

If you are constructing this XML, then consider a schema with simpler named elements:

 <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>

Then your code could be something like this:

 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;

I realize this is a significant structure change, but it will simplify all future processing and reduce the bytes going across the wire.

  • Related