1

been taxing my brain trying to figure out how to perform a linq xml query.

i'd like the query to return a list of all the "product" items where the category/name = "First Category" in the following xml

<catalog>
  <category>
    <name>First Category</name>
    <order>0</order>
    <product>
      <name>First Product</name>
      <order>0</order>
    </product>
    <product>
      <name>3 Product</name>
      <order>2</order>
    </product>
    <product>
      <name>2 Product</name>
      <order>1</order>
    </product>
  </category>
</catalog>

3 Answers 3

6

Like so:

    XDocument doc = XDocument.Parse(xml);
    var qry = from cat in doc.Root.Elements("category")
              where (string)cat.Element("name") == "First Category"
              from prod in cat.Elements("product")
              select prod;

or perhaps with an anonymous type too:

    XDocument doc = XDocument.Parse(xml);
    var qry = from cat in doc.Root.Elements("category")
              where (string)cat.Element("name") == "First Category"
              from prod in cat.Elements("product")
              select new
              {
                  Name = (string)prod.Element("name"),
                  Order = (int)prod.Element("order")
              };
    foreach (var prod in qry)
    {
        Console.WriteLine("{0}: {1}", prod.Order, prod.Name);
    }
Sign up to request clarification or add additional context in comments.

8 Comments

There would seem to be only one category with name First Category, so Single is probably more appropiate here.
I think it is safe to assume that this is a fragment from a larger xml block, otherwise the filtering itself is redundant. In which case you cannot say how many categories there are with given names...
In various UI frameworks, name implies uniqueness. I could probably think of several other examples. I don't think there's much point arguing over what is a rather subjective issue anyway.
I agree, this is mainly conjecture. The OP has both solutions anyway, so they can choose whichever. :)
I take it the explicit conversion to string won't complain if Element returns null?
|
1

Here's an example:

        string xml = @"your XML";

        XDocument doc = XDocument.Parse(xml);

        var products = from category in doc.Element("catalog").Elements("category")
                       where category.Element("name").Value == "First Category"
                       from product in category.Elements("product")
                       select new
                       {
                           Name = product.Element("name").Value,
                           Order = product.Element("order").Value
                       };
        foreach (var item in products)
        {
            Console.WriteLine("Name: {0} Order: {1}", item.Name, item.Order);
        }

Comments

0

You want to use the Single extension method here. Try the following:

var category = doc.RootNode.Elements("category").Single(
    c => c.Attribute("name").Value == "First Category");
var products = category.Elements("product");

Note that this assumes you only have one category with name "First Category". If you possibly have more, I recommend using Marc's solution; otherwise, this should be the more appropiate/efficient solution. Also, this will throw an exception if any category node doesn't have a name child node. Otherwise, it should do exactly what you want.

3 Comments

Now this is baffling me. This answer is fully correct, given the (IMO fair) assumption that the OP is only looking for one category called "First Category"...
I agree it should work (athough the attribute stuff could be simpler, and you run the risk of throwing exceptions if any of the elements/attributes are missing); +1 here... I don't know why, but all the original answers on this question got downvotes.
@Marc: Cheers. And yeah, I should probably add the caveat for null attribute objects, though if Name is guaranteed to exist... I've only downvoted MrTortoise's answer now. (I changed yours to an upvote once I reread the question and your answer properly!)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.