0

There is an xml file with the following structure

....
<workDomain>                      
...
<event>some value</event>
.....
    <event>
        <code codeContainer="CCVal1" code="4567">
        ...
        <code>
    </event>
</workDomain>

I am interested in the event with code children, not the simple event without any code children.

However, if I use the following linq query:

var res = from node in xDoc.Descendants(nsohr + "workDomain").Single().Descendants(nsohr + "event")
                      where node.Descendants(nsohr + "code").Single().Attribute("codeContainer").Value.Equals("CCVal1")
                      && node.Descendants(nsohr + "code").Single().Attribute("code").Value.Equals("4567")
                      select node;

returns nothing. That is I get: "Sequence contains no elements" exception if I attempt to iterate over res with foreach.

If I enforce the existence of children of event through an explicit constraint such as the one below:

var res = from node in xDoc.Descendants(nsohr + "workDomain").Single().Descendants(nsohr + "event")
                      where node.Descendants(nsohr + "code").Count() > 0
                      && node.Descendants(nsohr + "code").Single().Attribute("codeContainer").Value.Equals("CCVal1")
                      && node.Descendants(nsohr + "code").Single().Attribute("code").Value.Equals("4567")
                      select node;

Then everything works as expected. Why on earth do I have to add

node.Descendants(nsohr + "code").Count() > 0 ? The constrains on descendants should imply their existence, or so I think. This feels very unnatural to me. What am I missing here?

Update: Jon's example helped me see my misunderstanding about the way linq to xml works. I was somehow under the impression that the criteria I've placed on the nodes would determine the nodes which will be selected (incorrectly) thinking things work like a db query: db parsing sql and selecting data etc... I simply ended up calling methods on wrong objects for calling those methods. Jon's snippet with a small fix (assuming I'm not missing something here Jon) works as expected:

var res = xDoc.Descendants(nsohr + "workDomain")
              .Descendants(nsohr + "event")
              .Where(x => x.Elements("code")
                           .Any(y => (string) y.Attribute("codeContainer") == "CCVal1"
                                  && (string) y.Attribute("code") == "4567"));
4

2 回答 2

1

“什么都不返回”和“我得到一个异常”是非常不同的。

问题在这里:

 where node.Descendants(nsohr + "code")
           .Single().Attribute("codeContainer").Value.Equals("CCVal1")

您正在使用Single(),如果不完全是一个元素,则记录它会引发异常。果然,你有这个例外。

不过,您的查询可以变得更简单:

var res = xDoc.Descendants(nsohr + "workDomain")
              .Descendants(nsohr + "event")
              .Where(x => x.Elements("code")
                           .Any(x => (string) x.Attribute("codeContainer") == "CCVal1"
                                  && (string) x.Attribute("code") == "4567"));

(假设它code始终是 的直接子代event;如果不是,您可以使用Descendants代替Elements。)

换句话说,找到元素event的后代workDomain,其中至少一个子code子元素具有相关属性。

于 2013-06-20T17:54:27.453 回答
0

当你调用.Single()一个包含多个不是 1 的元素的集合时,你总是会得到一个异常。

node.Descendants(nsohr + "code").Single()是可能引发异常的段。

如果您的收藏(理论上)不应该只有 1 个元素,那么您不应该使用.Single()

不过,您显然已经找到了适合您的查询。还有其他问题吗?


为了将来参考,如果你只寻找一个元素中的 1 个,你可以使用类似Elementor的方法Descendant

您还可以调用ElementsDescendants元素集合。

于 2013-06-20T17:54:37.110 回答