tags:

views:

44

answers:

2

Hey Everyone, I have spent quite a few hours reading and learning about linq to xml, but i have hit a roadblock here. Here is an example of my xml file:

<project>
  <project_number>20071234</project_number> 
  <project_name>ProjectA</project_name>  
  <project_unc>\\fileserver1\projects\</project_unc> 
  <contract>
    <full_name>Contract 00 Project1</full_name> 
    <directory_name>00_Project1</directory_name> 
  </contract>
  <contract>
    <full_name>Contract 01 Project2</full_name> 
    <directory_name>01_Project2</directory_name> 
  </contract>
</project>
<project>
  <project_number>20081234</project_number> 
  <project_name>ProjectB</project_name> 
  <project_unc>\\fileserver2\projects\</project_unc> 
  <contract>
    <full_name>Contract 00 Project3</full_name> 
    <directory_name>00_project3</directory_name> 
  </contract>
  <contract>
    <full_name>Contract 01 Project4</full_name> 
    <directory_name>01_project4</directory_name> 
  </contract>
</project>

In my program someone is going to pick a project_number from a dropdown list. When they do this it will trigger a query on the XML file that will grab that project_number, and look for all contracts.

        XDocument XDoc = null;
        XDoc = XDocument.Load("projects.xml");
        List<ProjectContract> pc = new List<ProjectContract>(); //created in class
        var query = from xml in XDoc.Descendants("project") where (string)xml.Element("project_number") == dropDown1.SelectedItem
                     select new ProjectContract
                     {
                         fullname = (string)xml.Element("contract").Element("full_name"),
                         dirname = (string)xml.Element("contract").Element("directory_name")
                     };
        pc = query.ToList();

I'm obviously doing something wrong here, i just can't see what. This code only returns the first contract item from either project, but not both. Any help would be greatly appreciated!!

A: 

You need to get all the descendant contacts of the project element and then select a new project contact for each one. You could change your query as follows and it would work as you expect:

        var query = from xml in XDoc.Descendants("project")
                    from contactxml in xml.Descendants("contract")
                    where (string)xml.Element("project_number") 
                                                  == dropDown1.SelectedItem
                    select new ProjectContract
                    {
                        fullname = (string)contactxml.Element("full_name"),
                        dirname = (string)contactxml.Element("directory_name")
                    };

(I would use xml.Element("whatever").Value instead of xml.Element("whatever") though. Just looks nicer.)

jball
This is the answer right here! That is the first time in all of my searching i've seen two from statements in a row. Thank-you so much!!
Greg
Glad to help - you may find the [MSDN 101 LINQ Samples](http://msdn.microsoft.com/en-us/vcsharp/aa336746.aspx) to be a useful resource. See the [SelectMany examples](http://msdn.microsoft.com/en-us/vcsharp/aa336758.aspx#SelectManyMultiplefrom) for more on compound `from`.
jball
A: 

Try this

var query = from contract in XDoc.Descendants("contract")
            where contract.Parent.Element("project_number").Value == dropDown1.SelectedItem
            select new ProjectContract
                     {
                         fullname = (string)xml.Element("contract").Element("full_name"),
                         dirname = (string)xml.Element("contract").Element("directory_name")
                     };
Vinay B R
This would work, but looks like it would cause extra contract elements to be selected and then discarded in the filtering.
jball
i dont think its different from the query you have marked as answer. because the query does not break once it finds the contract whose project number matches yours. it continues to loop through your entire xml to see if any other elements match you filter. check it out by creating a huge xml and running both queries and checking the time consumed.
Vinay B R
Conceptually, your solution gets all contract elements under all project elements, and then filters out to just the needed ones. The compound `from` solution gets all project elements (generally assumed to be a smaller amount than the number of contract elements), filters out just the matching one(s), and then gets all descendant contract elements. I'm sure edge cases could exists, but generally speaking, exploiting the hierarchy of the document should result in less redundant processing.
jball
To clarify by example, assume that the xml generally has 100 projects with unique project numbers and each project averages 5 contracts. Your solution gets all 500 contracts and then filters checking each one against the project number condition. The compound from gets all 100 projects, filters each one against the project number condition, and then returns the contracts under the matching project(s). Your solution is then doing 5 times as much conditional checking because it's processing 400 extra contract elements.
jball