workvact
workvact

Reputation: 675

LINQ to XML complex query filtering

I have this code based on Microsoft docs.

https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/how-to-write-queries-with-complex-filtering

string xml =
  "<products>" +
    "<product name=\"p1\">" +
      "<market name=\"m1\">" +
        "<areacode>12345</areacode>" +
        "<areacode>12346</areacode>" +
      "</market>" +
      "<market name=\"m2\">" +
        "<areacode>12345</areacode>" +
        "<areacode>13346</areacode>" +
      "</market>" +
      "<market name=\"m3\">" +
        "<areacode>12346</areacode>" +
        "<areacode>13346</areacode>" +
      "</market>" +
    "</product>" +
    "<product name=\"p2\">" +
      "<market name=\"m1\">" +
        "<areacode>12340</areacode>" +
        "<areacode>12346</areacode>" +
      "</market>" +
      "<market name=\"m2\">" +
        "<areacode>12340</areacode>" +
        "<areacode>13346</areacode>" +
      "</market>" +
      "<market name=\"m3\">" +
        "<areacode>12346</areacode>" +
        "<areacode>13346</areacode>" +
      "</market>" +
    "</product>" +
  "</products>";
XElement prods = XElement.Parse(xml);
IEnumerable<XElement> els =
  from e1 in prods.Elements("product")
  where
    (string)e1.Attribute("name") == "p1" &&
    (
      from e2 in e1.Elements("market")
      where
        (
          from e3 in e2.Elements("areacode")
          where e3.Value == "12345"
          select e3
        ).Any()
      select e2
    ).Any()
  select e1;
foreach (XElement el in els)
  Console.WriteLine(el);

The output is

<product name="p1">
  <market name="m1">
    <areacode>12345</areacode>
    <areacode>12346</areacode>
  </market>
  <market name="m2">
    <areacode>12345</areacode>
    <areacode>13346</areacode>
  </market>
  <market name="m3">
    <areacode>12346</areacode>
    <areacode>13346</areacode>
  </market>
</product>

How can I exclude markets that do not have the specified area code from the output? Product name, market name and area codes are all required for the rest of the code if it matches the condition.

Upvotes: 0

Views: 30

Answers (1)

NetMage
NetMage

Reputation: 26917

There's no easy way to create a new tree that has just what you want, since you can't filter children directly. However, you can modify your tree:

prods.Descendants("market").Where(m => m.Descendants("areacode").All(a => a.Value != "13346")).Remove();
prods.Descendants("product").Where(p => !p.Descendants("market").Any()).Remove();

Upvotes: 1

Related Questions