I am trying to parse an xml file that contains info and lyrics about songs. Below is a complete sample XML file.
<?xml version='1.0' encoding='utf-8'?> <song xmlns="http://openlyrics.info/namespace/2009/song" version="0.8" createdIn="OpenLP 1.9.9" modifiedIn="OpenLP 1.9.9" modifiedDate="2015-12-02T00:52:19"> <properties> <titles> <title>_Les Test Song</title> <title>alternate title here</title> </titles> <comments> <comment>some comments or notes here</comment> </comments> <copyright>©some statement here</copyright> <verseOrder>i1 v1 c1 b1 p1 e1 o1</verseOrder> <ccliNo>123456789</ccliNo> <authors> <author>Author Unknown</author> </authors> <songbooks> <songbook name="Hymnal" entry="2"/> </songbooks> </properties> <lyrics> <verse name="v1"> <lines>verse one lyrics</lines> </verse> <verse name="c1"> <lines>Chorus 1 lyrics</lines> </verse> <verse name="b1"> <lines>Bridge 1 lyrics</lines> <lines>line 2</lines> <lines>line 0</lines> </verse> <verse name="p1"> <lines>Pre-chorus lyrics</lines> </verse> <verse name="i1"> <lines>intro lyrics</lines> </verse> <verse name="e1"> <lines>Ending lyrics</lines> </verse> <verse name="o1"> <lines>Other lyrics</lines> </verse> </lyrics> </song> Some things to note about the file contents:
- The file uses 1 namespace
- There are 2 main nodes within the primary <song> node named <properties> and <lyrics>
- The first "main" node <properties> contains metadata about the song
- The second "main" node <lyrics> contains a list of verses and their lyrics
- Within each <lyrics> node, there are 1 or more verses tagged as <verse>
- Within each <verse>, there are 1 or more lines to the verse tagged as <lines>
- I need to preserve the relationships of lines to verses to each song
- To restate the basic structure, a song has metadata and 1 or more verses, and a verse has 1 or more lines
My thoughts are to grab the song's metadata (author, title, etc.), then create a List of verses using a foreach loop, and within this loop, create a nested List of lines using another foreach loop.
I am open to using any technique, however, I have spent time trying both XMLDocument class and the XDocument class with Linq.
Here is what I have done so far with the XMLDocument class. My classes:
using System; using System.Collections.Generic; using System.Xml; using System.IO; namespace openlpimport { public class Song { public string title { get; set; } public string author { get; set; } public string copyright { get; set; } public string ccli { get; set; } public string hymnal { get; set; } public string notes { get; set; } public string playorder { get; set; } public List<Verse> verseList { get; set; } public Song() { verseList = new List<Verse>(); } } public class Verse { public string verseName { get; set; } public List<Lyric> lyricList { get; set; } public Verse() { lyricList = new List<Lyric>(); } } public class Lyric { public string verseLyric { get; set; } public Lyric() { verseLyric = "N/A"; } } Here is what I have for code:
public class XMLParser { public static Song ParseByXMLDocument() { var thisSong = new Song(); XmlDocument xmlDoc = new XmlDocument(); xmlDoc.Load(@"C:\\Users\Les\Documents\XML2TXT\_Les Test Song (Author Unknown).xml"); XmlNamespaceManager nsMgr = new XmlNamespaceManager(xmlDoc.NameTable); nsMgr.AddNamespace("ns", "http://openlyrics.info/namespace/2009/song"); XmlNode SongTitleNode = xmlDoc.SelectSingleNode("//ns:title", nsMgr); thisSong.title = SongTitleNode.InnerText; XmlNode SongAuthorNode = xmlDoc.SelectSingleNode("//ns:author", nsMgr); thisSong.author = SongAuthorNode.InnerText; XmlNode SongCopyrightNode = xmlDoc.SelectSingleNode("//ns:copyright", nsMgr); thisSong.copyright = SongCopyrightNode.InnerText; XmlNode SongCCLINode = xmlDoc.SelectSingleNode("//ns:ccliNo", nsMgr); thisSong.ccli = SongCCLINode.InnerText; XmlNode SongHymnalNode = xmlDoc.SelectSingleNode("//ns:songbook", nsMgr); thisSong.hymnal = SongHymnalNode.Attributes.GetNamedItem("entry").Value; XmlNode SongNotesNode = xmlDoc.SelectSingleNode("//ns:comment", nsMgr); thisSong.notes = SongNotesNode.InnerText; // Define nodes to loop through Song Verses XmlNodeList VerseListNode = xmlDoc.SelectNodes("//ns:verse", nsMgr); foreach (XmlNode node in VerseListNode) { var thisVerse = new Verse(); thisVerse.verseName = node.Attributes.GetNamedItem("name").Value; // Define nodes to loop through Song Verses XmlNodeList LineListNode = xmlDoc.SelectNodes("//ns:lines", nsMgr); foreach (XmlNode node2 in LineListNode) { var thisLyric = new Lyric(); thisLyric.verseLyric = node2.InnerText; thisVerse.lyricList.Add(thisLyric); } thisSong.verseList.Add(thisVerse); } return thisSong; } } The 2 PROBLEMS I have run into are this:
1) Using SelectSingleNode, the result returns only the first Course found in the file as the only Course for each Student.
Sample Result:
_Les Test Song
Author Unknown
@some statement here
123456789
2
some comments or notes here
v1
verse one lyrics
c1
verse one lyrics
b1
verse one lyrics
p1
verse one lyrics
i1
verse one lyrics
e1
verse one lyrics
o1
verse one lyrics
2) Alternatively, using SelectNodes, the result returns all of the Courses found in the file for every Student.
Sample Result:
_Les Test Song
Author Unknown
@some statement here
123456789
2
some comments or notes here
v1
verse one lyrics
chorus one lyrics
Bridge one lyrics
line 2
line 0rics
intro one lyrics
Ending one lyrics
Other one lyrics
c1
verse one lyrics
chorus one lyrics
Bridge one lyrics
line 2
line 0rics
intro one lyrics
Ending one lyrics
Other one lyrics
b1
verse one lyrics
chorus one lyrics
Bridge one lyrics
line 2
line 0rics
intro one lyrics
Ending one lyrics
Other one lyrics
p1
verse one lyrics
chorus one lyrics
Bridge one lyrics
line 2
line 0rics
intro one lyrics
Ending one lyrics
Other one lyrics
i1
verse one lyrics
chorus one lyrics
Bridge one lyrics
line 2
line 0rics
intro one lyrics
Ending one lyrics
Other one lyrics
e1
verse one lyrics
chorus one lyrics
Bridge one lyrics
line 2
line 0rics
intro one lyrics
Ending one lyrics
Other one lyrics
o1
verse one lyrics
chorus one lyrics
Bridge one lyrics
line 2
line 0rics
intro one lyrics
Ending one lyrics
Other one lyrics
Any guidance in how to get the grouping that mirrors the sample XML song file is most appreciated. Any c-sharp technique will do. Thank you in advance for reading through this rather verbose problem presentation.
No comments:
Post a Comment