Serialisierung – XML (allgemein)

Allgemein

  • im Beispiel wird ein Objekt mit seinen Unterobjekten als XML serialisiert und als Datei ObjektListe.xml gespeichert
  • Wichtig ist immer die Angabe der Standardkonstruktoren in allen Klassen, sonst werden Exceptions geworfen!
  • alle zu speichernden Elemente müssen public sein
  • Falls Objektreferenzen als public-Variablen verwendet werden, dann sollte man darauf achten, dass keine zirkulären Bezüge auftreten! Ggf. sollte man diese Variablen mit [XmlIgnore] überspringen.
  • ArrayList, List<T> (generische Listen) und ReadOnly-Properties werden nicht serialisiert!
  • Wichtig ist außerdem, dass nicht alle Elemente, z.B. Referenz-Variablen vom Typ “object”, als [XmlAttribute(“Name”)] definiert werden können. Die XMLTags müssen dann häufig in [XmlElement(“Name”)] umgeändert werden.

Beispielcode

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

// ein Enumerator, zur Demonstration
public enum ObjektTyp
{
    Viereck, // wird später als "Viereck" gespeichert
    [XmlEnum("D")]
    Dreieck, // wird später als "D" gespeichert
    [XmlEnum("Q")]
    Quadrat // wird später als "Q" gespeichert
}

// Basisobjekt zur Demonstration der Speicherung
// der Basis-Eigenschaften, importiert das abgeleitete
// Objekt "Objekt"
[XmlInclude(typeof(Objekt))]
public class BasisObjekt
{
    // Unterelement string
    [XmlElement("Name")]
    public string sName = "n/a";

    // Standardkonstruktor
    public BasisObjekt()
    {
    }
}

// Listenobjekt was innerhalb von ObjektListe verwaltet wird
// ist von BasisObjekt abgeleitet
public class Objekt : BasisObjekt
{
    // ein Beispiel-Attribut von Objekt
    [XmlAttribute("id")]
    public int iId;

    // private -> wird nicht gespeichert
    private float _a;

    // float-Property, wird erst nach allen lokalen public-Variablen gespeichert,
    // obwohl es von der Reihenfolge her vor _b kommen müsste
    [XmlElement]
    public float a
    {
        get
        {
            return _a;
        }

        set
        {
            _a = value;
        }
    }

    // float-Unterelement
    [XmlElement("b")]
    public float _b;

    // Enumerator-Unterelement
    [XmlElement("Typ")]
    public ObjektTyp otTyp;

    // ein ParameterArray mit 3 int-Parametern definieren
    [XmlArray("ParameterListe")]
    [XmlArrayItem("Parameter")]
    public int[] Params = new int[3];

    // Standardkonstruktor mit Aufruf des Konstruktors der Basisklasse
    public Objekt()
        : base()
    {
    }

    public Objekt(float fa, float fb, int iObjektId, ObjektTyp Typ)
    {
        _a = fa;
        _b = fb;
        iId = iObjektId;
        otTyp = Typ;
    }

    // kleine Ausgabefunktion zur Kontrolle der Objektvariablen nach dem Lesen
    public void Print()
    {
        Console.WriteLine(sName + "[" + otTyp.ToString() + "]");
        Console.WriteLine("ID: {0}", iId);
        for (int i = 0; i < 3; i++)
        {
            Console.WriteLine("Parameter {0}: {1}", i, Params[i]);
        }
        Console.WriteLine("{0} x {1} = {2}", _a, _b, _a * _b);
    }
}

// Rootobjekt [XmlRoot], das geladen und gespeichert werden soll  
[XmlRoot("Objektliste")]
public class ObjektListe
{
    // ein String
    [XmlElement("Name")]
    public string _sListenName;

    // dieses Element wird bei der Serialisierung ignoriert
    [XmlIgnore]
    public int _iID;

    // ein dynamisches List-Array mit Objekten definieren
    [XmlArray("Objekte")]
    [XmlArrayItem("Objekt")]
    public List<Objekt> Objekte = new List<Objekt>();

    // Standardkonstruktor
    public ObjektListe()
    {
    }

    public ObjektListe(string sListenName, int iID)
    {
        _sListenName = sListenName;
        _iID = iID;
    }
}

// Objekt serialisiert speichern 
private void btnSave_Click(object sender, EventArgs e)
{
    // Root-Objekt erstellen
    ObjektListe ol = new ObjektListe("Flächen", 1);

    // drei Listenelemente hinzufügen
    ol.Objekte.Add(new Objekt(1.2f, 3.4f, 1, ObjektTyp.Dreieck));
    ol.Objekte.Add(new Objekt(2.5f, 5.6f, 2, ObjektTyp.Viereck));
    ol.Objekte.Add(new Objekt(4.7f, 8.1f, 3, ObjektTyp.Quadrat));

    // Namen und Parameter des Listenelemente definieren
    ol.Objekte[0].sName = "Fläche 1";
    ol.Objekte[0].Params[0] = 1;
    ol.Objekte[0].Params[1] = 2;
    ol.Objekte[0].Params[2] = 3;

    ol.Objekte[1].sName = "Fläche 2";
    ol.Objekte[1].Params[0] = 4;
    ol.Objekte[1].Params[1] = 5;
    ol.Objekte[1].Params[2] = 6;

    ol.Objekte[2].sName = "Fläche 3";
    ol.Objekte[2].Params[0] = 7;
    ol.Objekte[2].Params[1] = 8;
    ol.Objekte[2].Params[2] = 9;

    // Stream öffnen
    FileStream fs = new FileStream("c:\\ObjektListe.xml", FileMode.Create);

    // Objekte als XML serialisieren
    XmlSerializer xs = new XmlSerializer(typeof(ObjektListe));
    xs.Serialize(fs, ol);

    // Stream schließen
    fs.Flush();
    fs.Close();
}

// Objekt laden und deserialisieren
private void btnLoad_Click(object sender, EventArgs e)
{
    // Stream öffnen 
    FileStream fs = new FileStream("c:\\ObjektListe.xml", FileMode.Open);

    // Objekt deserialisieren
    XmlSerializer xs = new XmlSerializer(typeof(ObjektListe));
    Object o = xs.Deserialize(fs);
    ObjektListe ol = o as ObjektListe;

    // wenn die Deserialisierung funktioniert hat  
    // Testdaten ausgeben (Print())
    if (ol != null)
    {
        for (int i = 0; i < ol.Objekte.Count; i++)
        {
            Objekt obj = ol.Objekte[i];

            if (obj != null)
            {
                obj.Print();
            }
        }
    }

    // Stream schließen
    fs.Close();
}
  • die gespeicherte Ausgabedatei ObjektListe.xml sieht wie folgt aus:
<?xml version="1.0"?>
<Objektliste xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <Name>Flächen</Name>
  <Objekte>
    <Objekt id="1">
      <Name>Fläche 1</Name>
      <b>3.4</b>
      <Typ>D</Typ>
      <ParameterListe>
        <Parameter>1</Parameter>
        <Parameter>2</Parameter>
        <Parameter>3</Parameter>
      </ParameterListe>
      <a>1.2</a>
    </Objekt>
    <Objekt id="2">
      <Name>Fläche 2</Name>
      <b>5.6</b>
      <Typ>Viereck</Typ>
      <ParameterListe>
        <Parameter>4</Parameter>
        <Parameter>5</Parameter>
        <Parameter>6</Parameter>
      </ParameterListe>
      <a>2.5</a>
    </Objekt>
    <Objekt id="3">
      <Name>Fläche 3</Name>
      <b>8.1</b>
      <Typ>Q</Typ>
      <ParameterListe>
        <Parameter>7</Parameter>
        <Parameter>8</Parameter>
        <Parameter>9</Parameter>
      </ParameterListe>
      <a>4.7</a>
    </Objekt>
  </Objekte>
</Objektliste>
  • nach dem Zurücklesen sollte Folgendes auf der Konsole ausgegeben werden:
Fläche 1[Dreieck]
ID: 1
Parameter 0: 1
Parameter 1: 2
Parameter 2: 3
1,2 x 3,4 = 4,08
Fläche 2[Viereck]
ID: 2
Parameter 0: 4
Parameter 1: 5
Parameter 2: 6
2,5 x 5,6 = 14
Fläche 3[Quadrat]
ID: 3
Parameter 0: 7
Parameter 1: 8
Parameter 2: 9
4,7 x 8,1 = 38,07
  • weiterführender Link: Link