XLinq question
-
My apologies if something like this has already been asked and answered; I did some Google searching, as well searching on this site, and didn't find it, so here goes. I'm new to the world of .NET 3.5 and Linq. What I have are 1 + n xml files. The first Xml file looks sort of like this:
<files>
<file id="1" name="(some guid)"/>
<file id="2" name="(some guid)"/>
</files>There are then files in the same directory, whose name matches the guid plus .xml, like so:
<file id="1">
<prop1>Value 1</prop1>
<prop1>Value 1</prop1>
<prop1>Value 1</prop1>
</file>What I'd like to be able to do is this: for each file listed in the first xml blob, I want to create an object based on the values in each of the other xml files that look like the 2nd blob, and return that as an IEnumerable<Thing>. Does anybody know where I can find an example of how to do this? Thanks in advance.
Jamie Nordmeyer
Portland, Oregon, USA
http://www.feralcodemonkies.com -
My apologies if something like this has already been asked and answered; I did some Google searching, as well searching on this site, and didn't find it, so here goes. I'm new to the world of .NET 3.5 and Linq. What I have are 1 + n xml files. The first Xml file looks sort of like this:
<files>
<file id="1" name="(some guid)"/>
<file id="2" name="(some guid)"/>
</files>There are then files in the same directory, whose name matches the guid plus .xml, like so:
<file id="1">
<prop1>Value 1</prop1>
<prop1>Value 1</prop1>
<prop1>Value 1</prop1>
</file>What I'd like to be able to do is this: for each file listed in the first xml blob, I want to create an object based on the values in each of the other xml files that look like the 2nd blob, and return that as an IEnumerable<Thing>. Does anybody know where I can find an example of how to do this? Thanks in advance.
Jamie Nordmeyer
Portland, Oregon, USA
http://www.feralcodemonkies.comIf I understand correctly. The first file contains references to other xml files whose names match the value of the name attribute. You then want to create an IEnumerable collection of the prop1 nodes from these files. Doesn't seem that difficult. Open the master file, read the file nodes and open the xml files in the name attribute. Store the prop1 nodes in a collection.
System.Xml.Linq.XDocument masterDoc = System.Xml.Linq.XDocument.Load("filename");
foreach(var node in masterDoc.Elements("files").Elements("file"))
{
string fileName = node.Attribute("name").Value + ".xml";
System.Xml.Linq.XDocument childDoc = System.Xml.Linq.XDocument.Load(fileName);var props = childDoc.Elements("file").Elements("prop1");
}
I know the language. I've read a book. - _Madmatt
-
If I understand correctly. The first file contains references to other xml files whose names match the value of the name attribute. You then want to create an IEnumerable collection of the prop1 nodes from these files. Doesn't seem that difficult. Open the master file, read the file nodes and open the xml files in the name attribute. Store the prop1 nodes in a collection.
System.Xml.Linq.XDocument masterDoc = System.Xml.Linq.XDocument.Load("filename");
foreach(var node in masterDoc.Elements("files").Elements("file"))
{
string fileName = node.Attribute("name").Value + ".xml";
System.Xml.Linq.XDocument childDoc = System.Xml.Linq.XDocument.Load(fileName);var props = childDoc.Elements("file").Elements("prop1");
}
I know the language. I've read a book. - _Madmatt
Hey Mark, thanks for that. I think I should've been more specific. I was wondering if there was a way to do it in Linq syntax. Regardless, I ultimately went with something very similar to what you provided. Thanks again for the reply.
Jamie Nordmeyer
Portland, Oregon, USA
http://www.feralcodemonkies.com -
Hey Mark, thanks for that. I think I should've been more specific. I was wondering if there was a way to do it in Linq syntax. Regardless, I ultimately went with something very similar to what you provided. Thanks again for the reply.
Jamie Nordmeyer
Portland, Oregon, USA
http://www.feralcodemonkies.comI took Mark's code and tried to LINQify :) it a little bit. Unfortunately there is no LINQ equivalent to select many so you have to do it as a method call.[^]
XDocument.Load("filename").Elements("files").Elements("file")).SelectMany(node =>
XDocument.Load(node.Attribute("name").Value + ".xml").Elements("file").Elements("prop1");Eslam Afifi
-
I took Mark's code and tried to LINQify :) it a little bit. Unfortunately there is no LINQ equivalent to select many so you have to do it as a method call.[^]
XDocument.Load("filename").Elements("files").Elements("file")).SelectMany(node =>
XDocument.Load(node.Attribute("name").Value + ".xml").Elements("file").Elements("prop1");Eslam Afifi
IMO this is horribly unreadable and a good example of the adage, "just because you can, doesn't mean you should".
I know the language. I've read a book. - _Madmatt
-
IMO this is horribly unreadable and a good example of the adage, "just because you can, doesn't mean you should".
I know the language. I've read a book. - _Madmatt
Thank you for your invaluable criticism Mr. Mark. I agree that "just because you can, doesn't mean you should". I was initially going to post something like this
XDocument.Load("filename").Elements("files").Elements("file")).SelectMany(node =>
{
string fileName = node.Attribute("name").Value + ".xml";
XDocument childDoc = XDocument.Load(fileName);
var props = childDoc.Elements("file").Elements("prop1");
});since I thought the OP might want to get them in one IEnumerable. So I used SelectMany instead of a foreach and accumulate the result in a List or something. But then I thought why not minimize the code a little, so I did. And it's not all that bad, it's still readable IMHO. On a second thought, the form in I'm posting now is probably better since it would allow error handling for invalid file paths returning an Enumerable.Empty and allow the query to continue. Thank you for your opinion. Have a nice day :rose:
Eslam Afifi
modified on Saturday, January 23, 2010 1:10 PM
-
Thank you for your invaluable criticism Mr. Mark. I agree that "just because you can, doesn't mean you should". I was initially going to post something like this
XDocument.Load("filename").Elements("files").Elements("file")).SelectMany(node =>
{
string fileName = node.Attribute("name").Value + ".xml";
XDocument childDoc = XDocument.Load(fileName);
var props = childDoc.Elements("file").Elements("prop1");
});since I thought the OP might want to get them in one IEnumerable. So I used SelectMany instead of a foreach and accumulate the result in a List or something. But then I thought why not minimize the code a little, so I did. And it's not all that bad, it's still readable IMHO. On a second thought, the form in I'm posting now is probably better since it would allow error handling for invalid file paths returning an Enumerable.Empty and allow the query to continue. Thank you for your opinion. Have a nice day :rose:
Eslam Afifi
modified on Saturday, January 23, 2010 1:10 PM
Thanks for the input from both you and Mark. I'll take both of your advise to heart, and go from there. I agree that just because you can doesn't imply that you should. That's one of the interesting things we need to deal with daily as developers, though; when is it to much reducing. I happen to love the ternary operator (int x = user.Name == "Bob" ? 1 : 0), but I've seen people that really hate it, and insist that only if/else blocks should be use. I guess it falls down to a matter of personal style. I personally like to shrink my code down as much as possible, but not so far that I can't read it 2 months for now. Again, thanks for both of your input! Very much appreciated. :)
Jamie Nordmeyer
Portland, Oregon, USA
http://www.feralcodemonkies.com -
Thanks for the input from both you and Mark. I'll take both of your advise to heart, and go from there. I agree that just because you can doesn't imply that you should. That's one of the interesting things we need to deal with daily as developers, though; when is it to much reducing. I happen to love the ternary operator (int x = user.Name == "Bob" ? 1 : 0), but I've seen people that really hate it, and insist that only if/else blocks should be use. I guess it falls down to a matter of personal style. I personally like to shrink my code down as much as possible, but not so far that I can't read it 2 months for now. Again, thanks for both of your input! Very much appreciated. :)
Jamie Nordmeyer
Portland, Oregon, USA
http://www.feralcodemonkies.comYou're welcome.
Eslam Afifi
-
I took Mark's code and tried to LINQify :) it a little bit. Unfortunately there is no LINQ equivalent to select many so you have to do it as a method call.[^]
XDocument.Load("filename").Elements("files").Elements("file")).SelectMany(node =>
XDocument.Load(node.Attribute("name").Value + ".xml").Elements("file").Elements("prop1");Eslam Afifi
Eslam Afifi wrote:
Unfortunately there is no LINQ equivalent to select many so you have to do it as a method call.
That's incorrect. Multiple "from" clauses in query expressions correspond to SelectMany calls.
var fileNodes = XDocument.Load("filename").Elements("files").Elements("file");
var allProp1 = from node in fileNodes
let document = XDocument.Load(node.Attribute("name").Value + ".xml")
from p1 in document.Elements("file").Elements("prop1") // this gets translated into SelectMany
select p1;Or if you like it unreadable in a single line:
from node in XDocument.Load("filename").Elements("files").Elements("file")
from p1 in XDocument.Load(node.Attribute("name").Value + ".xml").Elements("file").Elements("prop1")
select p1; -
Eslam Afifi wrote:
Unfortunately there is no LINQ equivalent to select many so you have to do it as a method call.
That's incorrect. Multiple "from" clauses in query expressions correspond to SelectMany calls.
var fileNodes = XDocument.Load("filename").Elements("files").Elements("file");
var allProp1 = from node in fileNodes
let document = XDocument.Load(node.Attribute("name").Value + ".xml")
from p1 in document.Elements("file").Elements("prop1") // this gets translated into SelectMany
select p1;Or if you like it unreadable in a single line:
from node in XDocument.Load("filename").Elements("files").Elements("file")
from p1 in XDocument.Load(node.Attribute("name").Value + ".xml").Elements("file").Elements("prop1")
select p1;You are absolutely correct. Thank you for correcting my mistake. I don't know what I was thinking when I wrote this :doh:
Eslam Afifi