Linq to XML, select all attributes and their values for a given node
I have an xml mapping file that looks something like this
<colourMappings>
<model name="modelX">
开发者_如何学JAVA <mapping colour="White" configCode="1"></mapping>
<mapping colour="Aluminium" configCode="2"></mapping>
<mapping colour="Black" configCode="3"></mapping>
<mapping colour="Blue" configCode="4"></mapping>
<mapping colour="White Pearl" configCode="5"></mapping>
<mapping colour="Graphite" configCode="6"></mapping>
<mapping colour="Gunmetal" configCode="7"></mapping>
<mapping colour="Indigo" configCode="8"></mapping>
<mapping colour="Red" configCode="9"></mapping>
</model>
<model name="modelY">
<mapping colour="White" configCode="1" stConfigCode= "xx" dgConfigCode="hj"></mapping>
<mapping colour="Aluminium" configCode="2" stConfigCode= "xy" dgConfigCode="gh"></mapping>
<mapping colour="Black" configCode="3" stConfigCode= "xt" dgConfigCode="fg"></mapping>
<mapping colour="Blue" configCode="4" stConfigCode= "sd" dgConfigCode="fg"></mapping>
<mapping colour="White Pearl" configCode="5" stConfigCode= "df" dgConfigCode="df"></mapping>
<mapping colour="Graphite" configCode="6" stConfigCode= "xc" dgConfigCode="df"></mapping>
<mapping colour="Gunmetal" configCode="7" stConfigCode= "cv" dgConfigCode="cv"></mapping>
<mapping colour="Indigo" configCode="8" stConfigCode= "zx" dgConfigCode="vb"></mapping>
<mapping colour="Red" configCode="9" stConfigCode= "fg" dgConfigCode="cv"></mapping>
</model>
</colourMappings>
I want to be able to pull out all the attributes and their values given a model name and colour
e.g.
given ModelY and White, I'd like to get configCode="1" stConfigCode= "xx" dgConfigCode="hj" This could be in any structure - array, list, whatever
I have been using Linq to XML but can't get the correct syntax
XDocument mappings = XDocument.Load(@"D:\colour_mappings.xml");
var q = from c in mappings.Descendants("model")
where (string)c.Attribute("name") == "modelY" && (string)c.Descendants("mapping").Attributes("colour").FirstOrDefault() == "White"
select c.Attributes();
anyone know how to do this?
Happy to use any method, doesn't necessarily need to be Linq
Update
Summarized in a method:
public IEnumerable<XAttribute> GetAttributes(string modelName, string colour)
{
XDocument mappings = XDocument.Load(@"D:\colour_mappings.xml");
var q1 =
from elm in mappings.Descendants("model")
where (string)elm.Attribute("name") == "modelY"
select elm;
var q2 =
from elm in q1.Descendants("mapping")
where (string)elm.Attribute("colour") == "White"
select elm.Attributes().Where(a => a.Name != "colour");
foreach (IEnumerable<XAttribute> attributeList in q2)
{
foreach (XAttribute attribute in attributeList)
{
yield return attribute;
}
}
}
as I am pushed for time I will use a 2 stage process
But would be interested to hear if this is possible in one query
var matchingModelXml = from c in mappings.Descendants("model")
where (string)c.Attribute("name") == "modelY"
select c;
var mappingAttributes = from b in matchingModelXml.Descendants("mapping")
where (string)b.Attribute("colour") == "White"
select b.Attributes();
Just because I like a challenge, here it is in one query:
XDocument test = XDocument.Parse("<colourMappings> <model name=\"modelX\"> <mapping colour=\"White\" configCode=\"1\"></mapping> <mapping colour=\"Aluminium\" configCode=\"2\"></mapping> <mapping colour=\"Black\" configCode=\"3\"></mapping> <mapping colour=\"Blue\" configCode=\"4\"></mapping> <mapping colour=\"White Pearl\" configCode=\"5\"></mapping> <mapping colour=\"Graphite\" configCode=\"6\"></mapping> <mapping colour=\"Gunmetal\" configCode=\"7\"></mapping> <mapping colour=\"Indigo\" configCode=\"8\"></mapping> <mapping colour=\"Red\" configCode=\"9\"></mapping> </model> <model name=\"modelY\"> <mapping colour=\"White\" configCode=\"1\" stConfigCode= \"xx\" dgConfigCode=\"hj\"></mapping> <mapping colour=\"Aluminium\" configCode=\"2\" stConfigCode= \"xy\" dgConfigCode=\"gh\"></mapping> <mapping colour=\"Black\" configCode=\"3\" stConfigCode= \"xt\" dgConfigCode=\"fg\"></mapping> <mapping colour=\"Blue\" configCode=\"4\" stConfigCode= \"sd\" dgConfigCode=\"fg\"></mapping> <mapping colour=\"White Pearl\" configCode=\"5\" stConfigCode= \"df\" dgConfigCode=\"df\"></mapping> <mapping colour=\"Graphite\" configCode=\"6\" stConfigCode= \"xc\" dgConfigCode=\"df\"></mapping> <mapping colour=\"Gunmetal\" configCode=\"7\" stConfigCode= \"cv\" dgConfigCode=\"cv\"></mapping> <mapping colour=\"Indigo\" configCode=\"8\" stConfigCode= \"zx\" dgConfigCode=\"vb\"></mapping> <mapping colour=\"Red\" configCode=\"9\" stConfigCode= \"fg\" dgConfigCode=\"cv\"></mapping> </model></colourMappings>");
var maps = from model in test.Root.Elements("model")
from attr in model.Attributes("name")
from mapping in model.Elements("mapping")
where attr.Value == "modelY" && mapping.Attribute("colour").Value == "White"
select new
{
configCode = mapping.Attribute("configCode").Value
, stConfigCode = mapping.Attribute("stConfigCode").Value
, dgConfigCode = mapping.Attribute("dgConfigCode").Value
};
foreach (var map in maps)
{
Console.Write("configCode: ");
Console.WriteLine(map.configCode);
Console.Write("stConfigCode: ");
Console.WriteLine(map.stConfigCode);
Console.Write("dgConfigCode: ");
Console.WriteLine(map.dgConfigCode);
}
I know this is ancient now, but I think the way to solve this problem without doing more processing than neccessary looks something like this:
mappings.Root.Elements()
.Where(cm => cm.Attribute("name").Value == "modelY")
.SelectMany(cm => cm.Elements()
.Where(m => m.Attribute("colour").Value == "White")
.SelectMany(m => m.Attributes()));
In query format, it would be:
from cm in doc.Root.Elements()
where cm.Attribute("name").Value == "modelY"
from m in cm.Elements()
where m.Attribute("colour").Value == "White"
from att in m.Attributes()
select att;
精彩评论