简体   繁体   中英

LINQ to XML Example that Excludes Elements where Descendants Contains Value

I'm new to LINQ to XML and was wondering if anyone could help me construct the following query.

I want to return all the <response> elements that do not contain a descendant <status> element that contains "404".

My XML is shown below. In this case, only the first <response> element (and descendants) should be returned.

<multistatus xmlns="DAV:">
  <response>
    <href>/principals/users/test/</href>
    <propstat>
      <prop>
        <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav">
          <href xmlns="DAV:">/calendars/__uids__/d817aaec-7d24-5b38-bc2f-6369da72cdd9</href>
        </calendar-home-set>
      </prop>
      <status>HTTP/1.1 200 OK</status>
    </propstat>
  </response>
  <response>
    <href>/principals/users/test/calendar-proxy-write/</href>
    <propstat>
      <prop>
        <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav" />
      </prop>
      <status>HTTP/1.1 404 Not Found</status>
    </propstat>
  </response>
  <response>
    <href>/principals/users/test/calendar-proxy-read/</href>
    <propstat>
      <prop>
        <calendar-home-set xmlns="urn:ietf:params:xml:ns:caldav" />
      </prop>
      <status>HTTP/1.1 404 Not Found</status>
    </propstat>
  </response>
</multistatus>

Assuming that your XML is stored in the string variable xml :

XDocument document = XDocument.Parse(xml);
XNamespace ns = document.Root.GetDefaultNamespace();

var responsesExcept404s = document
    .Descendants(ns + "response")
    .Where(x => !x.Descendants(ns + "status")
                  .Single()
                  .Value.Contains("404"));

Notice the usage of ns variable - since your XML has default namespace set via xmlns attribute, it is necessary to specify that namespace when using LINQ to XML (such as in Descendants() method).

Then you can simply iterate over results and, to make this super-useful, output them to the console:

responsesExcept404s.ToList().ForEach(Console.WriteLine);
XDocument xDoc = XDocument.Parse(xml);
XNamespace ns = XNamespace.Get("DAV:");
var responses = xDoc.Descendants(ns + "status")
                    .Where(s => !s.Value.Contains(" 404 "))
                    .Select(s => s.Parent.Parent);

Here ya go: (cheating with XPath)

        XDocument xdoc = XDocument.Load(new FileStream("XMLFile2.xml", FileMode.Open, FileAccess.Read));
        XPathNavigator nav = xdoc.CreateNavigator();
        var nsm = new XmlNamespaceManager(nav.NameTable);            
        nsm.AddNamespace("s", "DAV:");
        var nodes = xdoc.XPathSelectElements("s:multistatus/s:response[.//*[name(.)='status' and .='HTTP/1.1 404 Not Found']]", nsm);

Try this:

Document doc = XDocument.Load(path);
       XNamespace nsd = doc.Root.GetDefaultNamespace();
        var res = doc.Descendants(nsd +"response");                

        var filteredEle = new List<XElement>();

                    foreach (var ele in res)
                    {
                        if (CheckEle(ele,nsd))
                        {
                            filteredEle.Add(ele);
                        }
                    }    


    private bool CheckEle(XElement ele, XNamespace nsd)
        {
            return ele.Element(nsd + "propstat").Element(nsd + "status").Value != "HTTP/1.1 404 Not Found";
        }

You can get use the linq statement as shown below

XDocument doc = XDocument.Parse(xml);
List<XElement> responseWithOut404 = 
    (from element in doc.Descendants("response")
     let xElement = element.Descendants("status").First() 
     where !xElement.Value.Contains("404")
     select element)
     .ToList();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM