File: System\Data\XMLSchema.cs
Web Access
Project: src\src\libraries\System.Data.Common\src\System.Data.Common.csproj (System.Data.Common)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data.Common;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Xml;
using System.Xml.Schema;
 
namespace System.Data
{
    internal abstract class XMLSchema
    {
        [RequiresUnreferencedCode("Generic TypeConverters may require the generic types to be annotated. For example, NullableConverter requires the underlying type to be DynamicallyAccessedMembers All.")]
        internal static TypeConverter GetConverter(Type type)
        {
            return TypeDescriptor.GetConverter(type);
        }
 
        [RequiresUnreferencedCode("Calls into TypeDescriptor.GetProperties. Type cannot be statically discovered.")]
        internal static void SetProperties(object instance, XmlAttributeCollection attrs)
        {
            // This is called from both XSD and XDR schemas.
            // Do we really need it in XSD ???
            for (int i = 0; i < attrs.Count; i++)
            {
                if (attrs[i].NamespaceURI == Keywords.MSDNS)
                {
                    string name = attrs[i].LocalName;
                    string value = attrs[i].Value;
 
                    if (name == "DefaultValue" || name == "RemotingFormat")
                        continue;
                    // skip expressions, we will handle them after SetProperties (in xdrschema)
                    if (name == "Expression" && instance is DataColumn)
                        continue;
 
                    PropertyDescriptor? pd = TypeDescriptor.GetProperties(instance)[name];
                    if (pd != null)
                    {
                        // Standard property
                        Type type = pd.PropertyType;
 
                        TypeConverter converter = XMLSchema.GetConverter(type);
                        object? propValue;
                        if (converter.CanConvertFrom(typeof(string)))
                        {
                            propValue = converter.ConvertFromInvariantString(value);
                        }
                        else if (type == typeof(Type))
                        {
                            propValue = DataStorage.GetType(value);
                        }
                        else if (type == typeof(CultureInfo))
                        {
                            propValue = new CultureInfo(value);
                        }
                        else
                        {
                            throw ExceptionBuilder.CannotConvert(value, type.FullName);
                        }
                        pd.SetValue(instance, propValue);
                    }
                }
            }
        }// SetProperties
 
        internal static bool FEqualIdentity(XmlNode? node, string name, string ns)
        {
            if (node != null && node.LocalName == name && node.NamespaceURI == ns)
                return true;
 
            return false;
        }
 
        internal static bool GetBooleanAttribute(XmlElement element, string attrName, string attrNS, bool defVal)
        {
            string value = element.GetAttribute(attrName, attrNS);
            if (string.IsNullOrEmpty(value))
            {
                return defVal;
            }
            if ((value == Keywords.TRUE) || (value == Keywords.ONE_DIGIT))
            {
                return true;
            }
            if ((value == Keywords.FALSE) || (value == Keywords.ZERO_DIGIT))
            {
                return false;
            }
            // Error processing:
            throw ExceptionBuilder.InvalidAttributeValue(attrName, value);
        }
 
        internal static string GenUniqueColumnName(string proposedName, DataTable table)
        {
            if (table.Columns.IndexOf(proposedName) >= 0)
            {
                for (int i = 0; i <= table.Columns.Count; i++)
                {
                    string tempName = proposedName + "_" + (i).ToString(CultureInfo.InvariantCulture);
                    if (table.Columns.IndexOf(tempName) >= 0)
                    {
                        continue;
                    }
                    else
                    {
                        return tempName;
                    }
                }
            }
            return proposedName;
        }
    }
 
    internal sealed class ConstraintTable
    {
        public DataTable table;
        public XmlSchemaIdentityConstraint constraint;
        public ConstraintTable(DataTable t, XmlSchemaIdentityConstraint c)
        {
            table = t;
            constraint = c;
        }
    }
 
    internal sealed class XSDSchema : XMLSchema
    {
        private XmlSchemaSet? _schemaSet;
        private XmlSchemaElement? _dsElement;
        private DataSet? _ds;
        private string? _schemaName;
        private ArrayList? _columnExpressions;
        private Hashtable? _constraintNodes;
        private ArrayList? _refTables;
        private ArrayList? _complexTypes;
        private XmlSchemaObjectCollection? _annotations;
        private XmlSchemaObjectCollection? _elements;
        private Hashtable? _attributes;
        private Hashtable? _elementsTable;
        private Hashtable? _attributeGroups;
        private Hashtable? _schemaTypes;
        private Hashtable? _expressions;
        private Dictionary<DataTable, List<DataTable>>? _tableDictionary;
 
        private Hashtable? _udSimpleTypes;
 
        private Hashtable? _existingSimpleTypeMap;
 
        private bool _fromInference;
 
        internal bool FromInference
        {
            get
            {
                return _fromInference;
            }
            set
            {
                _fromInference = value;
            }
        }
 
        private void CollectElementsAnnotations(XmlSchema schema)
        {
            ArrayList schemaList = new ArrayList();
            CollectElementsAnnotations(schema, schemaList);
            schemaList.Clear();
        }
 
        private void CollectElementsAnnotations(XmlSchema schema, ArrayList schemaList)
        {
            if (schemaList.Contains(schema))
            {
                return;
            }
            schemaList.Add(schema);
 
            foreach (object item in schema.Items)
            {
                if (item is XmlSchemaAnnotation)
                {
                    _annotations!.Add((XmlSchemaAnnotation)item);
                }
                if (item is XmlSchemaElement elem)
                {
                    _elements!.Add(elem);
                    _elementsTable![elem.QualifiedName] = elem;
                }
                if (item is XmlSchemaAttribute)
                {
                    XmlSchemaAttribute attr = (XmlSchemaAttribute)item;
                    _attributes![attr.QualifiedName] = attr;
                }
                if (item is XmlSchemaAttributeGroup)
                {
                    XmlSchemaAttributeGroup attr = (XmlSchemaAttributeGroup)item;
                    _attributeGroups![attr.QualifiedName] = attr;
                }
                if (item is XmlSchemaType)
                {
                    string? MSDATATargetNamespace = null;
                    if (item is XmlSchemaSimpleType)
                    {
                        MSDATATargetNamespace = XSDSchema.GetMsdataAttribute((XmlSchemaType)item, Keywords.TARGETNAMESPACE);
                    }
 
                    XmlSchemaType type = (XmlSchemaType)item;
                    _schemaTypes![type.QualifiedName] = type;
 
                    // if we have a User Defined simple type, cache it so later we may need for mapping
                    // meanwhile more convinient solution would be to directly use schemaTypes, but it would be more complex to handle
                    XmlSchemaSimpleType? xmlSimpleType = (item as XmlSchemaSimpleType);
                    if (xmlSimpleType != null)
                    {
                        _udSimpleTypes ??= new Hashtable();
 
                        _udSimpleTypes[type.QualifiedName.ToString()] = xmlSimpleType;
                        DataColumn? dc = (DataColumn?)_existingSimpleTypeMap![type.QualifiedName.ToString()];
                        // Assumption is that our simple type qualified name ihas the same output as XmlSchemaSimpleType type.QualifiedName.ToString()
                        SimpleType? tmpSimpleType = dc?.SimpleType;
 
                        if (tmpSimpleType != null)
                        {
                            SimpleType tmpDataSimpleType = new SimpleType(xmlSimpleType);
                            string errorStr = tmpSimpleType.HasConflictingDefinition(tmpDataSimpleType);
                            if (errorStr.Length != 0)
                            {
                                throw ExceptionBuilder.InvalidDuplicateNamedSimpleTypeDelaration(tmpDataSimpleType.SimpleTypeQualifiedName!, errorStr);
                            }
                        }
                    }
                }
            }
            foreach (XmlSchemaExternal include in schema.Includes)
            {
                if (include is XmlSchemaImport)
                    continue;
                if (include.Schema != null)
                {
                    CollectElementsAnnotations(include.Schema, schemaList);
                }
            }
        }
 
        internal static string QualifiedName(string name)
        {
            if (!name.Contains(':'))
                return Keywords.XSD_PREFIXCOLON + name;
            else
                return name;
        }
 
        [RequiresUnreferencedCode(DataSet.RequiresUnreferencedCodeMessage)]
        internal static void SetProperties(object instance, XmlAttribute[]? attrs)
        {
            // This is called from both XSD and XDR schemas.
            // Do we really need it in XSD ???
            if (attrs == null)
                return;
            for (int i = 0; i < attrs.Length; i++)
            {
                if (attrs[i].NamespaceURI == Keywords.MSDNS)
                {
                    string name = attrs[i].LocalName;
                    string value = attrs[i].Value;
 
                    if (name == "DefaultValue" || name == "Ordinal" || name == "Locale" || name == "RemotingFormat")
                        continue;
 
                    if (name == "Expression" && instance is DataColumn) // we will handle columnexpressions at HandleColumnExpression
                        continue;
 
                    if (name == "DataType")
                    {
                        DataColumn? col = instance as DataColumn;
                        if (col != null)
                        {
                            col.DataType = DataStorage.GetType(value);
                        }
 
                        continue;
                    }
 
                    PropertyDescriptor? pd = TypeDescriptor.GetProperties(instance)[name];
                    if (pd != null)
                    {
                        // Standard property
                        Type type = pd.PropertyType;
 
                        TypeConverter converter = XMLSchema.GetConverter(type);
                        object? propValue;
                        if (converter.CanConvertFrom(typeof(string)))
                        {
                            propValue = converter.ConvertFromInvariantString(value);
                        }
                        else if (type == typeof(Type))
                        {
                            propValue = Type.GetType(value);
                        }
                        else if (type == typeof(CultureInfo))
                        {
                            propValue = new CultureInfo(value);
                        }
                        else
                        {
                            throw ExceptionBuilder.CannotConvert(value, type.FullName);
                        }
                        pd.SetValue(instance, propValue);
                    }
                }
            }
        }// SetProperties
 
        [RequiresUnreferencedCode(DataSet.RequiresUnreferencedCodeMessage)]
        private static void SetExtProperties(object instance, XmlAttribute[]? attrs)
        {
            PropertyCollection? props = null;
            if (attrs == null)
                return;
            for (int i = 0; i < attrs.Length; i++)
            {
                if (attrs[i].NamespaceURI == Keywords.MSPROPNS)
                {
                    if (props == null)
                    {
                        object? val = TypeDescriptor.GetProperties(instance)["ExtendedProperties"]!.GetValue(instance);
                        Debug.Assert(val is PropertyCollection, "We can set values only for classes that have ExtendedProperties");
                        props = (PropertyCollection)val;
                    }
                    string propName = XmlConvert.DecodeName(attrs[i].LocalName);
 
                    if (instance is ForeignKeyConstraint)
                    {
                        if (propName.StartsWith(Keywords.MSD_FK_PREFIX, StringComparison.Ordinal))
                            propName = propName.Substring(3);
                        else
                            continue;
                    }
                    if ((instance is DataRelation) && (propName.StartsWith(Keywords.MSD_REL_PREFIX, StringComparison.Ordinal)))
                    {
                        propName = propName.Substring(4);
                    }
                    else if ((instance is DataRelation) && (propName.StartsWith(Keywords.MSD_FK_PREFIX, StringComparison.Ordinal)))
                    {
                        continue;
                    }
 
                    props.Add(propName, attrs[i].Value);
                }
            }
        }// SetExtProperties
 
        private void HandleColumnExpression(object instance, XmlAttribute[]? attrs)
        {
            if (attrs == null)
                return;
            DataColumn? dc = instance as DataColumn;
            Debug.Assert(dc != null, "HandleColumnExpression is supposed to be called for DataColumn");
            if (dc != null)
            {
                for (int i = 0; i < attrs.Length; i++)
                {
                    if (attrs[i].NamespaceURI == Keywords.MSDNS)
                    {
                        if (attrs[i].LocalName == "Expression")
                        {
                            _expressions ??= new Hashtable();
                            _expressions[dc] = attrs[i].Value;
                            _columnExpressions!.Add(dc);
                            break;
                        }
                    }
                }
            }
        }
 
        internal static string? GetMsdataAttribute(XmlSchemaAnnotated node, string ln)
        {
            XmlAttribute[]? nodeAttributes = node.UnhandledAttributes;
            if (nodeAttributes != null)
                for (int i = 0; i < nodeAttributes.Length; i++)
                    if (nodeAttributes[i].LocalName == ln && nodeAttributes[i].NamespaceURI == Keywords.MSDNS)
                        return nodeAttributes[i].Value;
            return null;
        }
 
        [RequiresUnreferencedCode(DataSet.RequiresUnreferencedCodeMessage)]
        private static void SetExtProperties(object instance, XmlAttributeCollection attrs)
        {
            PropertyCollection? props = null;
            for (int i = 0; i < attrs.Count; i++)
            {
                if (attrs[i].NamespaceURI == Keywords.MSPROPNS)
                {
                    if (props == null)
                    {
                        object? val = TypeDescriptor.GetProperties(instance)["ExtendedProperties"]!.GetValue(instance);
                        Debug.Assert(val is PropertyCollection, "We can set values only for classes that have ExtendedProperties");
                        props = (PropertyCollection)val;
                    }
                    string propName = XmlConvert.DecodeName(attrs[i].LocalName);
                    props.Add(propName, attrs[i].Value);
                }
            }
        }// SetExtProperties
 
        [RequiresUnreferencedCode(DataSet.RequiresUnreferencedCodeMessage)]
        internal void HandleRefTableProperties(XmlSchemaElement element)
        {
            string typeName = GetInstanceName(element);
            DataTable? table = _ds!.Tables.GetTable(XmlConvert.DecodeName(typeName), element.QualifiedName.Namespace);
            Debug.Assert(table != null, "ref table should have been already created");
 
            SetProperties(table, element.UnhandledAttributes);
            SetExtProperties(table, element.UnhandledAttributes);
        }
 
        [RequiresUnreferencedCode(DataSet.RequiresUnreferencedCodeMessage)]
        internal void HandleRelation(XmlElement node, bool fNested)
        {
            string strName;
            string parentName;
            string childName;
            string[] parentNames;
            string[] childNames;
            string value;
            bool fCreateConstraints = false; //if we have a relation,
                                             //we do not have constraints
            DataRelationCollection rels = _ds!.Relations;
            DataRelation relation;
            DataColumn[] parentKey;
            DataColumn[] childKey;
            DataTable? parent;
            DataTable? child;
            int keyLength;
 
            strName = XmlConvert.DecodeName(node.GetAttribute(Keywords.NAME));
            for (int i = 0; i < rels.Count; ++i)
            {
                if (string.Equals(rels[i].RelationName, strName, StringComparison.Ordinal))
                    return;
            }
 
            parentName = node.GetAttribute(Keywords.MSD_PARENT, Keywords.MSDNS);
            if (string.IsNullOrEmpty(parentName))
                throw ExceptionBuilder.RelationParentNameMissing(strName);
            parentName = XmlConvert.DecodeName(parentName);
 
            childName = node.GetAttribute(Keywords.MSD_CHILD, Keywords.MSDNS);
            if (string.IsNullOrEmpty(childName))
                throw ExceptionBuilder.RelationChildNameMissing(strName);
            childName = XmlConvert.DecodeName(childName);
 
            value = node.GetAttribute(Keywords.MSD_PARENTKEY, Keywords.MSDNS);
            if (string.IsNullOrEmpty(value))
                throw ExceptionBuilder.RelationTableKeyMissing(strName);
 
            parentNames = value.TrimEnd(null).Split(new char[] { Keywords.MSD_KEYFIELDSEP, Keywords.MSD_KEYFIELDOLDSEP });
            value = node.GetAttribute(Keywords.MSD_CHILDKEY, Keywords.MSDNS);
            if (string.IsNullOrEmpty(value))
                throw ExceptionBuilder.RelationChildKeyMissing(strName);
 
            childNames = value.TrimEnd(null).Split(new char[] { Keywords.MSD_KEYFIELDSEP, Keywords.MSD_KEYFIELDOLDSEP });
 
            keyLength = parentNames.Length;
            if (keyLength != childNames.Length)
                throw ExceptionBuilder.MismatchKeyLength();
 
            parentKey = new DataColumn[keyLength];
            childKey = new DataColumn[keyLength];
 
            string parentNs = node.GetAttribute(Keywords.MSD_PARENTTABLENS, Keywords.MSDNS);
            string childNs = node.GetAttribute(Keywords.MSD_CHILDTABLENS, Keywords.MSDNS);
 
            parent = _ds.Tables.GetTableSmart(parentName, parentNs);
 
            if (parent == null)
                throw ExceptionBuilder.ElementTypeNotFound(parentName);
 
            child = _ds.Tables.GetTableSmart(childName, childNs);
 
            if (child == null)
                throw ExceptionBuilder.ElementTypeNotFound(childName);
 
            for (int i = 0; i < keyLength; i++)
            {
                parentKey[i] = parent.Columns[XmlConvert.DecodeName(parentNames[i])]!;
                if (parentKey[i] == null)
                    throw ExceptionBuilder.ElementTypeNotFound(parentNames[i]);
                childKey[i] = child.Columns[XmlConvert.DecodeName(childNames[i])]!;
                if (childKey[i] == null)
                    throw ExceptionBuilder.ElementTypeNotFound(childNames[i]);
            }
            relation = new DataRelation(strName, parentKey, childKey, fCreateConstraints);
            relation.Nested = fNested;
            SetExtProperties(relation, node.Attributes);
            _ds.Relations.Add(relation);
            if (FromInference && relation.Nested)
            {
                _tableDictionary![relation.ParentTable].Add(relation.ChildTable);
            }
        }
 
        private static bool HasAttributes(XmlSchemaObjectCollection attributes)
        {
            foreach (XmlSchemaObject so in attributes)
            {
                if (so is XmlSchemaAttribute)
                {
                    return true;
                }
                if (so is XmlSchemaAttributeGroup)
                {
                    return true;
                }
                if (so is XmlSchemaAttributeGroupRef)
                {
                    return true;
                }
            }
            return false;
        }
 
        private bool IsDatasetParticle(XmlSchemaParticle pt)
        {
            XmlSchemaObjectCollection? items = GetParticleItems(pt);
 
            if (items == null)
                return false; // empty element, threat it as table
 
            bool isChoice = FromInference && (pt is XmlSchemaChoice); // currently we add this support for choice, just for inference
 
 
            foreach (XmlSchemaAnnotated el in items)
            {
                if (el is XmlSchemaElement)
                {
                    // pushing max occur of choice element to its imidiate children of type xs:elements
                    if (isChoice && pt.MaxOccurs > decimal.One && (((XmlSchemaElement)el).SchemaType is XmlSchemaComplexType)) // we know frominference condition
                        ((XmlSchemaElement)el).MaxOccurs = pt.MaxOccurs;
 
                    if (((XmlSchemaElement)el).RefName.Name.Length != 0)
                    {
                        if (!FromInference || (((XmlSchemaElement)el).MaxOccurs != decimal.One && !(((XmlSchemaElement)el).SchemaType is XmlSchemaComplexType)))
                            continue;
                    }
 
 
                    if (!IsTable((XmlSchemaElement)el))
                        return false;
 
                    continue;
                }
 
                if (el is XmlSchemaParticle)
                {
                    if (!IsDatasetParticle((XmlSchemaParticle)el))
                        return false;
                }
            }
 
            return true;
        }
 
        private static int DatasetElementCount(XmlSchemaObjectCollection elements)
        {
            int nCount = 0;
            foreach (XmlSchemaElement XmlElement in elements)
            {
                if (GetBooleanAttribute(XmlElement, Keywords.MSD_ISDATASET,  /*default:*/ false))
                {
                    nCount++;
                }
            }
            return nCount;
        }
 
        private XmlSchemaElement? FindDatasetElement(XmlSchemaObjectCollection elements)
        {
            foreach (XmlSchemaElement XmlElement in elements)
            {
                if (GetBooleanAttribute(XmlElement, Keywords.MSD_ISDATASET,  /*default:*/ false))
                    return XmlElement;
            }
            if ((elements.Count == 1) || (FromInference && elements.Count > 0))
            { //let's see if this element looks like a DataSet
                XmlSchemaElement node = (XmlSchemaElement)elements[0];
                if (!GetBooleanAttribute(node, Keywords.MSD_ISDATASET,  /*default:*/ true))
                    return null;
 
                XmlSchemaComplexType? ct = node.SchemaType as XmlSchemaComplexType;
                if (ct == null)
                    return null;
 
                while (ct != null)
                {
                    if (HasAttributes(ct.Attributes))
                        return null;
 
                    if (ct.ContentModel is XmlSchemaSimpleContent)
                    {
                        XmlSchemaAnnotated? cContent = ((XmlSchemaSimpleContent)(ct.ContentModel)).Content;
                        if (cContent is XmlSchemaSimpleContentExtension ccExtension)
                        {
                            if (HasAttributes(ccExtension.Attributes))
                                return null;
                        }
                        else
                        {
                            XmlSchemaSimpleContentRestriction ccRestriction = ((XmlSchemaSimpleContentRestriction)cContent!);
                            if (HasAttributes(ccRestriction.Attributes))
                                return null;
                        }
                    }
 
 
                    XmlSchemaParticle? particle = GetParticle(ct);
                    if (particle != null)
                    {
                        if (!IsDatasetParticle(particle))
                            return null; // it's a table
                    }
 
                    if (ct.BaseXmlSchemaType is XmlSchemaComplexType)
                        ct = (XmlSchemaComplexType)ct.BaseXmlSchemaType;
                    else
                        break;
                }
 
 
                //if we are here there all elements are tables
                return node;
            }
            return null;
        }
 
        [RequiresUnreferencedCode(DataSet.RequiresUnreferencedCodeMessage)]
        [RequiresDynamicCode(DataSet.RequiresDynamicCodeMessage)]
        public void LoadSchema(XmlSchemaSet schemaSet, DataTable dt)
        {
            if (dt.DataSet != null)
                LoadSchema(schemaSet, dt.DataSet);
        }
 
        [RequiresUnreferencedCode(DataSet.RequiresUnreferencedCodeMessage)]
        [RequiresDynamicCode(DataSet.RequiresDynamicCodeMessage)]
        public void LoadSchema(XmlSchemaSet schemaSet, DataSet ds)
        { //Element schemaRoot, DataSet ds) {
            _constraintNodes = new Hashtable();
            _refTables = new ArrayList();
            _columnExpressions = new ArrayList();
            _complexTypes = new ArrayList();
            bool setRootNStoDataSet = false;
            bool newDataSet = (ds.Tables.Count == 0);
 
            if (schemaSet == null)
                return;
            _schemaSet = schemaSet;
            _ds = ds;
            ds._fIsSchemaLoading = true;
 
            foreach (XmlSchema schemaRoot in schemaSet.Schemas())
            {
                _schemaName = schemaRoot.Id;
 
                if (string.IsNullOrEmpty(_schemaName))
                {
                    _schemaName = "NewDataSet";
                }
                ds.DataSetName = XmlConvert.DecodeName(_schemaName);
                string? ns = schemaRoot.TargetNamespace;
                if (string.IsNullOrEmpty(ds._namespaceURI))
                {// set just one time, for backward compatibility
                    ds._namespaceURI = ns ?? string.Empty;           // see fx\Data\XDO\ReadXml\SchemaM2.xml for more info
                }
                break; // we just need to take Name and NS from first schema [V1.0 & v1.1 semantics]
            }
 
            _annotations = new XmlSchemaObjectCollection();
            _elements = new XmlSchemaObjectCollection();
            _elementsTable = new Hashtable();
            _attributes = new Hashtable();
            _attributeGroups = new Hashtable();
            _schemaTypes = new Hashtable();
            _tableDictionary = new Dictionary<DataTable, List<DataTable>>();
 
            _existingSimpleTypeMap = new Hashtable();
            foreach (DataTable dt in ds.Tables)
            {
                foreach (DataColumn dc in dt.Columns)
                {
                    if (dc.SimpleType != null && dc.SimpleType.Name != null && dc.SimpleType.Name.Length != 0)
                    {
                        _existingSimpleTypeMap[dc.SimpleType.SimpleTypeQualifiedName!] = dc;
                        //                        existingSimpleTypeMap[dc.SimpleType.SimpleTypeQualifiedName] = dc.SimpleType;
                    }
                }
            }
 
 
 
            foreach (XmlSchema schemaRoot in schemaSet.Schemas())
                CollectElementsAnnotations(schemaRoot);
 
 
 
            _dsElement = FindDatasetElement(_elements);
            if (_dsElement != null)
            {
                string mainName = GetStringAttribute(_dsElement, Keywords.MSD_MAINDATATABLE, "");
                if (null != mainName)
                {
                    ds.MainTableName = XmlConvert.DecodeName(mainName);
                }
            }
            else
            {
                if (FromInference)
                {
                    ds._fTopLevelTable = true; // Backward compatibility: for inference, if we do not read DataSet element
                }
                // we should not write it also
                setRootNStoDataSet = true;
                //incase of Root is not mapped to DataSet and is mapped to DataTable instead; to be backward compatible
                // we need to set the Namespace of Root to DataSet's namespace also(it would be NS of First DataTable in collection)
            }
 
            List<XmlQualifiedName> qnames = new List<XmlQualifiedName>();
 
            if (ds != null && ds._useDataSetSchemaOnly)
            {
                int dataSetElementCount = DatasetElementCount(_elements);
                if (dataSetElementCount == 0)
                {
                    throw ExceptionBuilder.IsDataSetAttributeMissingInSchema();
                }
                else if (dataSetElementCount > 1)
                {
                    throw ExceptionBuilder.TooManyIsDataSetAttributesInSchema();
                }
 
                XmlSchemaComplexType ct = (XmlSchemaComplexType)FindTypeNode(_dsElement!)!;
                if (ct.Particle != null)
                {
                    XmlSchemaObjectCollection? items = GetParticleItems(ct.Particle);
                    if (items != null)
                    {
                        foreach (XmlSchemaAnnotated el in items)
                        {
                            XmlSchemaElement? sel = el as XmlSchemaElement;
                            if (null != sel)
                            {
                                if (sel.RefName.Name.Length != 0)
                                {
                                    qnames.Add(sel.QualifiedName);
                                }
                            }
                        }
                    }
                }
            }
 
            // Walk all the top level Element tags.
            foreach (XmlSchemaElement element in _elements)
            {
                if (element == _dsElement)
                    continue;
                if (ds != null && ds._useDataSetSchemaOnly && _dsElement != null)
                {
                    if (_dsElement.Parent != element.Parent)
                    {
                        if (!qnames.Contains(element.QualifiedName))
                        {
                            continue;
                        }
                    }
                }
 
                string typeName = GetInstanceName(element);
                if (_refTables.Contains(element.QualifiedName.Namespace + ":" + typeName))
                {
                    HandleRefTableProperties(element);
                    continue;
                }
 
                _ = HandleTable(element);
 
            }
 
            if (_dsElement != null)
                HandleDataSet(_dsElement, newDataSet);
 
            foreach (XmlSchemaAnnotation annotation in _annotations)
            {
                HandleRelations(annotation, false);
            }
 
            //just add Expressions, at this point and if ColumnExpressions.Count > 0, this.expressions should not be null
            for (int i = 0; i < _columnExpressions.Count; i++)
            {
                DataColumn dc = ((DataColumn)(_columnExpressions[i])!);
                dc.Expression = (string)_expressions![dc]!;
            }
 
            foreach (DataTable dt in ds!.Tables)
            {
                if (dt.NestedParentRelations.Length == 0 && dt.Namespace == ds.Namespace)
                {
                    DataRelationCollection childRelations = dt.ChildRelations;
                    for (int j = 0; j < childRelations.Count; j++)
                    {
                        //  we need to do the same thing for nested child tables as they
                        if (childRelations[j].Nested && dt.Namespace == childRelations[j].ChildTable.Namespace)
                        {
                            // take NS from Parent table
                            childRelations[j].ChildTable._tableNamespace = null;
                        }
                    }
                    dt._tableNamespace = null;
                }
            }
 
            DataTable? tmpTable = ds.Tables[ds.DataSetName, ds.Namespace];
            if (tmpTable != null) // this fix is done to support round-trip problem in case if there is one table with same name and NS
                tmpTable._fNestedInDataset = true;
 
 
            // this fix is for backward compatibility with old inference engine
            if (FromInference && ds.Tables.Count == 0 && string.Equals(ds.DataSetName, "NewDataSet", StringComparison.Ordinal))
                ds.DataSetName = XmlConvert.DecodeName(((XmlSchemaElement)_elements[0]).Name)!;
 
 
            ds._fIsSchemaLoading = false; //reactivate column computations
 
 
            //for backward compatibility; we need to set NS of Root Element to DataSet, if root already does not mapped to dataSet
            if (setRootNStoDataSet)
            {
                if (ds.Tables.Count > 0)
                { // if there is table, take first one's NS
                    ds.Namespace = ds.Tables[0].Namespace;
                    ds.Prefix = ds.Tables[0].Prefix;
                }
                else
                {// otherwise, take TargetNS from first schema
                    Debug.Assert(schemaSet.Count == 1, "there should be one schema");
                    foreach (XmlSchema schemaRoot in schemaSet.Schemas())
                    { // we should have 1 schema
                        ds.Namespace = schemaRoot.TargetNamespace;
                    }
                }
            }
        }
 
        [RequiresUnreferencedCode(DataSet.RequiresUnreferencedCodeMessage)]
        private void HandleRelations(XmlSchemaAnnotation ann, bool fNested)
        {
            foreach (object __items in ann.Items)
                if (__items is XmlSchemaAppInfo)
                {
                    XmlNode[] relations = ((XmlSchemaAppInfo)__items).Markup!;
                    for (int i = 0; i < relations.Length; i++)
                        if (FEqualIdentity(relations[i], Keywords.MSD_RELATION, Keywords.MSDNS))
                            HandleRelation((XmlElement)relations[i], fNested);
                }
        }
 
        internal static XmlSchemaObjectCollection? GetParticleItems(XmlSchemaParticle? pt)
        {
            if (pt is XmlSchemaSequence)
                return ((XmlSchemaSequence)pt).Items;
            if (pt is XmlSchemaAll)
                return ((XmlSchemaAll)pt).Items;
            if (pt is XmlSchemaChoice)
                return ((XmlSchemaChoice)pt).Items;
            if (pt is XmlSchemaAny)
                return null;
            // the code below is a little hack for the SOM behavior
            if (pt is XmlSchemaElement)
            {
                XmlSchemaObjectCollection Items = new XmlSchemaObjectCollection();
                Items.Add(pt);
                return Items;
            }
            if (pt is XmlSchemaGroupRef)
                return GetParticleItems(((XmlSchemaGroupRef)pt).Particle);
            // should never get here.
            return null;
        }
 
        [RequiresUnreferencedCode(DataSet.RequiresUnreferencedCodeMessage)]
        [RequiresDynamicCode(DataSet.RequiresDynamicCodeMessage)]
        internal void HandleParticle(XmlSchemaParticle pt, DataTable table, ArrayList tableChildren, bool isBase)
        {
            XmlSchemaObjectCollection? items = GetParticleItems(pt);
 
            if (items == null)
                return;
 
            foreach (XmlSchemaAnnotated item in items)
            {
                XmlSchemaElement? el = item as XmlSchemaElement;
                if (el != null)
                {
                    if (FromInference && pt is XmlSchemaChoice && pt.MaxOccurs > decimal.One && (el.SchemaType is XmlSchemaComplexType))
                        el.MaxOccurs = pt.MaxOccurs;
 
 
                    DataTable? child;
                    // to decide if element is our table, we need to match both name and ns
                    // 286043 - SQL BU Defect Tracking
                    if (((el.Name == null) && (el.RefName.Name == table.EncodedTableName && el.RefName.Namespace == table.Namespace)) ||
                        (IsTable(el) && el.Name == table.TableName))
                    {
                        if (FromInference)
                        {
                            child = HandleTable(el);
                            Debug.Assert(child == table, "table not the same");
                        }
                        else
                        {
                            child = table;
                        }
                    }
                    else
                    {
                        child = HandleTable(el);
                        if (child == null && FromInference && el.Name == table.TableName)
                        {
                            child = table;
                        }
                    }
 
                    if (child == null)
                    {
                        if (!FromInference || el.Name != table.TableName)
                        {// check is required to support 1.1 inference behavior
                            HandleElementColumn(el, table, isBase);
                        }
                    }
                    else
                    {
                        DataRelation? relation = null;
                        if (el.Annotation != null)
                            HandleRelations(el.Annotation, true);
 
                        DataRelationCollection childRelations = table.ChildRelations;
                        for (int j = 0; j < childRelations.Count; j++)
                        {
                            if (!childRelations[j].Nested)
                                continue;
 
                            if (child == childRelations[j].ChildTable)
                                relation = childRelations[j];
                        }
 
                        if (relation == null)
                        {
                            tableChildren.Add(child); // how about prefix for this?
                            if (FromInference && table.UKColumnPositionForInference == -1)
                            { // this is done for Inference
                                int ukColumnPosition = -1;
                                foreach (DataColumn dc in table.Columns)
                                {
                                    if (dc.ColumnMapping == MappingType.Element)
                                        ukColumnPosition++;
                                }
                                table.UKColumnPositionForInference = ukColumnPosition + 1; // since it starts from
                            }
                        }
                    }
                }
                else
                {
                    HandleParticle((XmlSchemaParticle)item, table, tableChildren, isBase);
                }
            }
            return;
        }
 
        [RequiresUnreferencedCode(DataSet.RequiresUnreferencedCodeMessage)]
        [RequiresDynamicCode(DataSet.RequiresDynamicCodeMessage)]
        internal void HandleAttributes(XmlSchemaObjectCollection attributes, DataTable table, bool isBase)
        {
            foreach (XmlSchemaObject so in attributes)
            {
                if (so is XmlSchemaAttribute)
                {
                    HandleAttributeColumn((XmlSchemaAttribute)so, table, isBase);
                }
                else
                {  // XmlSchemaAttributeGroupRef
                    XmlSchemaAttributeGroupRef? groupRef = so as XmlSchemaAttributeGroupRef;
                    XmlSchemaAttributeGroup? schemaGroup = _attributeGroups![groupRef!.RefName] as XmlSchemaAttributeGroup;
                    if (schemaGroup != null)
                    {
                        HandleAttributeGroup(schemaGroup, table, isBase);
                    }
                }
            }
        }
 
        [RequiresUnreferencedCode(DataSet.RequiresUnreferencedCodeMessage)]
        [RequiresDynamicCode(DataSet.RequiresDynamicCodeMessage)]
        private void HandleAttributeGroup(XmlSchemaAttributeGroup attributeGroup, DataTable table, bool isBase)
        {
            foreach (XmlSchemaObject obj in attributeGroup.Attributes)
            {
                if (obj is XmlSchemaAttribute)
                {
                    HandleAttributeColumn((XmlSchemaAttribute)obj, table, isBase);
                }
                else
                { // XmlSchemaAttributeGroupRef
                    XmlSchemaAttributeGroupRef attributeGroupRef = (XmlSchemaAttributeGroupRef)obj;
                    XmlSchemaAttributeGroup? attributeGroupResolved;
                    if (attributeGroup.RedefinedAttributeGroup != null && attributeGroupRef.RefName == new XmlQualifiedName(attributeGroup.Name, attributeGroupRef.RefName.Namespace))
                    {
                        attributeGroupResolved = attributeGroup.RedefinedAttributeGroup;
                    }
                    else
                    {
                        attributeGroupResolved = (XmlSchemaAttributeGroup?)_attributeGroups![attributeGroupRef.RefName];
                    }
                    if (attributeGroupResolved != null)
                    {
                        HandleAttributeGroup(attributeGroupResolved, table, isBase);
                    }
                }
            }
        }
 
        [RequiresUnreferencedCode(DataSet.RequiresUnreferencedCodeMessage)]
        [RequiresDynamicCode(DataSet.RequiresDynamicCodeMessage)]
        internal void HandleComplexType(XmlSchemaComplexType ct, DataTable table, ArrayList tableChildren, bool isNillable)
        {
            if (_complexTypes!.Contains(ct))
                throw ExceptionBuilder.CircularComplexType(ct.Name!);
            bool isBase = false;
            _complexTypes.Add(ct);
 
 
            if (ct.ContentModel != null)
            {
                /*
                HandleParticle(ct.CompiledParticle, table, tableChildren, isBase);
                foreach (XmlSchemaAttribute s in ct.Attributes){
                    HandleAttributeColumn(s, table, isBase);
                }
                */
 
 
                if (ct.ContentModel is XmlSchemaComplexContent)
                {
                    XmlSchemaAnnotated? cContent = ((XmlSchemaComplexContent)(ct.ContentModel)).Content;
                    if (cContent is XmlSchemaComplexContentExtension ccExtension)
                    {
                        if (!(ct.BaseXmlSchemaType is XmlSchemaComplexType && FromInference))
                            HandleAttributes(ccExtension.Attributes, table, isBase);
 
                        if (ct.BaseXmlSchemaType is XmlSchemaComplexType)
                        {
                            HandleComplexType((XmlSchemaComplexType)ct.BaseXmlSchemaType, table, tableChildren, isNillable);
                        }
                        else
                        {
                            Debug.Assert(ct.BaseXmlSchemaType is XmlSchemaSimpleType, "Expected SimpleType or ComplexType");
                            if (ccExtension.BaseTypeName.Namespace != Keywords.XSDNS)
                            {
                                // this is UDSimpleType, pass Qualified name of type
                                HandleSimpleContentColumn(ccExtension.BaseTypeName.ToString(), table, isBase, ct.ContentModel.UnhandledAttributes, isNillable);
                            }
                            else
                            { // it is built in type
                                HandleSimpleContentColumn(ccExtension.BaseTypeName.Name, table, isBase, ct.ContentModel.UnhandledAttributes, isNillable);
                            }
                        }
                        if (ccExtension.Particle != null)
                            HandleParticle(ccExtension.Particle, table, tableChildren, isBase);
                        if (ct.BaseXmlSchemaType is XmlSchemaComplexType && FromInference)
                            HandleAttributes(ccExtension.Attributes, table, isBase);
                    }
                    else
                    {
                        Debug.Assert(cContent is XmlSchemaComplexContentRestriction, "Expected complexContent extension or restriction");
                        XmlSchemaComplexContentRestriction ccRestriction = ((XmlSchemaComplexContentRestriction)cContent);
                        if (!FromInference)
                            HandleAttributes(ccRestriction.Attributes, table, isBase);
                        if (ccRestriction.Particle != null)
                            HandleParticle(ccRestriction.Particle, table, tableChildren, isBase);
                        if (FromInference)
                            HandleAttributes(ccRestriction.Attributes, table, isBase);
                    }
                }
                else
                {
                    Debug.Assert(ct.ContentModel is XmlSchemaSimpleContent, "expected simpleContent or complexContent");
                    XmlSchemaAnnotated cContent = ((XmlSchemaSimpleContent)(ct.ContentModel)).Content!;
                    if (cContent is XmlSchemaSimpleContentExtension ccExtension)
                    {
                        HandleAttributes(ccExtension.Attributes, table, isBase);
                        if (ct.BaseXmlSchemaType is XmlSchemaComplexType)
                        {
                            HandleComplexType((XmlSchemaComplexType)ct.BaseXmlSchemaType, table, tableChildren, isNillable);
                        }
                        else
                        {
                            Debug.Assert(ct.BaseXmlSchemaType is XmlSchemaSimpleType, "Expected SimpleType or ComplexType");
                            HandleSimpleTypeSimpleContentColumn((XmlSchemaSimpleType)ct.BaseXmlSchemaType, ccExtension.BaseTypeName.Name, table, isBase, ct.ContentModel.UnhandledAttributes, isNillable);
                        }
                    }
                    else
                    {
                        Debug.Assert(cContent is XmlSchemaSimpleContentRestriction, "Expected SimpleContent extension or restriction");
                        XmlSchemaSimpleContentRestriction ccRestriction = ((XmlSchemaSimpleContentRestriction)cContent);
                        HandleAttributes(ccRestriction.Attributes, table, isBase);
                    }
                }
            }
            else
            {
                isBase = true;
                if (!FromInference)
                    HandleAttributes(ct.Attributes, table, isBase);
                if (ct.Particle != null)
                    HandleParticle(ct.Particle, table, tableChildren, isBase);
                if (FromInference)
                {
                    HandleAttributes(ct.Attributes, table, isBase);
                    if (isNillable) // this is for backward compatibility to support xsi:Nill=true
                        HandleSimpleContentColumn("string", table, isBase, null, isNillable);
                }
            }
 
            _complexTypes.Remove(ct);
        }
 
        internal static XmlSchemaParticle? GetParticle(XmlSchemaComplexType ct)
        {
            if (ct.ContentModel != null)
            {
                if (ct.ContentModel is XmlSchemaComplexContent)
                {
                    XmlSchemaAnnotated cContent = ((XmlSchemaComplexContent)(ct.ContentModel)).Content!;
                    if (cContent is XmlSchemaComplexContentExtension)
                    {
                        return ((XmlSchemaComplexContentExtension)cContent).Particle;
                    }
                    else
                    {
                        Debug.Assert(cContent is XmlSchemaComplexContentRestriction, "Expected complexContent extension or restriction");
                        return ((XmlSchemaComplexContentRestriction)cContent).Particle;
                    }
                }
                else
                {
                    Debug.Assert(ct.ContentModel is XmlSchemaSimpleContent, "expected simpleContent or complexContent");
                    return null;
                }
            }
            else
            {
                return ct.Particle;
            }
        }
 
        internal static DataColumn FindField(DataTable table, string field)
        {
            bool attribute = false;
            string colName = field;
 
            if (field.StartsWith('@'))
            {
                attribute = true;
                colName = field.Substring(1);
            }
 
            string[] split = colName.Split(':');
            colName = split[split.Length - 1];
 
            colName = XmlConvert.DecodeName(colName);
            DataColumn? col = table.Columns[colName];
            if (col == null)
                throw ExceptionBuilder.InvalidField(field);
 
            bool _attribute = (col.ColumnMapping == MappingType.Attribute) || (col.ColumnMapping == MappingType.Hidden);
 
            if (_attribute != attribute)
                throw ExceptionBuilder.InvalidField(field);
 
            return col;
        }
 
        internal static DataColumn[] BuildKey(XmlSchemaIdentityConstraint keyNode, DataTable table)
        {
            ArrayList keyColumns = new ArrayList();
 
            foreach (XmlSchemaXPath node in keyNode.Fields)
            {
                keyColumns.Add(FindField(table, node.XPath!));
            }
 
            DataColumn[] key = new DataColumn[keyColumns.Count];
            keyColumns.CopyTo(key, 0);
 
            return key;
        }
 
        internal static bool GetBooleanAttribute(XmlSchemaAnnotated element, string attrName, bool defVal)
        {
            string? value = GetMsdataAttribute(element, attrName);
            if (string.IsNullOrEmpty(value))
            {
                return defVal;
            }
            if ((value == Keywords.TRUE) || (value == Keywords.ONE_DIGIT))
            {
                return true;
            }
            if ((value == Keywords.FALSE) || (value == Keywords.ZERO_DIGIT))
            {
                return false;
            }
            // Error processing:
            throw ExceptionBuilder.InvalidAttributeValue(attrName, value);
        }
 
        internal static string GetStringAttribute(XmlSchemaAnnotated element, string attrName, string defVal)
        {
            string? value = GetMsdataAttribute(element, attrName);
            if (string.IsNullOrEmpty(value))
            {
                return defVal;
            }
            return value;
        }
 
        /*
        <key name="fk">
            <selector>../Customers</selector>
            <field>ID</field>
        </key>
        <keyref refer="fk">
            <selector>.</selector>
            <field>CustID</field>
        </keyref>
        */
 
        internal static AcceptRejectRule TranslateAcceptRejectRule(string? strRule)
        {
            if (strRule == "Cascade")
                return AcceptRejectRule.Cascade;
            else if (strRule == "None")
                return AcceptRejectRule.None;
            else
                return ForeignKeyConstraint.AcceptRejectRule_Default;
        }
 
        internal static Rule TranslateRule(string strRule)
        {
            if (strRule == "Cascade")
                return Rule.Cascade;
            else if (strRule == "None")
                return Rule.None;
            else if (strRule == "SetDefault")
                return Rule.SetDefault;
            else if (strRule == "SetNull")
                return Rule.SetNull;
            else
                return ForeignKeyConstraint.Rule_Default;
        }
 
        [RequiresUnreferencedCode(DataSet.RequiresUnreferencedCodeMessage)]
        internal void HandleKeyref(XmlSchemaKeyref keyref)
        {
            string refer = XmlConvert.DecodeName(keyref.Refer.Name); // check here!!!
            string name = XmlConvert.DecodeName(keyref.Name)!;
            name = GetStringAttribute(keyref, "ConstraintName", /*default:*/ name);
 
            // we do not process key defined outside the current node
 
            string tableName = GetTableName(keyref);
 
            string? tableNs = GetMsdataAttribute(keyref, Keywords.MSD_TABLENS);
 
            DataTable? table = _ds!.Tables.GetTableSmart(tableName, tableNs);
 
            if (table == null)
                return;
 
            if (string.IsNullOrEmpty(refer))
                throw ExceptionBuilder.MissingRefer(name);
 
            ConstraintTable? key = (ConstraintTable?)_constraintNodes![refer];
 
            if (key == null)
            {
                throw ExceptionBuilder.InvalidKey(name);
            }
 
            DataColumn[] pKey = BuildKey(key.constraint, key.table);
            DataColumn[] fKey = BuildKey(keyref, table);
 
            ForeignKeyConstraint? fkc = null;
 
            if (GetBooleanAttribute(keyref, Keywords.MSD_CONSTRAINTONLY,  /*default:*/ false))
            {
                int iExisting = fKey[0].Table!.Constraints.InternalIndexOf(name);
                if (iExisting > -1)
                {
                    if (fKey[0].Table!.Constraints[iExisting].ConstraintName != name)
                        iExisting = -1;
                }
 
                if (iExisting < 0)
                {
                    fkc = new ForeignKeyConstraint(name, pKey, fKey);
                    fKey[0].Table!.Constraints.Add(fkc);
                }
            }
            else
            {
                string relName = XmlConvert.DecodeName(GetStringAttribute(keyref, Keywords.MSD_RELATIONNAME, keyref.Name!));
 
                if (string.IsNullOrEmpty(relName))
                    relName = name;
 
                int iExisting = fKey[0].Table!.DataSet!.Relations.InternalIndexOf(relName);
                if (iExisting > -1)
                {
                    if (fKey[0].Table!.DataSet!.Relations[iExisting].RelationName != relName)
                        iExisting = -1;
                }
                DataRelation? relation;
                if (iExisting < 0)
                {
                    relation = new DataRelation(relName, pKey, fKey);
                    SetExtProperties(relation, keyref.UnhandledAttributes);
                    pKey[0].Table!.DataSet!.Relations.Add(relation);
 
                    if (FromInference && relation.Nested)
                    {
                        if (_tableDictionary!.TryGetValue(relation.ParentTable, out List<DataTable>? value))
                        {
                            value.Add(relation.ChildTable);
                        }
                    }
 
                    fkc = relation.ChildKeyConstraint!;
                    fkc.ConstraintName = name;
                }
                else
                {
                    relation = fKey[0].Table!.DataSet!.Relations[iExisting];
                }
                if (GetBooleanAttribute(keyref, Keywords.MSD_ISNESTED,  /*default:*/ false))
                {
                    relation.Nested = true;
                }
            }
 
            string? acceptRejectRule = GetMsdataAttribute(keyref, Keywords.MSD_ACCEPTREJECTRULE);
            string? updateRule = GetMsdataAttribute(keyref, Keywords.MSD_UPDATERULE);
            string? deleteRule = GetMsdataAttribute(keyref, Keywords.MSD_DELETERULE);
 
            if (fkc != null)
            {
                if (acceptRejectRule != null)
                    fkc.AcceptRejectRule = TranslateAcceptRejectRule(acceptRejectRule);
 
                if (updateRule != null)
                    fkc.UpdateRule = TranslateRule(updateRule);
 
                if (deleteRule != null)
                    fkc.DeleteRule = TranslateRule(deleteRule);
 
                SetExtProperties(fkc, keyref.UnhandledAttributes);
            }
        }
 
        [RequiresUnreferencedCode(DataSet.RequiresUnreferencedCodeMessage)]
        internal void HandleConstraint(XmlSchemaIdentityConstraint keyNode)
        {
            string? name;
 
            name = XmlConvert.DecodeName(keyNode.Name);
            if (string.IsNullOrEmpty(name))
                throw ExceptionBuilder.MissingAttribute(Keywords.NAME);
 
            if (_constraintNodes!.ContainsKey(name))
                throw ExceptionBuilder.DuplicateConstraintRead(name);
 
            // we do not process key defined outside the current node
            string tableName = GetTableName(keyNode);
            string? tableNs = GetMsdataAttribute(keyNode, Keywords.MSD_TABLENS);
 
            DataTable? table = _ds!.Tables.GetTableSmart(tableName, tableNs);
 
            if (table == null)
                return;
 
            _constraintNodes.Add(name, new ConstraintTable(table, keyNode));
 
            bool fPrimaryKey = GetBooleanAttribute(keyNode, Keywords.MSD_PRIMARYKEY,  /*default:*/ false);
            name = GetStringAttribute(keyNode, "ConstraintName", /*default:*/ name);
 
 
 
            DataColumn[] key = BuildKey(keyNode, table);
 
            if (0 < key.Length)
            {
                UniqueConstraint? found = (UniqueConstraint?)key[0].Table!.Constraints.FindConstraint(new UniqueConstraint(name, key));
 
                if (found == null)
                {
                    key[0].Table!.Constraints.Add(name, key, fPrimaryKey);
                    SetExtProperties(key[0].Table!.Constraints[name]!, keyNode.UnhandledAttributes);
                }
                else
                {
                    key = found.ColumnsReference;
                    SetExtProperties(found, keyNode.UnhandledAttributes);
                    if (fPrimaryKey)
                        key[0].Table!.PrimaryKey = key;
                }
                if (keyNode is XmlSchemaKey)
                {
                    for (int i = 0; i < key.Length; i++)
                        key[i].AllowDBNull = false;
                }
            }
        }
 
        [RequiresUnreferencedCode(DataSet.RequiresUnreferencedCodeMessage)]
        [RequiresDynamicCode(DataSet.RequiresDynamicCodeMessage)]
        internal DataTable InstantiateSimpleTable(XmlSchemaElement node)
        {
            DataTable? table;
            string typeName = XmlConvert.DecodeName(GetInstanceName(node));
            string _TableUri;
 
            _TableUri = node.QualifiedName.Namespace;
            table = _ds!.Tables.GetTable(typeName, _TableUri);
 
            if (!FromInference && table != null)
            {
                throw ExceptionBuilder.DuplicateDeclaration(typeName);
            }
 
            if (table == null)
            {
                table = new DataTable(typeName);
                table.Namespace = _TableUri;
                // If msdata:targetNamespace node on element, then use it to override table.Namespace.
                table.Namespace = GetStringAttribute(node, "targetNamespace", _TableUri);
 
                if (!FromInference)
                {
                    table.MinOccurs = node.MinOccurs;
                    table.MaxOccurs = node.MaxOccurs;
                }
                else
                {
                    string? prefix = GetPrefix(_TableUri);
                    if (prefix != null)
                        table.Prefix = prefix;
                }
 
                SetProperties(table, node.UnhandledAttributes);
                SetExtProperties(table, node.UnhandledAttributes);
            }
 
 
            XmlSchemaComplexType? ct = node.SchemaType as XmlSchemaComplexType;
            // We assume node.ElementSchemaType.BaseSchemaType to be null for
            //  <xs:element name="foo"/> and not null for <xs:element name="foo" type="xs:string"/>
            bool isSimpleContent = ((node.ElementSchemaType!.BaseXmlSchemaType != null) || (ct != null && ct.ContentModel is XmlSchemaSimpleContent));
 
            if (!FromInference || (isSimpleContent && table.Columns.Count == 0))
            {// for inference backward compatibility
                HandleElementColumn(node, table, false);
                string colName;
 
                if (FromInference)
                {
                    int i = 0;
                    colName = typeName + "_Text";
                    while (table.Columns[colName] != null)
                        colName += i++;
                }
                else
                {
                    colName = typeName + "_Column";
                }
 
                table.Columns[0].ColumnName = colName;
                table.Columns[0].ColumnMapping = MappingType.SimpleContent;
            }
 
            if (!FromInference || _ds.Tables.GetTable(typeName, _TableUri) == null)
            { // for inference; special case: add table if does not exists in collection
                _ds.Tables.Add(table);
                if (FromInference)
                {
                    _tableDictionary!.Add(table, new List<DataTable>());
                }
            }
 
            // handle all the unique and key constraints related to this table
 
            if ((_dsElement != null) && (_dsElement.Constraints != null))
            {
                foreach (XmlSchemaIdentityConstraint key in _dsElement.Constraints)
                {
                    if (key is XmlSchemaKeyref)
                        continue;
                    if (GetTableName(key) == table.TableName)
                        HandleConstraint(key);
                }
            }
            table._fNestedInDataset = false;
 
            return (table);
        }
 
 
        internal static string GetInstanceName(XmlSchemaAnnotated node)
        {
            string? instanceName = null;
 
            Debug.Assert((node is XmlSchemaElement) || (node is XmlSchemaAttribute), "GetInstanceName should only be called on attribute or elements");
 
            if (node is XmlSchemaElement el)
            {
                instanceName = el.Name ?? el.RefName.Name;
            }
            else if (node is XmlSchemaAttribute attr)
            {
                instanceName = attr.Name ?? attr.RefName.Name;
            }
 
            Debug.Assert((instanceName != null) && (instanceName.Length != 0), "instanceName cannot be null or empty. There's an error in the XSD compiler");
 
            return instanceName;
        }
 
        // Sequences of handling Elements, Attributes and Text-only column should be the same as in InferXmlSchema
        [RequiresUnreferencedCode(DataSet.RequiresUnreferencedCodeMessage)]
        [RequiresDynamicCode(DataSet.RequiresDynamicCodeMessage)]
        internal DataTable InstantiateTable(XmlSchemaElement node, XmlSchemaComplexType typeNode, bool isRef)
        {
            DataTable? table;
            string typeName = GetInstanceName(node);
            ArrayList tableChildren = new ArrayList();
 
            string _TableUri;
 
            _TableUri = node.QualifiedName.Namespace;
 
            table = _ds!.Tables.GetTable(XmlConvert.DecodeName(typeName), _TableUri);
            // TOD: Do not do this fix
            //            if (table == null && node.RefName.IsEmpty && !IsTopLevelElement(node) && _TableUri != null && _TableUri.Length > 0) {
            //                _TableUri = null;    // it means form="qualified", so child element inherits namespace. amirhmy
            //            }
 
            if (!FromInference || (FromInference && table == null))
            {
                if (table != null)
                {
                    if (isRef)
                        return table;
                    else
                        throw ExceptionBuilder.DuplicateDeclaration(typeName);
                }
 
                if (isRef)
                    _refTables!.Add(_TableUri + ":" + typeName);
 
                table = new DataTable(XmlConvert.DecodeName(typeName));
                table.TypeName = node.SchemaTypeName;
 
                table.Namespace = _TableUri;
                table.Namespace = GetStringAttribute(node, "targetNamespace", _TableUri);
 
                //table.Prefix = node.Prefix;
                string? value = GetStringAttribute(typeNode, Keywords.MSD_CASESENSITIVE, "");
                if (value.Length == 0)
                {
                    value = GetStringAttribute(node, Keywords.MSD_CASESENSITIVE, "");
                }
                if (0 < value.Length)
                {
                    if ((value == Keywords.TRUE) || (value == "True"))
                        table.CaseSensitive = true;
                    if ((value == Keywords.FALSE) || (value == "False"))
                        table.CaseSensitive = false;
                }
 
                value = GetMsdataAttribute(node, Keywords.MSD_LOCALE);
                if (null != value)
                { // set by user
                    if (0 < value.Length)
                    {
                        // <... msdata:Locale="en-US"/>
                        table.Locale = new CultureInfo(value);
                    }
                    else
                    {
                        table.Locale = CultureInfo.InvariantCulture;
                    }
                }
 
                // else inherit from DataSet, not set by user
 
                if (!FromInference)
                {
                    table.MinOccurs = node.MinOccurs;
                    table.MaxOccurs = node.MaxOccurs;
                }
                else
                {
                    string? prefix = GetPrefix(_TableUri);
                    if (prefix != null)
                        table.Prefix = prefix;
                }
 
                _ds.Tables.Add(table);
                if (FromInference)
                {
                    _tableDictionary!.Add(table, new List<DataTable>());
                }
            }
 
            HandleComplexType(typeNode, table!, tableChildren, node.IsNillable);
 
            for (int i = 0; i < table!.Columns.Count; i++)
                table.Columns[i].SetOrdinalInternal(i);
 
            /*
                        if (xmlContent == XmlContent.Mixed) {
                            string textColumn = GenUniqueColumnName(table.TableName+ "_Text", table);
                            table.XmlText = new DataColumn(textColumn, typeof(string), null, MappingType.Text);
                        } */
 
            SetProperties(table, node.UnhandledAttributes);
            SetExtProperties(table, node.UnhandledAttributes);
 
            // handle all the unique and key constraints related to this table
            if ((_dsElement != null) && (_dsElement.Constraints != null))
            {
                foreach (XmlSchemaIdentityConstraint key in _dsElement.Constraints)
                {
                    if (key is XmlSchemaKeyref)
                        continue;
                    if (GetTableName(key) == table.TableName)
                    {
                        // respect the NS if it is specified for key, otherwise just go with table name check
                        if (GetTableNamespace(key) == table.Namespace || GetTableNamespace(key) == null)
                            HandleConstraint(key);
                        /*                     if (GetTableNamespace(key) != null) {
                                                    if (GetTableNamespace(key) == table.Namespace)
                                                        HandleConstraint(key);
                                                }
                                                else {
                                                    HandleConstraint(key);
                                                }
                        */
                    }
                }
            }
 
            foreach (DataTable _tableChild in tableChildren)
            {
                if (_tableChild != table && table.Namespace == _tableChild.Namespace)
                    _tableChild._tableNamespace = null;
 
                if ((_dsElement != null) && (_dsElement.Constraints != null))
                {
                    foreach (XmlSchemaIdentityConstraint key in _dsElement.Constraints)
                    {
                        XmlSchemaKeyref? keyref = key as XmlSchemaKeyref;
                        if (keyref == null)
                            continue;
 
                        bool isNested = GetBooleanAttribute(keyref, Keywords.MSD_ISNESTED,  /*default:*/ false);
                        if (!isNested)
                            continue;
                        if (GetTableName(keyref) == _tableChild.TableName)
                        {
                            if (_tableChild.DataSet!.Tables.InternalIndexOf(_tableChild.TableName) < -1)
                            { // if we have multiple tables with the same name
                                if (GetTableNamespace(keyref) == _tableChild.Namespace)
                                {
                                    HandleKeyref(keyref);
                                }
                            }
                            else
                            {
                                HandleKeyref(keyref);
                            }
                        }
                    }
                }
 
                DataRelation? relation = null;
 
                DataRelationCollection childRelations = table.ChildRelations;
                for (int j = 0; j < childRelations.Count; j++)
                {
                    if (!childRelations[j].Nested)
                        continue;
 
                    if (_tableChild == childRelations[j].ChildTable)
                        relation = childRelations[j];
                }
 
                if (relation != null)
                    continue;
 
                DataColumn parentKey;
                if (FromInference)
                {
                    int position = table.UKColumnPositionForInference; // we keep posiotion of unique key column here, for inference
                    if (position == -1)
                        foreach (DataColumn dc in table.Columns)
                        {
                            if (dc.ColumnMapping == MappingType.Attribute)
                            {
                                position = dc.Ordinal;
                                break;
                            }
                        }
                    parentKey = table.AddUniqueKey(position);
                }
                else
                {
                    parentKey = table.AddUniqueKey();
                }
 
                // foreign key in the child table
                DataColumn childKey = _tableChild.AddForeignKey(parentKey);
 
                // when we add  unique key, we do set prefix; but for Fk we do not do . So for backward compatibility
                if (FromInference)
                    childKey.Prefix = _tableChild.Prefix;
                //                    childKey.Prefix = GetPrefix(childKey.Namespace);
 
                // create relationship
                // setup relationship between parent and this table
                relation = new DataRelation(table.TableName + "_" + _tableChild.TableName, parentKey, childKey, true);
                relation.Nested = true;
                _tableChild.DataSet!.Relations.Add(relation);
                if (FromInference && relation.Nested)
                {
                    if (_tableDictionary!.TryGetValue(relation.ParentTable, out List<DataTable>? value))
                    {
                        value.Add(relation.ChildTable);
                    }
                }
            }
 
            return table;
        }
 
        private sealed class NameType : IComparable
        {
            public readonly string name;
            [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.PublicFields)]
            public readonly Type type;
            public NameType(string n, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.PublicFields)] Type t)
            {
                name = n;
                type = t;
            }
            public int CompareTo(object? obj) { return string.Compare(name, (string?)obj, StringComparison.Ordinal); }
        };
 
        public static Type XsdtoClr(string xsdTypeName)
        {
#if DEBUG
            for (int i = 1; i < s_mapNameTypeXsd.Length; ++i)
            {
                Debug.Assert((s_mapNameTypeXsd[i - 1].CompareTo(s_mapNameTypeXsd[i].name)) < 0, $"incorrect sorting {s_mapNameTypeXsd[i].name}");
            }
#endif
            int index = Array.BinarySearch(s_mapNameTypeXsd, xsdTypeName);
            if (index < 0)
            {
                throw ExceptionBuilder.UndefinedDatatype(xsdTypeName);
            }
            return s_mapNameTypeXsd[index].type;
        }
 
        // XSD spec: http://www.w3.org/TR/xmlschema-2/
        //    April: http://www.w3.org/TR/2000/WD-xmlschema-2-20000407/datatypes.html
        //    Fabr:  http://www.w3.org/TR/2000/WD-xmlschema-2-20000225/
        private static readonly NameType[] s_mapNameTypeXsd = {
            new NameType("ENTITIES",           typeof(string)     ), /* XSD Apr */
            new NameType("ENTITY",             typeof(string)     ), /* XSD Apr */
            new NameType("ID",                 typeof(string)     ), /* XSD Apr */
            new NameType("IDREF",              typeof(string)     ), /* XSD Apr */
            new NameType("IDREFS",             typeof(string)     ), /* XSD Apr */
            new NameType("NCName",             typeof(string)     ), /* XSD Apr */
            new NameType("NMTOKEN",            typeof(string)     ), /* XSD Apr */
            new NameType("NMTOKENS",           typeof(string)     ), /* XSD Apr */
            new NameType("NOTATION",           typeof(string)     ), /* XSD Apr */
            new NameType("Name",               typeof(string)     ), /* XSD Apr */
            new NameType("QName",              typeof(string)     ), /* XSD Apr */
            new NameType("anyType",            typeof(object)     ), /* XSD Apr */
            new NameType("anyURI",             typeof(System.Uri) ), /* XSD Apr */
            new NameType("base64Binary",       typeof(byte[])     ), /* XSD Apr : abstruct */
            new NameType("boolean",            typeof(bool)       ), /* XSD Apr */
            new NameType("byte",               typeof(sbyte)      ), /* XSD Apr */
            new NameType("date",               typeof(DateTime)   ), /* XSD Apr */
            new NameType("dateTime",           typeof(DateTime)   ), /* XSD Apr */
            new NameType("decimal",            typeof(decimal)    ), /* XSD 2001 March */
            new NameType("double",             typeof(double)     ), /* XSD Apr */
            new NameType("duration",           typeof(TimeSpan)   ), /* XSD Apr */
            new NameType("float",              typeof(float)      ), /* XSD Apr */
            new NameType("gDay",               typeof(DateTime)   ), /* XSD Apr */
            new NameType("gMonth",             typeof(DateTime)   ), /* XSD Apr */
            new NameType("gMonthDay",          typeof(DateTime)   ), /* XSD Apr */
            new NameType("gYear",              typeof(DateTime)   ), /* XSD Apr */
            new NameType("gYearMonth",         typeof(DateTime)   ), /* XSD Apr */
            new NameType("hexBinary",          typeof(byte[])     ), /* XSD Apr : abstruct */
            new NameType("int",                typeof(int)        ), /* XSD Apr */
            new NameType("integer",            typeof(long)       ), /* XSD Apr */ // <xs:element name="" msdata:DataType="System.Numerics.BigInteger" type="xs:integer" minOccurs="0" />
            new NameType("language",           typeof(string)     ), /* XSD Apr */
            new NameType("long",               typeof(long)       ), /* XSD Apr */
            new NameType("negativeInteger",    typeof(long)       ), /* XSD Apr */
            new NameType("nonNegativeInteger", typeof(ulong)      ), /* XSD Apr */
            new NameType("nonPositiveInteger", typeof(long)       ), /* XSD Apr */
            new NameType("normalizedString",   typeof(string)     ), /* XSD Apr */
            new NameType("positiveInteger",    typeof(ulong)      ), /* XSD Apr */
            new NameType("short",              typeof(short)      ), /* XSD Apr */
            new NameType("string",             typeof(string)     ), /* XSD Apr */
            new NameType("time",               typeof(DateTime)   ), /* XSD Apr */
            new NameType("unsignedByte",       typeof(byte)       ), /* XSD Apr */
            new NameType("unsignedInt",        typeof(uint)       ), /* XSD Apr */
            new NameType("unsignedLong",       typeof(ulong)      ), /* XSD Apr */
            new NameType("unsignedShort",      typeof(ushort)     ), /* XSD Apr */
        };
 
        private static NameType FindNameType(string name)
        {
#if DEBUG
            for (int i = 1; i < s_mapNameTypeXsd.Length; ++i)
            {
                Debug.Assert((s_mapNameTypeXsd[i - 1].CompareTo(s_mapNameTypeXsd[i].name)) < 0, $"incorrect sorting {s_mapNameTypeXsd[i].name}");
            }
#endif
            int index = Array.BinarySearch(s_mapNameTypeXsd, name);
            if (index < 0)
            {
                throw ExceptionBuilder.UndefinedDatatype(name);
            }
            return s_mapNameTypeXsd[index];
        }
 
        // input param dt is a "qName" for UDSimpleType else it assumes it's a XSD builtin simpleType
        [return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)]
        private Type ParseDataType(string dt)
        {
            if (!IsXsdType(dt))
            {
                if (_udSimpleTypes != null)
                {
                    XmlSchemaSimpleType? simpleType = (XmlSchemaSimpleType?)_udSimpleTypes[dt];
                    if (simpleType == null)
                    { // it is not named simple type, it is not  XSD type, it should be unsupported type like xs:token
                        throw ExceptionBuilder.UndefinedDatatype(dt);
                    }
                    SimpleType rootType = new SimpleType(simpleType);
                    while (rootType.BaseSimpleType != null)
                    {
                        rootType = rootType.BaseSimpleType;
                    }
 
                    return ParseDataType(rootType.BaseType!);
                }
            }
            NameType nt = FindNameType(dt);
            return nt.type;
        }
        /*  later we may need such a function
                private Boolean IsUDSimpleType(string qname) {
                    if (udSimpleTypes == null)
                        return false;
                    return (udSimpleTypes.Contains(qname));
                }
        */
        internal static bool IsXsdType(string name)
        {
#if DEBUG
            for (int i = 1; i < s_mapNameTypeXsd.Length; ++i)
            {
                Debug.Assert((s_mapNameTypeXsd[i - 1].CompareTo(s_mapNameTypeXsd[i].name)) < 0, $"incorrect sorting {s_mapNameTypeXsd[i].name}");
            }
#endif
            int index = Array.BinarySearch(s_mapNameTypeXsd, name);
            if (index < 0)
            {
#if DEBUG
                // Let's check that we really don't have this name:
                foreach (NameType nt in s_mapNameTypeXsd)
                {
                    Debug.Assert(nt.name != name, $"FindNameType('{name}') -- failed. Existed name not found");
                }
#endif
                return false;
            }
            Debug.Assert(s_mapNameTypeXsd[index].name == name, $"FindNameType('{name}') -- failed. Wrong name found");
            return true;
        }
 
 
        internal XmlSchemaAnnotated? FindTypeNode(XmlSchemaAnnotated node)
        {
            // this function is returning null
            // if the typeNode for node is in the XSD namespace.
 
            XmlSchemaAttribute? attr = node as XmlSchemaAttribute;
            XmlSchemaElement? el = node as XmlSchemaElement;
            bool isAttr = false;
            if (attr != null)
            {
                isAttr = true;
            }
 
            string _type = isAttr ? attr!.SchemaTypeName.Name : el!.SchemaTypeName.Name;
            string _typeNs = isAttr ? attr!.SchemaTypeName.Namespace : el!.SchemaTypeName.Namespace;
            if (_typeNs == Keywords.XSDNS)
                return null;
            XmlSchemaAnnotated? typeNode;
            if (string.IsNullOrEmpty(_type))
            {
                _type = isAttr ? attr!.RefName.Name : el!.RefName.Name;
                if (string.IsNullOrEmpty(_type))
                    typeNode = isAttr ? attr!.SchemaType : el!.SchemaType;
                else
                    typeNode = isAttr ? FindTypeNode((XmlSchemaAnnotated)_attributes![attr!.RefName]!) : FindTypeNode((XmlSchemaAnnotated)_elementsTable![el!.RefName]!);
            }
            else
                typeNode = (XmlSchemaAnnotated?)_schemaTypes![isAttr ? ((XmlSchemaAttribute)node).SchemaTypeName : ((XmlSchemaElement)node).SchemaTypeName];
            return typeNode;
        }
 
        [RequiresUnreferencedCode(DataSet.RequiresUnreferencedCodeMessage)]
        [RequiresDynamicCode(DataSet.RequiresDynamicCodeMessage)]
        internal void HandleSimpleTypeSimpleContentColumn(XmlSchemaSimpleType typeNode, string strType, DataTable table, bool isBase, XmlAttribute[]? attrs, bool isNillable)
        {
            // disallow multiple simple content columns for the table
            if (FromInference && table.XmlText != null)
            { // backward compatibility for inference
                return;
            }
 
            Type? type;
            SimpleType? xsdType = null;
 
            //            if (typeNode.QualifiedName.Namespace != Keywords.XSDNS) { // this means UDSimpleType
            if (!string.IsNullOrEmpty(typeNode.QualifiedName.Name) && typeNode.QualifiedName.Namespace != Keywords.XSDNS)
            { // this means UDSimpleType
                xsdType = new SimpleType(typeNode);
                strType = typeNode.QualifiedName.ToString(); // use qualified name
                type = ParseDataType(typeNode.QualifiedName.ToString());
            }
            else
            {// previous code V 1.1
                XmlSchemaSimpleType? ancestor = typeNode.BaseXmlSchemaType as XmlSchemaSimpleType;
                if ((ancestor != null) && (ancestor.QualifiedName.Namespace != Keywords.XSDNS))
                {
                    xsdType = new SimpleType(typeNode);
                    SimpleType rootType = xsdType;
 
                    while (rootType.BaseSimpleType != null)
                    {
                        rootType = rootType.BaseSimpleType;
                    }
                    type = ParseDataType(rootType.BaseType!);
                    strType = xsdType.Name!;
                }
                else
                {
                    type = ParseDataType(strType);
                }
            }
 
 
            DataColumn column;
 
            string colName;
            if (FromInference)
            {
                int i = 0;
                colName = table.TableName + "_Text";
                while (table.Columns[colName] != null)
                {
                    colName += i++;
                }
            }
            else
                colName = table.TableName + "_text";
 
            string columnName = colName;
            bool isToAdd = true;
            if ((!isBase) && (table.Columns.Contains(columnName, true)))
            {
                column = table.Columns[columnName]!;
                isToAdd = false;
            }
            else
            {
                column = new DataColumn(columnName, type, null, MappingType.SimpleContent);
            }
 
            SetProperties(column, attrs);
            HandleColumnExpression(column, attrs);
            SetExtProperties(column, attrs);
 
            string tmp = (-1).ToString(CultureInfo.CurrentCulture);
            string? defValue = null;
            //try to see if attributes contain allownull
            column.AllowDBNull = isNillable;
 
            if (attrs != null)
                for (int i = 0; i < attrs.Length; i++)
                {
                    if (attrs[i].LocalName == Keywords.MSD_ALLOWDBNULL && attrs[i].NamespaceURI == Keywords.MSDNS)
                        if (attrs[i].Value == Keywords.FALSE)
                            column.AllowDBNull = false;
                    if (attrs[i].LocalName == Keywords.MSD_ORDINAL && attrs[i].NamespaceURI == Keywords.MSDNS)
                        tmp = attrs[i].Value;
                    if (attrs[i].LocalName == Keywords.MSD_DEFAULTVALUE && attrs[i].NamespaceURI == Keywords.MSDNS)
                        defValue = attrs[i].Value;
                }
            int ordinal = (int)Convert.ChangeType(tmp, typeof(int), null);
 
 
            //SetExtProperties(column, attr.UnhandledAttributes);
 
            if ((column.Expression != null) && (column.Expression.Length != 0))
            {
                _columnExpressions!.Add(column);
            }
 
            // Update XSD type to point to simple types actual namespace instead of normalized default namespace in case of remoting
            if (xsdType != null && xsdType.Name != null && xsdType.Name.Length > 0)
            {
                if (XSDSchema.GetMsdataAttribute(typeNode, Keywords.TARGETNAMESPACE) != null)
                {
                    column.XmlDataType = xsdType.SimpleTypeQualifiedName;
                }
            }
            else
            {
                column.XmlDataType = strType;
            }
            column.SimpleType = xsdType;
 
            //column.Namespace = typeNode.SourceUri;
            if (isToAdd)
            {
                if (FromInference)
                {
                    column.Prefix = GetPrefix(table.Namespace);
                    column.AllowDBNull = true;
                }
                if (ordinal > -1 && ordinal < table.Columns.Count)
                    table.Columns.AddAt(ordinal, column);
                else
                    table.Columns.Add(column);
            }
 
            if (defValue != null)
                try
                {
                    column.DefaultValue = column.ConvertXmlToObject(defValue);
                }
                catch (System.FormatException)
                {
                    throw ExceptionBuilder.CannotConvert(defValue, type.FullName);
                }
        }
 
        [RequiresUnreferencedCode(DataSet.RequiresUnreferencedCodeMessage)]
        [RequiresDynamicCode(DataSet.RequiresDynamicCodeMessage)]
        internal void HandleSimpleContentColumn(string strType, DataTable table, bool isBase, XmlAttribute[]? attrs, bool isNillable)
        {
            // for Named Simple type support : We should not received anything here other than string.
            // there can not be typed simple content
            // disallow multiple simple content columns for the table
            if (FromInference && table.XmlText != null) // backward compatibility for inference
                return;
 
            Type? type;
            if (strType == null)
            {
                return;
            }
            type = ParseDataType(strType); // we pass it correctly when we call the method, no need to special check.
            DataColumn column;
 
 
            string colName;
            if (FromInference)
            {
                int i = 0;
                colName = table.TableName + "_Text";
                while (table.Columns[colName] != null)
                {
                    colName += i++;
                }
            }
            else
                colName = table.TableName + "_text";
 
            string columnName = colName;
            bool isToAdd = true;
 
            if ((!isBase) && (table.Columns.Contains(columnName, true)))
            {
                column = table.Columns[columnName]!;
                isToAdd = false;
            }
            else
            {
                column = new DataColumn(columnName, type, null, MappingType.SimpleContent);
            }
 
            SetProperties(column, attrs);
            HandleColumnExpression(column, attrs);
            SetExtProperties(column, attrs);
 
            string tmp = (-1).ToString(CultureInfo.CurrentCulture);
            string? defValue = null;
            //try to see if attributes contain allownull
            column.AllowDBNull = isNillable;
 
            if (attrs != null)
                for (int i = 0; i < attrs.Length; i++)
                {
                    if (attrs[i].LocalName == Keywords.MSD_ALLOWDBNULL && attrs[i].NamespaceURI == Keywords.MSDNS)
                        if (attrs[i].Value == Keywords.FALSE)
                            column.AllowDBNull = false;
                    if (attrs[i].LocalName == Keywords.MSD_ORDINAL && attrs[i].NamespaceURI == Keywords.MSDNS)
                        tmp = attrs[i].Value;
                    if (attrs[i].LocalName == Keywords.MSD_DEFAULTVALUE && attrs[i].NamespaceURI == Keywords.MSDNS)
                        defValue = attrs[i].Value;
                }
            int ordinal = (int)Convert.ChangeType(tmp, typeof(int), null);
 
 
            //SetExtProperties(column, attr.UnhandledAttributes);
 
            if ((column.Expression != null) && (column.Expression.Length != 0))
            {
                _columnExpressions!.Add(column);
            }
 
            column.XmlDataType = strType;
            column.SimpleType = null;
 
            //column.Namespace = typeNode.SourceUri;
            if (FromInference)
                column.Prefix = GetPrefix(column.Namespace);
            if (isToAdd)
            {
                if (FromInference) // move this setting to SetProperties
                    column.AllowDBNull = true;
                if (ordinal > -1 && ordinal < table.Columns.Count)
                    table.Columns.AddAt(ordinal, column);
                else
                    table.Columns.Add(column);
            }
 
            if (defValue != null)
                try
                {
                    column.DefaultValue = column.ConvertXmlToObject(defValue);
                }
                catch (System.FormatException)
                {
                    throw ExceptionBuilder.CannotConvert(defValue, type.FullName);
                }
        }
 
        [RequiresUnreferencedCode(DataSet.RequiresUnreferencedCodeMessage)]
        [RequiresDynamicCode(DataSet.RequiresDynamicCodeMessage)]
        internal void HandleAttributeColumn(XmlSchemaAttribute attrib, DataTable table, bool isBase)
        {
            Type? type;
            XmlSchemaAttribute? attr = attrib.Name != null ? attrib : (XmlSchemaAttribute)_attributes![attrib.RefName]!;
 
 
            XmlSchemaAnnotated? typeNode = FindTypeNode(attr);
            string? strType;
            SimpleType? xsdType = null;
 
            if (typeNode == null)
            {
                strType = attr.SchemaTypeName.Name;
                if (string.IsNullOrEmpty(strType))
                {
                    strType = string.Empty;
                    type = typeof(string);
                }
                else
                {
                    if (attr.SchemaTypeName.Namespace != Keywords.XSDNS) // it is UD Simple Type, can it be?
                        type = ParseDataType(attr.SchemaTypeName.ToString());
                    else
                        type = ParseDataType(attr.SchemaTypeName.Name);
                }
            }
            else if (typeNode is XmlSchemaSimpleType)
            {
                XmlSchemaSimpleType node = (typeNode as XmlSchemaSimpleType)!;
                xsdType = new SimpleType(node);
                if (!string.IsNullOrEmpty(node.QualifiedName.Name) && node.QualifiedName.Namespace != Keywords.XSDNS)
                {
                    // this means UDSimpleType
                    strType = node.QualifiedName.ToString(); // use qualified name
                    type = ParseDataType(node.QualifiedName.ToString()); // search with QName
                }
                else
                {
                    type = ParseDataType(xsdType.BaseType!);
                    strType = xsdType.Name;
                    if (xsdType.Length == 1 && type == typeof(string))
                    {
                        type = typeof(char);
                    }
                }
            }
            else if (typeNode is XmlSchemaElement)
            {
                strType = ((XmlSchemaElement)typeNode).SchemaTypeName.Name;
                type = ParseDataType(strType);
            }
            else
            {
                if (typeNode.Id == null)
                    throw ExceptionBuilder.DatatypeNotDefined();
                else
                    throw ExceptionBuilder.UndefinedDatatype(typeNode.Id);
            }
 
            DataColumn column;
            string columnName = XmlConvert.DecodeName(GetInstanceName(attr));
            bool isToAdd = true;
 
            if ((!isBase || FromInference) && (table.Columns.Contains(columnName, true)))
            {
                column = table.Columns[columnName]!;
                isToAdd = false;
 
                if (FromInference)
                { // for backward compatibility with old inference
                  // throw eception if same column is being aded with different mapping
                    if (column.ColumnMapping != MappingType.Attribute)
                        throw ExceptionBuilder.ColumnTypeConflict(column.ColumnName);
                    // in previous inference , if we have incoming column with different NS, we think as different column and
                    //while adding , since there is no NS concept for datacolumn, we used to throw exception
                    // simulate the same behavior.
                    if ((string.IsNullOrEmpty(attrib.QualifiedName.Namespace) && string.IsNullOrEmpty(column._columnUri)) || // backward compatibility :SQL BU DT 310912
                        (string.Equals(attrib.QualifiedName.Namespace, column.Namespace, StringComparison.Ordinal)))
                    {
                        return; // backward compatibility
                    }
                    column = new DataColumn(columnName, type, null, MappingType.Attribute); // this is to fix issue with Exception we used to throw for old inference engine if column
                    //exists with different namespace; while adding it to columncollection
                    isToAdd = true;
                }
            }
            else
            {
                column = new DataColumn(columnName, type, null, MappingType.Attribute);
            }
 
            SetProperties(column, attr.UnhandledAttributes);
            HandleColumnExpression(column, attr.UnhandledAttributes);
            SetExtProperties(column, attr.UnhandledAttributes);
 
            if ((column.Expression != null) && (column.Expression.Length != 0))
            {
                _columnExpressions!.Add(column);
            }
 
            if (xsdType != null && xsdType.Name != null && xsdType.Name.Length > 0)
            {
                if (XSDSchema.GetMsdataAttribute(typeNode!, Keywords.TARGETNAMESPACE) != null)
                {
                    column.XmlDataType = xsdType.SimpleTypeQualifiedName;
                }
            }
            else
            {
                column.XmlDataType = strType;
            }
 
            column.SimpleType = xsdType;
 
            column.AllowDBNull = !(attrib.Use == XmlSchemaUse.Required);
            column.Namespace = attrib.QualifiedName.Namespace;
            column.Namespace = GetStringAttribute(attrib, "targetNamespace", column.Namespace);
 
            if (isToAdd)
            {
                if (FromInference)
                { // move this setting to SetProperties
                    column.AllowDBNull = true;
                    column.Prefix = GetPrefix(column.Namespace);
                }
                table.Columns.Add(column);
            }
 
            if (attrib.Use == XmlSchemaUse.Prohibited)
            {
                column.ColumnMapping = MappingType.Hidden;
 
                column.AllowDBNull = GetBooleanAttribute(attr, Keywords.MSD_ALLOWDBNULL, true);
                string? defValue = GetMsdataAttribute(attr, Keywords.MSD_DEFAULTVALUE);
                if (defValue != null)
                    try
                    {
                        column.DefaultValue = column.ConvertXmlToObject(defValue);
                    }
                    catch (System.FormatException)
                    {
                        throw ExceptionBuilder.CannotConvert(defValue, type.FullName);
                    }
            }
 
 
            // XDR March change
            string? strDefault = (attrib.Use == XmlSchemaUse.Required) ? GetMsdataAttribute(attr, Keywords.MSD_DEFAULTVALUE) : attr.DefaultValue;
            if ((attr.Use == XmlSchemaUse.Optional) && (strDefault == null))
                strDefault = attr.FixedValue;
 
            if (strDefault != null)
                try
                {
                    column.DefaultValue = column.ConvertXmlToObject(strDefault);
                }
                catch (System.FormatException)
                {
                    throw ExceptionBuilder.CannotConvert(strDefault, type.FullName);
                }
        }
 
        [RequiresUnreferencedCode(DataSet.RequiresUnreferencedCodeMessage)]
        [RequiresDynamicCode(DataSet.RequiresDynamicCodeMessage)]
        internal void HandleElementColumn(XmlSchemaElement elem, DataTable table, bool isBase)
        {
            Type? type;
            XmlSchemaElement? el = elem.Name != null ? elem : (XmlSchemaElement?)_elementsTable![elem.RefName];
 
            if (el == null) // it's possible due to some XSD compiler optimizations
                return; // do nothing
 
            XmlSchemaAnnotated? typeNode = FindTypeNode(el);
            string? strType = null;
            SimpleType? xsdType = null;
 
            if (typeNode == null)
            {
                strType = el.SchemaTypeName.Name;
                if (string.IsNullOrEmpty(strType))
                {
                    strType = string.Empty;
                    type = typeof(string);
                }
                else
                {
                    type = ParseDataType(el.SchemaTypeName.Name);
                }
            }
            else if (typeNode is XmlSchemaSimpleType)
            {
                XmlSchemaSimpleType? simpleTypeNode = typeNode as XmlSchemaSimpleType;
                xsdType = new SimpleType(simpleTypeNode!);
                // ((XmlSchemaSimpleType)typeNode).Name != null && ((XmlSchemaSimpleType)typeNode).Name.Length != 0 check is for annonymos simple type,
                // it should be  user defined  Named  simple type
                if (!string.IsNullOrEmpty(((XmlSchemaSimpleType)typeNode).Name) && ((XmlSchemaSimpleType)typeNode).QualifiedName.Namespace != Keywords.XSDNS)
                {
                    strType = ((XmlSchemaSimpleType)typeNode).QualifiedName.ToString(); // use qualified name
                    type = ParseDataType(strType);
                }
                else
                {
                    simpleTypeNode = (xsdType.XmlBaseType != null && xsdType.XmlBaseType.Namespace != Keywords.XSDNS) ?
                                                _schemaTypes![xsdType.XmlBaseType] as XmlSchemaSimpleType :
                                                null;
                    while (simpleTypeNode != null)
                    {
                        xsdType.LoadTypeValues(simpleTypeNode);
                        simpleTypeNode = (xsdType.XmlBaseType != null && xsdType.XmlBaseType.Namespace != Keywords.XSDNS) ?
                                                    _schemaTypes![xsdType.XmlBaseType] as XmlSchemaSimpleType :
                                                    null;
                    }
 
                    type = ParseDataType(xsdType.BaseType!);
                    strType = xsdType.Name;
 
                    if (xsdType.Length == 1 && type == typeof(string))
                    {
                        type = typeof(char);
                    }
                }
            }
            else if (typeNode is XmlSchemaElement)
            { // theoratically no named simpletype should come here
                strType = ((XmlSchemaElement)typeNode).SchemaTypeName.Name;
                type = ParseDataType(strType);
            }
            else if (typeNode is XmlSchemaComplexType)
            {
                if (string.IsNullOrEmpty(XSDSchema.GetMsdataAttribute(elem, Keywords.MSD_DATATYPE)))
                {
                    throw ExceptionBuilder.DatatypeNotDefined();
                }
                else
                {
                    type = typeof(object);
                }
            }
            else
            {
                if (typeNode.Id == null)
                    throw ExceptionBuilder.DatatypeNotDefined();
                else
                    throw ExceptionBuilder.UndefinedDatatype(typeNode.Id);
            }
 
            DataColumn column;
            string columnName = XmlConvert.DecodeName(GetInstanceName(el));
            bool isToAdd = true;
 
            if (((!isBase) || FromInference) && (table.Columns.Contains(columnName, true)))
            {
                column = table.Columns[columnName]!;
                isToAdd = false;
 
                if (FromInference)
                { // for backward compatibility with old inference
                    if (column.ColumnMapping != MappingType.Element)
                        throw ExceptionBuilder.ColumnTypeConflict(column.ColumnName);
                    // in previous inference , if we have incoming column with different NS, we think as different column and
                    //while adding , since there is no NS concept for datacolumn, we used to throw exception
                    // simulate the same behavior.
                    if ((string.IsNullOrEmpty(elem.QualifiedName.Namespace) && string.IsNullOrEmpty(column._columnUri)) || // backward compatibility :SQL BU DT 310912
                        (string.Equals(elem.QualifiedName.Namespace, column.Namespace, StringComparison.Ordinal)))
                    {
                        return; // backward compatibility
                    }
                    column = new DataColumn(columnName, type, null, MappingType.Element); // this is to fix issue with Exception we used to throw for old inference engine if column
                    //exists with different namespace; while adding it to columncollection
                    isToAdd = true;
                }
            }
            else
            {
                column = new DataColumn(columnName, type, null, MappingType.Element);
            }
 
            SetProperties(column, el.UnhandledAttributes);
            HandleColumnExpression(column, el.UnhandledAttributes);
            SetExtProperties(column, el.UnhandledAttributes);
 
            if (!string.IsNullOrEmpty(column.Expression))
            {
                _columnExpressions!.Add(column);
            }
 
            // Update XSD type to point to simple types actual namespace instead of normalized default namespace in case of remoting
            if (xsdType != null && xsdType.Name != null && xsdType.Name.Length > 0)
            {
                if (XSDSchema.GetMsdataAttribute(typeNode!, Keywords.TARGETNAMESPACE) != null)
                {
                    column.XmlDataType = xsdType.SimpleTypeQualifiedName;
                }
            }
            else
            {
                column.XmlDataType = strType;
            }
            column.SimpleType = xsdType;
 
            column.AllowDBNull = FromInference || (elem.MinOccurs == 0) || elem.IsNillable;
 
 
            if (!elem.RefName.IsEmpty || elem.QualifiedName.Namespace != table.Namespace)
            { // if ref element (or in different NS) it is global element, so form MUST BE Qualified
                column.Namespace = elem.QualifiedName.Namespace;
                column.Namespace = GetStringAttribute(el, "targetNamespace", column.Namespace);
            }
            else
            { // it is local, hence check for 'form' on local element, if not specified, check for 'elemenfformdefault' on schema element
                if (elem.Form == XmlSchemaForm.Unqualified)
                {
                    column.Namespace = string.Empty;
                }
                else if (elem.Form == XmlSchemaForm.None)
                {
                    XmlSchemaObject e = elem.Parent!;
                    while (e.Parent != null)
                    {
                        e = e.Parent;
                    }
                    if (((XmlSchema)e).ElementFormDefault == XmlSchemaForm.Unqualified)
                    {
                        column.Namespace = string.Empty;
                    }
                }
                else
                {
                    column.Namespace = elem.QualifiedName.Namespace;
                    column.Namespace = GetStringAttribute(el, "targetNamespace", column.Namespace);
                }
            }
 
            string tmp = GetStringAttribute(elem, Keywords.MSD_ORDINAL, (-1).ToString(CultureInfo.CurrentCulture));
            int ordinal = (int)Convert.ChangeType(tmp, typeof(int), null);
 
            if (isToAdd)
            {
                if (ordinal > -1 && ordinal < table.Columns.Count)
                    table.Columns.AddAt(ordinal, column);
                else
                    table.Columns.Add(column);
            }
 
            if (column.Namespace == table.Namespace)
                column._columnUri = null; // to not raise a column change namespace again
 
            if (FromInference)
            {// search for prefix after adding to table, so NS has its final value, and
                column.Prefix = GetPrefix(column.Namespace); // it can inherit its NS from DataTable, if it is null
            }
 
            string? strDefault = el.DefaultValue;
            if (strDefault != null)
                try
                {
                    column.DefaultValue = column.ConvertXmlToObject(strDefault);
                }
                catch (System.FormatException)
                {
                    throw ExceptionBuilder.CannotConvert(strDefault, type.FullName);
                }
        }
 
        [RequiresUnreferencedCode(DataSet.RequiresUnreferencedCodeMessage)]
        [RequiresDynamicCode(DataSet.RequiresDynamicCodeMessage)]
        internal void HandleDataSet(XmlSchemaElement node, bool isNewDataSet)
        {
            string? dsName = node.Name;
            string dsNamespace = node.QualifiedName.Namespace;
 
            List<DataTable> tableSequenceList = new List<DataTable>();
 
            string? value = GetMsdataAttribute(node, Keywords.MSD_LOCALE);
            if (null != value)
            { // set by user
                if (0 != value.Length)
                {
                    // <... msdata:Locale="en-US"/>
                    _ds!.Locale = new CultureInfo(value);
                }
                else
                {
                    _ds!.Locale = CultureInfo.InvariantCulture;
                }
            }
            else
            { // not set by user
                // MSD_LOCALE overrides MSD_USECURRENTLOCALE
                if (GetBooleanAttribute(node, Keywords.MSD_USECURRENTLOCALE, false))
                {
                    _ds!.SetLocaleValue(CultureInfo.CurrentCulture, false);
                }
                else
                {
                    // Everett behavior before <... msdata:UseCurrentLocale="true"/>
                    _ds!.SetLocaleValue(new CultureInfo(0x409), false);
                }
            }
 
            // reuse variable
            value = GetMsdataAttribute(node, Keywords.MSD_DATASETNAME);
            if (!string.IsNullOrEmpty(value))
            {
                dsName = value;
            }
 
            value = GetMsdataAttribute(node, Keywords.MSD_DATASETNAMESPACE);
            if (!string.IsNullOrEmpty(value))
            {
                dsNamespace = value;
            }
 
            SetProperties(_ds, node.UnhandledAttributes);
            SetExtProperties(_ds, node.UnhandledAttributes);
 
 
            if (!string.IsNullOrEmpty(dsName))
                _ds.DataSetName = XmlConvert.DecodeName(dsName);
 
            //            _ds.Namespace = node.QualifiedName.Namespace;
            _ds.Namespace = dsNamespace;
 
            if (FromInference)
                _ds.Prefix = GetPrefix(_ds.Namespace);
 
            XmlSchemaComplexType ct = (XmlSchemaComplexType)FindTypeNode(node)!;
            if (ct.Particle != null)
            {
                XmlSchemaObjectCollection? items = GetParticleItems(ct.Particle);
 
                if (items == null)
                {
                    return;
                }
 
                foreach (XmlSchemaAnnotated el in items)
                {
                    if (el is XmlSchemaElement)
                    {
                        if (((XmlSchemaElement)el).RefName.Name.Length != 0)
                        {
                            if (!FromInference)
                            {
                                continue;
                            }
                            else
                            {
                                DataTable? tempTable = _ds.Tables.GetTable(XmlConvert.DecodeName(GetInstanceName((XmlSchemaElement)el)), node.QualifiedName.Namespace);
                                if (tempTable != null)
                                {
                                    tableSequenceList.Add(tempTable); // if ref table is created, add it
                                }
                                bool isComplexTypeOrValidElementType = false;
                                if (node.ElementSchemaType != null || !(((XmlSchemaElement)el).SchemaType is XmlSchemaComplexType))
                                {
                                    isComplexTypeOrValidElementType = true;
                                }
                                //                          bool isComplexTypeOrValidElementType = (node.ElementType != null || !(((XmlSchemaElement)el).SchemaType is XmlSchemaComplexType));
                                if ((((XmlSchemaElement)el).MaxOccurs != decimal.One) && (!isComplexTypeOrValidElementType))
                                {
                                    continue;
                                }
                            }
                        }
 
                        DataTable? child = HandleTable((XmlSchemaElement)el);
                        if (child != null)
                        {
                            child._fNestedInDataset = true;
                        }
                        if (FromInference)
                        {
                            tableSequenceList.Add(child!);
                        }
                    }
                    else if (el is XmlSchemaChoice)
                    { // should we check for inference?
                        XmlSchemaObjectCollection choiceItems = ((XmlSchemaChoice)el).Items;
                        if (choiceItems == null)
                            continue;
                        foreach (XmlSchemaAnnotated choiceEl in choiceItems)
                        {
                            if (choiceEl is XmlSchemaElement)
                            {
                                if (((XmlSchemaParticle)el).MaxOccurs > decimal.One && (((XmlSchemaElement)choiceEl).SchemaType is XmlSchemaComplexType)) // amir
                                    ((XmlSchemaElement)choiceEl).MaxOccurs = ((XmlSchemaParticle)el).MaxOccurs;
                                if ((((XmlSchemaElement)choiceEl).RefName.Name.Length != 0) && (!FromInference && ((XmlSchemaElement)choiceEl).MaxOccurs != decimal.One && !(((XmlSchemaElement)choiceEl).SchemaType is XmlSchemaComplexType)))
                                    continue;
 
                                DataTable child = HandleTable((XmlSchemaElement)choiceEl)!;
                                if (FromInference)
                                {
                                    tableSequenceList.Add(child);
                                }
                                if (child != null)
                                {
                                    child._fNestedInDataset = true;
                                }
                            }
                        }
                    }
                }
            }
 
            // Handle the non-nested keyref constraints
            if (node.Constraints != null)
            {
                foreach (XmlSchemaIdentityConstraint key in node.Constraints)
                {
                    XmlSchemaKeyref? keyref = key as XmlSchemaKeyref;
                    if (keyref == null)
                        continue;
 
                    bool isNested = GetBooleanAttribute(keyref, Keywords.MSD_ISNESTED,  /*default:*/ false);
                    if (isNested)
                        continue;
 
                    HandleKeyref(keyref);
                }
            }
            if (FromInference && isNewDataSet)
            {
                List<DataTable> _tableList = new List<DataTable>(_ds.Tables.Count);
                foreach (DataTable dt in tableSequenceList)
                {
                    AddTablesToList(_tableList, dt);
                }
                _ds.Tables.ReplaceFromInference(_tableList); // replace the list with the one in correct order: BackWard compatibility for inference
            }
        }
 
        private void AddTablesToList(List<DataTable> tableList, DataTable dt)
        { // kind of depth _first travarsal
            if (!tableList.Contains(dt))
            {
                tableList.Add(dt);
                foreach (DataTable childTable in _tableDictionary![dt])
                {
                    AddTablesToList(tableList, childTable);
                }
            }
        }
 
        private string? GetPrefix(string ns)
        {
            if (ns == null)
                return null;
            foreach (XmlSchema schemaRoot in _schemaSet!.Schemas())
            {
                XmlQualifiedName[] qualifiedNames = schemaRoot.Namespaces.ToArray();
                for (int i = 0; i < qualifiedNames.Length; i++)
                {
                    if (qualifiedNames[i].Namespace == ns)
                        return qualifiedNames[i].Name;
                }
            }
            return null;
        }
 
        private string? GetNamespaceFromPrefix(string? prefix)
        {
            if ((prefix == null) || (prefix.Length == 0))
                return null;
            foreach (XmlSchema schemaRoot in _schemaSet!.Schemas())
            {
                XmlQualifiedName[] qualifiedNames = schemaRoot.Namespaces.ToArray();
                for (int i = 0; i < qualifiedNames.Length; i++)
                {
                    if (qualifiedNames[i].Name == prefix)
                        return qualifiedNames[i].Namespace;
                }
            }
            return null;
        }
 
 
        private string? GetTableNamespace(XmlSchemaIdentityConstraint key)
        {
            string xpath = key.Selector!.XPath!;
            string[] split = xpath.Split('/');
            string prefix;
 
            string QualifiedTableName = split[split.Length - 1]; //get the last string after '/' and ':'
 
            if ((QualifiedTableName == null) || (QualifiedTableName.Length == 0))
                throw ExceptionBuilder.InvalidSelector(xpath);
 
            if (QualifiedTableName.Contains(':'))
                prefix = QualifiedTableName.Substring(0, QualifiedTableName.IndexOf(':'));
            else
                return GetMsdataAttribute(key, Keywords.MSD_TABLENS);
 
            prefix = XmlConvert.DecodeName(prefix);
 
            return GetNamespaceFromPrefix(prefix);
        }
 
        private static string GetTableName(XmlSchemaIdentityConstraint key)
        {
            string xpath = key.Selector!.XPath!;
            string[] split = xpath.Split('/', ':');
            string tableName = split[split.Length - 1]; //get the last string after '/' and ':'
 
            if ((tableName == null) || (tableName.Length == 0))
                throw ExceptionBuilder.InvalidSelector(xpath);
 
            tableName = XmlConvert.DecodeName(tableName);
            return tableName;
        }
 
        internal bool IsTable(XmlSchemaElement node)
        {
            if (node.MaxOccurs == decimal.Zero)
                return false;
 
            XmlAttribute[]? attribs = node.UnhandledAttributes;
            if (attribs != null)
            {
                for (int i = 0; i < attribs.Length; i++)
                {
                    XmlAttribute attrib = attribs[i];
                    if (attrib.LocalName == Keywords.MSD_DATATYPE &&
                        attrib.Prefix == Keywords.MSD &&
                        attrib.NamespaceURI == Keywords.MSDNS)
                        return false;
                }
            }
 
            object? typeNode = FindTypeNode(node);
 
            if ((node.MaxOccurs > decimal.One) && typeNode == null)
            {
                return true;
            }
 
 
            if ((typeNode == null) || !(typeNode is XmlSchemaComplexType))
            {
                return false;
            }
 
            XmlSchemaComplexType ctNode = (XmlSchemaComplexType)typeNode;
 
            if (ctNode.IsAbstract)
                throw ExceptionBuilder.CannotInstantiateAbstract(node.Name!);
 
            return true;
        }
 
        //        internal bool IsTopLevelElement (XmlSchemaElement node) {
        //            return (elements.IndexOf(node) != -1);
        //        }
        [RequiresUnreferencedCode(DataSet.RequiresUnreferencedCodeMessage)]
        [RequiresDynamicCode(DataSet.RequiresDynamicCodeMessage)]
        internal DataTable? HandleTable(XmlSchemaElement node)
        {
            if (!IsTable(node))
                return null;
 
            object? typeNode = FindTypeNode(node);
 
            if ((node.MaxOccurs > decimal.One) && typeNode == null)
            {
                return InstantiateSimpleTable(node);
            }
 
            DataTable table = InstantiateTable(node, (XmlSchemaComplexType)typeNode!, (node.RefName != null)); // this is wrong , correct check should be node.RefName.IsEmpty
 
            table._fNestedInDataset = false;
            return table;
        }
    }
 
    internal sealed class XmlIgnoreNamespaceReader : XmlNodeReader
    {
        private readonly List<string> _namespacesToIgnore;
        //
        // Constructor
        //
        internal XmlIgnoreNamespaceReader(XmlDocument xdoc, string[] namespacesToIgnore) : base(xdoc)
        {
            _namespacesToIgnore = new List<string>(namespacesToIgnore);
        }
 
        //
        // XmlReader implementation
        //
 
        public override bool MoveToFirstAttribute()
        {
            if (base.MoveToFirstAttribute())
            {
                if (_namespacesToIgnore.Contains(NamespaceURI) ||
                    (NamespaceURI == Keywords.XML_XMLNS && LocalName != "lang"))
                { //try next one
                    return MoveToNextAttribute();
                }
                else
                {
                    return true;
                }
            }
            return false;
        }
 
        public override bool MoveToNextAttribute()
        {
            bool moved, flag;
            do
            {
                moved = false;
                flag = false;
                if (base.MoveToNextAttribute())
                {
                    moved = true;
 
                    if (_namespacesToIgnore.Contains(NamespaceURI) ||
                        (NamespaceURI == Keywords.XML_XMLNS && LocalName != "lang"))
                    {
                        flag = true;
                    }
                }
            } while (flag);
            return moved;
        }
    }
}