Exemple #1
0
        private ChoXmlWriter <T> WithField(string name, string xPath = null, Type fieldType       = null, ChoFieldValueTrimOption fieldValueTrimOption = ChoFieldValueTrimOption.Trim,
                                           bool isXmlAttribute       = false, bool isAnyXmlNode   = false, string fieldName = null, Func <object, object> valueConverter = null, bool isNullable   = false,
                                           object defaultValue       = null, object fallbackValue = null, bool encodeValue  = true, string fullyQualifiedMemberName      = null, string formatText = null)
        {
            if (!name.IsNullOrEmpty())
            {
                if (!_clearFields)
                {
                    ClearFields();
                    Configuration.MapRecordFields(Configuration.RecordType);
                }

                string fnTrim = name.NTrim();
                ChoXmlRecordFieldConfiguration fc = null;
                PropertyDescriptor             pd = null;
                xPath = xPath.IsNullOrWhiteSpace() ? $"//{fnTrim}" : xPath;

                if (Configuration.XmlRecordFieldConfigurations.Any(o => o.Name == fnTrim))
                {
                    fc = Configuration.XmlRecordFieldConfigurations.Where(o => o.Name == fnTrim).First();
                    Configuration.XmlRecordFieldConfigurations.Remove(fc);
                }
                else
                {
                    pd = ChoTypeDescriptor.GetNestedProperty(typeof(T), fullyQualifiedMemberName.IsNullOrWhiteSpace() ? name : fullyQualifiedMemberName);
                }

                var nfc = new ChoXmlRecordFieldConfiguration(fnTrim, xPath)
                {
                    FieldType            = fieldType,
                    FieldValueTrimOption = fieldValueTrimOption,
                    IsXmlAttribute       = isXmlAttribute,
                    FieldName            = fieldName,
                    ValueConverter       = valueConverter,
                    IsNullable           = isNullable,
                    DefaultValue         = defaultValue,
                    FallbackValue        = fallbackValue,
                    EncodeValue          = encodeValue,
                    FormatText           = formatText,
                    IsAnyXmlNode         = isAnyXmlNode
                };

                if (fullyQualifiedMemberName.IsNullOrWhiteSpace())
                {
                    nfc.PropertyDescriptor = fc != null ? fc.PropertyDescriptor : pd;
                    nfc.DeclaringMember    = fc != null ? fc.DeclaringMember : fullyQualifiedMemberName;
                }
                else
                {
                    pd = ChoTypeDescriptor.GetNestedProperty(typeof(T), fullyQualifiedMemberName);
                    nfc.PropertyDescriptor = pd;
                    nfc.DeclaringMember    = fullyQualifiedMemberName;
                }

                Configuration.XmlRecordFieldConfigurations.Add(nfc);
            }

            return(this);
        }
        private string CleanFieldValue(ChoXmlRecordFieldConfiguration config, Type fieldType, string fieldValue, bool?encodeValue)
        {
            if (fieldValue == null)
            {
                return(fieldValue);
            }

            ChoFieldValueTrimOption fieldValueTrimOption = ChoFieldValueTrimOption.Trim;

            if (config.FieldValueTrimOption == null)
            {
                //if (fieldType == typeof(string))
                //    fieldValueTrimOption = ChoFieldValueTrimOption.None;
            }
            else
            {
                fieldValueTrimOption = config.FieldValueTrimOption.Value;
            }

            switch (fieldValueTrimOption)
            {
            case ChoFieldValueTrimOption.Trim:
                fieldValue = fieldValue.Trim();
                break;

            case ChoFieldValueTrimOption.TrimStart:
                fieldValue = fieldValue.TrimStart();
                break;

            case ChoFieldValueTrimOption.TrimEnd:
                fieldValue = fieldValue.TrimEnd();
                break;
            }

            if (config.Size != null)
            {
                if (fieldValue.Length > config.Size.Value)
                {
                    if (!config.Truncate)
                    {
                        throw new ChoParserException("Incorrect field value length found for '{0}' member [Expected: {1}, Actual: {2}].".FormatString(config.FieldName, config.Size.Value, fieldValue.Length));
                    }
                    else
                    {
                        fieldValue = fieldValue.Substring(0, config.Size.Value);
                    }
                }
            }

            if (encodeValue != null && !encodeValue.Value && fieldValue != null)
            {
                return(System.Net.WebUtility.HtmlEncode(fieldValue));
            }

            return(System.Net.WebUtility.HtmlDecode(fieldValue));
        }
Exemple #3
0
        public void Write(DataTable dt)
        {
            ChoGuard.ArgumentNotNull(dt, "DataTable");
            if (Configuration.UseXmlSerialization)
            {
                Write(dt);
                return;
            }

            DataTable schemaTable = dt;
            dynamic   expando     = new ExpandoObject();
            var       expandoDic  = (IDictionary <string, object>)expando;

            string rootName    = dt.DataSet == null || dt.DataSet.DataSetName.IsNullOrWhiteSpace() ? "Root" : dt.DataSet.DataSetName;
            string elementName = dt.TableName.IsNullOrWhiteSpace() ? "XElement" : dt.TableName;

            if (Configuration.XPath.IsNullOrWhiteSpace())
            {
                Configuration.XPath = "{0}/{1}".FormatString(rootName, elementName);
            }

            if (Configuration.XmlRecordFieldConfigurations.IsNullOrEmpty())
            {
                string colName     = null;
                Type   colType     = null;
                int    startIndex  = 0;
                int    fieldLength = 0;
                foreach (DataColumn col in schemaTable.Columns)
                {
                    colName = col.ColumnName;
                    colType = col.DataType;
                    //if (!colType.IsSimple()) continue;

                    var obj = new ChoXmlRecordFieldConfiguration(colName, xPath: null);
                    Configuration.XmlRecordFieldConfigurations.Add(obj);
                    startIndex += fieldLength;
                }
            }

            foreach (DataRow row in dt.Rows)
            {
                expandoDic.Clear();

                foreach (var fc in Configuration.XmlRecordFieldConfigurations)
                {
                    expandoDic.Add(fc.Name, row[fc.Name]);
                }

                Write(expando);
            }
        }
Exemple #4
0
        public ChoXmlReader <T> WithFields(params string[] fieldsNames)
        {
            string fnTrim = null;

            if (!fieldsNames.IsNullOrEmpty())
            {
                PropertyDescriptor             pd = null;
                ChoXmlRecordFieldConfiguration fc = null;
                foreach (string fn in fieldsNames)
                {
                    if (fn.IsNullOrEmpty())
                    {
                        continue;
                    }
                    if (!_clearFields)
                    {
                        ClearFields();
                        Configuration.MapRecordFields(Configuration.RecordType);
                    }

                    fnTrim = fn.NTrim();
                    if (Configuration.XmlRecordFieldConfigurations.Any(o => o.Name == fnTrim))
                    {
                        fc = Configuration.XmlRecordFieldConfigurations.Where(o => o.Name == fnTrim).First();
                        Configuration.XmlRecordFieldConfigurations.Remove(Configuration.XmlRecordFieldConfigurations.Where(o => o.Name == fnTrim).First());
                    }
                    else
                    {
                        pd = ChoTypeDescriptor.GetProperty(typeof(T), fn);
                    }

                    var nfc = new ChoXmlRecordFieldConfiguration(fnTrim, $"/{fnTrim}");
                    nfc.PropertyDescriptor = fc != null ? fc.PropertyDescriptor : pd;
                    nfc.DeclaringMember    = fc != null ? fc.DeclaringMember : null;
                    if (pd != null)
                    {
                        if (nfc.FieldType == null)
                        {
                            nfc.FieldType = pd.PropertyType;
                        }
                    }

                    Configuration.XmlRecordFieldConfigurations.Add(nfc);
                }
            }

            return(this);
        }
Exemple #5
0
        public void Write(IDataReader dr)
        {
            ChoGuard.ArgumentNotNull(dr, "DataReader");
            if (Configuration.UseXmlSerialization)
            {
                Write(dr);
                return;
            }

            DataTable schemaTable = dr.GetSchemaTable();
            dynamic   expando     = new ExpandoObject();
            var       expandoDic  = (IDictionary <string, object>)expando;

            //int ordinal = 0;
            if (Configuration.XmlRecordFieldConfigurations.IsNullOrEmpty())
            {
                string colName     = null;
                Type   colType     = null;
                int    startIndex  = 0;
                int    fieldLength = 0;
                foreach (DataRow row in schemaTable.Rows)
                {
                    colName = row["ColumnName"].CastTo <string>();
                    colType = row["DataType"] as Type;
                    //if (!colType.IsSimple()) continue;

                    var obj = new ChoXmlRecordFieldConfiguration(colName, xPath: null);
                    Configuration.XmlRecordFieldConfigurations.Add(obj);
                    startIndex += fieldLength;
                }
            }

            var ordinals = Configuration.XmlRecordFieldConfigurations.ToDictionary(c => c.Name, c => dr.HasColumn(c.Name) ? dr.GetOrdinal(c.Name) : -1);

            while (dr.Read())
            {
                expandoDic.Clear();

                foreach (var fc in ordinals)
                {
                    expandoDic.Add(fc.Key, fc.Value == -1 ? null : dr[fc.Value]);
                }

                Write(expando);
            }
        }
        private XmlAttributeOverrides GetXmlOverrides(ChoXmlRecordFieldConfiguration fieldConfig, Type fieldType = null)
        {
            if (fieldType == null)
            {
                return(null);
            }

            XmlAttributeOverrides overrides = null;
            var xattribs = new XmlAttributes();
            var xroot    = new XmlRootAttribute(fieldConfig.FieldName);

            xattribs.XmlRoot = xroot;
            overrides        = new XmlAttributeOverrides();
            fieldType        = fieldType == null ? fieldConfig.FieldType : fieldType;
            overrides.Add(fieldType, xattribs);
            return(overrides);
        }
Exemple #7
0
        public void Write(IDataReader dr)
        {
            ChoGuard.ArgumentNotNull(dr, "DataReader");

            DataTable schemaTable = dr.GetSchemaTable();
            dynamic   expando     = new ExpandoObject();
            var       expandoDic  = (IDictionary <string, object>)expando;

            //int ordinal = 0;
            if (Configuration.XmlRecordFieldConfigurations.IsNullOrEmpty())
            {
                string colName     = null;
                Type   colType     = null;
                int    startIndex  = 0;
                int    fieldLength = 0;
                foreach (DataRow row in schemaTable.Rows)
                {
                    colName = row["ColumnName"].CastTo <string>();
                    colType = row["DataType"] as Type;
                    //if (!colType.IsSimple()) continue;

                    var obj = new ChoXmlRecordFieldConfiguration(colName, xPath: null);
                    Configuration.XmlRecordFieldConfigurations.Add(obj);
                    startIndex += fieldLength;
                }
            }

            while (dr.Read())
            {
                expandoDic.Clear();

                foreach (var fc in Configuration.XmlRecordFieldConfigurations)
                {
                    expandoDic.Add(fc.Name, dr[fc.Name]);
                }

                Write(expando);
            }
        }
        private void DiscoverRecordFields(Type recordType)
        {
            if (!IsDynamicObject)
            {
                XmlRecordFieldConfigurations.Clear();

                if (ChoTypeDescriptor.GetProperties(recordType).Where(pd => pd.Attributes.OfType <ChoXmlNodeRecordFieldAttribute>().Any()).Any())
                {
                    foreach (PropertyDescriptor pd in ChoTypeDescriptor.GetProperties(recordType).Where(pd => pd.Attributes.OfType <ChoXmlNodeRecordFieldAttribute>().Any()))
                    {
                        //if (!pd.PropertyType.IsSimple())
                        //    throw new ChoRecordConfigurationException("Property '{0}' is not a simple type.".FormatString(pd.Name));

                        var obj = new ChoXmlRecordFieldConfiguration(pd.Name, pd.Attributes.OfType <ChoXmlNodeRecordFieldAttribute>().First());
                        if (obj.XPath.IsNullOrWhiteSpace())
                        {
                            obj.XPath = $"//{obj.FieldName}|//@{obj.FieldName}";
                        }

                        obj.FieldType = pd.PropertyType;
                        XmlRecordFieldConfigurations.Add(obj);
                    }
                }
                else
                {
                    foreach (PropertyDescriptor pd in ChoTypeDescriptor.GetProperties(recordType))
                    {
                        //if (!pd.PropertyType.IsSimple())
                        //    throw new ChoRecordConfigurationException("Property '{0}' is not a simple type.".FormatString(pd.Name));

                        var obj = new ChoXmlRecordFieldConfiguration(pd.Name, $"//{pd.Name}|//@{pd.Name}");
                        obj.FieldType = pd.PropertyType;
                        XmlRecordFieldConfigurations.Add(obj);
                    }
                }
            }
        }
        private bool FillRecord(object rec, Tuple <long, XElement> pair)
        {
            long     lineNo;
            XElement node;

            lineNo = pair.Item1;
            node   = pair.Item2;

            fXElements  = null;
            fieldValue  = null;
            fieldConfig = null;
            pi          = null;
            xpn         = node.CreateNavigator(Configuration.NamespaceManager.NameTable);
            ToDictionary(node);

            foreach (KeyValuePair <string, ChoXmlRecordFieldConfiguration> kvp in Configuration.RecordFieldConfigurationsDict)
            {
                fieldValue  = null;
                fieldConfig = kvp.Value;
                if (Configuration.PIDict != null)
                {
                    Configuration.PIDict.TryGetValue(kvp.Key, out pi);
                }

                if (fieldConfig.XPath == "text()")
                {
                    if (Configuration.GetNameWithNamespace(node.Name) == fieldConfig.FieldName)
                    {
                        object value = node;
                        if (!RaiseBeforeRecordFieldLoad(rec, pair.Item1, kvp.Key, ref value))
                        {
                            continue;
                        }
                        if (fieldConfig.ValueConverter != null)
                        {
                            value = fieldConfig.ValueConverter(value);
                        }

                        fieldValue = value is XElement ? ((XElement)value).ToObjectFromXml(typeof(ChoDynamicObject)) : value;

                        //fieldValue = value is XElement ? node.Value : value;
                    }
                    else if (Configuration.ColumnCountStrict)
                    {
                        throw new ChoParserException("Missing '{0}' xml node.".FormatString(fieldConfig.FieldName));
                    }
                }
                else
                {
                    if (/*!fieldConfig.UseCache && */ !xDict.ContainsKey(fieldConfig.FieldName))
                    {
                        xNodes.Clear();
                        foreach (XPathNavigator z in xpn.Select(fieldConfig.XPath, Configuration.NamespaceManager))
                        {
                            xNodes.Add(z.UnderlyingObject);
                        }

                        object value = xNodes;
                        if (!RaiseBeforeRecordFieldLoad(rec, pair.Item1, kvp.Key, ref value))
                        {
                            continue;
                        }

                        if (fieldConfig.ValueConverter != null)
                        {
                            fieldValue = fieldConfig.ValueConverter(value);
                        }
                        else
                        {
                            //object[] xNodes = ((IEnumerable)node.XPathEvaluate(fieldConfig.XPath, Configuration.NamespaceManager)).OfType<object>().ToArray();
                            //continue;
                            XAttribute[] fXAttributes = xNodes.OfType <XAttribute>().ToArray();
                            if (!fXAttributes.IsNullOrEmpty()) //fXAttribute != null)
                            {
                                //fieldValue = fXAttribute.Value;
                                if (fieldConfig.FieldType == null)
                                {
                                    if (fXAttributes.Length == 1)
                                    {
                                        if (fieldConfig.ItemConverter != null)
                                        {
                                            fieldValue = fieldConfig.ItemConverter(fXAttributes[0]);
                                        }
                                        else
                                        {
                                            fieldValue = fXAttributes[0].Value;
                                        }
                                    }
                                    else
                                    {
                                        List <object> arr = new List <object>();
                                        foreach (var ele in fXAttributes)
                                        {
                                            if (fieldConfig.ItemConverter != null)
                                            {
                                                arr.Add(fieldConfig.ItemConverter(ele));
                                            }
                                            else
                                            {
                                                arr.Add(ele.Value);
                                            }
                                        }

                                        fieldValue = arr.ToArray();
                                    }
                                }
                                else if (fieldConfig.FieldType == typeof(string) || fieldConfig.FieldType.IsSimple())
                                {
                                    XAttribute fXElement = fXAttributes.FirstOrDefault();
                                    if (fXElement != null)
                                    {
                                        if (fieldConfig.ItemConverter != null)
                                        {
                                            fieldValue = fieldConfig.ItemConverter(fXElement);
                                        }
                                        else
                                        {
                                            fieldValue = fXElement.Value;
                                        }
                                    }
                                }
                                else if (fieldConfig.FieldType.IsCollection())
                                {
                                    List <object> list     = new List <object>();
                                    Type          itemType = fieldConfig.FieldType.GetItemType().GetUnderlyingType();

                                    foreach (var ele in fXAttributes)
                                    {
                                        if (fieldConfig.ItemConverter != null)
                                        {
                                            list.Add(fieldConfig.ItemConverter(ele));
                                        }
                                        else
                                        {
                                            if (itemType.IsSimple())
                                            {
                                                list.Add(ChoConvert.ConvertTo(ele.Value, itemType));
                                            }
                                            else
                                            {
                                                list.Add(ele.Value);
                                            }
                                        }
                                    }
                                    fieldValue = list.ToArray();
                                }
                                else
                                {
                                    XAttribute fXElement = fXAttributes.FirstOrDefault();
                                    if (fXElement != null)
                                    {
                                        if (fieldConfig.ItemConverter != null)
                                        {
                                            fieldValue = fieldConfig.ItemConverter(fXElement);
                                        }
                                        else
                                        {
                                            fieldValue = fXElement.Value;
                                        }
                                    }
                                }
                            }
                            else
                            {
                                fXElements = xNodes.OfType <XElement>().ToArray();

                                if (!fXElements.IsNullOrEmpty())
                                {
                                    if (fieldConfig.IsArray != null && fieldConfig.IsArray.Value)
                                    {
                                        List <object> list     = new List <object>();
                                        Type          itemType = fieldConfig.FieldType != null?fieldConfig.FieldType.GetItemType().GetUnderlyingType() :
                                                                     typeof(ChoDynamicObject);

                                        foreach (var ele in fXElements)
                                        {
                                            if (fieldConfig.ItemConverter != null)
                                            {
                                                list.Add(fieldConfig.ItemConverter(ele));
                                            }
                                            else
                                            {
                                                if (itemType.IsSimple())
                                                {
                                                    list.Add(ChoConvert.ConvertTo(ele.Value, itemType));
                                                }
                                                else
                                                {
                                                    if (itemType == typeof(ChoDynamicObject))
                                                    {
                                                        list.Add(ele.ToDynamic());
                                                    }
                                                    else
                                                    {
                                                        list.Add(ele.ToObjectFromXml(itemType, GetXmlOverrides(fieldConfig)));
                                                    }
                                                }
                                            }
                                        }
                                        fieldValue = list.ToArray();
                                    }
                                    else
                                    {
                                        if (fieldConfig.FieldType == null ||
                                            fieldConfig.FieldType == typeof(object) ||
                                            fieldConfig.FieldType.GetItemType() == typeof(object))
                                        {
                                            if (fXElements.Length == 1)
                                            {
                                                if (fieldConfig.ItemConverter != null)
                                                {
                                                    fieldValue = fieldConfig.ItemConverter(fXElements[0]);
                                                }
                                                else
                                                {
                                                    fieldValue = fXElements[0].ToObjectFromXml(typeof(ChoDynamicObject));
                                                }
                                            }
                                            else
                                            {
                                                List <object> arr = new List <object>();
                                                foreach (var ele in fXElements)
                                                {
                                                    if (fieldConfig.ItemConverter != null)
                                                    {
                                                        arr.Add(fieldConfig.ItemConverter(ele));
                                                    }
                                                    else
                                                    {
                                                        arr.Add(ele.ToObjectFromXml(typeof(ChoDynamicObject)) as ChoDynamicObject);
                                                    }
                                                }

                                                fieldValue = arr.ToArray();
                                            }
                                        }
                                        else if (fieldConfig.FieldType == typeof(string) || fieldConfig.FieldType.IsSimple())
                                        {
                                            XElement fXElement = fXElements.FirstOrDefault();
                                            if (fXElement != null)
                                            {
                                                if (fieldConfig.ItemConverter != null)
                                                {
                                                    fieldValue = fieldConfig.ItemConverter(fXElement);
                                                }
                                                else
                                                {
                                                    fieldValue = fXElement.Value;
                                                }
                                            }
                                        }
                                        else if (fieldConfig.FieldType.IsCollection())
                                        {
                                            List <object> list     = new List <object>();
                                            Type          itemType = fieldConfig.FieldType.GetItemType().GetUnderlyingType();

                                            //if (!itemType.IsSimple())
                                            //{
                                            //    fXElements = fXElements.SelectMany(e => e.Elements()).ToArray();
                                            //}

                                            foreach (var ele in fXElements)
                                            {
                                                if (fieldConfig.ItemConverter != null)
                                                {
                                                    list.Add(fieldConfig.ItemConverter(ele));
                                                }
                                                else
                                                {
                                                    if (itemType.IsSimple())
                                                    {
                                                        list.Add(ChoConvert.ConvertTo(ele.Value, itemType));
                                                    }
                                                    else
                                                    {
                                                        list.Add(ele.ToObjectFromXml(itemType, null));
                                                    }
                                                }
                                            }

                                            fieldValue = list.ToArray();
                                        }
                                        else
                                        {
                                            XElement fXElement = fXElements.FirstOrDefault(); //.SelectMany(e => e.Elements()).FirstOrDefault();
                                            if (fXElement != null)
                                            {
                                                if (fieldConfig.ItemConverter != null)
                                                {
                                                    fieldValue = fieldConfig.ItemConverter(fXElement);
                                                }
                                                else
                                                {
                                                    fieldValue = fXElement.ToObjectFromXml(fieldConfig.FieldType, null);
                                                }
                                            }
                                        }
                                    }
                                }
                                else
                                {
                                    XText[] xTexts = xNodes.OfType <XText>().ToArray();
                                    if (!xTexts.IsNullOrEmpty())
                                    {
                                        if (fieldConfig.FieldType == null)
                                        {
                                            if (xTexts.Length == 1)
                                            {
                                                if (fieldConfig.ItemConverter != null)
                                                {
                                                    fieldValue = fieldConfig.ItemConverter(xTexts[0]);
                                                }
                                                else
                                                {
                                                    fieldValue = xTexts[0].Value;
                                                }
                                            }
                                            else
                                            {
                                                List <object> arr = new List <object>();
                                                foreach (var ele in xTexts)
                                                {
                                                    if (fieldConfig.ItemConverter != null)
                                                    {
                                                        arr.Add(fieldConfig.ItemConverter(ele));
                                                    }
                                                    else
                                                    {
                                                        arr.Add(ele.Value);
                                                    }
                                                }

                                                fieldValue = arr.ToArray();
                                            }
                                        }
                                        else if (fieldConfig.FieldType == typeof(string) || fieldConfig.FieldType.IsSimple())
                                        {
                                            XText fXElement = xTexts.FirstOrDefault();
                                            if (fXElement != null)
                                            {
                                                if (fieldConfig.ItemConverter != null)
                                                {
                                                    fieldValue = fieldConfig.ItemConverter(fXElement);
                                                }
                                                else
                                                {
                                                    fieldValue = fXElement.Value;
                                                }
                                            }
                                        }
                                        else if (fieldConfig.FieldType.IsCollection())
                                        {
                                            List <object> list     = new List <object>();
                                            Type          itemType = fieldConfig.FieldType.GetItemType().GetUnderlyingType();

                                            foreach (var ele in xTexts)
                                            {
                                                if (fieldConfig.ItemConverter != null)
                                                {
                                                    list.Add(fieldConfig.ItemConverter(ele));
                                                }
                                                else
                                                {
                                                    if (itemType.IsSimple())
                                                    {
                                                        list.Add(ChoConvert.ConvertTo(ele.Value, itemType));
                                                    }
                                                    else
                                                    {
                                                        list.Add(ele.Value);
                                                    }
                                                }
                                            }
                                            fieldValue = list.ToArray();
                                        }
                                        else
                                        {
                                            XText fXElement = xTexts.FirstOrDefault();
                                            if (fXElement != null)
                                            {
                                                if (fieldConfig.ItemConverter != null)
                                                {
                                                    fieldValue = fieldConfig.ItemConverter(fXElement);
                                                }
                                                else
                                                {
                                                    fieldValue = fXElement.Value;
                                                }
                                            }
                                        }
                                    }
                                    else if (Configuration.ColumnCountStrict)
                                    {
                                        throw new ChoParserException("Missing '{0}' xml node.".FormatString(fieldConfig.FieldName));
                                    }
                                }
                            }
                        }
                    }
                    else
                    {
                        if (xDict[fieldConfig.FieldName].Count == 1)
                        {
                            fieldValue = xDict[fieldConfig.FieldName][0];
                        }
                        else
                        {
                            fieldValue = xDict[fieldConfig.FieldName];
                        }

                        if (!RaiseBeforeRecordFieldLoad(rec, pair.Item1, kvp.Key, ref fieldValue))
                        {
                            continue;
                        }

                        if (fieldConfig.ValueConverter != null)
                        {
                            fieldValue = fieldConfig.ValueConverter(fieldValue);
                        }
                    }
                }

                if (Configuration.IsDynamicObject)
                {
                    if (fieldValue != null && kvp.Value.FieldType == null && lineNo == 1)
                    {
                        kvp.Value.FieldType = fieldValue is ICollection?fieldValue.GetType() : fieldValue.GetType().IsSimple() ? DiscoverFieldType(fieldValue as string) : null;
                    }
                }
                else
                {
                    if (pi != null)
                    {
                        kvp.Value.FieldType = pi.PropertyType;
                    }
                    else
                    {
                        kvp.Value.FieldType = typeof(string);
                    }
                }

                if (fieldValue is string)
                {
                    fieldValue = CleanFieldValue(fieldConfig, kvp.Value.FieldType, fieldValue as string, kvp.Value.EncodeValue);
                }

                try
                {
                    bool ignoreFieldValue = fieldConfig.IgnoreFieldValue(fieldValue);
                    if (ignoreFieldValue)
                    {
                        fieldValue = fieldConfig.IsDefaultValueSpecified ? fieldConfig.DefaultValue : null;
                    }

                    if (Configuration.IsDynamicObject)
                    {
                        var dict = rec as IDictionary <string, Object>;

                        if (!fieldConfig.IsArray.CastTo <bool>())
                        {
                            dict.ConvertNSetMemberValue(kvp.Key, kvp.Value, ref fieldValue, Configuration.Culture);
                        }
                        else
                        {
                            dict[kvp.Key] = fieldValue;
                        }

                        if ((Configuration.ObjectValidationMode & ChoObjectValidationMode.MemberLevel) == ChoObjectValidationMode.MemberLevel)
                        {
                            dict.DoMemberLevelValidation(kvp.Key, kvp.Value, Configuration.ObjectValidationMode);
                        }
                    }
                    else
                    {
                        if (pi != null)
                        {
                            rec.ConvertNSetMemberValue(kvp.Key, kvp.Value, ref fieldValue, Configuration.Culture);
                        }
                        else
                        {
                            throw new ChoMissingRecordFieldException("Missing '{0}' property in {1} type.".FormatString(kvp.Key, ChoType.GetTypeName(rec)));
                        }

                        if ((Configuration.ObjectValidationMode & ChoObjectValidationMode.MemberLevel) == ChoObjectValidationMode.MemberLevel)
                        {
                            rec.DoMemberLevelValidation(kvp.Key, kvp.Value, Configuration.ObjectValidationMode);
                        }
                    }

                    if (!RaiseAfterRecordFieldLoad(rec, pair.Item1, kvp.Key, fieldValue))
                    {
                        return(false);
                    }
                }
                catch (ChoParserException)
                {
                    Reader.IsValid = false;
                    throw;
                }
                catch (ChoMissingRecordFieldException)
                {
                    Reader.IsValid = false;
                    if (Configuration.ThrowAndStopOnMissingField)
                    {
                        throw;
                    }
                }
                catch (Exception ex)
                {
                    Reader.IsValid = false;
                    ChoETLFramework.HandleException(ref ex);

                    if (fieldConfig.ErrorMode == ChoErrorMode.ThrowAndStop)
                    {
                        throw;
                    }

                    try
                    {
                        if (Configuration.IsDynamicObject)
                        {
                            var dict = rec as IDictionary <string, Object>;

                            if (dict.SetFallbackValue(kvp.Key, kvp.Value, Configuration.Culture, ref fieldValue))
                            {
                                dict.DoMemberLevelValidation(kvp.Key, kvp.Value, Configuration.ObjectValidationMode);
                            }
                            else if (dict.SetDefaultValue(kvp.Key, kvp.Value, Configuration.Culture))
                            {
                                dict.DoMemberLevelValidation(kvp.Key, kvp.Value, Configuration.ObjectValidationMode);
                            }
                            else
                            {
                                throw new ChoReaderException($"Failed to parse '{fieldValue}' value for '{fieldConfig.FieldName}' field.", ex);
                            }
                        }
                        else if (pi != null)
                        {
                            if (rec.SetFallbackValue(kvp.Key, kvp.Value, Configuration.Culture))
                            {
                                rec.DoMemberLevelValidation(kvp.Key, kvp.Value, Configuration.ObjectValidationMode);
                            }
                            else if (rec.SetDefaultValue(kvp.Key, kvp.Value, Configuration.Culture))
                            {
                                rec.DoMemberLevelValidation(kvp.Key, kvp.Value, Configuration.ObjectValidationMode);
                            }
                            else
                            {
                                throw new ChoReaderException($"Failed to parse '{fieldValue}' value for '{fieldConfig.FieldName}' field.", ex);
                            }
                        }
                        else
                        {
                            throw new ChoReaderException($"Failed to parse '{fieldValue}' value for '{fieldConfig.FieldName}' field.", ex);
                        }
                    }
                    catch (Exception innerEx)
                    {
                        if (ex == innerEx.InnerException)
                        {
                            if (fieldConfig.ErrorMode == ChoErrorMode.IgnoreAndContinue)
                            {
                                continue;
                            }
                            else
                            {
                                if (!RaiseRecordFieldLoadError(rec, pair.Item1, kvp.Key, fieldValue, ex))
                                {
                                    throw new ChoReaderException($"Failed to parse '{fieldValue}' value for '{fieldConfig.FieldName}' field.", ex);
                                }
                            }
                        }
                        else
                        {
                            throw new ChoReaderException("Failed to assign '{0}' fallback value to '{1}' field.".FormatString(fieldValue, fieldConfig.FieldName), innerEx);
                        }
                    }
                }
            }

            return(true);
        }
        public override void Validate(object state)
        {
            base.Validate(state);

            //if (XPath.IsNull())
            //    throw new ChoRecordConfigurationException("XPath can't be null or whitespace.");

            if (XPath.IsNullOrWhiteSpace())
            {
                if (!IsDynamicObject && (RecordType.IsGenericType && RecordType.GetGenericTypeDefinition() == typeof(KeyValuePair <,>)))
                {
                    NodeName = NodeName.IsNullOrWhiteSpace() ? "KeyValuePair" : NodeName;
                    RootName = RootName.IsNullOrWhiteSpace() ? "KeyValuePairs" : RootName;
                }
                else if (!IsDynamicObject && !typeof(IChoScalarObject).IsAssignableFrom(RecordType))
                {
                    NodeName = NodeName.IsNullOrWhiteSpace() ? RecordType.Name : NodeName;
                    RootName = RootName.IsNullOrWhiteSpace() ? NodeName.ToPlural() : RootName;
                }
            }
            else
            {
                RootName = RootName.IsNullOrWhiteSpace() ? XPath.SplitNTrim("/").Where(t => !t.IsNullOrWhiteSpace() && t.NTrim() != "." && t.NTrim() != ".." && t.NTrim() != "*").FirstOrDefault() : RootName;
                NodeName = NodeName.IsNullOrWhiteSpace() ? XPath.SplitNTrim("/").Where(t => !t.IsNullOrWhiteSpace() && t.NTrim() != "." && t.NTrim() != ".." && t.NTrim() != "*").Skip(1).FirstOrDefault() : NodeName;
            }

            string rootName = null;
            string nodeName = null;
            ChoXmlDocumentRootAttribute da = TypeDescriptor.GetAttributes(RecordType).OfType <ChoXmlDocumentRootAttribute>().FirstOrDefault();

            if (da != null)
            {
                rootName = da.Name;
            }
            else
            {
                XmlRootAttribute ra = TypeDescriptor.GetAttributes(RecordType).OfType <XmlRootAttribute>().FirstOrDefault();
                if (ra != null)
                {
                    nodeName = ra.ElementName;
                }
            }

            RootName = RootName.IsNullOrWhiteSpace() && !rootName.IsNullOrWhiteSpace() ? rootName : RootName;
            NodeName = NodeName.IsNullOrWhiteSpace() && !nodeName.IsNullOrWhiteSpace() ? nodeName : NodeName;

            RootName = RootName.IsNullOrWhiteSpace() && !NodeName.IsNullOrWhiteSpace() ? NodeName.ToPlural() : RootName;
            if (!RootName.IsNullOrWhiteSpace() && RootName.ToSingular() != RootName)
            {
                NodeName = NodeName.IsNullOrWhiteSpace() && !RootName.IsNullOrWhiteSpace() ? RootName.ToSingular() : NodeName;
            }

            if (RootName.IsNullOrWhiteSpace())
            {
                RootName = "Root";
            }
            if (NodeName.IsNullOrWhiteSpace())
            {
                NodeName = "XElement";
            }

            //Encode Root and node names
            RootName = System.Net.WebUtility.HtmlEncode(RootName);
            NodeName = System.Net.WebUtility.HtmlEncode(NodeName);

            string[] fieldNames = null;
            XElement xpr        = null;

            if (state is Tuple <long, XElement> )
            {
                xpr = ((Tuple <long, XElement>)state).Item2;
            }
            else
            {
                fieldNames = state as string[];
            }

            if (AutoDiscoverColumns &&
                XmlRecordFieldConfigurations.Count == 0)
            {
                if (RecordType != null && !IsDynamicObject &&
                    ChoTypeDescriptor.GetProperties(RecordType).Where(pd => pd.Attributes.OfType <ChoXmlNodeRecordFieldAttribute>().Any()).Any())
                {
                    DiscoverRecordFields(RecordType);
                }
                else if (xpr != null)
                {
                    XmlRecordFieldConfigurations.AddRange(DiscoverRecordFieldsFromXElement(xpr));
                }
                else if (!fieldNames.IsNullOrEmpty())
                {
                    foreach (string fn in fieldNames)
                    {
                        if (IgnoredFields.Contains(fn))
                        {
                            continue;
                        }

                        if (fn.StartsWith("_"))
                        {
                            string fn1 = fn.Substring(1);
                            var    obj = new ChoXmlRecordFieldConfiguration(fn, xPath: $"./{fn1}");
                            obj.FieldName      = fn1;
                            obj.IsXmlAttribute = true;
                            XmlRecordFieldConfigurations.Add(obj);
                        }
                        else if (fn.EndsWith("_"))
                        {
                            string fn1 = fn.Substring(0, fn.Length - 1);
                            var    obj = new ChoXmlRecordFieldConfiguration(fn, xPath: $"./{fn1}");
                            obj.FieldName  = fn1;
                            obj.IsXmlCDATA = true;
                            XmlRecordFieldConfigurations.Add(obj);
                        }
                        else
                        {
                            var obj = new ChoXmlRecordFieldConfiguration(fn, xPath: $"./{fn}");
                            XmlRecordFieldConfigurations.Add(obj);
                        }
                    }
                }
            }
            else
            {
                IsComplexXPathUsed = false;

                foreach (var fc in XmlRecordFieldConfigurations)
                {
                    if (fc.IsArray == null)
                    {
                        fc.IsArray = typeof(ICollection).IsAssignableFrom(fc.FieldType);
                    }

                    if (fc.FieldName.IsNullOrWhiteSpace())
                    {
                        fc.FieldName = fc.Name;
                    }

                    if (fc.XPath.IsNullOrWhiteSpace())
                    {
                        fc.XPath = $"/{fc.FieldName}|/@{fc.FieldName}";
                    }
                    else
                    {
                        if (fc.XPath == fc.FieldName ||
                            fc.XPath == $"/{fc.FieldName}" || fc.XPath == $"/{fc.FieldName}" || fc.XPath == $"/{fc.FieldName}" ||
                            fc.XPath == $"/@{fc.FieldName}" || fc.XPath == $"/@{fc.FieldName}" || fc.XPath == $"/@{fc.FieldName}"
                            )
                        {
                        }
                        else
                        {
                            IsComplexXPathUsed = true;
                            fc.UseCache        = false;
                        }
                    }
                }
            }

            if (XmlRecordFieldConfigurations.Count <= 0)
            {
                throw new ChoRecordConfigurationException("No record fields specified.");
            }

            //Validate each record field
            foreach (var fieldConfig in XmlRecordFieldConfigurations)
            {
                fieldConfig.Validate(this);
            }

            //Check field position for duplicate
            string[] dupFields = XmlRecordFieldConfigurations.GroupBy(i => i.Name)
                                 .Where(g => g.Count() > 1)
                                 .Select(g => g.Key).ToArray();

            if (dupFields.Length > 0)
            {
                throw new ChoRecordConfigurationException("Duplicate field(s) [Name(s): {0}] found.".FormatString(String.Join(",", dupFields)));
            }

            PIDict = new Dictionary <string, System.Reflection.PropertyInfo>();
            PDDict = new Dictionary <string, PropertyDescriptor>();
            foreach (var fc in XmlRecordFieldConfigurations)
            {
                var pd1 = fc.DeclaringMember.IsNullOrWhiteSpace() ? ChoTypeDescriptor.GetProperty(RecordType, fc.Name)
                    : ChoTypeDescriptor.GetProperty(RecordType, fc.DeclaringMember);
                if (pd1 != null)
                {
                    fc.PropertyDescriptor = pd1;
                }

                if (fc.PropertyDescriptor == null)
                {
                    fc.PropertyDescriptor = TypeDescriptor.GetProperties(RecordType).AsTypedEnumerable <PropertyDescriptor>().Where(pd => pd.Name == fc.Name).FirstOrDefault();
                }
                if (fc.PropertyDescriptor == null)
                {
                    continue;
                }

                PIDict.Add(fc.Name, fc.PropertyDescriptor.ComponentType.GetProperty(fc.PropertyDescriptor.Name));
                PDDict.Add(fc.Name, fc.PropertyDescriptor);
            }

            RecordFieldConfigurationsDict = XmlRecordFieldConfigurations.OrderBy(c => c.IsXmlAttribute).Where(i => !i.Name.IsNullOrWhiteSpace()).ToDictionary(i => i.Name);

            if (XmlRecordFieldConfigurations.Where(e => e.IsNullable).Any() ||
                NullValueHandling == ChoNullValueHandling.Default)
            {
                if (NamespaceManager != null)
                {
                    if (!NamespaceManager.HasNamespace("xsi"))
                    {
                        NamespaceManager.AddNamespace("xsi", ChoXmlSettings.XmlSchemaInstanceNamespace);
                    }
                    if (!NamespaceManager.HasNamespace("xsd"))
                    {
                        NamespaceManager.AddNamespace("xsd", ChoXmlSettings.XmlSchemaNamespace);
                    }
                }
            }

            LoadNCacheMembers(XmlRecordFieldConfigurations);
        }
        private void DiscoverRecordFields(Type recordType, string declaringMember, bool optIn = false)
        {
            if (recordType == null)
            {
                return;
            }
            if (!recordType.IsDynamicType())
            {
                IsComplexXPathUsed = false;
                Type pt = null;
                if (optIn) //ChoTypeDescriptor.GetProperties(recordType).Where(pd => pd.Attributes.OfType<ChoXmlNodeRecordFieldAttribute>().Any()).Any())
                {
                    foreach (PropertyDescriptor pd in ChoTypeDescriptor.GetProperties(recordType))
                    {
                        pt = pd.PropertyType.GetUnderlyingType();
                        var  fa     = pd.Attributes.OfType <ChoXmlNodeRecordFieldAttribute>().FirstOrDefault();
                        bool optIn1 = fa == null || fa.UseXmlSerialization ? optIn : ChoTypeDescriptor.GetProperties(pt).Where(pd1 => pd1.Attributes.OfType <ChoXmlNodeRecordFieldAttribute>().Any()).Any();
                        if (false) //optIn1 && !pt.IsSimple() && !typeof(IEnumerable).IsAssignableFrom(pt))
                        {
                            DiscoverRecordFields(pt, declaringMember == null ? pd.Name : "{0}.{1}".FormatString(declaringMember, pd.Name), optIn1);
                        }
                        else if (pd.Attributes.OfType <ChoXmlNodeRecordFieldAttribute>().Any())
                        {
                            bool   useCache = true;
                            string xpath    = null;
                            ChoXmlNodeRecordFieldAttribute attr = ChoTypeDescriptor.GetPropetyAttribute <ChoXmlNodeRecordFieldAttribute>(pd);
                            if (attr.XPath.IsNullOrEmpty())
                            {
                                if (!attr.FieldName.IsNullOrWhiteSpace())
                                {
                                    attr.XPath = $"/{attr.FieldName}|/@{attr.FieldName}";
                                }
                                else
                                {
                                    attr.XPath = xpath = $"/{pd.Name}|/@{pd.Name}";
                                }
                                IsComplexXPathUsed = true;
                            }
                            else
                            {
                                useCache = false;
                            }

                            var obj = new ChoXmlRecordFieldConfiguration(pd.Name, attr, pd.Attributes.OfType <Attribute>().ToArray());
                            obj.FieldType          = pt;
                            obj.PropertyDescriptor = pd;
                            obj.DeclaringMember    = declaringMember == null ? null : "{0}.{1}".FormatString(declaringMember, pd.Name);
                            obj.UseCache           = useCache;
                            if (obj.XPath.IsNullOrWhiteSpace())
                            {
                                if (!obj.FieldName.IsNullOrWhiteSpace())
                                {
                                    obj.XPath = $"/{obj.FieldName}|/@{obj.FieldName}";
                                }
                                else
                                {
                                    obj.XPath = $"/{obj.Name}|/@{obj.Name}";
                                }
                            }

                            obj.FieldType = pd.PropertyType.GetUnderlyingType();
                            if (!XmlRecordFieldConfigurations.Any(c => c.Name == pd.Name))
                            {
                                XmlRecordFieldConfigurations.Add(obj);
                            }
                        }
                    }
                }
                else
                {
                    foreach (PropertyDescriptor pd in ChoTypeDescriptor.GetProperties(recordType))
                    {
                        XmlIgnoreAttribute xiAttr = pd.Attributes.OfType <XmlIgnoreAttribute>().FirstOrDefault();
                        if (xiAttr != null)
                        {
                            continue;
                        }

                        pt = pd.PropertyType.GetUnderlyingType();
                        if (false) //pt != typeof(object) && !pt.IsSimple() && !typeof(IEnumerable).IsAssignableFrom(pt))
                        {
                            DiscoverRecordFields(pt, declaringMember == null ? pd.Name : "{0}.{1}".FormatString(declaringMember, pd.Name), optIn);
                        }
                        else
                        {
                            var obj = new ChoXmlRecordFieldConfiguration(pd.Name, $"/{pd.Name}|/@{pd.Name}");
                            obj.FieldType          = pt;
                            obj.PropertyDescriptor = pd;
                            obj.DeclaringMember    = declaringMember == null ? null : "{0}.{1}".FormatString(declaringMember, pd.Name);
                            StringLengthAttribute slAttr = pd.Attributes.OfType <StringLengthAttribute>().FirstOrDefault();
                            if (slAttr != null && slAttr.MaximumLength > 0)
                            {
                                obj.Size = slAttr.MaximumLength;
                            }

                            XmlElementAttribute xAttr = pd.Attributes.OfType <XmlElementAttribute>().FirstOrDefault();
                            if (xAttr != null && !xAttr.ElementName.IsNullOrWhiteSpace())
                            {
                                obj.FieldName = xAttr.ElementName;
                            }
                            else
                            {
                                XmlAttributeAttribute xaAttr = pd.Attributes.OfType <XmlAttributeAttribute>().FirstOrDefault();
                                if (xAttr != null && !xaAttr.AttributeName.IsNullOrWhiteSpace())
                                {
                                    obj.FieldName = xaAttr.AttributeName;
                                }
                                else
                                {
                                    DisplayNameAttribute dnAttr = pd.Attributes.OfType <DisplayNameAttribute>().FirstOrDefault();
                                    if (dnAttr != null && !dnAttr.DisplayName.IsNullOrWhiteSpace())
                                    {
                                        obj.FieldName = dnAttr.DisplayName.Trim();
                                    }
                                    else
                                    {
                                        DisplayAttribute dpAttr = pd.Attributes.OfType <DisplayAttribute>().FirstOrDefault();
                                        if (dpAttr != null)
                                        {
                                            if (!dpAttr.ShortName.IsNullOrWhiteSpace())
                                            {
                                                obj.FieldName = dpAttr.ShortName;
                                            }
                                            else if (!dpAttr.Name.IsNullOrWhiteSpace())
                                            {
                                                obj.FieldName = dpAttr.Name;
                                            }
                                        }
                                    }
                                }
                            }
                            DisplayFormatAttribute dfAttr = pd.Attributes.OfType <DisplayFormatAttribute>().FirstOrDefault();
                            if (dfAttr != null && !dfAttr.DataFormatString.IsNullOrWhiteSpace())
                            {
                                obj.FormatText = dfAttr.DataFormatString;
                            }
                            if (dfAttr != null && !dfAttr.NullDisplayText.IsNullOrWhiteSpace())
                            {
                                obj.NullValue = dfAttr.NullDisplayText;
                            }
                            if (!XmlRecordFieldConfigurations.Any(c => c.Name == pd.Name))
                            {
                                XmlRecordFieldConfigurations.Add(obj);
                            }
                        }
                    }
                }
            }
        }
        public override void Validate(object state)
        {
            base.Validate(state);

            //if (XPath.IsNull())
            //    throw new ChoRecordConfigurationException("XPath can't be null or whitespace.");

            if (XPath.IsNullOrWhiteSpace())
            {
                if (!IsDynamicObject && (RecordType.IsGenericType && RecordType.GetGenericTypeDefinition() == typeof(KeyValuePair <,>)))
                {
                    NodeName = NodeName.IsNullOrWhiteSpace() ? "KeyValuePair" : NodeName;
                    RootName = RootName.IsNullOrWhiteSpace() ? "KeyValuePairs" : RootName;
                }
                else if (!IsDynamicObject && !typeof(IChoScalarObject).IsAssignableFrom(RecordType))
                {
                    NodeName = NodeName.IsNullOrWhiteSpace() ? RecordType.Name : NodeName;
                    RootName = RootName.IsNullOrWhiteSpace() ? NodeName.ToPlural() : NodeName;
                }
            }
            else
            {
                RootName = RootName.IsNullOrWhiteSpace() ? XPath.SplitNTrim("/").Where(t => !t.IsNullOrWhiteSpace() && t.NTrim() != "." && t.NTrim() != ".." && t.NTrim() != "*").FirstOrDefault() : RootName;
                NodeName = NodeName.IsNullOrWhiteSpace() ? XPath.SplitNTrim("/").Where(t => !t.IsNullOrWhiteSpace() && t.NTrim() != "." && t.NTrim() != ".." && t.NTrim() != "*").Skip(1).FirstOrDefault() : NodeName;
            }

            string rootName = null;
            string nodeName = null;
            ChoXmlDocumentRootAttribute da = TypeDescriptor.GetAttributes(RecordType).OfType <ChoXmlDocumentRootAttribute>().FirstOrDefault();

            if (da != null)
            {
                rootName = da.Name;
            }
            else
            {
                XmlRootAttribute ra = TypeDescriptor.GetAttributes(RecordType).OfType <XmlRootAttribute>().FirstOrDefault();
                if (ra != null)
                {
                    nodeName = ra.ElementName;
                }
            }

            RootName = RootName.IsNullOrWhiteSpace() && !rootName.IsNullOrWhiteSpace() ? rootName : RootName;
            NodeName = NodeName.IsNullOrWhiteSpace() && !nodeName.IsNullOrWhiteSpace() ? nodeName : NodeName;

            RootName = RootName.IsNullOrWhiteSpace() && !NodeName.IsNullOrWhiteSpace() ? NodeName.ToPlural() : RootName;
            if (!RootName.IsNullOrWhiteSpace() && RootName.ToSingular() != RootName)
            {
                NodeName = NodeName.IsNullOrWhiteSpace() && !RootName.IsNullOrWhiteSpace() ? RootName.ToSingular() : NodeName;
            }

            if (RootName.IsNullOrWhiteSpace())
            {
                RootName = "Root";
            }
            if (NodeName.IsNullOrWhiteSpace())
            {
                NodeName = "XElement";
            }

            //Encode Root and node names
            RootName = System.Net.WebUtility.HtmlEncode(RootName);
            NodeName = System.Net.WebUtility.HtmlEncode(NodeName);

            string[] fieldNames = null;
            XElement xpr        = null;

            if (state is Tuple <long, XElement> )
            {
                xpr = ((Tuple <long, XElement>)state).Item2;
            }
            else
            {
                fieldNames = state as string[];
            }

            if (AutoDiscoverColumns &&
                XmlRecordFieldConfigurations.Count == 0)
            {
                if (RecordType != null && !IsDynamicObject &&
                    ChoTypeDescriptor.GetProperties(RecordType).Where(pd => pd.Attributes.OfType <ChoXmlNodeRecordFieldAttribute>().Any()).Any())
                {
                    DiscoverRecordFields(RecordType);
                }
                else if (xpr != null)
                {
                    IsComplexXPathUsed = false;
                    ChoXmlNamespaceManager nsMgr = new ChoXmlNamespaceManager(NamespaceManager);

                    Dictionary <string, ChoXmlRecordFieldConfiguration> dict = new Dictionary <string, ChoXmlRecordFieldConfiguration>(StringComparer.CurrentCultureIgnoreCase);
                    string name = null;
                    foreach (var attr in xpr.Attributes())
                    {
                        if (!attr.IsValidAttribute(XmlSchemaNamespace, JSONSchemaNamespace))
                        {
                            continue;
                        }

                        if (!IsInNamespace(xpr.Name, attr.Name))
                        {
                            continue;
                        }
                        //if (!attr.Name.NamespaceName.IsNullOrWhiteSpace()) continue;

                        name = GetNameWithNamespace(xpr.Name, attr.Name);

                        if (!dict.ContainsKey(name))
                        {
                            dict.Add(name, new ChoXmlRecordFieldConfiguration(attr.Name.LocalName, $"./@{name}")
                            {
                                FieldName = name
                            });                                                                                                         // DefaultNamespace.IsNullOrWhiteSpace() ? $"//@{name}" : $"//@{DefaultNamespace}" + ":" + $"{name}") { IsXmlAttribute = true });
                        }
                        else
                        {
                            throw new ChoRecordConfigurationException("Duplicate field(s) [Name(s): {0}] found.".FormatString(name));
                        }
                    }

                    bool hasElements = false;
                    //var z = xpr.Elements().ToArray();
                    XElement ele = null;
                    foreach (var kvp in xpr.Elements().GroupBy(e => e.Name.LocalName).Select(g => new { Name = g.Key, Value = g.ToArray() }))
                    {
                        if (kvp.Value.Length == 1)
                        {
                            ele = kvp.Value.First();
                            if (!IsInNamespace(ele.Name))
                            {
                                continue;
                            }

                            name = GetNameWithNamespace(ele.Name);

                            hasElements = true;
                            if (!dict.ContainsKey(name))
                            {
                                dict.Add(name, new ChoXmlRecordFieldConfiguration(ele.Name.LocalName, $"./{name}")
                                {
                                    FieldName = name
                                });                                                                                                       // DefaultNamespace.IsNullOrWhiteSpace() ? $"//{name}" : $"//{DefaultNamespace}" + ":" + $"{name}"));
                            }
                            else
                            {
                                if (dict[name].IsXmlAttribute)
                                {
                                    throw new ChoRecordConfigurationException("Duplicate field(s) [Name(s): {0}] found.".FormatString(name));
                                }

                                dict[name].IsArray = true;
                            }
                        }
                        else if (kvp.Value.Length > 1)
                        {
                            ele = kvp.Value.First();
                            if (!IsInNamespace(ele.Name))
                            {
                                continue;
                            }

                            name = GetNameWithNamespace(ele.Name);

                            hasElements = true;
                            if (!dict.ContainsKey(name))
                            {
                                dict.Add(name, new ChoXmlRecordFieldConfiguration(xpr.Name.LocalName, $"./{name}")
                                {
                                    FieldName = name
                                });                                                                                                       // DefaultNamespace.IsNullOrWhiteSpace() ? $"//{name}" : $"//{DefaultNamespace}" + ":" + $"{name}"));
                            }
                            else
                            {
                                if (dict[name].IsXmlAttribute)
                                {
                                    throw new ChoRecordConfigurationException("Duplicate field(s) [Name(s): {0}] found.".FormatString(name));
                                }

                                dict[name].IsArray = true;
                            }
                        }
                    }

                    //foreach (var ele in xpr.Elements())
                    //{
                    //    if (!IsInNamespace(ele.Name))
                    //        continue;

                    //    name = GetNameWithNamespace(ele.Name);

                    //    hasElements = true;
                    //    if (!dict.ContainsKey(name))
                    //        dict.Add(name, new ChoXmlRecordFieldConfiguration(ele.Name.LocalName, $"/{name}") { FieldName = name }); // DefaultNamespace.IsNullOrWhiteSpace() ? $"//{name}" : $"//{DefaultNamespace}" + ":" + $"{name}"));
                    //    else
                    //    {
                    //        if (dict[name].IsXmlAttribute)
                    //            throw new ChoRecordConfigurationException("Duplicate field(s) [Name(s): {0}] found.".FormatString(name));

                    //        dict[name].IsArray = true;
                    //    }
                    //}

                    if (!hasElements)
                    {
                        if (IsInNamespace(xpr.Name))
                        {
                            //name = xpr.Name.LocalName;
                            name = GetNameWithNamespace(xpr.Name);
                            dict.Add(name, new ChoXmlRecordFieldConfiguration(name, "text()")
                            {
                                FieldName = name
                            });
                        }
                    }

                    foreach (ChoXmlRecordFieldConfiguration obj in dict.Values)
                    {
                        XmlRecordFieldConfigurations.Add(obj);
                    }
                }
                else if (!fieldNames.IsNullOrEmpty())
                {
                    foreach (string fn in fieldNames)
                    {
                        if (fn.StartsWith("_"))
                        {
                            string fn1 = fn.Substring(1);
                            var    obj = new ChoXmlRecordFieldConfiguration(fn, xPath: $"./{fn1}");
                            obj.FieldName      = fn1;
                            obj.IsXmlAttribute = true;
                            XmlRecordFieldConfigurations.Add(obj);
                        }
                        else if (fn.EndsWith("_"))
                        {
                            string fn1 = fn.Substring(0, fn.Length - 1);
                            var    obj = new ChoXmlRecordFieldConfiguration(fn, xPath: $"./{fn1}");
                            obj.FieldName  = fn1;
                            obj.IsXmlCDATA = true;
                            XmlRecordFieldConfigurations.Add(obj);
                        }
                        else
                        {
                            var obj = new ChoXmlRecordFieldConfiguration(fn, xPath: $"./{fn}");
                            XmlRecordFieldConfigurations.Add(obj);
                        }
                    }
                }
            }
            else
            {
                IsComplexXPathUsed = false;

                foreach (var fc in XmlRecordFieldConfigurations)
                {
                    if (fc.IsArray == null)
                    {
                        fc.IsArray = typeof(ICollection).IsAssignableFrom(fc.FieldType);
                    }

                    if (fc.FieldName.IsNullOrWhiteSpace())
                    {
                        fc.FieldName = fc.Name;
                    }

                    if (fc.XPath.IsNullOrWhiteSpace())
                    {
                        fc.XPath = $"./{fc.FieldName}|.//@{fc.FieldName}";
                    }
                    else
                    {
                        if (fc.XPath == fc.FieldName ||
                            fc.XPath == $"./{fc.FieldName}" || fc.XPath == $"./{fc.FieldName}" || fc.XPath == $"./{fc.FieldName}" ||
                            fc.XPath == $"./@{fc.FieldName}" || fc.XPath == $"./@{fc.FieldName}" || fc.XPath == $"./@{fc.FieldName}"
                            )
                        {
                        }
                        else
                        {
                            IsComplexXPathUsed = true;
                            fc.UseCache        = false;
                        }
                    }
                }
            }

            if (XmlRecordFieldConfigurations.Count <= 0)
            {
                throw new ChoRecordConfigurationException("No record fields specified.");
            }

            //Validate each record field
            foreach (var fieldConfig in XmlRecordFieldConfigurations)
            {
                fieldConfig.Validate(this);
            }

            //Check field position for duplicate
            string[] dupFields = XmlRecordFieldConfigurations.GroupBy(i => i.Name)
                                 .Where(g => g.Count() > 1)
                                 .Select(g => g.Key).ToArray();

            if (dupFields.Length > 0)
            {
                throw new ChoRecordConfigurationException("Duplicate field(s) [Name(s): {0}] found.".FormatString(String.Join(",", dupFields)));
            }

            PIDict = new Dictionary <string, System.Reflection.PropertyInfo>();
            PDDict = new Dictionary <string, PropertyDescriptor>();
            foreach (var fc in XmlRecordFieldConfigurations)
            {
                if (fc.PropertyDescriptor == null)
                {
                    fc.PropertyDescriptor = ChoTypeDescriptor.GetProperties(RecordType).Where(pd => pd.Name == fc.Name).FirstOrDefault();
                }
                if (fc.PropertyDescriptor == null)
                {
                    continue;
                }

                PIDict.Add(fc.PropertyDescriptor.Name, fc.PropertyDescriptor.ComponentType.GetProperty(fc.PropertyDescriptor.Name));
                PDDict.Add(fc.PropertyDescriptor.Name, fc.PropertyDescriptor);
            }

            RecordFieldConfigurationsDict = XmlRecordFieldConfigurations.OrderBy(c => c.IsXmlAttribute).Where(i => !i.Name.IsNullOrWhiteSpace()).ToDictionary(i => i.Name);

            if (XmlRecordFieldConfigurations.Where(e => e.IsNullable).Any() ||
                NullValueHandling == ChoNullValueHandling.Default)
            {
                if (NamespaceManager != null)
                {
                    if (!NamespaceManager.HasNamespace("xsi"))
                    {
                        NamespaceManager.AddNamespace("xsi", ChoXmlSettings.XmlSchemaInstanceNamespace);
                    }
                    if (!NamespaceManager.HasNamespace("xsd"))
                    {
                        NamespaceManager.AddNamespace("xsd", ChoXmlSettings.XmlSchemaNamespace);
                    }
                }
            }

            LoadNCacheMembers(XmlRecordFieldConfigurations);
        }
Exemple #13
0
        private bool FillRecord(object rec, Tuple <long, XElement> pair)
        {
            long     lineNo;
            XElement node;

            lineNo = pair.Item1;
            node   = pair.Item2;

            fXElements  = null;
            fieldValue  = null;
            fieldConfig = null;
            pi          = null;
            xpn         = node.CreateNavigator(Configuration.NamespaceManager.NameTable);
            ToDictionary(node);

            foreach (KeyValuePair <string, ChoXmlRecordFieldConfiguration> kvp in Configuration.RecordFieldConfigurationsDict)
            {
                fieldValue  = null;
                fieldConfig = kvp.Value;
                if (Configuration.PIDict != null)
                {
                    Configuration.PIDict.TryGetValue(kvp.Key, out pi);
                }

                if (fieldConfig.XPath == "text()")
                {
                    if (Configuration.GetNameWithNamespace(node.Name) == fieldConfig.FieldName)
                    {
                        fieldValue = node.Value;
                    }
                    else if (Configuration.ColumnCountStrict)
                    {
                        throw new ChoParserException("Missing '{0}' xml node.".FormatString(fieldConfig.FieldName));
                    }
                }
                else
                {
                    if (!fieldConfig.UseCache && !xDict.ContainsKey(fieldConfig.FieldName))
                    {
                        xNodes.Clear();
                        foreach (XPathNavigator z in xpn.Select(fieldConfig.XPath, Configuration.NamespaceManager))
                        {
                            xNodes.Add(z.UnderlyingObject);
                        }

                        //object[] xNodes = ((IEnumerable)node.XPathEvaluate(fieldConfig.XPath, Configuration.NamespaceManager)).OfType<object>().ToArray();
                        //continue;
                        XAttribute fXAttribute = xNodes.OfType <XAttribute>().FirstOrDefault();
                        if (fXAttribute != null)
                        {
                            fieldValue = fXAttribute.Value;
                        }
                        else
                        {
                            fXElements = xNodes.OfType <XElement>().ToArray();
                            if (fXElements != null)
                            {
                                if (fieldConfig.IsCollection)
                                {
                                    List <string> list = new List <string>();
                                    foreach (var ele in fXElements)
                                    {
                                        list.Add(ele.Value);
                                    }
                                    fieldValue = list.ToArray();
                                }
                                else
                                {
                                    XElement fXElement = fXElements.FirstOrDefault();
                                    if (fXElement != null)
                                    {
                                        fieldValue = fXElement.Value;
                                    }
                                }
                            }
                            else if (Configuration.ColumnCountStrict)
                            {
                                throw new ChoParserException("Missing '{0}' xml node.".FormatString(fieldConfig.FieldName));
                            }
                        }
                    }
                    else
                    {
                        if (xDict[fieldConfig.FieldName].Count == 1)
                        {
                            fieldValue = xDict[fieldConfig.FieldName][0];
                        }
                        else
                        {
                            fieldValue = xDict[fieldConfig.FieldName];
                        }
                    }
                }
                if (rec is ExpandoObject)
                {
                    if (kvp.Value.FieldType == null)
                    {
                        kvp.Value.FieldType = fieldValue is ICollection ? typeof(string[]) : typeof(string);
                    }
                }
                else
                {
                    if (pi != null)
                    {
                        kvp.Value.FieldType = pi.PropertyType;
                    }
                    else
                    {
                        kvp.Value.FieldType = typeof(string);
                    }
                }

                if (!(fieldValue is ICollection))
                {
                    fieldValue = CleanFieldValue(fieldConfig, kvp.Value.FieldType, fieldValue as string);
                }

                if (!RaiseBeforeRecordFieldLoad(rec, pair.Item1, kvp.Key, ref fieldValue))
                {
                    continue;
                }

                try
                {
                    bool ignoreFieldValue = fieldConfig.IgnoreFieldValue(fieldValue);
                    if (ignoreFieldValue)
                    {
                        fieldValue = fieldConfig.IsDefaultValueSpecified ? fieldConfig.DefaultValue : null;
                    }

                    if (Configuration.IsDynamicObject)
                    {
                        var dict = rec as IDictionary <string, Object>;

                        dict.ConvertNSetMemberValue(kvp.Key, kvp.Value, ref fieldValue, Configuration.Culture);

                        if ((Configuration.ObjectValidationMode & ChoObjectValidationMode.MemberLevel) == ChoObjectValidationMode.MemberLevel)
                        {
                            dict.DoMemberLevelValidation(kvp.Key, kvp.Value, Configuration.ObjectValidationMode);
                        }
                    }
                    else
                    {
                        if (pi != null)
                        {
                            rec.ConvertNSetMemberValue(kvp.Key, kvp.Value, ref fieldValue, Configuration.Culture);
                        }
                        else
                        {
                            throw new ChoMissingRecordFieldException("Missing '{0}' property in {1} type.".FormatString(kvp.Key, ChoType.GetTypeName(rec)));
                        }

                        if ((Configuration.ObjectValidationMode & ChoObjectValidationMode.MemberLevel) == ChoObjectValidationMode.MemberLevel)
                        {
                            rec.DoMemberLevelValidation(kvp.Key, kvp.Value, Configuration.ObjectValidationMode);
                        }
                    }

                    if (!RaiseAfterRecordFieldLoad(rec, pair.Item1, kvp.Key, fieldValue))
                    {
                        return(false);
                    }
                }
                catch (ChoParserException)
                {
                    throw;
                }
                catch (ChoMissingRecordFieldException)
                {
                    if (Configuration.ThrowAndStopOnMissingField)
                    {
                        throw;
                    }
                }
                catch (Exception ex)
                {
                    ChoETLFramework.HandleException(ex);

                    if (fieldConfig.ErrorMode == ChoErrorMode.ThrowAndStop)
                    {
                        throw;
                    }

                    try
                    {
                        if (Configuration.IsDynamicObject)
                        {
                            var dict = rec as IDictionary <string, Object>;

                            if (dict.SetFallbackValue(kvp.Key, kvp.Value, Configuration.Culture, ref fieldValue))
                            {
                                dict.DoMemberLevelValidation(kvp.Key, kvp.Value, Configuration.ObjectValidationMode);
                            }
                            else if (dict.SetDefaultValue(kvp.Key, kvp.Value, Configuration.Culture))
                            {
                                dict.DoMemberLevelValidation(kvp.Key, kvp.Value, Configuration.ObjectValidationMode);
                            }
                            else
                            {
                                throw new ChoReaderException($"Failed to parse '{fieldValue}' value for '{fieldConfig.FieldName}' field.", ex);
                            }
                        }
                        else if (pi != null)
                        {
                            if (rec.SetFallbackValue(kvp.Key, kvp.Value, Configuration.Culture))
                            {
                                rec.DoMemberLevelValidation(kvp.Key, kvp.Value, Configuration.ObjectValidationMode);
                            }
                            else if (rec.SetDefaultValue(kvp.Key, kvp.Value, Configuration.Culture))
                            {
                                rec.DoMemberLevelValidation(kvp.Key, kvp.Value, Configuration.ObjectValidationMode);
                            }
                            else
                            {
                                throw new ChoReaderException($"Failed to parse '{fieldValue}' value for '{fieldConfig.FieldName}' field.", ex);
                            }
                        }
                        else
                        {
                            throw new ChoReaderException($"Failed to parse '{fieldValue}' value for '{fieldConfig.FieldName}' field.", ex);
                        }
                    }
                    catch (Exception innerEx)
                    {
                        if (ex == innerEx.InnerException)
                        {
                            if (fieldConfig.ErrorMode == ChoErrorMode.IgnoreAndContinue)
                            {
                                continue;
                            }
                            else
                            {
                                if (!RaiseRecordFieldLoadError(rec, pair.Item1, kvp.Key, fieldValue, ex))
                                {
                                    throw new ChoReaderException($"Failed to parse '{fieldValue}' value for '{fieldConfig.FieldName}' field.", ex);
                                }
                            }
                        }
                        else
                        {
                            throw new ChoReaderException("Failed to assign '{0}' fallback value to '{1}' field.".FormatString(fieldValue, fieldConfig.FieldName), innerEx);
                        }
                    }
                }
            }

            return(true);
        }
Exemple #14
0
 internal ChoXmlRecordFieldConfigurationMap(ChoXmlRecordFieldConfiguration config)
 {
     _config = config;
 }
        public override void Validate(object state)
        {
            base.Validate(state);

            if (XPath.IsNull())
            {
                throw new ChoRecordConfigurationException("XPath can't be null or whitespace.");
            }

            if (XPath.IsNullOrWhiteSpace())
            {
                if (RecordType != null)
                {
                    NodeName = RecordType.Name;
                    RootName = RecordType.Namespace;
                }
            }
            else
            {
                RootName = XPath.SplitNTrim("/").Where(t => !t.IsNullOrWhiteSpace() && t.NTrim() != "." && t.NTrim() != ".." && t.NTrim() != "*").FirstOrDefault();
                NodeName = XPath.SplitNTrim("/").Where(t => !t.IsNullOrWhiteSpace() && t.NTrim() != "." && t.NTrim() != ".." && t.NTrim() != "*").Skip(1).FirstOrDefault();
            }

            if (RootName.IsNullOrWhiteSpace())
            {
                ChoXmlDocumentRootAttribute da = TypeDescriptor.GetAttributes(RecordType).OfType <ChoXmlDocumentRootAttribute>().FirstOrDefault();
                if (da != null)
                {
                    NodeName = da.Name;
                }
                if (RootName.IsNullOrWhiteSpace())
                {
                    RootName = "Root";
                }
            }

            if (NodeName.IsNullOrWhiteSpace())
            {
                if (!IsDynamicObject)
                {
                    XmlRootAttribute ra = TypeDescriptor.GetAttributes(RecordType).OfType <XmlRootAttribute>().FirstOrDefault();
                    if (ra != null)
                    {
                        NodeName = ra.ElementName;
                    }
                }

                if (NodeName.IsNullOrWhiteSpace())
                {
                    NodeName = "XElement";
                }
            }

            //Encode Root and node names
            RootName = System.Net.WebUtility.HtmlEncode(RootName);
            NodeName = System.Net.WebUtility.HtmlEncode(NodeName);

            string[] fieldNames = null;
            XElement xpr        = null;

            if (state is Tuple <long, XElement> )
            {
                xpr = ((Tuple <long, XElement>)state).Item2;
            }
            else
            {
                fieldNames = state as string[];
            }

            if (AutoDiscoverColumns &&
                XmlRecordFieldConfigurations.Count == 0)
            {
                if (RecordType != null && !IsDynamicObject &&
                    ChoTypeDescriptor.GetProperties(RecordType).Where(pd => pd.Attributes.OfType <ChoXmlNodeRecordFieldAttribute>().Any()).Any())
                {
                    IsComplexXPathUsed = false;

                    long   startIndex = 0;
                    long   size       = 0;
                    string xpath      = null;
                    bool   useCache   = true;
                    ChoXmlNodeRecordFieldAttribute attr = null;
                    foreach (PropertyDescriptor pd in ChoTypeDescriptor.GetProperties(RecordType).Where(pd => pd.Attributes.OfType <ChoXmlNodeRecordFieldAttribute>().Any()))
                    {
                        //if (!pd.PropertyType.IsSimple())
                        //    throw new ChoRecordConfigurationException("Property '{0}' is not a simple type.".FormatString(pd.Name));

                        attr = ChoTypeDescriptor.GetPropetyAttribute <ChoXmlNodeRecordFieldAttribute>(pd);
                        if (attr.XPath.IsNullOrEmpty())
                        {
                            xpath = $"//{pd.Name}|//@{pd.Name}";
                            IsComplexXPathUsed = true;
                        }
                        else
                        {
                            useCache = false;
                        }

                        var obj = new ChoXmlRecordFieldConfiguration(pd.Name, xpath);
                        obj.FieldType = pd.PropertyType;
                        obj.UseCache  = useCache;
                        XmlRecordFieldConfigurations.Add(obj);

                        startIndex += size;
                    }

                    //RecordLength = startIndex;
                }
                else if (xpr != null)
                {
                    IsComplexXPathUsed = false;
                    ChoXmlNamespaceManager nsMgr = new ChoXmlNamespaceManager(NamespaceManager);

                    Dictionary <string, ChoXmlRecordFieldConfiguration> dict = new Dictionary <string, ChoXmlRecordFieldConfiguration>(StringComparer.CurrentCultureIgnoreCase);
                    string name = null;
                    foreach (var attr in xpr.Attributes())
                    {
                        //if (!attr.Name.NamespaceName.IsNullOrWhiteSpace()) continue;

                        name = GetNameWithNamespace(attr.Name);

                        if (!dict.ContainsKey(name))
                        {
                            dict.Add(name, new ChoXmlRecordFieldConfiguration(name, $"//@{name}")); // DefaultNamespace.IsNullOrWhiteSpace() ? $"//@{name}" : $"//@{DefaultNamespace}" + ":" + $"{name}") { IsXmlAttribute = true });
                        }
                        else
                        {
                            throw new ChoRecordConfigurationException("Duplicate field(s) [Name(s): {0}] found.".FormatString(name));
                        }
                    }

                    bool hasElements = false;
                    var  z           = xpr.Elements().Where(a => !a.HasElements).ToArray();
                    foreach (var ele in xpr.Elements().Where(a => !a.HasElements))
                    {
                        name = GetNameWithNamespace(ele.Name);

                        hasElements = true;
                        if (!dict.ContainsKey(name))
                        {
                            dict.Add(name, new ChoXmlRecordFieldConfiguration(name, $"//{name}")); // DefaultNamespace.IsNullOrWhiteSpace() ? $"//{name}" : $"//{DefaultNamespace}" + ":" + $"{name}"));
                        }
                        else
                        {
                            if (dict[name].IsXmlAttribute)
                            {
                                throw new ChoRecordConfigurationException("Duplicate field(s) [Name(s): {0}] found.".FormatString(name));
                            }

                            dict[name].IsCollection = true;
                        }
                    }

                    if (!hasElements)
                    {
                        name = xpr.Name.LocalName;
                        dict.Add(name, new ChoXmlRecordFieldConfiguration(name, "text()"));
                    }

                    foreach (ChoXmlRecordFieldConfiguration obj in dict.Values)
                    {
                        XmlRecordFieldConfigurations.Add(obj);
                    }
                }
                else if (!fieldNames.IsNullOrEmpty())
                {
                    foreach (string fn in fieldNames)
                    {
                        var obj = new ChoXmlRecordFieldConfiguration(fn, xPath: $"//{fn}");
                        XmlRecordFieldConfigurations.Add(obj);
                    }
                }
            }
            else
            {
                IsComplexXPathUsed = false;

                foreach (var fc in XmlRecordFieldConfigurations)
                {
                    if (fc.XPath.IsNullOrWhiteSpace())
                    {
                        fc.XPath = $"//{fc.FieldName}|//@{fc.FieldName}";
                    }
                    else
                    {
                        if (fc.XPath == fc.FieldName ||
                            fc.XPath == $"//{fc.FieldName}" || fc.XPath == $"/{fc.FieldName}" || fc.XPath == $"./{fc.FieldName}" ||
                            fc.XPath == $"//@{fc.FieldName}" || fc.XPath == $"/@{fc.FieldName}" || fc.XPath == $"./@{fc.FieldName}"
                            )
                        {
                        }
                        else
                        {
                            IsComplexXPathUsed = true;
                            fc.UseCache        = false;
                        }
                    }
                }
            }

            if (XmlRecordFieldConfigurations.Count <= 0)
            {
                throw new ChoRecordConfigurationException("No record fields specified.");
            }

            //Validate each record field
            foreach (var fieldConfig in XmlRecordFieldConfigurations)
            {
                fieldConfig.Validate(this);
            }

            //Check field position for duplicate
            string[] dupFields = XmlRecordFieldConfigurations.GroupBy(i => i.Name)
                                 .Where(g => g.Count() > 1)
                                 .Select(g => g.Key).ToArray();

            if (dupFields.Length > 0)
            {
                throw new ChoRecordConfigurationException("Duplicate field(s) [Name(s): {0}] found.".FormatString(String.Join(",", dupFields)));
            }

            RecordFieldConfigurationsDict = XmlRecordFieldConfigurations.OrderBy(c => c.IsXmlAttribute).Where(i => !i.Name.IsNullOrWhiteSpace()).ToDictionary(i => i.Name);

            LoadNCacheMembers(XmlRecordFieldConfigurations);
        }
Exemple #16
0
        private ChoXmlReader <T> WithField(string name, string xPath              = null, Type fieldType = null, ChoFieldValueTrimOption fieldValueTrimOption = ChoFieldValueTrimOption.Trim, bool isXmlAttribute = false, string fieldName = null, bool isArray = false,
                                           Func <object, object> valueConverter   = null,
                                           Func <object, object> itemConverter    = null,
                                           Func <object, object> customSerializer = null,
                                           object defaultValue = null, object fallbackValue                    = null,
                                           bool encodeValue    = false, string fullyQualifiedMemberName        = null, string formatText = null,
                                           string nullValue    = null, Func <XElement, Type> fieldTypeSelector = null)
        {
            if (!name.IsNullOrEmpty())
            {
                if (!_clearFields)
                {
                    ClearFields();
                    Configuration.MapRecordFields(Configuration.RecordType);
                }

                string fnTrim = name.NTrim();
                ChoXmlRecordFieldConfiguration fc = null;
                PropertyDescriptor             pd = null;
                if (Configuration.XmlRecordFieldConfigurations.Any(o => o.Name == fnTrim))
                {
                    fc = Configuration.XmlRecordFieldConfigurations.Where(o => o.Name == fnTrim).First();
                    Configuration.XmlRecordFieldConfigurations.Remove(fc);
                }
                else
                {
                    pd = ChoTypeDescriptor.GetNestedProperty(typeof(T), fullyQualifiedMemberName.IsNullOrWhiteSpace() ? name : fullyQualifiedMemberName);
                }

                var nfc = new ChoXmlRecordFieldConfiguration(fnTrim, xPath)
                {
                    FieldType            = fieldType,
                    FieldValueTrimOption = fieldValueTrimOption,
                    IsXmlAttribute       = isXmlAttribute,
                    FieldName            = fieldName,
                    IsArray           = isArray,
                    ValueConverter    = valueConverter,
                    ItemConverter     = itemConverter,
                    CustomSerializer  = customSerializer,
                    DefaultValue      = defaultValue,
                    FallbackValue     = fallbackValue,
                    EncodeValue       = encodeValue,
                    FormatText        = formatText,
                    NullValue         = nullValue,
                    FieldTypeSelector = fieldTypeSelector,
                };
                if (fullyQualifiedMemberName.IsNullOrWhiteSpace())
                {
                    nfc.PropertyDescriptor = fc != null ? fc.PropertyDescriptor : pd;
                    nfc.DeclaringMember    = fc != null ? fc.DeclaringMember : fullyQualifiedMemberName;
                }
                else
                {
                    pd = ChoTypeDescriptor.GetNestedProperty(typeof(T), fullyQualifiedMemberName);
                    nfc.PropertyDescriptor = pd;
                    nfc.DeclaringMember    = fullyQualifiedMemberName;
                }
                if (pd != null)
                {
                    if (nfc.FieldType == null)
                    {
                        nfc.FieldType = pd.PropertyType;
                    }
                }
                Configuration.XmlRecordFieldConfigurations.Add(nfc);
            }

            return(this);
        }
Exemple #17
0
        private bool ToText(long index, object rec, out string recText)
        {
            if (typeof(IChoScalarObject).IsAssignableFrom(Configuration.RecordType))
            {
                rec = Activator.CreateInstance(Configuration.RecordType, rec);
            }

            recText = null;
            if (rec == null)
            {
                if (Configuration.NullValueHandling == ChoNullValueHandling.Ignore)
                {
                    return(false);
                }
                else if (Configuration.NullValueHandling == ChoNullValueHandling.Default)
                {
                    rec = Activator.CreateInstance(Configuration.RecordType);
                }
                else
                {
                    recText = @"<{0} xsi:nil=""true"" />".FormatString(Configuration.NodeName
                                                                       ).Indent(Configuration.Indent * 1, Configuration.IndentChar.ToString());
                    return(true);
                }
            }

            StringBuilder msg        = new StringBuilder();
            object        fieldValue = null;
            string        fieldText  = null;
            ChoXmlRecordFieldConfiguration fieldConfig = null;

            if (Configuration.ColumnCountStrict)
            {
                CheckColumnsStrict(rec);
            }

            //bool firstColumn = true;
            PropertyInfo pi = null;
            bool         isElementClosed = false;
            bool         isElementStart  = false;

            foreach (KeyValuePair <string, ChoXmlRecordFieldConfiguration> kvp in GetOrderedKVP())
            {
                fieldConfig = kvp.Value;
                fieldValue  = null;
                fieldText   = String.Empty;
                if (Configuration.PIDict != null)
                {
                    Configuration.PIDict.TryGetValue(kvp.Key, out pi);
                }

                if (Configuration.ThrowAndStopOnMissingField)
                {
                    if (Configuration.IsDynamicObject)
                    {
                        var dict = rec.ToDynamicObject() as IDictionary <string, Object>;
                        if (!dict.ContainsKey(kvp.Key))
                        {
                            throw new ChoMissingRecordFieldException("No matching property found in the object for '{0}' Xml node.".FormatString(fieldConfig.FieldName));
                        }
                    }
                    else
                    {
                        if (pi == null)
                        {
                            throw new ChoMissingRecordFieldException("No matching property found in the object for '{0}' Xml node.".FormatString(fieldConfig.FieldName));
                        }
                    }
                }

                try
                {
                    if (Configuration.IsDynamicObject)
                    {
                        IDictionary <string, Object> dict = rec.ToDynamicObject() as IDictionary <string, Object>;
                        fieldValue = dict[kvp.Key]; // dict.GetValue(kvp.Key, Configuration.FileHeaderConfiguration.IgnoreCase, Configuration.Culture);
                        if (kvp.Value.FieldType == null)
                        {
                            if (fieldValue == null)
                            {
                                kvp.Value.FieldType = typeof(string);
                            }
                            else
                            {
                                kvp.Value.FieldType = fieldValue.GetType();
                            }
                        }
                    }
                    else
                    {
                        if (pi != null)
                        {
                            fieldValue = ChoType.GetPropertyValue(rec, pi);
                            if (kvp.Value.FieldType == null)
                            {
                                kvp.Value.FieldType = pi.PropertyType;
                            }
                        }
                        else
                        {
                            kvp.Value.FieldType = typeof(string);
                        }
                    }

                    //Discover default value, use it if null
                    if (fieldValue == null)
                    {
                        if (fieldConfig.IsDefaultValueSpecified)
                        {
                            fieldValue = fieldConfig.DefaultValue;
                        }
                    }

                    if (!RaiseBeforeRecordFieldWrite(rec, index, kvp.Key, ref fieldValue))
                    {
                        return(false);
                    }

                    if (fieldConfig.ValueConverter != null)
                    {
                        fieldValue = fieldConfig.ValueConverter(fieldValue);
                    }
                    else
                    {
                        rec.GetNConvertMemberValue(kvp.Key, kvp.Value, Configuration.Culture, ref fieldValue, true);
                    }

                    if ((Configuration.ObjectValidationMode & ChoObjectValidationMode.ObjectLevel) == ChoObjectValidationMode.MemberLevel)
                    {
                        rec.DoMemberLevelValidation(kvp.Key, kvp.Value, Configuration.ObjectValidationMode, fieldValue);
                    }

                    if (!RaiseAfterRecordFieldWrite(rec, index, kvp.Key, fieldValue))
                    {
                        return(false);
                    }
                }
                catch (ChoParserException)
                {
                    throw;
                }
                catch (ChoMissingRecordFieldException)
                {
                    if (Configuration.ThrowAndStopOnMissingField)
                    {
                        throw;
                    }
                }
                catch (Exception ex)
                {
                    ChoETLFramework.HandleException(ex);

                    if (fieldConfig.ErrorMode == ChoErrorMode.ThrowAndStop)
                    {
                        throw;
                    }

                    try
                    {
                        if (Configuration.IsDynamicObject)
                        {
                            var dict = rec.ToDynamicObject() as IDictionary <string, Object>;

                            if (dict.GetFallbackValue(kvp.Key, kvp.Value, Configuration.Culture, ref fieldValue))
                            {
                                dict.DoMemberLevelValidation(kvp.Key, kvp.Value, Configuration.ObjectValidationMode, fieldValue);
                            }
                            else if (dict.GetDefaultValue(kvp.Key, kvp.Value, Configuration.Culture, ref fieldValue))
                            {
                                dict.DoMemberLevelValidation(kvp.Key, kvp.Value, Configuration.ObjectValidationMode, fieldValue);
                            }
                            else
                            {
                                throw new ChoWriterException($"Failed to write '{fieldValue}' value for '{fieldConfig.FieldName}' member.", ex);
                            }
                        }
                        else if (pi != null)
                        {
                            if (rec.GetFallbackValue(kvp.Key, kvp.Value, Configuration.Culture, ref fieldValue))
                            {
                                rec.DoMemberLevelValidation(kvp.Key, kvp.Value, Configuration.ObjectValidationMode);
                            }
                            else if (rec.GetDefaultValue(kvp.Key, kvp.Value, Configuration.Culture, ref fieldValue))
                            {
                                rec.DoMemberLevelValidation(kvp.Key, kvp.Value, Configuration.ObjectValidationMode, fieldValue);
                            }
                            else
                            {
                                throw new ChoWriterException($"Failed to write '{fieldValue}' value for '{fieldConfig.FieldName}' member.", ex);
                            }
                        }
                        else
                        {
                            throw new ChoWriterException($"Failed to write '{fieldValue}' value for '{fieldConfig.FieldName}' member.", ex);
                        }
                    }
                    catch (Exception innerEx)
                    {
                        if (ex == innerEx.InnerException)
                        {
                            if (fieldConfig.ErrorMode == ChoErrorMode.IgnoreAndContinue)
                            {
                                continue;
                            }
                            else
                            {
                                if (!RaiseRecordFieldWriteError(rec, index, kvp.Key, fieldText, ex))
                                {
                                    throw new ChoWriterException($"Failed to write '{fieldValue}' value of '{kvp.Key}' member.", ex);
                                }
                            }
                        }
                        else
                        {
                            throw new ChoWriterException("Failed to use '{0}' fallback value for '{1}' member.".FormatString(fieldValue, kvp.Key), innerEx);
                        }
                    }
                }

                if (fieldValue == null)
                {
                    if (!fieldConfig.IsXmlAttribute && fieldConfig.IsNullable)
                    {
                        if (Configuration.RecordType == typeof(ChoScalarObject))
                        {
                            if (!isElementStart)
                            {
                                msg.Append(@"<{0} xsi:nil=""true""".FormatString(Configuration.NodeName).Indent(Configuration.Indent, Configuration.IndentChar.ToString()));
                                isElementStart = true;
                            }
                            if (!isElementClosed)
                            {
                                msg.AppendFormat(">{0}", Configuration.EOLDelimiter);
                                isElementClosed = true;
                            }
                        }
                        else
                        {
                            if (!isElementStart)
                            {
                                msg.Append("<{0}".FormatString(Configuration.NodeName).Indent(Configuration.Indent, Configuration.IndentChar.ToString()));
                                isElementStart = true;
                            }
                            if (!isElementClosed)
                            {
                                msg.AppendFormat(">{0}", Configuration.EOLDelimiter);
                                isElementClosed = true;
                            }
                            msg.Append(@"<{0} xsi:nil=""true"" />{1}".FormatString(fieldConfig.FieldName,
                                                                                   Configuration.EOLDelimiter).Indent(Configuration.Indent * 2, Configuration.IndentChar.ToString()));
                        }
                    }
                    else
                    {
                        if (Configuration.RecordType != typeof(ChoScalarObject))
                        {
                            if (!isElementStart)
                            {
                                msg.Append("<{0}".FormatString(Configuration.NodeName).Indent(Configuration.Indent, Configuration.IndentChar.ToString()));
                                isElementStart = true;
                            }
                        }
                        //isElementClosed = true;
                        fieldText = String.Empty;
                    }
                }
                else
                {
                    if (!isElementStart)
                    {
                        msg.Append("<{0}".FormatString(Configuration.NodeName).Indent(Configuration.Indent, Configuration.IndentChar.ToString()));
                        isElementStart = true;
                    }
                    if (fieldValue.GetType().IsSimple())
                    {
                        fieldText = fieldValue.ToString();
                        if (Configuration.RecordType == typeof(ChoScalarObject))
                        {
                            if (fieldConfig.IsXmlAttribute)
                            {
                                msg.Append(@" {0}=""{1}""".FormatString(fieldConfig.FieldName, NormalizeFieldValue(kvp.Key, fieldText, kvp.Value.Size, kvp.Value.Truncate, kvp.Value.QuoteField, GetFieldValueJustification(kvp.Value.FieldValueJustification, kvp.Value.FieldType), GetFillChar(kvp.Value.FillChar, kvp.Value.FieldType), false)));
                            }
                            else
                            {
                                if (!isElementClosed)
                                {
                                    msg.AppendFormat(">{0}", Configuration.EOLDelimiter);
                                    isElementClosed = true;
                                }
                                msg.Append("{0}{1}".FormatString(
                                               NormalizeFieldValue(kvp.Key, fieldText, kvp.Value.Size, kvp.Value.Truncate, kvp.Value.QuoteField, GetFieldValueJustification(kvp.Value.FieldValueJustification, kvp.Value.FieldType), GetFillChar(kvp.Value.FillChar, kvp.Value.FieldType), false),
                                               Configuration.EOLDelimiter).Indent(Configuration.Indent * 2, Configuration.IndentChar.ToString()));
                            }
                        }
                        else if (fieldConfig.IsXmlAttribute)
                        {
                            msg.Append(@" {0}=""{1}""".FormatString(fieldConfig.FieldName, NormalizeFieldValue(kvp.Key, fieldText, kvp.Value.Size, kvp.Value.Truncate, kvp.Value.QuoteField, GetFieldValueJustification(kvp.Value.FieldValueJustification, kvp.Value.FieldType), GetFillChar(kvp.Value.FillChar, kvp.Value.FieldType), false)));
                        }
                        else
                        {
                            if (!isElementClosed)
                            {
                                msg.AppendFormat(">{0}", Configuration.EOLDelimiter);
                                isElementClosed = true;
                            }
                            msg.Append("<{0}>{1}</{0}>{2}".FormatString(fieldConfig.FieldName,
                                                                        NormalizeFieldValue(kvp.Key, fieldText, kvp.Value.Size, kvp.Value.Truncate, kvp.Value.QuoteField, GetFieldValueJustification(kvp.Value.FieldValueJustification, kvp.Value.FieldType), GetFillChar(kvp.Value.FillChar, kvp.Value.FieldType), false),
                                                                        Configuration.EOLDelimiter).Indent(Configuration.Indent * 2, Configuration.IndentChar.ToString()));
                        }
                    }
                    else
                    {
                        fieldText = ChoUtility.XmlSerialize(fieldValue);
                        fieldText = _beginTagRegex.Replace(fieldText, delegate(Match thisMatch)
                        {
                            return("<{0}>".FormatString(fieldConfig.FieldName));
                        });
                        fieldText = _endTagRegex.Replace(fieldText, delegate(Match thisMatch)
                        {
                            return("</{0}>".FormatString(fieldConfig.FieldName));
                        });
                        if (!isElementClosed)
                        {
                            msg.AppendFormat(">{0}", Configuration.EOLDelimiter);
                            isElementClosed = true;
                        }
                        msg.Append("{0}{1}".FormatString(fieldText,
                                                         Configuration.EOLDelimiter).Indent(Configuration.Indent * 2, Configuration.IndentChar.ToString()));
                    }
                }
            }

            if (!isElementClosed && msg.Length > 0)
            {
                msg.AppendFormat(">{0}", Configuration.EOLDelimiter);
                isElementClosed = true;
            }
            if (isElementStart)
            {
                msg.Append("</{0}>".FormatString(Configuration.NodeName).Indent(Configuration.Indent, Configuration.IndentChar.ToString()));
                isElementStart = false;
            }

            recText = msg.ToString();
            return(true);
        }
Exemple #18
0
        private bool ToText(long index, object rec, out string recText)
        {
            recText = null;
            StringBuilder msg        = new StringBuilder();
            object        fieldValue = null;
            string        fieldText  = null;
            ChoXmlRecordFieldConfiguration fieldConfig = null;

            if (Configuration.ColumnCountStrict)
            {
                CheckColumnsStrict(rec);
            }

            //bool firstColumn = true;
            PropertyInfo pi = null;
            bool         isElementClosed = false;

            msg.AppendFormat("{1}<{0}", Configuration.NodeName, Configuration.Indent);
            foreach (KeyValuePair <string, ChoXmlRecordFieldConfiguration> kvp in Configuration.RecordFieldConfigurationsDict)
            {
                fieldConfig = kvp.Value;
                fieldValue  = null;
                fieldText   = String.Empty;
                if (Configuration.PIDict != null)
                {
                    Configuration.PIDict.TryGetValue(kvp.Key, out pi);
                }

                if (Configuration.ThrowAndStopOnMissingField)
                {
                    if (Configuration.IsDynamicObject)
                    {
                        var dict = rec.ToDynamicObject() as IDictionary <string, Object>;
                        if (!dict.ContainsKey(kvp.Key))
                        {
                            throw new ChoMissingRecordFieldException("No matching property found in the object for '{0}' Xml node.".FormatString(fieldConfig.FieldName));
                        }
                    }
                    else
                    {
                        if (pi == null)
                        {
                            throw new ChoMissingRecordFieldException("No matching property found in the object for '{0}' Xml node.".FormatString(fieldConfig.FieldName));
                        }
                    }
                }

                try
                {
                    if (Configuration.IsDynamicObject)
                    {
                        IDictionary <string, Object> dict = rec.ToDynamicObject() as IDictionary <string, Object>;
                        fieldValue = dict[kvp.Key]; // dict.GetValue(kvp.Key, Configuration.FileHeaderConfiguration.IgnoreCase, Configuration.Culture);
                        if (kvp.Value.FieldType == null)
                        {
                            if (fieldValue == null)
                            {
                                kvp.Value.FieldType = typeof(string);
                            }
                            else
                            {
                                kvp.Value.FieldType = fieldValue.GetType();
                            }
                        }
                    }
                    else
                    {
                        if (pi != null)
                        {
                            fieldValue = ChoType.GetPropertyValue(rec, pi);
                            if (kvp.Value.FieldType == null)
                            {
                                kvp.Value.FieldType = pi.PropertyType;
                            }
                        }
                        else
                        {
                            kvp.Value.FieldType = typeof(string);
                        }
                    }

                    //Discover default value, use it if null
                    if (fieldValue == null)
                    {
                        if (fieldConfig.IsDefaultValueSpecified)
                        {
                            fieldValue = fieldConfig.DefaultValue;
                        }
                    }

                    if (!RaiseBeforeRecordFieldWrite(rec, index, kvp.Key, ref fieldValue))
                    {
                        return(false);
                    }

                    rec.GetNConvertMemberValue(kvp.Key, kvp.Value, Configuration.Culture, ref fieldValue);

                    if ((Configuration.ObjectValidationMode & ChoObjectValidationMode.ObjectLevel) == ChoObjectValidationMode.MemberLevel)
                    {
                        rec.DoMemberLevelValidation(kvp.Key, kvp.Value, Configuration.ObjectValidationMode, fieldValue);
                    }

                    if (!RaiseAfterRecordFieldWrite(rec, index, kvp.Key, fieldValue))
                    {
                        return(false);
                    }
                }
                catch (ChoParserException)
                {
                    throw;
                }
                catch (ChoMissingRecordFieldException)
                {
                    if (Configuration.ThrowAndStopOnMissingField)
                    {
                        throw;
                    }
                }
                catch (Exception ex)
                {
                    ChoETLFramework.HandleException(ex);

                    if (fieldConfig.ErrorMode == ChoErrorMode.ThrowAndStop)
                    {
                        throw;
                    }

                    try
                    {
                        if (Configuration.IsDynamicObject)
                        {
                            var dict = rec.ToDynamicObject() as IDictionary <string, Object>;

                            if (dict.GetFallbackValue(kvp.Key, kvp.Value, Configuration.Culture, ref fieldValue))
                            {
                                dict.DoMemberLevelValidation(kvp.Key, kvp.Value, Configuration.ObjectValidationMode, fieldValue);
                            }
                            else if (dict.GetDefaultValue(kvp.Key, kvp.Value, Configuration.Culture, ref fieldValue))
                            {
                                dict.DoMemberLevelValidation(kvp.Key, kvp.Value, Configuration.ObjectValidationMode, fieldValue);
                            }
                            else
                            {
                                throw new ChoWriterException($"Failed to write '{fieldValue}' value for '{fieldConfig.FieldName}' member.", ex);
                            }
                        }
                        else if (pi != null)
                        {
                            if (rec.GetFallbackValue(kvp.Key, kvp.Value, Configuration.Culture, ref fieldValue))
                            {
                                rec.DoMemberLevelValidation(kvp.Key, kvp.Value, Configuration.ObjectValidationMode);
                            }
                            else if (rec.GetDefaultValue(kvp.Key, kvp.Value, Configuration.Culture, ref fieldValue))
                            {
                                rec.DoMemberLevelValidation(kvp.Key, kvp.Value, Configuration.ObjectValidationMode, fieldValue);
                            }
                            else
                            {
                                throw new ChoWriterException($"Failed to write '{fieldValue}' value for '{fieldConfig.FieldName}' member.", ex);
                            }
                        }
                        else
                        {
                            throw new ChoWriterException($"Failed to write '{fieldValue}' value for '{fieldConfig.FieldName}' member.", ex);
                        }
                    }
                    catch (Exception innerEx)
                    {
                        if (ex == innerEx.InnerException)
                        {
                            if (fieldConfig.ErrorMode == ChoErrorMode.IgnoreAndContinue)
                            {
                                continue;
                            }
                            else
                            {
                                if (!RaiseRecordFieldWriteError(rec, index, kvp.Key, fieldText, ex))
                                {
                                    throw new ChoWriterException($"Failed to write '{fieldValue}' value of '{kvp.Key}' member.", ex);
                                }
                            }
                        }
                        else
                        {
                            throw new ChoWriterException("Failed to use '{0}' fallback value for '{1}' member.".FormatString(fieldValue, kvp.Key), innerEx);
                        }
                    }
                }

                if (fieldValue == null)
                {
                    fieldText = String.Empty;
                }
                else
                {
                    fieldText = fieldValue.ToString();
                }

                if (fieldConfig.IsXmlAttribute)
                {
                    msg.Append(@" {0}=""{1}""".FormatString(fieldConfig.FieldName, NormalizeFieldValue(kvp.Key, fieldText, kvp.Value.Size, kvp.Value.Truncate, kvp.Value.QuoteField, GetFieldValueJustification(kvp.Value.FieldValueJustification, kvp.Value.FieldType), GetFillChar(kvp.Value.FillChar, kvp.Value.FieldType), false)));
                }
                else
                {
                    if (!isElementClosed)
                    {
                        msg.AppendFormat(">{0}", Configuration.EOLDelimiter);
                        isElementClosed = true;
                    }
                    msg.Append("{2}{2}<{0}>{1}</{0}>{3}".FormatString(fieldConfig.FieldName,
                                                                      NormalizeFieldValue(kvp.Key, fieldText, kvp.Value.Size, kvp.Value.Truncate, kvp.Value.QuoteField, GetFieldValueJustification(kvp.Value.FieldValueJustification, kvp.Value.FieldType), GetFillChar(kvp.Value.FillChar, kvp.Value.FieldType), false),
                                                                      Configuration.Indent, Configuration.EOLDelimiter));
                }
            }

            if (!isElementClosed)
            {
                msg.AppendFormat(">{0}", Configuration.EOLDelimiter);
                isElementClosed = true;
            }
            msg.AppendFormat("{1}</{0}>", Configuration.NodeName, Configuration.Indent);

            recText = msg.ToString();
            return(true);
        }