vbali

<%= "addicted to code" %>

XML serialization

A .NET keretrendszer egyik általam rendkívül kedvelt szolgáltatása az XML szerializáció. Mostanában az adatszerkezeteket úgy tervezem meg, hogy előtte egy XML file-ban jelenítem meg az elérni kívánt adatstruktúrát, majd ehhez igazítom az adatokat kezelő osztályt. Egy egyszerű példával élve a Pocket Revelation-ből, ahol az XML állomány formátuma eleve adott:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?xml version="1.0" encoding="utf-8" ?>
<revelationdata version="0.4.7" dataversion="1">

  <entry type="folder">
      <name>Folder</name>
      <description>Description of the folder</description>
      <updated>1153820841</updated>

      <entry type="folder">
          <name>Subfolder</name>
          <description>Description of the subfolder</description>
          <updated>1153904513</updated>

          <entry type="creditcard">
              <name>CreditCard name</name>
              <description>CreditCard description</description>
              <updated>1153820891</updated>
              <field id="creditcard-cardtype">Card type</field>
              <field id="creditcard-cardnumber">Card number</field>
              <field id="creditcard-expirydate">Expirity date</field>
              <field id="creditcard-ccv">CCV number</field>
              <field id="generic-pin">PIN</field>
          </entry>
      </entry>

      <entry type="email">
          <name>Email name</name>
          <description>Email description</description>
          <updated>1153821003</updated>
          <field id="generic-email">Email</field>
          <field id="generic-hostname">hostname</field>
          <field id="generic-username">username</field>
          <field id="generic-password">password</field>
      </entry>

  </entry>
</revelationdata>

Az XML állomány kezeléséhez kapcsolódó C# osztály kódja:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
using System;
using System.Xml;
using System.Xml.Serialization;
using System.Collections;
using System.IO;
using System.Text;

namespace PocketRevelation
{
 [XmlRoot ("revelationdata")]
  public class RevelationData
  {
     [XmlElement ("entry", Type = typeof (Entry))]
      public ArrayList  Entries;
     [XmlAttribute ("version")]
      public string     Version;
     [XmlAttribute ("dataversion")]
      public int        DataVersion;

      public RevelationData ()
      {
          Entries = new ArrayList ();
      }

      public byte[] Serialize ()
      {
          XmlSerializer xmlSerializer = new XmlSerializer (typeof (RevelationData));
          MemoryStream memoryStream = new MemoryStream ();
          xmlSerializer.Serialize (memoryStream, this);
          byte[] serializedXml = memoryStream.GetBuffer ();
          memoryStream.Close ();
          return serializedXml;
      }

      public static RevelationData Deserialize (string xmlFileName)
      {
          byte[] buffer = new byte[1024];
          FileStream fileStream;
          try {
              fileStream = File.OpenRead (xmlFileName);
          }
          catch (Exception e) {
              throw new FileNotFoundException(e.Message);
          }
          MemoryStream memoryStream = new MemoryStream ();
          while (true)
          {
              int cbRead = fileStream.Read (buffer, 0, buffer.Length);
              if (cbRead <= 0)
                  break;
              memoryStream.Write (buffer, 0, cbRead);
          }
          memoryStream.Position = 0;

          XmlSerializer xmlSerializer = new XmlSerializer (typeof (RevelationData));
          RevelationData revelationData = (RevelationData) xmlSerializer.Deserialize (memoryStream);
          memoryStream.Close ();
          fileStream.Close ();
          return revelationData;
      }
  }

  public class Entry
  {
     [XmlIgnoreAttribute]
      private static readonly DateTime MinValue = new DateTime(1970, 1, 1);
 
     [XmlElement ("name")]
      public string        Name;
     [XmlElement ("description")]
      public string        Description;
     [XmlIgnoreAttribute]
      public DateTime       Updated;
     [XmlAttribute ("type")]
      public string        Type;
     [XmlElement ("field", Type = typeof (Field))]
      public ArrayList  Fields;
     [XmlElement ("entry", Type = typeof (Entry))]
      public ArrayList  Childs;
 
     [XmlElement ("updated")]
      public long  UpdatedLong {
          get { return (long)(Updated - MinValue).TotalSeconds; }
          set { Updated = MinValue + new TimeSpan (value * TimeSpan.TicksPerSecond); }
      }

      public Entry()
      {
          Fields = new ArrayList ();
          Childs = new ArrayList ();
      }
  }

  public class Field
  {
         [XmlAttribute ("id")]
      public string        Id;
     [XmlTextAttribute]
      public string        Value;
  }

  public class RevelationDatabase
  {
      private string            _xmlFileName;
      private RevelationData    _revelationData;

      public string filename {
          get { return _xmlFileName; }
          set { _xmlFileName = value; }
      }

      public RevelationData revelationData {
          get { return _revelationData; }
      }

      public RevelationDatabase (string filename)
      {
          _xmlFileName = filename;
          _revelationData = new RevelationData ();
      }

      public void Load ()
      {
          _revelationData = RevelationData.Deserialize (_xmlFileName);
      }
  }
}