Exemple #1
0
        /// <summary>
        /// The method evaluates whether give name equals to the header name set
        /// in the descriptor.
        /// </summary>
        /// <remarks>
        /// This internal method detects its result by comparing the determined header
        /// name either by using lower and upper cases or by ignoring it.
        /// </remarks>
        /// <param name="header">
        /// The name to be compared.
        /// </param>
        /// <param name="exactly">
        /// If true, then an case-sensitive string comparison is performed.
        /// Otherwise as case-insensitive string comparison is performed.
        /// </param>
        /// <param name="descriptor">
        /// The column descriptor to get header information from.
        /// </param>
        /// <returns>
        /// True, if given name equals the header name within the descriptor,
        /// and false if not.
        /// </returns>
        private static Boolean IsHeaderName(String header, Boolean exactly, ItemDescriptor descriptor)
        {
            String other = CsvImporter <TInstance> .GetHeaderName(descriptor);

            StringComparison flags = exactly ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase;

            return(String.Compare(header, other, flags) == 0);
        }
Exemple #2
0
        /// <summary>
        /// This method tries to load all values from given file using given
        /// settings.
        /// </summary>
        /// <remarks>
        /// The settings parameter describes how the data within given file should be
        /// processed. For example, users may define the expected culture, the expected
        /// file encoding, which separator is used and so on.
        /// </remarks>
        /// <param name="filename">
        /// The fully qualified path of the input file.
        /// </param>
        /// <param name="settings">
        /// The settings to be used to process file data.
        /// </param>
        /// <returns>
        /// A list of classes of  <typeparamref name="TInstance"/>.
        /// </returns>
        /// <exception cref="ArgumentException">
        /// This exception is thrown in case of an invalid file name.
        /// </exception>
        /// <exception cref="FileNotFoundException">
        /// This exception is thrown in case of a file with given name does not
        /// exist.
        /// </exception>
        public static IEnumerable <TInstance> Load(String filename, CsvSettings settings)
        {
            if (String.IsNullOrWhiteSpace(filename))
            {
                throw new ArgumentException("The filename should not be empty.", nameof(filename));
            }

            if (!File.Exists(filename))
            {
                throw new FileNotFoundException($"File {filename} could not be found.");
            }

            using (Stream stream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                return(CsvImporter <TInstance> .Load(stream, settings));
            }
        }
Exemple #3
0
        /// <summary>
        /// This method tries to determine whether given list of cells contain
        /// all and only header names.
        /// </summary>
        /// <remarks>
        /// The order of headers does not matter in this validation because of
        /// it only checks whether all the header names are included. Further,
        /// each name comparison is done by ignoring upper and lower cases.
        /// </remarks>
        /// <param name="headers">
        /// The list of cells to be verified, which should contain header names.
        /// </param>
        /// <param name="descriptors">
        /// The list of descriptors representing a single line.
        /// </param>
        /// <returns>
        /// True is returned when all header names have occurred at least once,
        /// no matter at which position a header name has occurred. Otherwise,
        /// false is returned.
        /// </returns>
        private static Boolean IsHeaderLine(List <String> headers, List <ItemDescriptor> descriptors)
        {
            Int32 verified = 0;

            for (Int32 index = 0; index < headers.Count; index++)
            {
                foreach (ItemDescriptor descriptor in descriptors)
                {
                    if (CsvImporter <TInstance> .IsHeaderName(headers[index], false, descriptor))
                    {
                        verified++;
                        break;
                    }
                }
            }

            return(verified == headers.Count);
        }
Exemple #4
0
        /// <summary>
        /// This method tries to validate given headers by applying exact
        /// validation rules.
        /// </summary>
        /// <remarks>
        /// Exact validation rules means in detail that each string in given headers
        /// must exactly match its corresponding header name. Furthermore, exactly
        /// match means that each header name is compared by applying a case-sensitive
        /// name check. It also means that each header position must be the same
        /// position which is defined within given descriptors.
        /// </remarks>
        /// <param name="headers">
        /// The list of header names to be validated.
        /// </param>
        /// <param name="descriptors">
        /// The list of descriptors representing a single line.
        /// </param>
        /// <exception cref="FormatException">
        /// This exception is thrown as soon as one of the header validation rules
        /// has been violated.
        /// </exception>
        /// <exception cref="ArgumentOutOfRangeException">
        /// This exception might be thrown if accessing the lists fails.
        /// </exception>
        private static void ValidateHeader(List <String> headers, List <ItemDescriptor> descriptors)
        {
            // Keep in mind, the column validation has already checked the column count. And it is trusted
            // in that an Argument Out Of Range Exception is thrown if there was a made mistake beforehand.

            for (Int32 index = 0; index < headers.Count; index++)
            {
                String         header     = headers[index];
                ItemDescriptor descriptor = descriptors[index];

                if (!CsvImporter <TInstance> .IsHeaderName(header, true, descriptor))
                {
                    throw new FormatException(
                              $"Header validation mismatch. Header name \"{header}\" at column {index} does not fit " +
                              $"to the expected header name \"{CsvImporter<TInstance>.GetHeaderName(descriptor)}.\"");
                }
            }
        }
Exemple #5
0
        /// <summary>
        /// This method tries to process given line according to given set of parameters.
        /// </summary>
        /// <remarks>
        /// This method processes given line by splitting it into its pieces and then by
        /// trying to convert each element into its type-safe object expression.
        /// </remarks>
        /// <param name="line">
        /// The line to be processed.
        /// </param>
        /// <param name="separator">
        /// The separator to be used to split given line at.
        /// </param>
        /// <param name="exactly">
        /// An exception of type 'FormatException' is throw if this parameter is 'true' and
        /// converting one of the values has failed. Otherwise, each variable is set to a
        /// default value. Which default value will be used in such a failure case depends
        /// on current data type. For example, strings using &lt;null&gt; as default value,
        /// 'false' is used as default for Boolean types, and the corresponding max-value is
        /// used for all other types.
        /// </param>
        /// <param name="culture">
        /// The culture information to be used for data conversion.
        /// </param>
        /// <param name="mapping">
        /// The value mappings to be used for an extended data interpretation.
        /// </param>
        /// <param name="descriptors">
        /// A list of data type descriptor items that help interpreting data.
        /// </param>
        /// <returns>
        /// An instance of class of type <typeparamref name="TInstance"/>.
        /// </returns>
        /// <exception cref="InvalidOperationException">
        /// This exception is thrown for example if <typeparamref name="TInstance"/> does not
        /// provide a default constructor.
        /// </exception>
        /// <exception cref="FormatException">
        /// This exception is thrown for example if 'exactly' is set to 'true' and one of the
        /// data items could not be converted.
        /// </exception>
        /// <exception cref="NotSupportedException">
        /// This exception is thrown as soon as a class of type <typeparamref name="TInstance"/>
        /// wants to use an unsupported data type.
        /// </exception>
        private static TInstance ProcessLine(String line, Char separator, Boolean exactly, CultureInfo culture, CsvMappings mapping, List <ItemDescriptor> descriptors)
        {
            TInstance result = CsvImporter <TInstance> .Construct(); // throws

            List <String> values = ProcessHelper.SplitIntoCells(line, separator);

            for (Int32 index = 0; index < values.Count; index++)
            {
                // A simple break is possible because of column validation has been done already.
                if (index >= descriptors.Count)
                {
                    break;
                }

                String       value    = values[index];
                PropertyInfo property = descriptors[index].Origin;
                Type         type     = property.PropertyType;

                property.SetValue(result, TypeConverter.IntoObject(value, type, exactly, culture, mapping)); // throws
            }

            return(result);
        }
Exemple #6
0
        /// <summary>
        /// This method tries to load all values from given stream using given
        /// settings.
        /// </summary>
        /// <remarks>
        /// The settings parameter describes how the data within given file should be
        /// processed. For example, users may define the expected culture, the expected
        /// file encoding, which separator is used and so on.
        /// </remarks>
        /// <param name="stream">
        /// The stream to read data from.
        /// </param>
        /// <param name="settings">
        /// The settings to be used to process stream data.
        /// </param>
        /// <returns>
        /// A list of classes of  <typeparamref name="TInstance"/>.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// This exception is thrown either if given stream or if given settings is
        /// invalid.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// This exception is thrown in case of given stream does not have read access.
        /// </exception>
        public static IEnumerable <TInstance> Load(Stream stream, CsvSettings settings)
        {
            List <TInstance> values = new List <TInstance>();

            if (stream == null)
            {
                throw new ArgumentNullException(nameof(stream), $"The stream to read the data from is invalid.");
            }

            if (!stream.CanRead)
            {
                throw new ArgumentException("No read access to given stream.", nameof(stream));
            }

            if (settings == null)
            {
                throw new ArgumentNullException(nameof(settings), "The CSV settings are invalid.");
            }

            TypeDescriptor descriptor = TypeProcessor.LoadDescriptor <TInstance>();

            // NOTE: Keep in mind! All item descriptors are confirmed and ordered already.
            //       This means they are in the right (which means expected) order! Therefore,
            //       something like "search for right column" is absolutely redundant.

            List <ItemDescriptor> items = descriptor.Settings.ToList();
            List <String>         lines = new List <String>();

            using (StreamReader reader = new StreamReader(stream, settings.Encoding))
            {
                while (!reader.EndOfStream)
                {
                    String line = reader.ReadLine();
                    if (!String.IsNullOrWhiteSpace(line))
                    {
                        lines.Add(line);
                    }
                }
            }

            if (lines.Count > 0)
            {
                Char        separator = settings.Separator;
                Boolean     exactly   = settings.Exactly;
                CultureInfo culture   = settings.Culture;
                Boolean     heading   = settings.Heading;
                CsvMappings mapping   = settings.Mappings;

                CsvImporter <TInstance> .ValidateColumns(lines, separator, exactly, items); // throws

                Int32 index = 0;

                List <String> cells = ProcessHelper.SplitIntoCells(lines[index], separator);

                if (CsvImporter <TInstance> .IsHeaderLine(cells, items))
                {
                    // An exact header validation is performed, but only if the first
                    // line represents a header and Heading and Exactly are both enabled.
                    // In such a case a Format Exception is thrown as soon as the header
                    // does not exactly fit! In this conjunction, the validation must pass
                    // the case-sensitive check as well as the position check.

                    if (heading && exactly)
                    {
                        CsvImporter <TInstance> .ValidateHeader(cells, items); // throws
                    }

                    index++;
                }

                for (; index < lines.Count; index++)
                {
                    values.Add(CsvImporter <TInstance> .ProcessLine(lines[index], separator, exactly, culture, mapping, items));
                }
            }

            return(values);
        }
Exemple #7
0
 /// <summary>
 /// This method tries to load all values from given stream.
 /// </summary>
 /// <remarks>
 /// This method performes loading of data with default settings. Using
 /// default settings means that the header is processed, but only if one
 /// exist. Further, The information for header processing is taken from
 /// column attributes or from property names.
 /// </remarks>
 /// <param name="stream">
 /// The stream to read data from.
 /// </param>
 /// <returns>
 /// A list of classes of  <typeparamref name="TInstance"/>.
 /// </returns>
 /// <exception cref="ArgumentNullException">
 /// This exception is thrown in case of given stream is invalid.
 /// </exception>
 /// <exception cref="ArgumentException">
 /// This exception is thrown in case of given stream does not have read access.
 /// </exception>
 public static IEnumerable <TInstance> Load(Stream stream)
 {
     return(CsvImporter <TInstance> .Load(stream, new CsvSettings()));
 }
Exemple #8
0
 /// <summary>
 /// This method tries to load all values from given file.
 /// </summary>
 /// <remarks>
 /// This method performes loading of data with default settings. Using
 /// default settings means that the header is processed, but only if one
 /// exist. Further, the information for header processing is taken from
 /// column attributes or from property names.
 /// </remarks>
 /// <param name="filename">
 /// The fully qualified path of the input file.
 /// </param>
 /// <returns>
 /// A list of classes of <typeparamref name="TInstance"/>.
 /// </returns>
 /// <exception cref="ArgumentException">
 /// This exception is thrown in case of an invalid file name.
 /// </exception>
 /// <exception cref="FileNotFoundException">
 /// This exception is thrown in case of a file with given name does not
 /// exist.
 /// </exception>
 public static IEnumerable <TInstance> Load(String filename)
 {
     return(CsvImporter <TInstance> .Load(filename, new CsvSettings()));
 }