457

How can I generate valid XML in C#?

Braiam
  • 1
  • 11
  • 47
  • 78
Dan Esparza
  • 28,047
  • 29
  • 99
  • 127

9 Answers9

524

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).

meJustAndrew
  • 6,011
  • 8
  • 50
  • 76
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • 11
    Don't forget about XStreamingElement, http://msdn.microsoft.com/en-us/library/system.xml.linq.xstreamingelement.aspx. :) – Todd White Nov 12 '08 at 16:12
  • 1
    For XmlWriter example it is important to note that you need to close the writer at the end for it to properly work - writer.Close() is needed after the writer.WriteEndElement(). – Marko Mar 03 '15 at 19:39
  • It's true what @Marko says: It is important to close the writer properly. There is also another way to do that, in stead of calling writer.Close() directly. You can wrap the call to Create() in a using statement like this: using(XmlWriter writer = XmlWriter.Create(Console.Out)) { writer.WriteStartElement("Foo"); etc } There is another (a bit more enhanced) example of XmlWriter here: https://www.dotnetperls.com/xmlwriter – Morten Oct 10 '18 at 11:28
  • @Morten Sure if XmlWriter implements the IDisposable then using statement is the best option. – Marko Oct 11 '18 at 04:01
  • Good old XMLDocument has it all. Straight, simple and clear if you are creating XML document. – FrenkyB May 23 '19 at 01:47
60

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).

Tadhg
  • 193
  • 1
  • 3
  • 20
24
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)
                         )
            );
rem
  • 16,745
  • 37
  • 112
  • 180
Vincent
  • 1
  • 1
  • 2
10

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.

Mikael Söderström
  • 1,008
  • 8
  • 15
  • 7
    That is, if you want the *computer* to write the XML as fast as possible. If you, the developer, want to create XML in the easiest and most natural way, XmlWriter is probably not the solution! – sjy Feb 24 '14 at 08:01
5

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

Bob
  • 97,670
  • 29
  • 122
  • 130
4

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);
            }
    }
}

}
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
swdev
  • 4,997
  • 8
  • 64
  • 106
1

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.

FlySwat
  • 172,459
  • 74
  • 246
  • 311
1

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.

Todd
  • 5,017
  • 1
  • 25
  • 16
-3

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.

GurdeepS
  • 65,107
  • 109
  • 251
  • 387
  • 11
    Except when you forget to encode something properly and write illegal Xml. – Robert Paulson Nov 13 '08 at 21:07
  • 3
    This answer got absolutely slammed, but based upon this question I took a look at one of my own implementations where I build XML. For my particular project I consistently found that building via StringBuilder resulted in processing times 10% faster than using XDocument/XmlWriter. But, I feel comfortable with XML, and that's for my particular project. (For reference, final XML sizes are around 3.4 MB, with over 8000 lines.) – James Skemp Oct 24 '10 at 15:38
  • 2
    I'd be curious to know if you measured the trade off between application performance (are we talking millisecond improvements here?) and application maintenance (do your engineers need to familiarize themselves with the code for an hour before making changes now?) – Dan Esparza Aug 10 '11 at 17:25