Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get the position (index in order) of an XML element using LINQ?

I have XML exactly like this format:

<?xml version="1.0" encoding="utf-8"?>
<book>
    <chapter>
        <verse>This is verse 1</verse>
        <verse>This is verse 2</verse>
        <verse>This is verse 3</verse>
        <verse>This is verse 4</verse>
    </chapter>
    <chapter>
        <verse>This is verse 1</verse>
        <verse>This is verse 2</verse>
    </chapter>
    <chapter>
        <verse>This is verse 1</verse>
    </chapter>
</book>

In C# using Linq, I need to be able to get the XML element of a specific position or index, based on the value of the function state.getChapterNumber(). For example, if the value were 4, I need to grab the 4th chapter element from the XML document.

XDocument book = XDocument.Load(string.Format("Translations/NWT/{0}.xml", state.BookName));
var verses = from chapter in book.Decendants()
             where state.getChapterNumber() == (WHAT DO I PUT HERE TO MATCH THE VALUE??)
             from verse in chapter.Descendants("p").Elements()
             select new
             {
                 VerseNumber = verse.Attribute("n").Value,
                 Text = verse.Value,
                 LastVerseInParagraph = verse.Parent.Elements().LastOrDefault().Value,
                 FirstVerseInParagraph = verse.Parent.Elements().FirstOrDefault().Value
             };

Please help, this is really important and has been holding me back for days. All I want to do is be able to get verses from any chapter set that I choose in the book.

like image 580
Guy Micciche Avatar asked Sep 02 '25 04:09

Guy Micciche


1 Answers

Well to start with, I don't think you wanted the second descendant overall - you wanted the second chapter, which isn't necessarily the same thing. Fortunately it's easy to do:

// Use 1 for the second chapter, 2 for "element 2" (i.e. the third element) etc
var chapter = book.Descendants("chapter").ElementAt(1);

var verses = from verse in chapter...

EDIT: For the verse number, use the overload of Select which provides the element index:

var verses = chapter.Element("verse")
                    .Select((element, index) => new {
                                VerseNumber = index + 1,
                                Text = element.Value
                            });

I don't think it makes much sense for every verse to have the first and last verse in the paragraph, personally. It's not really a feature of that verse, is it?

like image 53
Jon Skeet Avatar answered Sep 04 '25 23:09

Jon Skeet