Reading XML with a Namespace via XElement
-
2 มีนาคม 2553 18:38
I'm working on an application that includes an RSS reader, and came across something I don't know how to handle.
The XML file is formed like so:
<?xml version="1.0" encoding="windows-1251"?> <rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/"> <channel> <title>Feed Title</title> <link>http://feed.net/</link> <language>en</language> <description>A really cool feed</description> <generator>DataLife Engine</generator> <item> <title>Item Title</title> <guid isPermaLink="true">http://feed.net/item.html</guid> <link>http://feed.net/item.html</link> <description><![CDATA[<div align="center">a bunch of HTML in here</div><br /><br />]]></description> <category><![CDATA[Category Name]]></category> <dc:creator>Creator Name</dc:creator> <pubDate>Tue, 02 Mar 2010 17:34:33 +0300</pubDate> </item> </channel> </rss>
The problem I have is this:
When I attempt to read the creator element withNewItem.Creator = thisItem.Element("creator").Value;I get an error, because thisItem.Element("creator") is null. How can I correctly resolve this element? I've tried
NewItem.Creator = thisItem.Element("dc:creator").Value;but that gives me an error saying that ":" is not a valid character in an element name.
I'm guessing I'll have to parse the namespace and prepend it to the element name, but how would I do that?
Thanks!
Gabe
ตอบทั้งหมด
-
2 มีนาคม 2553 18:55
Do you know the namespace when writing the code? Then you can simply do
XNamespace dc = "http://purl.org/dc/elements/1.1/";
in your code and then use e.g.
thisItem.Element(dc + "creator).Value
MVP XML My blog- เสนอเป็นคำตอบโดย Leonid GanelineMVP 9 มีนาคม 2553 1:36
- ทำเครื่องหมายเป็นคำตอบโดย Vitek Karas - MSFTMicrosoft, Moderator 10 มีนาคม 2553 10:40
-
3 มีนาคม 2553 14:43Yes, that will work if I always know the namespace, but I'm concerned that, since this will be reading RSS feeds "in the wild", that I might not always know the namespace beforehand.
-
3 มีนาคม 2553 16:06
Yes, that will work if I always know the namespace, but I'm concerned that, since this will be reading RSS feeds "in the wild", that I might not always know the namespace beforehand.
But how do you identify which element(s) you are interested in? A feed can have any kind of elements in any namespace, which ones are you looking for?
MVP XML My blog- เสนอเป็นคำตอบโดย Vitek Karas - MSFTMicrosoft, Moderator 5 มีนาคม 2553 11:46
- ทำเครื่องหมายเป็นคำตอบโดย Vitek Karas - MSFTMicrosoft, Moderator 10 มีนาคม 2553 10:39
-
9 มีนาคม 2553 2:42ผู้ดูแล
Hello Gabe,
How is the problem at your side? If you need any further assistance, please feel free to let us know.
Have a nice day!
Best Regards,
Lingzhi SunMSDN Subscriber Support in Forum
If you have any feedback on our support, please contact msdnmg@microsoft.com
Please remember to mark the replies as answers if they help and unmark them if they provide no help.
Welcome to the All-In-One Code Framework! If you have any feedback, please tell us. -
28 เมษายน 2555 8:36
Hey guys, I'm struggling on this same issue in a Metro xaml + c# app. The sample documentation for rss works great, except when you're feed included dc:creator instead of authors.
Here's the code I've got so far based on the discussions above.
foreach (SyndicationItem item in feed.Items) { WriterItem WriterItem = new WriterItem(); WriterItem.Title = item.Title.Text; WriterItem.PubDate = item.PublishedDate.DateTime; XNamespace dc = "http://purl.org/dc/elements/1.1/"; WriterItem.Author = item(dc + "creator").ToString; //WriterItem.Author = item.Authors[0].Name.ToString();techAU http://techAU.tv
-
28 เมษายน 2555 10:07
I think you are struggling with a different API, namely the SyndicationFeed/SyndicationItem API. I think the API is complex but poorly documented, I managed to fiddle together a sample nevertheless:
SyndicationFeed feed; using (XmlReader xr = XmlReader.Create("../../XMLFile7.xml")) { feed = SyndicationFeed.Load(xr); } const string dcNs = "http://purl.org/dc/elements/1.1/"; foreach (SyndicationItem item in feed.Items) { List<SyndicationElementExtension> elements = item.ElementExtensions.Where(el => el.OuterNamespace == dcNs && el.OuterName == "creator").ToList(); List<string> creators = new List<string>(elements.Count); foreach (SyndicationElementExtension element in elements) { using (XmlReader xr = element.GetReader()) { XElement xEl = XElement.ReadFrom(xr) as XElement; creators.Add(xEl.Value); } } Console.WriteLine("Item {0} has {1} creators: ", item.Title != null ? item.Title.Text : "", creators.Count); foreach (string creator in creators) { Console.WriteLine("{0}", creator); } Console.WriteLine(); }
There might be easier ways to read out such elements, unfortunately there is not much documentation on those classes.MVP Data Platform Development My blog
-
28 เมษายน 2555 10:23
Here is a simplification of the code, as far as the LINQ part is concerned:
SyndicationFeed feed; using (XmlReader xr = XmlReader.Create("sheet.rss")) { feed = SyndicationFeed.Load(xr); } const string dcNs = "http://purl.org/dc/elements/1.1/"; foreach (SyndicationItem item in feed.Items) { List<string> creators = item .ElementExtensions .Where(el => el.OuterNamespace == dcNs && el.OuterName == "creator") .Select(el => (XElement.ReadFrom(el.GetReader()) as XElement).Value) .ToList(); Console.WriteLine("Item {0} has {1} creators: ", item.Title != null ? item.Title.Text : "", creators.Count); foreach (string creator in creators) { Console.WriteLine("{0}", creator); } Console.WriteLine(); }
MVP Data Platform Development My blog
- เสนอเป็นคำตอบโดย Martin Honnen 28 เมษายน 2555 10:24
-
28 เมษายน 2555 11:48Thanks, but hasn't helped. I agree the SyndicationItems is poorly documented for WinRT xaml c#. Will persist with searching on a solution.
techAU http://techAU.tv
-
28 เมษายน 2555 12:16
The code I posted works with .NET 4.0 but it seems the API is different with WinRT.
I currently have no way here to write/compile/test against WinRT so the following is meant purely as a suggestion based on the MSDN docs:
foreach (SyndicationItem item in feed.Items) { List<string> creators = item .ElementExtensions .Where(el => el.NodeNamespace = "http://purl.org/dc/elements/1.1/" && el.NodeName == "creator") .Select(el => el.NodeValue) .ToList(); Console.WriteLine("Item {0} has {1} creators: ", item.Title != null ? item.Title.Text : "", creators.Count); foreach (string creator in creators) { Console.WriteLine("{0}", creator); } Console.WriteLine(); }
MVP Data Platform Development My blog
-
28 เมษายน 2555 12:42Close, but there's no .where parameter in the ElementExtensions. Appreciate your help.
techAU http://techAU.tv
-
28 เมษายน 2555 13:09
The Where and Select are LINQ query methods, if that is not supported then try a simple foreach loop along the lines of e.g.
foreach (SyndicationItem item in feed.Items) { List<string> creators = new List<string>(); foreach (var el in item.ElementExtensions) { if (el.NodeNamespace == "http://purl.org/dc/elements/1.1/" && el.NodeName == "creator") { creators.Add(el.NodeValue); } } Console.WriteLine("Item {0} has {1} creators: ", item.Title != null ? item.Title.Text : "", creators.Count); foreach (string creator in creators) { Console.WriteLine("{0}", creator); } Console.WriteLine(); }
MVP Data Platform Development My blog
-
28 เมษายน 2555 13:53
That was definitely helpful and my code now doesn't show any errors.. it does compile, but when I seen no author text, I started debugging and seen that after it hit the foreach line the rest was skipped passed. Any ideas? I think we're almost there.
foreach (SyndicationItem item in feed.Items) { FeedItem feedItem = new FeedItem(); feedItem.Title = item.Title.Text; feedItem.PubDate = item.PublishedDate.DateTime; //Get Author from dc:creator field in RSS List<string> creators = new List<string>(); foreach (var el in item.ElementExtensions) { if (el.NodeNamespace == "http://purl.org/dc/elements/1.1/" && el.NodeName == "creator") { creators.Add(el.NodeValue); } } foreach (string creator in creators) { feedItem.Author = creator; }techAU http://techAU.tv
-
28 เมษายน 2555 14:54
Does the feed you want to read in declare the prefix "dc" for the namespace URI "http://purl.org/dc/elements/1.1/" used in the code sample? Or is a different URL declared there?
And what does the debugger show for
item.ElementExtensions
are the any elements contained in that collection? What's it Count property?
MVP Data Platform Development My blog
-
28 เมษายน 2555 21:34
Hey Martin, yes the feed absolutely uses the ns URI is http://purl.org/dc/elements/1.1/
As for the return from item.ElementExtensions, it says the count is 6, but as I said passes right over it.
Happy to provide further info.
techAU http://techAU.tv
-
29 เมษายน 2555 9:54
As for the return from item.ElementExtensions, it says the count is 6, but as I said passes right over it.
Happy to provide further info.
I am not sure what to suggest, if the Count property shows 6 items then I don't understand why a foreach loop does not process them.
Does using an explicit type with e.g.
foreach (ISyndicationNode el in item.ElementExtensions) { ... }
process the items in the collection?
It might be better to ask in a forum for Metro style app development with C#, hopefully other developers there are more successful on helping with the code than I am by trying to read the documentation.
MVP Data Platform Development My blog