Reputation: 4219
I'm using the NPR XML API with C#. I have a story XML object, with three link
nodes, with the only difference being the type
attribute.
<story id="485432424">
<link type="html">http://www.npr.org/2016/07/10/485432424/with-administrative-corruption-in-afghanistan-u-s-troops-presence-won-t-make-any?ft=nprml&f=1149</link>
<link type="api">http://api.npr.org/query?id=485432424&apiKey=MDIxNjY4ODAwMDE0NTAxMjAwODQ4ZTA1Nw000</link>
<link type="short">http://n.pr/29EFodu</link>
I know I could deserialize these links into an array, and call something like story.Links[0]
to get the html
link version, but that seems like poor design. What would be preferable is to have an HTML, API, and Short property directly in my Story
object, so I could access it like this: story.Link.HTML
or story.Link.API
.
Is there any way to achieve this with the Microsoft XML library? I haven't found any decorator that would do something like this, unfortunately.
Upvotes: 1
Views: 70
Reputation: 4016
You could use XDocument:
void Main()
{
var xml = @"<story id=""485432424"">
<link type=""html"">http://www.npr.org/2016/07/10/485432424/with-administrative-corruption-in-afghanistan-u-s-troops-presence-won-t-make-any?ft=nprml&f=1149</link>
<link type=""api"">http://api.npr.org/query?id=485432424&apiKey=MDIxNjY4ODAwMDE0NTAxMjAwODQ4ZTA1Nw000</link>
<link type=""short"">http://n.pr/29EFodu</link>
</story>";
using (var reader = new StringReader(xml))
{
var stories = new List<Story>();
var xDoc = XDocument.Load(reader);
foreach (var storyElement in xDoc.Elements("story"))
{
var story = new Story();
foreach (var linkElement in storyElement.Elements("link"))
{
var value = linkElement.Attribute("type").Value;
if (value == "html")
story.Html = linkElement.Value;
else if (value == "api")
story.Api = linkElement.Value;
else if (value == "short")
story.Short = linkElement.Value;
}
stories.Add(story);
}
// process stories;
}
}
public class Story
{
public string Html { get; set; }
public string Api { get; set; }
public string Short { get; set;}
}
Upvotes: 1
Reputation: 4043
This is kind of an old school way to do it, but I'd do something like the below and just create my own class structure.
class Program
{
static void Main(string[] args)
{
string sXml = @"<story id=""485432424"">
<link type=""html"">http://www.npr.org/2016/07/10/485432424/with-administrative-corruption-in-afghanistan-u-s-troops-presence-won-t-make-any?ft=nprml&f=1149</link>
<link type=""api"">http://api.npr.org/query?id=485432424&apiKey=MDIxNjY4ODAwMDE0NTAxMjAwODQ4ZTA1Nw000</link>
<link type=""short"">http://n.pr/29EFodu</link>
</story>";
System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
doc.LoadXml(sXml);
Story story = new Story(doc.DocumentElement);
Console.Write(story.ToString());
Console.ReadLine();
}
}
class Story
{
public Link Link { get; set; }
public Story(System.Xml.XmlNode nStory)
{
this.Link = new Link();
foreach (System.Xml.XmlNode nLink in nStory.ChildNodes)
{
if (nLink.NodeType == System.Xml.XmlNodeType.Element)
{
this.Link.AddLink(nLink);
}
}
}
public override string ToString()
{
return new StringBuilder().Append(
"Html: ").Append(this.Link.Html).Append(Environment.NewLine).Append(
"Api: ").Append(this.Link.Api).Append(Environment.NewLine).Append(
"Short: ").Append(this.Link.Short).Append(Environment.NewLine).ToString();
}
}
class Link
{
public string Html { get; set; }
public string Api { get; set; }
public string Short { get; set; }
public Link()
{
}
public void AddLink(System.Xml.XmlNode nLink)
{
switch (nLink.Attributes["type"].Value)
{
case "html":
Html = nLink.InnerText;
break;
case "api":
Api = nLink.InnerText;
break;
case "short":
Short = nLink.InnerText;
break;
}
}
}
Upvotes: 1