2010-09-26 55 views
0

我花了不少时间阅读和了解LINQ to XML,但我在这里遇到了障碍。这里是我的XML文件的示例:LINQ to XML查询 - 代码只返回第一项

<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> 

在我的程序中,有人会从下拉列表中选择一个project_number。当他们这样做时,它将触发对将捕获该project_number的XML文件的查询,并查找所有合同。

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(); 

我明显在这里做错了事;我什么都看不到。此代码只返回来自任一项目的第一个合同项目,但不是两者。

回答

1

您需要获取项目元素的所有后代联系人,然后为每个联系人选择一个新的项目联系人。你可以改变你的查询,如下所示,当你想到它会工作:(。我会用xml.Element("whatever").Value代替xml.Element("whatever")虽然只是看起来更好)

 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") 
        }; 

+0

这在这里就是答案!这是我所有搜索中第一次从连续发表的文章中看到两篇。非常感谢!! – Greg 2010-09-26 06:39:00

+0

很高兴为您提供帮助 - 您可能会发现[MSDN 101 LINQ示例](http://msdn.microsoft.com/zh-cn/vcsharp/aa336746.aspx)是一个有用的资源。有关复合'from'的更多信息,请参见[SelectMany示例](http://msdn.microsoft.com/zh-cn/vcsharp/aa336758.aspx#SelectManyMultiplefrom)。 – jball 2010-09-26 17:56:01

0

试试这个

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") 
        }; 
+0

这会起作用,但看起来像会导致额外的契约元素被选中,然后在过滤中被丢弃。 – jball 2010-09-26 17:58:06

+0

我不认为它与你标记为答案的查询不同。因为查询一旦找到其项目编号匹配你的合同就不会中断。它会继续遍历整个XML,看看是否有其他元素与您的过滤器匹配。通过创建一个巨大的xml并运行两个查询并检查消耗的时间来检查它。 – 2010-09-27 14:56:09

+0

从概念上讲,您的解决方案可以获取所有项目元素下的所有合同元素,然后过滤出所需的合约元素。复合'from'解决方案获取所有项目元素(通常假定其数量比契约元素的数量更小),过滤掉匹配的元素,然后获取所有后代契约元素。我确信边缘案例可能存在,但一般来说,利用文件的层次结构应该导致更少的冗余处理。 – jball 2010-09-28 17:57:32