6

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);
 }

3 Answers 3

12

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);
    }
}
Sign up to request clarification or add additional context in comments.

5 Comments

Hi Jon! I used your code but my urlList still empty! :( (i parse xml from a string).
@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...
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);
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).
@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.
3
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"));

2 Comments

That will return an IEnumerable<IEnumerable<XElement>> which I don't think is what was wanted...
The way that Descendants() works, there's no need to use SelectMany - there's an overload which starts with an IEnumerable<XElement>.
1

Try this:

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

foreach (string loc in query)
{
    urlList.Add(loc);
}

Comments

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.