2

So if I have XML that looks something like this....

<people>
    <person>
        <name>a</name>
    </person>
    <person>
        <name>b</name>
    </person>
</people>

What's the best/easiest way to parse this into a C# array called 'people' where people[0] is the first person object, and then how would it be formatted and how would I go about accessing it?

Thanks!

abatishchev
  • 98,240
  • 88
  • 296
  • 433
stingray-11
  • 448
  • 2
  • 7
  • 25
  • 4
    What did you try already? – wRAR Feb 06 '13 at 22:50
  • A good place to start would be http://msdn.microsoft.com/en-us/library/bb387067.aspx – Jim Mischel Feb 06 '13 at 22:54
  • You can use either XmlReader or Linq to Xml or XmlSerialization - now you can do some reading and come back with specific questions – Pawel Feb 06 '13 at 22:55
  • @JimMischel the example in the article you pointed to is so baaad - especially for beginners. You can do the same without aggregates just by doing this `Console.WriteLine(string.Concat(root.DescendantNodes().OfType()));` - much simpler and probably much faster. – Pawel Feb 06 '13 at 23:02

6 Answers6

4

You could use LINQ-To-Xml to load this file into an array.

To simply handle the object after loading them you could create a class representing a person:

public class Person
{
    public string Name { get; set; }
} 

Then load the file using the XElement.Load-method:

var document = XElement.Load("persons.xml");
var persons = document.Elements("Person")
    .Select(p => new Person{ Name = p.Element("Name").Value }
    .ToArray();
Spontifixus
  • 6,570
  • 9
  • 45
  • 63
  • In all of these answers I'm getting an error that it doesn't contain a definition for the Select method, which is strange... Why? – stingray-11 Feb 07 '13 at 00:07
2

My C# is rusty, but this is simple enough using XML serialization

Deserializing (reading), modifying, then serializing (writing):

using System;
using System.IO;
using System.Xml.Serialization;

namespace ConsoleApplication1
{

    [XmlRoot("people")]
    public class People
    {
        [XmlElement("person")]
        public Person[] person { get; set; }
    }

    [Serializable]
    public class Person
    {
        [XmlElement("name")]
        public string Name { get; set; }
    }

    class Program
    {
        public static void Main(string[] args)
        {
            People people = null;
            XmlSerializer serializer = new XmlSerializer(typeof(People));
            using (StreamReader reader = new StreamReader("people.xml"))
            {
                people = (People)serializer.Deserialize(reader);
            }
            people.person[0].Name = "Dan";
            using (StreamWriter writer = new StreamWriter("people.xml"))
            {
                serializer.Serialize(writer, people);
            }
        }
    }
}
djv
  • 15,168
  • 7
  • 48
  • 72
  • I keep getting this error no matter which solution I use: System.Collections.Generic.IEnumerable' does not contain a definition for 'Select' and no extension method 'Select' accepting a first argument of type 'System.Collections.Generic.IEnumerable' could be found – stingray-11 Feb 07 '13 at 00:13
  • Then you didn't try this one as it doesn't use LINQ – djv Feb 07 '13 at 02:16
  • Not sure but you probably need `using System.Xml.Linq;` – djv Feb 07 '13 at 03:10
1

You can do it easily with LinqToXml:

var doc = XDocument.Parse(myXmlString); // .Load("filepath");
var persons = doc.Root
                 .Elements("Person")
                 .Select(x=> new Person {Name= x.Element("Name").Value})
                 .ToArray();

It will return you an array of Person's defined as below.

Person

public class Person{
     public string Name {get; set;}
}
mipe34
  • 5,596
  • 3
  • 26
  • 38
0

Assuming:

class Person
{
    public string Name { get; set; }
}

Then (query syntax):

var arr = (from p in XDocument.Load(path) // or .Parse(str)
                              .Root
                              .Elements("person")
           select new Person
           {
               Name = (string)p.Attribute("name")
           }).ToArray();

The same in Extension Methods syntax:

XDocument.Load(path)
         .Root
         .Elements("person")
         .Select(p => new new Person
             {
                 Name = (string)p.Attribute("name")
             })
         .ToArray();
abatishchev
  • 98,240
  • 88
  • 296
  • 433
0
var doc = XDocument.Parse(input);
string[] names = doc.Root.Descendants("name").Select(x => x.Value).ToArray();

If the input xml format is as simple as the one you provided the above statement is sufficient, otherwise add this where clause to not capture other name elements in your xml file:

string[] names = doc.Root.Descendants("name")
                        .Where(x => x.Parent.Name == "person")
                        .Select(x => x.Value).ToArray();
Sina Iravanian
  • 16,011
  • 4
  • 34
  • 45
0

One line is enough.

var people=XDocument.Load(path).Root.Elements().Select(y => y.Elements().ToDictionary(x => x.Name, x => x.Value)).ToArray();

You need to specify following namespaces for testing

using System.Xml.Linq;
using System.Collections.Generic;
using System.Collections;
using System.Linq;

test code

var path=@"c:\people.xml";
var people=XDocument.Load(path).Root.Elements().Select(y => y.Elements().ToDictionary(x => x.Name, x => x.Value)).ToArray();

foreach(var person in people) {
    Console.WriteLine("name = {0}", person["name"]);
    Console.WriteLine("name = {0}", person["age"]); // requires person have a age defined in your xml file
}

the sample xml for test

<people>
    <person>
        <name>Humbert Humbert</name>
        <age>36</age>
    </person>

    <person>
        <name>Lolita</name>
        <age>12</age>
    </person>
</people>
Ken Kin
  • 4,503
  • 3
  • 38
  • 76