Listing 1. Pomocnicza klasy wykorzystywana do serializacji.

public class Serializator
{
   public Serializator(){}

   public object DeserializujXML(string xml, Type typ)
   {
      object obj = null;
      MemoryStream ms = new MemoryStream(
         System.Text.Encoding.UTF8.GetBytes(xml));
      XmlSerializer xs = new XmlSerializer(typ);
      obj = xs.Deserialize(ms);
      ms.Close();
      return obj;
   }

   public string SerializujObiekt(object o)
   {
      string wynik = string.Empty;
      XmlSerializer xs = new XmlSerializer(o.GetType());
      XmlSerializerNamespaces ns = 
         new XmlSerializerNamespaces();
      ns.Add(string.Empty, string.Empty);
      MemoryStream ms = new MemoryStream();
      xs.Serialize(ms, o, ns);
      byte[] tab = new byte[ms.Length];
      ms.Position = 0;
      ms.Read(tab, 0, (int)ms.Length);
      wynik = System.Text.Encoding.UTF8.GetString(tab);
      ms.Close();
      return wynik;
   }
}

Listing 2. Przykład dokumentu XMLowego reprezentującego fakturę.

<?xml version="1.0"?>

<faktura numer="938/FG/03/05" data-wystawienia="2004-04-05">
   <sprzedawca>
      <nazwa>Sklepik Komputerowy</nazwa>
      <ulica>Wielkiego Cybernetyka 5</ulica>
      <miasto>Abak</miasto>
      <kod-pocztowy>20-492</kod-pocztowy>
      <NIP>110-943-12-01</NIP>
   </sprzedawca>
   <nabywca>
      <nazwa>Doktor Paj-Chi-Wo</nazwa>
      <ulica>Golarza 3</ulica>
      <miasto>Zabajka</miasto>		
      <kod-pocztowy>12-945</kod-pocztowy>
   </nabywca>
   <towary>
      <towar>
         <nazwa>Koprocesor</nazwa>
         <cena>12.00</cena>
         <ilosc>3</ilosc>
         <stawka-VAT>22</stawka-VAT>
         <wartosc-VAT>2.64</wartosc-VAT>
         <wartosc-netto>36</wartosc-netto>
      </towar>
   </towary>
</faktura>

Listing 3. Klasy wykorzystywane w procesach serializacji oraz deserializacji.

public class Faktura
{
   public string Numer = string.Empty;
   public Adres Nabywca = null;
   public Adres Sprzedawca = null;
   public Towar[] Towary = null;
   public DateTime DataWystawienia;
   public Faktura() {}
   public Faktura(string numer, Adres nabywca, 
      Adres sprzedawca, Towar[] towary)
   {
      Numer = numer;
      Nabywca = nabywca;
      Sprzedawca = sprzedawca;
      Towary = towary;
      DataWystawienia = DateTime.Now;
   }
}
public class Adres 
{
   public string Nazwa;
   public string Ulica;
   public string Miasto;
   public string Kod;
   public string NIP;
   public Adres() {}
   public Adres(string nazwa, string ulica, 
      string miasto, string kod, string NIP)
   {
      Nazwa = nazwa;
      Ulica = ulica;
      Miasto = miasto;
      Kod = kod;
      this.NIP = NIP;
   }
}
public class Towar
{
   public string Nazwa;
   public int Ilosc;
   public float Cena;
   public byte VAT;
   public Towar(){}
   public Towar(string nazwa, int ilosc, float cena, byte VAT) 
   {
      Nazwa = nazwa;
      Ilosc = ilosc;
      Cena = cena;
      this.VAT = VAT;
   }
}

Listing 4. Kod klienta wykonującego serializację.

public class SerializatorKlient
{
   [STAThread]
   public static void Main(string[] args)
   {
      Serializuj();
   }
   private static void Serializuj()
   {
      Faktura f = new Faktura("602/04/BLC/04",
         new Adres("Jan Kowalski", "Malinowa 1/4", "12-234", "Kotoploty", string.Empty),
         new Adres("Blachy sp. z o.o.", "Blacharska 30-45", "Blachownia", "04-234", "990-595-43-05"),
         new Towar[] { new Towar("Blacha miedziana", 3, 45.5f, 22) });

      Console.Out.Write(new Serializator().SerializujObiekt(f));
   }
}

Listing 5. Przykład klasy ze zdefiniowanymi atrybutami kontrolującymi serializację.

[XmlRoot("faktura")]
public class Faktura
{
   private DateTime dataWystawienia;

   [XmlAttribute("numer")]
   public string Numer = string.Empty;

   [XmlElement("sprzedawca")]
   public Adres Sprzedawca = null;

   [XmlElement("nabywca")]
   public Adres Nabywca = null;

   [XmlArray("towary"), XmlArrayItem("towar")]
   public Towar[] Towary = null;

   public Faktura(){}

   public Faktura(string numer, Adres nabywca, Adres sprzedawca, Towar[] towary)
   {
      Numer = numer;
      Nabywca = nabywca;
      Sprzedawca = sprzedawca;
      Towary = towary;
      dataWystawienia = DateTime.Now;
   }

   [XmlAttribute("data-wystawienia")]
   public String DataWystawienia
   {
      get
      {
         return dataWystawienia.ToString("dd-MM-yyyy");
      }

      set
      {
         string[] tokens = value.Split(new char[] {'-'});
         dataWystawienia = new DateTime(
            int.Parse(tokens[0]), 
            int.Parse(tokens[1]), 
            int.Parse(tokens[2]));
      }
   }
}

Listing 6. Kod klienta wykonującego deserializację.

public class DeserializatorKlient
{
   [STAThread]
   public static void Main(string[] args)
   {
      Deserializuj(args[0]);
   }

   private static void Deserializuj(string xmlPath)
   {
      XmlDocument xmlDoc = new XmlDocument();
      xmlDoc.Load(xmlPath);

      Faktura f = (Faktura)new Serializator().DeserializujXML(xmlDoc.OuterXml, typeof(Faktura));

      Console.Out.Write("Deserializacja {0}powiodla sie", f == null ? "nie ": string.Empty);
   }
}

Listing 7. Schemat XSD wykorzystany do automatycznego wygenerowania klas do serializacji.

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

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
   <xs:element name="faktura">
      <xs:complexType>
         <xs:sequence>
            <xs:element name="sprzedawca" type="podmiot-typ" />
            <xs:element name="nabywca" type="podmiot-typ" />
            <xs:element name="towary" type="towary-typ" />
         </xs:sequence>
         <xs:attribute name="numer" type="xs:string" use="required"/>
         <xs:attribute name="data-wystawienia" type="xs:date" use="required"/>
      </xs:complexType>
   </xs:element>
   <xs:complexType name="podmiot-typ">
      <xs:sequence>
         <xs:element name="nazwa" type="xs:string" minOccurs="1" maxOccurs="1"/>
         <xs:element name="ulica" type="xs:string" minOccurs="1" maxOccurs="1"/>
         <xs:element name="miasto" type="xs:string" minOccurs="1" maxOccurs="1"/>
         <xs:element name="kod-pocztowy" type="xs:string" minOccurs="1" maxOccurs="1" />
         <xs:element name="NIP" type="xs:string" minOccurs="0" maxOccurs="1" />
      </xs:sequence>
   </xs:complexType>
   <xs:complexType name="towary-typ">
      <xs:sequence>
         <xs:element name="towar" type="towar-typ" minOccurs="1" maxOccurs="unbounded"/>
      </xs:sequence>
   </xs:complexType>
   <xs:complexType name="towar-typ">
      <xs:sequence>
         <xs:element name="nazwa" type="xs:string" minOccurs="1" maxOccurs="1"/>
         <xs:element name="cena" minOccurs="1" maxOccurs="1">
            <xs:simpleType>
               <xs:restriction base="xs:float">
                  <xs:pattern value="\d*.\d\d" />
               </xs:restriction>
            </xs:simpleType>
         </xs:element>
         <xs:element name="ilosc" type="xs:int" minOccurs="1" maxOccurs="1"/>
         <xs:element name="stawka-VAT" type="xs:int" minOccurs="1" maxOccurs="1"/>
      </xs:sequence>
   </xs:complexType>
</xs:schema>

Listing 8. Przykładowe klasy wygenerowane za pomocą narzędzia xsd.exe.

[System.Xml.Serialization.XmlRootAttribute(Namespace="", IsNullable=false)]
public class faktura 
{
   [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
   public podmiottyp sprzedawca;

   [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
   public podmiottyp nabywca;

   [System.Xml.Serialization.XmlArrayAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
   [System.Xml.Serialization.XmlArrayItemAttribute("towar", 
gbForm=System.Xml.Schema.XmlSchemaForm.Unqualified, IsNullable=false)]
      public towartyp[] towary;

      [System.Xml.Serialization.XmlAttributeAttribute()]
      public string numer;

      [System.Xml.Serialization.XmlAttributeAttribute("data-wystawienia", DataType="date")]
      public System.DateTime datawystawienia;
}

[System.Xml.Serialization.XmlTypeAttribute(TypeName="podmiot-typ")]
public class podmiottyp 
{
   [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
   public string nazwa;

   [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
   public string ulica;

   [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
   public string miasto;

   [System.Xml.Serialization.XmlElementAttribute("kod-pocztowy", 
Form=System.Xml.Schema. XmlSchemaForm.Unqualified)]
      public string kodpocztowy;

   [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
   public string NIP;
}

Listing 9. Przykładowe klasy bazujące na klasach wygenerowanych za pomocą narzędzia xsd.exe.

[XmlRoot("faktura")]
public class Faktura
{
   private faktura fakturaBazowa = new faktura();

   public Faktura(){}

   public Faktura(string numer, Adres nabywca, Adres sprzedawca, Towar[] towary)
   {
      Numer = numer;
      this.nabywca = nabywca;
      this.sprzedawca = sprzedawca;
      this.towary = towary;
      fakturaBazowa.datawystawienia = DateTime.Now;
   }

   [XmlElement("sprzedawca")]
   public Adres sprzedawca;

   [XmlElement("nabywca")]
   public Adres nabywca;

   [XmlArray("towary"), XmlArrayItem("towar")]
   public Towar[] towary;

   [XmlAttribute("numer")]
   public string Numer
   {
      get
      {
         return fakturaBazowa.numer;
      }
      set
      {
         fakturaBazowa.numer = value;
      }
   }

   [XmlAttribute("data-wystawienia")]
   public String DataWystawienia
   {
      get
      {
        return fakturaBazowa.datawystawienia.ToString("dd-MM-yyyy");
      }
      set
      {
         string[] tokens = value.Split(new char[] {'-'});
         fakturaBazowa.datawystawienia = new DateTime(int.Parse(tokens[0]), 
            int.Parse(tokens[1]), 
            int.Parse(tokens[2]));
      }
   }
}

public class Adres : podmiottyp
{
   public Adres() {}
   public Adres(string nazwa, string ulica, string miasto, string kod, string NIP)
   {
      this.nazwa = nazwa;
      this.ulica = ulica;
      this.miasto = miasto;
      kodpocztowy = kod;
      this.NIP = NIP == string.Empty ? null : NIP;
   }
}