Reputation: 1397
I have Xml that looks like...
<root>
<extension>
<Obj>
<Id>12345</Id>
<NameValuePair>
<Name>Prop1</Name>
<Value>Value1</Value>
</NameValuePair>
<NameValuePair>
<Name>Prop2</Name>
<Value>Value2</Value>
</NameValuePair>
<NameValuePair>
<Name>Prop3</Name>
<Value>Value3</Value>
</NameValuePair>
</Obj>
<Obj>
<Id>67890</Id>
<NameValuePair>
<Name>Prop4</Name>
<Value>Value5</Value>
</NameValuePair>
<NameValuePair>
<Name>Prop5</Name>
<Value>Value5</Value>
</NameValuePair>
<NameValuePair>
<Name>Prop6</Name>
<Value>Value6</Value>
</NameValuePair>
</Obj>
</extension>
</root>
I am trying to use XDocument / Linq to XML to achieve..
Id: 12345
Prop1: Value1
Prop2: Value2
Prop3: Value3
Id: 67890
Prop1: Value1
Prop2: Value2
Prop3: Value3
I already know the Id that needs to be looked up, in the code here i have hardcoded it as "12345" as per the example... this is what i have so far...
var val = xmlDoc.Element("extension").Elements("Obj")
.Where(i => (string)i.Element("Id") == "12345" &&
(string)i.Element("NameValuePair").Element("Name") == "Prop2")
.Select(i => (string)i.Element("NameValuePair").Element("Value")).FirstOrDefault();
What seems to be happening though is that each time i "try" to get a value... it just returns NULL..
Ultimately, I am trying to put it into an object such as...
internal class MyClass
{
public string Id { get; internal set; }
public string Prop1 { get; internal set; }
public string Prop2 { get; internal set; }
public string Prop3 { get; internal set; }
}
Any tips?
Upvotes: 0
Views: 184
Reputation: 34433
Use a dictionary instead of properties in the class. I did it with xml linq :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication74
{
class Program
{
const string FILENAME = @"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
List<MyClass> myClasses = doc.Descendants("Obj").Select(x => new MyClass() {
Id = (int)x.Element("Id"),
dict1 = x.Elements("NameValuePair").GroupBy(y => (string)y.Element("Name"), z => (string)z.Element("Value"))
.ToDictionary(y => y.Key, z => z.FirstOrDefault()),
dict2 = x.Elements("NameValuePair").GroupBy(y => (string)y.Element("Name"), z => (string)z.Element("Value"))
.ToDictionary(y => y.Key, z => z.ToList())
}).ToList();
}
}
internal class MyClass
{
public int Id { get; internal set; }
public Dictionary<string,string> dict1 { get; set; }
public Dictionary<string, List<string>> dict2 { get; set; }
}
}
Upvotes: 1
Reputation: 2936
You can convert your values to Lookup
if for the same Prop
you have multiple Value
// use temporary variable to increase performance of item.Element, I'm not sure that all 'Obj' element contains 'Id'
XElement idElement = null;
var values = doc.Descendants("Obj")
.Where(item => (idElement = item.Element("Id")) != null && idElement.Value == "12345")
.Descendants("NameValuePair")
.ToLookup(o => o.Element("Name").Value, o => new { Id = idElement.Value, Value = o.Element("Value").Value });
foreach (var valuesByProp in values)
{
foreach (var prop in valuesByProp)
{
Console.WriteLine($"{prop.Id}, {valuesByProp.Key}, {prop.Value}");
}
}
Or you can directly group all NameValuePair
by Id
and then group by Prop
var values = doc.Descendants("Obj")
.ToLookup(o => o.Element("Id").Value,
o => o.Descendants("NameValuePair").ToLookup(p => p.Element("Name").Value, p => p.Element("Value").Value));
foreach (var groupById in values)
{
foreach (var groupByProp in groupById)
{
foreach (var valuesByProp in groupByProp)
{
foreach (var value in valuesByProp)
{
Console.WriteLine($"{groupById.Key}, {valuesByProp.Key}, {value}");
}
}
}
}
Upvotes: 0