Alexander
Alexander

Reputation: 4219

Deserializing array of XML with attributes C#

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&amp;f=1149</link>
  <link type="api">http://api.npr.org/query?id=485432424&amp;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

Answers (2)

JanDotNet
JanDotNet

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&amp;f=1149</link>
      <link type=""api"">http://api.npr.org/query?id=485432424&amp;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

Lawrence Johnson
Lawrence Johnson

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&amp;f=1149</link>
                <link type=""api"">http://api.npr.org/query?id=485432424&amp;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

Related Questions