Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HiveStatistics/sources/HeuristicLab.Persistence/3.3/Default/Xml/XmlParser.cs @ 12689

Last change on this file since 12689 was 12689, checked in by dglaser, 9 years ago

#2388: Merged trunk into HiveStatistics branch

File size: 10.9 KB
RevLine 
[3742]1#region License Information
2/* HeuristicLab
[12012]3 * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
[3742]4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
[1454]22using System;
23using System.Collections;
[4068]24using System.Collections.Generic;
[1454]25using System.IO;
[4068]26using System.IO.Compression;
27using System.Xml;
[1454]28using HeuristicLab.Persistence.Core;
[4068]29using HeuristicLab.Persistence.Core.Tokens;
[1454]30using HeuristicLab.Persistence.Interfaces;
31
32namespace HeuristicLab.Persistence.Default.Xml {
[12689]33  /// <summary>
34  /// Type of compression used for the Xml stream or file.
35  /// </summary>
36  public enum CompressionType {
37    GZip,
38    Zip
39  }
[1454]40
[3028]41  /// <summary>
42  /// Main entry point of persistence loading from XML. Use the static
43  /// methods to load from a file or stream.
44  /// </summary>
[1454]45  public class XmlParser : IEnumerable<ISerializationToken> {
46
[3293]47    private readonly XmlTextReader reader;
[1454]48    private delegate IEnumerator<ISerializationToken> Handler();
49    private readonly Dictionary<string, Handler> handlers;
50
[3028]51    /// <summary>
52    /// Initializes a new instance of the <see cref="XmlParser"/> class.
53    /// </summary>
54    /// <param name="input">The input.</param>
[1454]55    public XmlParser(TextReader input) {
[3293]56      reader = new XmlTextReader(input);
57      reader.WhitespaceHandling = WhitespaceHandling.All;
58      reader.Normalization = false;
[1454]59      handlers = new Dictionary<string, Handler> {
[1612]60                     {XmlStringConstants.PRIMITIVE, ParsePrimitive},
61                     {XmlStringConstants.COMPOSITE, ParseComposite},
62                     {XmlStringConstants.REFERENCE, ParseReference},
63                     {XmlStringConstants.NULL, ParseNull},
64                     {XmlStringConstants.METAINFO, ParseMetaInfo},
[3005]65                     {XmlStringConstants.TYPE, ParseTypeInfo},
[1454]66                   };
67    }
68
[3028]69    /// <summary>
70    /// Returns an enumerator that iterates through the serialization tokens.
71    /// </summary>
72    /// <returns>
73    /// An that can be used to iterate through the collection of serialization tokens.
74    /// </returns>
[1454]75    public IEnumerator<ISerializationToken> GetEnumerator() {
76      while (reader.Read()) {
77        if (!reader.IsStartElement()) {
78          break;
79        }
80        IEnumerator<ISerializationToken> iterator;
81        try {
82          iterator = handlers[reader.Name].Invoke();
[4068]83        }
84        catch (KeyNotFoundException) {
[1625]85          throw new PersistenceException(String.Format(
86            "Invalid XML tag \"{0}\" in persistence file.",
[1454]87            reader.Name));
88        }
89        while (iterator.MoveNext()) {
90          yield return iterator.Current;
91        }
92      }
93    }
94
[3028]95    /// <summary>
96    /// Returns an enumerator that iterates through the serialization tokens.
97    /// </summary>
98    /// <returns>
99    /// An that can be used to iterate through the collection of serialization tokens.
100    /// </returns>
101    IEnumerator IEnumerable.GetEnumerator() {
102      return GetEnumerator();
103    }
104
[1454]105    private IEnumerator<ISerializationToken> ParsePrimitive() {
106      int? id = null;
107      string idString = reader.GetAttribute("id");
108      if (idString != null)
109        id = int.Parse(idString);
[1616]110      string name = reader.GetAttribute("name");
111      int typeId = int.Parse(reader.GetAttribute("typeId"));
[3005]112      string typeName = reader.GetAttribute("typeName");
113      string serializer = reader.GetAttribute("serializer");
114      if (typeName != null)
115        yield return new TypeToken(typeId, typeName, serializer);
[1616]116      XmlReader inner = reader.ReadSubtree();
117      inner.Read();
118      string xml = inner.ReadInnerXml();
[1703]119      inner.Close();
[1616]120      yield return new PrimitiveToken(name, typeId, id, new XmlString(xml));
[1454]121    }
122
123    private IEnumerator<ISerializationToken> ParseComposite() {
[1566]124      string name = reader.GetAttribute("name");
[1454]125      string idString = reader.GetAttribute("id");
126      int? id = null;
127      if (idString != null)
128        id = int.Parse(idString);
[1564]129      int typeId = int.Parse(reader.GetAttribute("typeId"));
[3005]130      string typeName = reader.GetAttribute("typeName");
131      string serializer = reader.GetAttribute("serializer");
132      if (typeName != null)
133        yield return new TypeToken(typeId, typeName, serializer);
[1454]134      yield return new BeginToken(name, typeId, id);
135      IEnumerator<ISerializationToken> iterator = GetEnumerator();
136      while (iterator.MoveNext())
137        yield return iterator.Current;
138      yield return new EndToken(name, typeId, id);
139    }
140
141    private IEnumerator<ISerializationToken> ParseReference() {
142      yield return new ReferenceToken(
143        reader.GetAttribute("name"),
144        int.Parse(reader.GetAttribute("ref")));
145    }
146
147    private IEnumerator<ISerializationToken> ParseNull() {
148      yield return new NullReferenceToken(reader.GetAttribute("name"));
149    }
150
[1553]151    private IEnumerator<ISerializationToken> ParseMetaInfo() {
152      yield return new MetaInfoBeginToken();
153      IEnumerator<ISerializationToken> iterator = GetEnumerator();
154      while (iterator.MoveNext())
155        yield return iterator.Current;
156      yield return new MetaInfoEndToken();
157    }
158
[3005]159    private IEnumerator<ISerializationToken> ParseTypeInfo() {
160      yield return new TypeToken(
161        int.Parse(reader.GetAttribute("id")),
162        reader.GetAttribute("typeName"),
163        reader.GetAttribute("serializer"));
164    }
165
[3028]166    /// <summary>
167    /// Parses the type cache.
168    /// </summary>
169    /// <param name="reader">The reader.</param>
170    /// <returns>A list of type mapping entries.</returns>
[1454]171    public static List<TypeMapping> ParseTypeCache(TextReader reader) {
[1625]172      try {
173        var typeCache = new List<TypeMapping>();
174        XmlReader xmlReader = XmlReader.Create(reader);
175        while (xmlReader.Read()) {
176          if (xmlReader.Name == XmlStringConstants.TYPE) {
177            typeCache.Add(new TypeMapping(
178              int.Parse(xmlReader.GetAttribute("id")),
179              xmlReader.GetAttribute("typeName"),
180              xmlReader.GetAttribute("serializer")));
181          }
[1454]182        }
[1625]183        return typeCache;
[4068]184      }
185      catch (PersistenceException) {
[1625]186        throw;
[4068]187      }
188      catch (Exception e) {
[1625]189        throw new PersistenceException("Unexpected exception during type cache parsing.", e);
[1454]190      }
191    }
192
[3028]193    /// <summary>
194    /// Deserializes an object from the specified filename.
195    /// </summary>
196    /// <param name="filename">The filename.</param>
197    /// <returns>A fresh object instance</returns>
[1734]198    public static object Deserialize(string filename) {
[3913]199      TimeSpan start = System.Diagnostics.Process.GetCurrentProcess().TotalProcessorTime;
200      try {
[11650]201        using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read)) {
[12584]202          try {
203            using (ZipArchive zip = new ZipArchive(fs)) {
204              return Deserialize(zip);
205            }
[11650]206          }
[12584]207          catch (Exception) {
208            return DeserializeWithGZip(fs);
209          }
[3913]210        }
[4068]211      }
212      finally {
[3913]213        TimeSpan end = System.Diagnostics.Process.GetCurrentProcess().TotalProcessorTime;
214        Tracing.Logger.Info(string.Format(
215          "deserialization of {0} took {1} seconds",
216          filename, (end - start).TotalSeconds));
[2874]217      }
[1734]218    }
219
[3028]220    /// <summary>
221    /// Deserializes the specified filename.
222    /// </summary>
223    /// <typeparam name="T">object type expected from the serialized file</typeparam>
224    /// <param name="filename">The filename.</param>
225    /// <returns>A fresh object of type T</returns>
226    public static T Deserialize<T>(string filename) {
227      return (T)Deserialize(filename);
228    }
229
230    /// <summary>
231    /// Deserializes an object from the specified stream.
232    /// </summary>
233    /// <typeparam name="T">object type expected from the serialized stream</typeparam>
234    /// <param name="stream">The stream.</param>
[12689]235    /// <param name="compressionType">Type of compression, default is GZip.</param>
[3028]236    /// <returns>A fresh object instance.</returns>
[12689]237    public static T Deserialize<T>(Stream stream, CompressionType compressionType = CompressionType.GZip) {
238      return (T)Deserialize(stream, compressionType);
[3028]239    }
240
[12467]241    /// <summary>
242    /// Deserializes an object from the specified stream.
243    /// </summary>
244    /// <param name="stream">The stream.</param>
[12689]245    /// <param name="compressionType">Type of compression, default is GZip.</param>
[12467]246    /// <returns>A fresh object instance.</returns>
[12689]247    public static object Deserialize(Stream stream, CompressionType compressionType = CompressionType.GZip) {
248      if (compressionType == CompressionType.Zip) {
249        ZipArchive zipFile = new ZipArchive(stream);
250        return Deserialize(zipFile);
[12467]251      } else {
[12689]252        try {
253          using (StreamReader reader = new StreamReader(new GZipStream(stream, CompressionMode.Decompress))) {
254            XmlParser parser = new XmlParser(reader);
255            Deserializer deserializer = new Deserializer(new TypeMapping[] { });
256            return deserializer.Deserialize(parser);
257          }
258        }
259        catch (PersistenceException) {
260          throw;
261        }
262        catch (Exception x) {
263          throw new PersistenceException("Unexpected exception during deserialization", x);
264        }
[12467]265      }
266    }
267
[11650]268    private static object Deserialize(ZipArchive zipFile) {
[1779]269      try {
[11650]270        ZipArchiveEntry typecache = zipFile.GetEntry("typecache.xml");
271        if (typecache == null) throw new PersistenceException("file does not contain typecache.xml");
272        Deserializer deSerializer;
273        using (StreamReader sr = new StreamReader(typecache.Open())) {
274          deSerializer = new Deserializer(ParseTypeCache(sr));
275        }
276
277        ZipArchiveEntry data = zipFile.GetEntry("data.xml");
278        if (data == null) throw new PersistenceException("file does not contain data.xml");
279        object result;
280        using (StreamReader sr = new StreamReader(data.Open())) {
281          XmlParser parser = new XmlParser(sr);
282          result = deSerializer.Deserialize(parser);
283        }
284
[1625]285        return result;
[4068]286      }
287      catch (PersistenceException) {
[1625]288        throw;
[4068]289      }
290      catch (Exception e) {
[1625]291        throw new PersistenceException("Unexpected exception during deserialization", e);
292      }
[1454]293    }
[1566]294  }
[1564]295}
Note: See TracBrowser for help on using the repository browser.