How to read data from xml of specific format - c#

I want to read xml as below using linq. I want to read all elements and their sub elements and values to use in to my code. For example I want to read ParameterID2, and its child elements and display those.
<?xml version="1.0" encoding="utf-8"?>
<labelled>
<historyRecord recordedtime="12/12/1906">
<ParameterID2>
<parameterName>SWVersion</parameterName>
<engineeringUnit>###</engineeringUnit>
<previousValue>R1.2.3</previousValue>
</ParameterID2>
<ParameterID3>
<parameterName>SWVersion</parameterName>
<engineeringUnit>###</engineeringUnit>
<previousValue>R1.2.3</previousValue>
</ParameterID3>
<ParameterID4>
<parameterName>SWVersion</parameterName>
<engineeringUnit>###</engineeringUnit>
<previousValue>R1.2.3</previousValue>
</ParameterID4>
<ParameterID5>
<parameterName>SWVersion</parameterName>
<engineeringUnit>###</engineeringUnit>
<previousValue>R1.2.3</previousValue>
</ParameterID5>
</historyRecord>
</labelled>
I tried as code given below.
string xmlDocPath = "C:\\Users\\Dipak\\Desktop\\Documentation.xml";
string timestamp = "12/12/1906"; // this can vary
XDocument xmlDdoc = XDocument.Load(xmlDocPath);
var selectRecord = from recordS in xmlDdoc.Descendants("historyRecord").Where
(recordS => (string)recordS.Attribute("recordedtime") == timestamp)
select new
{
parameterID1 = recordS.Element("ParameterID2").Name,
// parameterID2 = recordS.Element("ParameterID3"),
parameterName = recordS.Element("parameterName").Value,
engineeringUnit = recordS.Element("engineeringUnit").Value,
previousValue = recordS.Element("previousValue").Value,
};

Related

DeSerialize From XML By LINQ

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

How to use Linq To XML to get multiple elements and store them differently?

<MainData id="1" >
<Info>
<Date>2015-06-08 15:00:00</Date>
</Info>
<Data DataRef="uu91"/>
<Data DataRef="uu92">
</Data>
</MainData>
I have an xml file and I want to take the two data element and store them into two different variable so when I do the same value comes out. when I receive these two values I would like to get the ID, Date...
var data = from item in retreiveOptaHomeFixturesXml.Descendants("MainData")
select new
{
ID = item.Attribute("id").Value,
Date = item.Element("Info").Element("Date").Value,
DataRef1 = item.Element("Data").Attribute("DataRef").Value,
Dataref2 = item.Element("Data").Attribute("DataRef").Value,
};
Ideally you should be fetching the DataRef into a list because in each MainData you will have multiple data with DataRef attribute. You can do it like this:-
var data = from item in x1.Descendants("MainData")
let dataNodes = item.Elements("Data")
select new
{
ID = item.Attribute("id").Value,
Date = item.Element("Info").Element("Date").Value,
DataRef1Ref2 = dataNodes.Select(x => (string)x.Attribute("DataRef"))
.ToList()
};

How properly work with LINQ to XML?

I have generated such xml file
<?xml version="1.0" encoding="utf-8"?>
<Requestes>
<Single_Request num="1">
<numRequest>212</numRequest>
<IDWork>12</IDWork>
<NumObject>21</NumObject>
<lvlPriority>2</lvlPriority>
<NumIn1Period>21</NumIn1Period>
</Single_Request>
</Requestes>
My aim is to get IDWork,numRequest and etc elements. I tried to get them this way:
foreach (XElement el in doc.Root.Elements())
{
if (el.Name == "Single_Request")
{
string num = el.Elements("numRequest").Value;
// but he says, that he cant do this .Value because it doest exist at all
}
}
How to fix this?
You have this error, because Elements("numRequest") returns collection of elements, not single element. You should use Element("numRequest") instead.
Also I suggest you to use query for getting elements by name instead of enumerating all elements and verifying their names:
var request = doc.Root.Element("Single_Request");
var num = (int)request.Element("numRequest");
Usually you use anonymous types or custom objects to group values parsed from xml:
var query = from r in doc.Root.Elements("Single_Request")
where (int)r.Attribute("num") == 1 // condition
select new {
NumRequest = (int)request.Element("numRequest"),
IdWork = (int)request.Element("IDWork"),
NumObject = (int)request.Element("NumObject")
};
var request = query.SinlgleOrDefault();
// use request.IdWork

Querying XML elements with identical name with Linq

I have the following XML:
<?xml version="1.0" encoding="UTF-8"?>
<ProductTypes>
<ProductType Name="MyProduct">
<Amount>100</Amount>
<Pattern Length="1" AllowedCharacters="ABCD"/>
<Pattern Length="7" AllowedCharacters="EFGH"/>
</ProductType>
</ProductTypes>
Using Linq to XML I can successfully extract information from any number of the element ProductType. However I also need the information from all of the elements Pattern.
XElement xml = XElement.Load("pattern_config.xml");
var productTypes = from productType in xml.Elements("ProductType")
select new {
Name = productType.Attribute("Name").Value,
Amount = Convert.ToInt32(productType.Element("Amount").Value)
// How to get all Pattern elements from that ProductType?
};
How can I do this? Or would you recommend another way accessing this XML?
You can nest queries.
var productTypes = from productType in xml.Elements("ProductType")
select new {
Name = productType.Attribute("Name").Value,
Amount = Convert.ToInt32(productType.Element("Amount").Value),
// How to get all Pattern elements from that ProductType?
Patterns = from patt in productType.Elements("Pattern")
select new { Length = int.Parse(patt.Attribute("Length").Value),
.... }
};

Parsing XML document using .Descendents(value)

I am trying to parse an xml document that I have created. However xml.Descendants(value) doesn't work if value has certain characters (including space, which is my problem).
My xml is structured like this:
<stockists>
<stockistCountry country="Great Britain">
<stockist>
<name></name>
<address></address>
</stockist>
</stockistCountry>
<stockistCountry country="Germany">
<stockist>
<name></name>
<address></address>
</stockist>
</stockistCountry>
...
</stockists>
And my C# code for parsing looks like this:
string path = String.Format("~/Content/{0}/Content/Stockists.xml", Helper.Helper.ResolveBrand());
XElement xml = XElement.Load(Server.MapPath(path));
var stockistCountries = from s in xml.Descendants("stockistCountry")
select s;
StockistCountryListViewModel stockistCountryListViewModel = new StockistCountryListViewModel
{
BrandStockists = new List<StockistListViewModel>()
};
foreach (var stockistCountry in stockistCountries)
{
StockistListViewModel stockistListViewModel = new StockistListViewModel()
{
Country = stockistCountry.FirstAttribute.Value,
Stockists = new List<StockistDetailViewModel>()
};
var stockist = from s in xml.Descendants(stockistCountry.FirstAttribute.Value) // point of failure for 'Great Britain'
select s;
foreach (var stockistDetail in stockist)
{
StockistDetailViewModel stockistDetailViewModel = new StockistDetailViewModel
{
StoreName = stockistDetail.FirstNode.ToString(),
Address = stockistDetail.LastNode.ToString()
};
stockistListViewModel.Stockists.Add(stockistDetailViewModel);
}
stockistCountryListViewModel.BrandStockists.Add(stockistListViewModel);
}
return View(stockistCountryListViewModel);
I am wondering if I am approaching the Xml parsing correctly, whether I shouldn't have spaces in my attributes etc? How to fix it so that Great Britain will parse
However xml.Descendants(value) doesn't work if value has certain characters
XElement.Descendants() expects an XName for the tag, not for the value.
And XML tags are indeed not allowed to contain spaces.
Your sample XML however only contains a value for an attribute, and the space there is fine.
Update:
I think you need
//var stockist = from s in xml.Descendants(stockistCountry.FirstAttribute.Value)
// select s;
var stockists = stockistCountry.Descendants("stockist");

Categories

Resources