451
votes

How can I generate valid XML in C#?

9

9 Answers

519
votes

It depends on the scenario. XmlSerializer is certainly one way and has the advantage of mapping directly to an object model. In .NET 3.5, XDocument, etc. are also very friendly. If the size is very large, then XmlWriter is your friend.

For an XDocument example:

Console.WriteLine(
    new XElement("Foo",
        new XAttribute("Bar", "some & value"),
        new XElement("Nested", "data")));

Or the same with XmlDocument:

XmlDocument doc = new XmlDocument();
XmlElement el = (XmlElement)doc.AppendChild(doc.CreateElement("Foo"));
el.SetAttribute("Bar", "some & value");
el.AppendChild(doc.CreateElement("Nested")).InnerText = "data";
Console.WriteLine(doc.OuterXml);

If you are writing a large stream of data, then any of the DOM approaches (such as XmlDocument/XDocument, etc.) will quickly take a lot of memory. So if you are writing a 100 MB XML file from CSV, you might consider XmlWriter; this is more primitive (a write-once firehose), but very efficient (imagine a big loop here):

XmlWriter writer = XmlWriter.Create(Console.Out);
writer.WriteStartElement("Foo");
writer.WriteAttributeString("Bar", "Some & value");
writer.WriteElementString("Nested", "data");
writer.WriteEndElement();

Finally, via XmlSerializer:

[Serializable]
public class Foo
{
    [XmlAttribute]
    public string Bar { get; set; }
    public string Nested { get; set; }
}
...
Foo foo = new Foo
{
    Bar = "some & value",
    Nested = "data"
};
new XmlSerializer(typeof(Foo)).Serialize(Console.Out, foo);

This is a nice model for mapping to classes, etc.; however, it might be overkill if you are doing something simple (or if the desired XML doesn't really have a direct correlation to the object model). Another issue with XmlSerializer is that it doesn't like to serialize immutable types : everything must have a public getter and setter (unless you do it all yourself by implementing IXmlSerializable, in which case you haven't gained much by using XmlSerializer).

60
votes

The best thing hands down that I have tried is LINQ to XSD (which is unknown to most developers). You give it an XSD Schema and it generates a perfectly mapped complete strongly-typed object model (based on LINQ to XML) for you in the background, which is really easy to work with - and it updates and validates your object model and XML in real-time. While it's still "Preview", I have not encountered any bugs with it.

If you have an XSD Schema that looks like this:

  <xs:element name="RootElement">
     <xs:complexType>
      <xs:sequence>
        <xs:element name="Element1" type="xs:string" />
        <xs:element name="Element2" type="xs:string" />
      </xs:sequence>
       <xs:attribute name="Attribute1" type="xs:integer" use="optional" />
       <xs:attribute name="Attribute2" type="xs:boolean" use="required" />
     </xs:complexType>
  </xs:element>

Then you can simply build XML like this:

RootElement rootElement = new RootElement;
rootElement.Element1 = "Element1";
rootElement.Element2 = "Element2";
rootElement.Attribute1 = 5;
rootElement.Attribute2 = true;

Or simply load an XML from file like this:

RootElement rootElement = RootElement.Load(filePath);

Or save it like this:

rootElement.Save(string);
rootElement.Save(textWriter);
rootElement.Save(xmlWriter);

rootElement.Untyped also yields the element in form of a XElement (from LINQ to XML).

24
votes
new XElement("Foo",
       from s in nameValuePairList
       select
             new XElement("Bar",
                  new XAttribute("SomeAttr", "SomeAttrValue"),
                          new XElement("Name", s.Name),
                          new XElement("Value", s.Value)
                         )
            );
10
votes

XmlWriter is the fastest way to write good XML. XDocument, XMLDocument and some others works good aswell, but are not optimized for writing XML. If you want to write the XML as fast as possible, you should definitely use XmlWriter.

4
votes

In the past I have created my XML Schema, then used a tool to generate C# classes which will serialize to that schema. The XML Schema Definition Tool is one example

http://msdn.microsoft.com/en-us/library/x6c1kb0s(VS.71).aspx

4
votes

I think this resource should suffice for a moderate XML save/load: Read/Write XML using C#.

My task was to store musical notation. I choose XML, because I guess .NET has matured enough to allow easy solution for the task. I was right :)

This is my song file prototype:

<music judul="Kupu-Kupu yang Lucu" pengarang="Ibu Sud" tempo="120" birama="4/4" nadadasar="1=F" biramapembilang="4" biramapenyebut="4">
    <not angka="1" oktaf="0" naikturun="" nilai="1"/>
    <not angka="2" oktaf="0" naikturun="" nilai="0.5"/>
    <not angka="5" oktaf="1" naikturun="/" nilai="0.25"/>
    <not angka="2" oktaf="0" naikturun="\" nilai="0.125"/>
    <not angka="1" oktaf="0" naikturun="" nilai="0.0625"/>
</music>

That can be solved quite easily:

For Save to File:

 private void saveToolStripMenuItem_Click(object sender, EventArgs e)
 {
     saveFileDialog1.Title = "Save Song File";
     saveFileDialog1.Filter = "Song Files|*.xsong";
     if (saveFileDialog1.ShowDialog() == DialogResult.OK)
     {
         FileStream fs = new FileStream(saveFileDialog1.FileName, FileMode.Create);
         XmlTextWriter w = new XmlTextWriter(fs, Encoding.UTF8);
         w.WriteStartDocument();
         w.WriteStartElement("music");
         w.WriteAttributeString("judul", Program.music.getTitle());
         w.WriteAttributeString("pengarang", Program.music.getAuthor());
         w.WriteAttributeString("tempo", Program.music.getTempo()+"");
         w.WriteAttributeString("birama", Program.music.getBirama());
         w.WriteAttributeString("nadadasar", Program.music.getNadaDasar());
         w.WriteAttributeString("biramapembilang", Program.music.getBiramaPembilang()+"");
         w.WriteAttributeString("biramapenyebut", Program.music.getBiramaPenyebut()+"");

         for (int i = 0; i < listNotasi.Count; i++)
         {
             CNot not = listNotasi[i];
             w.WriteStartElement("not");
             w.WriteAttributeString("angka", not.getNot() + "");
             w.WriteAttributeString("oktaf", not.getOktaf() + "");
             String naikturun="";
             if(not.isTurunSetengah())naikturun="\\";
             else if(not.isNaikSetengah())naikturun="/";
             w.WriteAttributeString("naikturun",naikturun);
             w.WriteAttributeString("nilai", not.getNilaiNot()+"");
             w.WriteEndElement();
         }
         w.WriteEndElement();

         w.Flush();
         fs.Close();
     }

 }

For load file:

openFileDialog1.Title = "Open Song File";
openFileDialog1.Filter = "Song Files|*.xsong";
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
    FileStream fs = new FileStream(openFileDialog1.FileName, FileMode.Open);
    XmlTextReader r = new XmlTextReader(fs);

    while (r.Read())
    {
        if (r.NodeType == XmlNodeType.Element)
        {
            if (r.Name.ToLower().Equals("music"))
            {
                Program.music = new CMusic(r.GetAttribute("judul"),
                    r.GetAttribute("pengarang"),
                    r.GetAttribute("birama"),
                    Convert.ToInt32(r.GetAttribute("tempo")),
                    r.GetAttribute("nadadasar"),
                    Convert.ToInt32(r.GetAttribute("biramapembilang")),
                    Convert.ToInt32(r.GetAttribute("biramapenyebut")));
            }
            else
                if (r.Name.ToLower().Equals("not"))
                {
                    CNot not = new CNot(Convert.ToInt32(r.GetAttribute("angka")), Convert.ToInt32(r.GetAttribute("oktaf")));
                    if (r.GetAttribute("naikturun").Equals("/"))
                    {
                        not.setNaikSetengah();
                    }
                    else if (r.GetAttribute("naikturun").Equals("\\"))
                    {
                        not.setTurunSetengah();
                    }
                    not.setNilaiNot(Convert.ToSingle(r.GetAttribute("nilai")));
                    listNotasi.Add(not);
                }
        }
        else
            if (r.NodeType == XmlNodeType.Text)
            {
                Console.WriteLine("\tVALUE: " + r.Value);
            }
    }
}

}
}
1
votes

For simple things, I just use the XmlDocument/XmlNode/XmlAttribute classes and XmlDocument DOM found in System.XML.

It generates the XML for me, I just need to link a few items together.

However, on larger things, I use XML serialization.

1
votes

For simple cases, I would also suggest looking at XmlOutput a fluent interface for building Xml.

XmlOutput is great for simple Xml creation with readable and maintainable code, while generating valid Xml. The orginal post has some great examples.

-3
votes

As above.

I use stringbuilder.append().

Very straightforward, and you can then do xmldocument.load(strinbuilder object as parameter).

You will probably find yourself using string.concat within the append parameter, but this is a very straightforward approach.