Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Persistence/3.3/Default/Xml/XmlParser.cs @ 3017

Last change on this file since 3017 was 3005, checked in by epitzer, 14 years ago

add support for type information interleaving and subsequently true streaming (#548)

File size: 6.7 KB
Line 
1using System.Xml;
2using System.Collections.Generic;
3using System;
4using System.Collections;
5using System.IO;
6using HeuristicLab.Persistence.Core;
7using HeuristicLab.Persistence.Interfaces;
8using ICSharpCode.SharpZipLib.Zip;
9using HeuristicLab.Persistence.Core.Tokens;
10using System.IO.Compression;
11
12namespace HeuristicLab.Persistence.Default.Xml {
13
14  public class XmlParser : IEnumerable<ISerializationToken> {
15
16    private readonly XmlReader reader;
17    private delegate IEnumerator<ISerializationToken> Handler();
18    private readonly Dictionary<string, Handler> handlers;
19
20    public XmlParser(TextReader input) {
21      XmlReaderSettings settings = new XmlReaderSettings {
22        ConformanceLevel = ConformanceLevel.Document,
23        IgnoreWhitespace = true,
24        IgnoreComments = true
25      };
26      reader = XmlReader.Create(input, settings);
27      handlers = new Dictionary<string, Handler> {
28                     {XmlStringConstants.PRIMITIVE, ParsePrimitive},
29                     {XmlStringConstants.COMPOSITE, ParseComposite},
30                     {XmlStringConstants.REFERENCE, ParseReference},
31                     {XmlStringConstants.NULL, ParseNull},
32                     {XmlStringConstants.METAINFO, ParseMetaInfo},
33                     {XmlStringConstants.TYPE, ParseTypeInfo},
34                   };
35    }
36
37    public IEnumerator<ISerializationToken> GetEnumerator() {
38      while (reader.Read()) {
39        if (!reader.IsStartElement()) {
40          break;
41        }
42        IEnumerator<ISerializationToken> iterator;
43        try {
44          iterator = handlers[reader.Name].Invoke();
45        } catch (KeyNotFoundException) {
46          throw new PersistenceException(String.Format(
47            "Invalid XML tag \"{0}\" in persistence file.",
48            reader.Name));
49        }
50        while (iterator.MoveNext()) {
51          yield return iterator.Current;
52        }
53      }
54    }
55
56    private IEnumerator<ISerializationToken> ParsePrimitive() {
57      int? id = null;
58      string idString = reader.GetAttribute("id");
59      if (idString != null)
60        id = int.Parse(idString);
61      string name = reader.GetAttribute("name");
62      int typeId = int.Parse(reader.GetAttribute("typeId"));
63      string typeName = reader.GetAttribute("typeName");
64      string serializer = reader.GetAttribute("serializer");
65      if (typeName != null)
66        yield return new TypeToken(typeId, typeName, serializer);
67      XmlReader inner = reader.ReadSubtree();
68      inner.Read();
69      string xml = inner.ReadInnerXml();
70      inner.Close();
71      yield return new PrimitiveToken(name, typeId, id, new XmlString(xml));
72    }
73
74    private IEnumerator<ISerializationToken> ParseComposite() {
75      string name = reader.GetAttribute("name");
76      string idString = reader.GetAttribute("id");
77      int? id = null;
78      if (idString != null)
79        id = int.Parse(idString);
80      int typeId = int.Parse(reader.GetAttribute("typeId"));
81      string typeName = reader.GetAttribute("typeName");
82      string serializer = reader.GetAttribute("serializer");
83      if (typeName != null)
84        yield return new TypeToken(typeId, typeName, serializer);
85      yield return new BeginToken(name, typeId, id);
86      IEnumerator<ISerializationToken> iterator = GetEnumerator();
87      while (iterator.MoveNext())
88        yield return iterator.Current;
89      yield return new EndToken(name, typeId, id);
90    }
91
92    private IEnumerator<ISerializationToken> ParseReference() {
93      yield return new ReferenceToken(
94        reader.GetAttribute("name"),
95        int.Parse(reader.GetAttribute("ref")));
96    }
97
98    private IEnumerator<ISerializationToken> ParseNull() {
99      yield return new NullReferenceToken(reader.GetAttribute("name"));
100    }
101
102    private IEnumerator<ISerializationToken> ParseMetaInfo() {
103      yield return new MetaInfoBeginToken();
104      IEnumerator<ISerializationToken> iterator = GetEnumerator();
105      while (iterator.MoveNext())
106        yield return iterator.Current;
107      yield return new MetaInfoEndToken();
108    }
109
110    private IEnumerator<ISerializationToken> ParseTypeInfo() {
111      yield return new TypeToken(
112        int.Parse(reader.GetAttribute("id")),
113        reader.GetAttribute("typeName"),
114        reader.GetAttribute("serializer"));
115    }
116
117    IEnumerator IEnumerable.GetEnumerator() {
118      return GetEnumerator();
119    }
120
121    public static List<TypeMapping> ParseTypeCache(TextReader reader) {
122      try {
123        var typeCache = new List<TypeMapping>();
124        XmlReader xmlReader = XmlReader.Create(reader);
125        while (xmlReader.Read()) {
126          if (xmlReader.Name == XmlStringConstants.TYPE) {
127            typeCache.Add(new TypeMapping(
128              int.Parse(xmlReader.GetAttribute("id")),
129              xmlReader.GetAttribute("typeName"),
130              xmlReader.GetAttribute("serializer")));
131          }
132        }
133        return typeCache;
134      } catch (PersistenceException) {
135        throw;
136      } catch (Exception e) {
137        throw new PersistenceException("Unexpected exception during type cache parsing.", e);
138      }
139    }
140
141    public static object Deserialize(string filename) {
142      using (ZipFile file = new ZipFile(filename)) {
143        return Deserialize(file);
144      }
145    }
146
147    public static object Deserialize(Stream stream) {
148      try {
149        using (StreamReader reader = new StreamReader(new GZipStream(stream, CompressionMode.Decompress))) {
150          XmlParser parser = new XmlParser(reader);
151          Deserializer deserializer = new Deserializer(new TypeMapping[] { });
152          return deserializer.Deserialize(parser);
153        }
154      } catch (PersistenceException) {
155        throw;
156      } catch (Exception x) {
157        throw new PersistenceException("Unexpected exception during deserialization", x);
158      }
159    }
160
161    private static object Deserialize(ZipFile zipFile) {
162      try {
163        ZipEntry typecache = zipFile.GetEntry("typecache.xml");
164        if (typecache == null)
165          throw new PersistenceException("file does not contain typecache.xml");
166        Deserializer deSerializer = new Deserializer(ParseTypeCache(new StreamReader(zipFile.GetInputStream(typecache))));
167        ZipEntry data = zipFile.GetEntry("data.xml");
168        if (data == null)
169          throw new PersistenceException("file does not contain data.xml");
170        XmlParser parser = new XmlParser(
171          new StreamReader(zipFile.GetInputStream(data)));
172        object result = deSerializer.Deserialize(parser);
173        zipFile.Close();
174        return result;
175      } catch (PersistenceException) {
176        throw;
177      } catch (Exception e) {
178        throw new PersistenceException("Unexpected exception during deserialization", e);
179      }
180    }
181  }
182}
Note: See TracBrowser for help on using the repository browser.