views:

108

answers:

4

I'm building an Parts app in order to learn C# and WPF. I trying having trouble adding new parts using XmlWriter. I can create the xml file, but can not figure how to add additional parts. Should I be using something else like XmlDocument? Here is my code behind:

private void btnSave_Click(object sender, RoutedEventArgs e)
    {

        XmlWriterSettings settings = new XmlWriterSettings();
        settings.Encoding = Encoding.UTF8;
        settings.Indent = true;

        using (XmlWriter writer = XmlWriter.Create("f:\\MyParts.xml", settings))
        {
            writer.WriteStartDocument();
            writer.WriteStartElement("MyParts");
            writer.WriteStartElement("parts");
            writer.WriteStartElement("item");
            writer.WriteString(txtbxitem.Text);
            writer.WriteEndElement();

            writer.WriteStartElement("color");
            writer.WriteString(txtbxcolor.Text);
            writer.WriteEndElement();

            writer.WriteStartElement("size");
            writer.WriteString(txtbxsize.Text);
            writer.WriteEndElement();

            writer.WriteEndElement();
            writer.WriteEndDocument();

            writer.Flush();
            writer.Close();

        }
    }

This code creates the xml file and a node correctly, but how do I add additional parts? Here is what I am trying to create:

 <?xml version="1.0" encoding="ISO-8859-1" ?> 

<MyParts>
  <parts>
    <item>Part1</item>
    <color>Red</color>
    <size>SM</size>
  </parts>
  <parts>
    <item>Part2</item>
    <color>Blue</color>
    <size>XXL</size>
  </parts>
</MyParts>
+5  A: 

Personally I'd suggest using LINQ to XML. It's a much easier API to use than XmlDocument.

But yes, if you want to modify an existing document then typically using an in-memory representation is simpler than using a streaming API. It's possible to do the latter of course, but it's not easy.

Here's an example to create the same XML as you've already got (other than the declaration: any reason you'd want to use Latin-1 instead of something like UTF-8 which can represent the whole of Unicode, btw?)

var doc = new XDocument(
  new XElement("MyParts",
    new XElement("parts",
      new XElement("item", "Part1"),
      new XElement("color", "Red"),
      new XElement("size", "SM")),
    new XElement("parts",
      new XElement("item", "Part2"),
      new XElement("color", "Blue"),
      new XElement("size", "XXL"))));

Then if you wanted to add another part:

doc.Root.Add(
  new XElement("parts",
    new XElement("item", "Part3"),
    new XElement("color", "Green"),
    new XElement("size", "L")));

Admittedly I'd expect you'd want to encapsulate the "create a parts element" bit into a method to avoid repeating it all the time... but hopefully you get the picture.

Jon Skeet
Would you say LINQ to XML is the best way to go for creating and editing xml files using c#? I want to spend my learning time wisely.
Lone Starr
@Lone: Assuming you can use .NET 3.5 or higher, it's the best solution for *most* problems. If you're dealing with a huge file, `XmlReader` may be useful, but I would at least *start* with LINQ to XML.
Jon Skeet
I agree with @Jon: easier is better! Here I'm dealing with a simple Xml document and XDocument is pretty good and easy to construct my content (what you see is what you get)
Junior Mayhé
A: 

Use a loop, and you'll end up with something like:

    var parts = new List<Part>() { ...... parts here ...... };        

    using (XmlWriter writer = XmlWriter.Create("f:\\MyParts.xml", settings))
    {
        writer.WriteStartDocument();
        writer.WriteStartElement("MyParts");

        foreach(var part in parts)
        {
            writer.WriteStartElement("parts");
            writer.WriteStartElement("item");
            writer.WriteString(part.Item);
            writer.WriteEndElement(); // </item>

            writer.WriteStartElement("color");
            writer.WriteString(part.Color);
            writer.WriteEndElement();

            writer.WriteStartElement("size");
            writer.WriteString(part.Size);
            writer.WriteEndElement(); // </size>

            writer.WriteEndElement(); // </parts>
        }
        writer.WriteEndElement(); // </MyParts>
        writer.WriteEndDocument();

        writer.Flush();
        writer.Close();

    }

The general idea is that, for each part in your list of parts, you write the "parts" (should be "part"?) tag and all of its contents, filling item, color and size with data from a Part class, which in its simplest form might be:

class Part
{
    public string Item { get; set; }
    public Color Color { get; set; }
    public string Size { get; set; }
}
Martin Törnwall
I'm getting errors, but will keep trying.
Lone Starr
What errors, specifically?
Martin Törnwall
A: 

The code above does exactly what it looks like: writes an element "MyParts" and then writes a child element "parts" and then a child element "item" with a value of whatever is in your text box.

This smells suspiciously like homework, and is readily Google-able, so I'm only going to give a quick pseudo-answer.

You (may) want to:

  1. Create appropriate class(es) for parts that have the members you want
  2. Create a collection of those items
  3. Update that in-memory collection from your UI
  4. Save the collection using the XML formatting and functionality of your choice (including but not limited to what you are doing above, or LINQ to XML, or XML Serialization, or...)
Wonko the Sane
I thought editing a xml file was going to be easy. I've googled for days now, which probably best describes my skill level. I didn't even know where to start, but finally got to xmlwriter which worked (as you know) but then I was pointed at XmlDocument. All I tried always overwrites but doesn't append. I did see LINQ to XML during my search, so know I'm going to search that. I'll also check out XML Serialization.
Lone Starr
A: 

Have you considered using the out of the box XML Serialization that comes with .NET? You just populate your objects within some collection and then use the XML Serializer to persist to a file. You can then use the DeSerializer to hydrate your objects.

This would allow your to spend more time on your application's UI (WPF), and logic. All you need to do is all the Serializable attribute to your class.

Here's a good example: http://www.jonasjohn.de/snippets/csharp/xmlserializer-example.htm

The biggest benefit is that as you build your data object over time, the serialization/de-serialization will grow with it.

Babak Naffas