Select nodes Linq to Xml C#

31,092

Solution 1

I suspect the problem is that you're going from document.Elements("url") instead of document.Root.Elements("url")... so it's looking for a root element of url, which doesn't exist.

Try this:

List<string> urlList = doc.Root.Elements("url")
                               .Elements("loc")
                               .Select(x => (string) x)
                               .ToList();

Note that I haven't used Descendants here, as the loc elements are all directly beneath url elements anyway.

Another alternative you could use if the only loc elements are the right ones anyway, is just:

List<string> urlList = doc.Descendants("loc")
                          .Select(x => (string) x)
                          .ToList();

(I'm assuming urlList was empty beforehand... for this sort of situation I like to use LINQ for the whole operation and eliminate foreach loops that are just adding to a collection.)

EDIT: The code works for me. Here's a short but complete program:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;

class Test
{
    static void Main(string[] args)
    {
        string xml = @"<?xml version=""1.0"" encoding=""UTF-8""?>
    <urlset>    
        <url>
            <loc>element1</loc>
            <changefreq>daily</changefreq>
            <priority>0.2</priority>
        </url>
        <url>
            <loc>element2</loc>
            <changefreq>daily</changefreq>
            <priority>0.2</priority>
        </url>
    </urlset>";

        XDocument doc = XDocument.Parse(xml);
        List<string> urlList = doc.Root
                                  .Elements("url")
                                  .Elements("loc")
                                  .Select(x => (string) x)
                                  .ToList();
        Console.WriteLine(urlList.Count);
    }
}

Solution 2

var xDoc = XDocument.Parse(
    @"<urlset>    
        <url>
            <loc>element1</loc>
            <changefreq>daily</changefreq>
            <priority>0.2</priority>
        </url>
        <url>
            <loc>element2</loc>
            <changefreq>daily</changefreq>
            <priority>0.2</priority>
        </url>
    </urlset>");
var locElements = xDoc.Descendants("url").SelectMany(el => el.Descendants("loc"));

Solution 3

Try this:

var query = for x in xDoc.Descendants("url")
            select (string)x.Element("loc");

foreach (string loc in query)
{
    urlList.Add(loc);
}
Share:
31,092
Chelsea_cole
Author by

Chelsea_cole

truyen tien hiep

Updated on August 07, 2020

Comments

  • Chelsea_cole
    Chelsea_cole over 3 years

    XML file format:

    <?xml version="1.0" encoding="UTF-8"?>
        <urlset>    
            <url>
                <loc>element1</loc>
                <changefreq>daily</changefreq>
                <priority>0.2</priority>
            </url>
            <url>
                <loc>element2</loc>
                <changefreq>daily</changefreq>
                <priority>0.2</priority>
            </url>
        <urlset>
    

    I want to select all "loc" nodes (element1, element2), but this not work!!!

     foreach (XElement item in document.Elements("url").Descendants("loc")) // Change into what?
     {
          urlList.Add(item.Value);
     }
    
  • Jon Skeet
    Jon Skeet over 12 years
    That will return an IEnumerable<IEnumerable<XElement>> which I don't think is what was wanted...
  • Chelsea_cole
    Chelsea_cole over 12 years
    Hi Jon! I used your code but my urlList still empty! :( (i parse xml from a string).
  • Jon Skeet
    Jon Skeet over 12 years
    @Chelsea_cole: Works for me - I've posted a complete program showing it working. Note that I had to fix up your original XML, from <urlset> at the end to </urlset>. Please try my code, and then see what the difference is between that and what you were trying...
  • Chelsea_cole
    Chelsea_cole over 12 years
    Your code really work! But still not for me :( Maybe it's because my streamreader string?) StreamReader streamReader = new StreamReader(@"D:\data.xml"); string text = streamReader.ReadToEnd(); streamReader.Close(); XDocument doc = XDocument.Parse(text);
  • Jon Skeet
    Jon Skeet over 12 years
    It's more likely to be because your XML isn't the same as what you've posted. But it's not a great idea to parse XML like that anyway: it's assuming UTF-8, whereas XDocument can do the right thing for multiple encodings; you should use a using statement instead of closing explicitly; to read the whole of a file you can use File.ReadAllText; you can do all of this in one call anyway with XDocument.Load(string).
  • Jon Skeet
    Jon Skeet over 12 years
    The way that Descendants() works, there's no need to use SelectMany - there's an overload which starts with an IEnumerable<XElement>.
  • Jon Skeet
    Jon Skeet over 12 years
    @CJohnson: I suggest you ask a new question with a short but complete example of what you're trying to do then. It's impossible to tell what's wrong just from your comment.