123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380 |
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Xml.Schema;
- using System.IO;
- using System.Xml;
- namespace Wayne.Lib.IO
- {
- /// <summary>
- /// A class that can be used to convert XML documents that conforms to the FlatFile.xsd into flat text files.
- /// </summary>
- public class FlatFileFormatter
- {
- #region Fields
- XmlSchemaSet schemaSet;
- #endregion
- #region Construction
- /// <summary>
- /// Initializes a new intance of the Flat file formatter.
- /// </summary>
- public FlatFileFormatter()
- {
- schemaSet = new XmlSchemaSet();
- using (var schemaStream = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream("Wayne.Lib.IO.FlatFileFormatter.FlatFile.xsd"))
- {
- XmlSchema schema = XmlSchema.Read(schemaStream, null);
- schemaSet.Add(schema);
- schemaSet.Compile();
- }
- }
- #endregion
- #region Public methods
- /// <summary>
- /// Creates a text file from the specified flat file XML document stream.
- /// </summary>
- /// <param name="flatFileXmlStream">A stream that contains a Flat file XML document.</param>
- /// <param name="fileName">File that should be created by the formatting routine.</param>
- public void Format(Stream flatFileXmlStream, string fileName)
- {
- //Start by validating the input stream, so it is a correct flatfile XML file.
- ValidateFile(flatFileXmlStream);
- HandleXml(flatFileXmlStream, fileName);
- }
- #endregion
- #region Private methods
- private void ValidateFile(Stream flatFileXmlStream)
- {
- long startPosition = flatFileXmlStream.Position;
- XmlReaderSettings validationReaderSettings = new XmlReaderSettings();
- validationReaderSettings.Schemas = schemaSet;
- validationReaderSettings.CloseInput = false;
- //There is a bug in the compact/full framework boundary that makes, that if we set the validation type to Schema, it is actually set to
- //'Auto'. Therefore we need to do this very hack and check if we are running compact framework for real or if we are running a CF assembly
- //in a full-framework environment.
- if (System.Environment.OSVersion.Platform == PlatformID.WinCE)
- validationReaderSettings.ValidationType = ValidationType.Schema;
- else
- validationReaderSettings.ValidationType = (System.Xml.ValidationType)4;
- try
- {
- using (XmlReader validationReader = XmlReader.Create(flatFileXmlStream, validationReaderSettings))
- {
- while (validationReader.Read()) { }
- }
- }
- catch (XmlSchemaException xmlSchemaException)
- {
- throw new FlatFileFormatException("Invalid flat file Xml. Xml schema validation failed.", xmlSchemaException);
- }
- flatFileXmlStream.Position = startPosition;
- }
- private void HandleXml(Stream flatFileXmlStream, string fileName)
- {
- try
- {
- string fieldSeparator = "";
- string recordSeparator = "\r\n";
- using (XmlReader reader = XmlReader.Create(flatFileXmlStream))
- {
- Dictionary<string, string> predefinedFormats = new Dictionary<string, string>();
- using (Stream outputFile = FileSupport.Open(fileName, FileMode.Create, FileAccess.Write, FileShare.Read, 100, 100))
- {
- while (reader.Read())
- {
- switch (reader.NodeType)
- {
- case XmlNodeType.Element:
- {
- if (reader.LocalName == "Section")
- {
- if (reader.MoveToAttribute("fieldSeparator"))
- fieldSeparator = reader.Value;
- if (reader.MoveToAttribute("recordSeparator"))
- recordSeparator = reader.Value;
- reader.MoveToElement();
- }
- else if (reader.LocalName == "FormatDefinitions")
- HandleFormatDefinitions(reader, predefinedFormats);
- else if (reader.LocalName == "Record")
- HandleRecord(reader, predefinedFormats, outputFile, fieldSeparator, recordSeparator);
- break;
- }
- case XmlNodeType.EndElement:
- {
- if (reader.LocalName == "FlatFile")
- return;
- break;
- }
- }
- }
- }
- }
- }
- catch (Exception exception)
- {
- throw new FlatFileFormatException("Exception when formatting flat file.", exception);
- }
- }
- private void HandleFormatDefinitions(XmlReader reader, Dictionary<string, string> predefinedFormats)
- {
- bool moved = false;
- while (true)
- {
- if (!moved)
- if (!reader.Read())
- break;
- moved = false;
- switch (reader.NodeType)
- {
- case XmlNodeType.Element:
- {
- if (reader.LocalName == "Format")
- {
- if (reader.MoveToAttribute("formatId"))
- {
- string formatId;
- formatId = reader.Value;
- reader.MoveToElement();
- string format = reader.ReadElementContentAsString();
- moved = true;
- predefinedFormats.Add(formatId, format);
- }
- }
- break;
- }
- case XmlNodeType.EndElement:
- {
- if (reader.LocalName == "FormatDefinitions")
- return;
- break;
- }
- }
- }
- }
- #region Inner class Field
- private class Field
- {
- #region Fields
- object value;
- string format;
- #endregion
- #region Construction
- public Field(string type, string format, string value)
- {
- this.format = format;
- #region Decode the type & value
- switch (type)
- {
- case "String":
- {
- this.value = value;
- break;
- }
- case "Boolean":
- {
- this.value = XmlConvert.ToBoolean(value);
- break;
- }
- case "Byte":
- {
- this.value = XmlConvert.ToByte(value);
- break;
- }
- case "Int16":
- {
- this.value = XmlConvert.ToInt16(value);
- break;
- }
- case "Int32":
- {
- this.value = XmlConvert.ToInt32(value);
- break;
- }
- case "Int64":
- {
- this.value = XmlConvert.ToInt64(value);
- break;
- }
- case "UInt16":
- {
- this.value = XmlConvert.ToUInt64(value);
- break;
- }
- case "UInt32":
- {
- this.value = XmlConvert.ToUInt32(value);
- break;
- }
- case "UInt64":
- {
- this.value = XmlConvert.ToUInt64(value);
- break;
- }
- case "Decimal":
- {
- this.value = XmlConvert.ToDecimal(value);
- break;
- }
- case "Double":
- {
- this.value = XmlConvert.ToDouble(value);
- break;
- }
- case "DateTime":
- {
- this.value = XmlConvert.ToDateTime(value, XmlDateTimeSerializationMode.Unspecified);
- break;
- }
- }
- #endregion
- }
- #endregion
- #region Properties
- public object Value
- {
- get { return value; }
- }
- public string Format
- {
- get { return format; }
- }
- #endregion
- }
- #endregion
- private void HandleRecord(XmlReader reader, Dictionary<string, string> predefinedFormats, Stream outputFile, string fieldSeparator, string recordSeparator)
- {
- bool endRecordFound = false;
- List<Field> fieldList = new List<Field>();
- bool moved = false;
- while (!endRecordFound)
- {
- if (!moved)
- endRecordFound = !reader.Read();
- moved = false;
- if (!endRecordFound)
- {
- switch (reader.NodeType)
- {
- case XmlNodeType.Element:
- {
- if (reader.LocalName == "Field")
- {
- string type = "String";
- string format = null;
- string definedFormatId = null;
- string value;
- if (reader.MoveToAttribute("type"))
- type = reader.Value;
- if (reader.MoveToAttribute("format"))
- format = reader.Value;
- if (reader.MoveToAttribute("formatId"))
- definedFormatId = reader.Value;
- reader.MoveToContent();
- value = reader.ReadElementContentAsString();
- moved = true;
- //If there was no format defined, try to find a predefined format, if that was specified. Otherwise run with no format.
- if ((format == null) && (definedFormatId != null))
- predefinedFormats.TryGetValue(definedFormatId, out format);
- Field field = new Field(type, format, value);
- fieldList.Add(field);
- }
- break;
- }
- case XmlNodeType.Text:
- {
- }
- break;
- case XmlNodeType.EndElement:
- {
- if (reader.LocalName == "Record")
- endRecordFound = true;
- break;
- }
- }
- }
- }
- //Time to save the data.
- StringBuilder formatStringBuilder = new StringBuilder();
- object[] valueList = new object[fieldList.Count];
- for (int i = 0; i < fieldList.Count; i++)
- {
- valueList[i] = fieldList[i].Value;
- formatStringBuilder.Append("{");
- formatStringBuilder.Append(i.ToString(System.Globalization.CultureInfo.InvariantCulture));
- //Append
- if (fieldList[i].Format != null)
- {
- formatStringBuilder.Append(",");
- formatStringBuilder.Append(fieldList[i].Format);
- }
- formatStringBuilder.Append("}");
- //If this is the last field, we should not insert any field separator.
- if (i != (fieldList.Count - 1))
- formatStringBuilder.Append(fieldSeparator);
- }
- //Insert the record separator.
- formatStringBuilder.Append(recordSeparator);
- string formattedRecord = string.Format(System.Globalization.CultureInfo.InvariantCulture, formatStringBuilder.ToString(), valueList);
- byte[] encodedData = Encoding.Default.GetBytes(formattedRecord);
- outputFile.Write(encodedData, 0, encodedData.Length);
- }
- #endregion
- }
- }
|