C# Adding data to xml file

2019-01-29 03:43发布

问题:

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>

回答1:

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.



回答2:

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


回答3:

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


回答4:

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.