I am working on some XML documents and trying to parse them into Lists. I have read the following answers and articles but, I couldn't find a way to parse optional "Values" tag and it's elements for the code below.
http://blogs.msdn.com/b/ericwhite/archive/2009/05/14/working-with-optional-elements-and-attributes-in-linq-to-xml-queries.aspx , LINQ to XML optional element query , Can XML with optional elements be used with LINQ and Anonymous Types? , How to Parse Optional or Null XML Elements & Attributes with LINQ?
The code:
XDocument xdoc1 = XDocument.Load("sample.xml");
List<Message> messages = new List<Message>();
messages = (from _message in xdoc1.Element("Messages").Elements("Message")
select new Message
{
Id = _message.Element("Id").Value,
Alias = _message.Element("Alias").Value,
Fields = (from _field in _message.Element("Fields").Elements("Field")
select new Field
{
FieldName = _field.Element("FieldName").Value,
StartIndex = Convert.ToInt16(_field.Element("StartIndex").Value),
StopIndex = Convert.ToInt16(_field.Element("StopIndex").Value),
DefaultBits = _field.Element("DefaultBits").Value,
CalculationMethod = (CalculationMethods.Types)Enum.Parse(typeof(CalculationMethods.Types), _field.Element("CalculationMethod").Value),
Values = (from _value in _field.Element("Values").Elements("Value")
select new Value
{
Bits = _value.Element("Bits").Value,
Meaning = _value.Element("Meaning").Value
}).ToList()
}).ToList()
}).ToList();
Some "Fields" has "Field"s with "FieldName", "StartIndex", "StopIndex", "DefaultBits", "CalculationMethod" and optionally "Values". How can I fix the code for optional "Values" tags in XML?
Instead of using .Value
, use the explicit conversions in XElement
. So for example:
FieldName = (string) _field.Element("FieldName"),
StartIndex = (short?) _field.Element("StartIndex")
You'll end up with null values for absent elements, because that's what the custom conversions on XElement
do when the operand is null (and the return type is a reference type or a nullable value type).
For Values
, it's even easier - you just need to change _field.Element("Values")
to _field.Elements("Values")
:
Values = (from _value in _field.Elements("Values").Elements("Value")
select new Value
{
Bits = _value.Element("Bits").Value,
Meaning = _value.Element("Meaning").Value
}).ToList()
That way, _field.Elements("Values")
will return an empty sequence if there's no Values
element.
See more on this question at Stackoverflow