|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Collections;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Xml;
namespace System.Xml.Schema
{
/// <summary>
/// Infer class serves for inferring XML Schema from given XML instance document.
/// </summary>
public sealed class XmlSchemaInference
{
internal static readonly XmlQualifiedName ST_boolean = new XmlQualifiedName("boolean", XmlSchema.Namespace);
internal static readonly XmlQualifiedName ST_byte = new XmlQualifiedName("byte", XmlSchema.Namespace);
internal static readonly XmlQualifiedName ST_unsignedByte = new XmlQualifiedName("unsignedByte", XmlSchema.Namespace);
internal static readonly XmlQualifiedName ST_short = new XmlQualifiedName("short", XmlSchema.Namespace);
internal static readonly XmlQualifiedName ST_unsignedShort = new XmlQualifiedName("unsignedShort", XmlSchema.Namespace);
internal static readonly XmlQualifiedName ST_int = new XmlQualifiedName("int", XmlSchema.Namespace);
internal static readonly XmlQualifiedName ST_unsignedInt = new XmlQualifiedName("unsignedInt", XmlSchema.Namespace);
internal static readonly XmlQualifiedName ST_long = new XmlQualifiedName("long", XmlSchema.Namespace);
internal static readonly XmlQualifiedName ST_unsignedLong = new XmlQualifiedName("unsignedLong", XmlSchema.Namespace);
internal static readonly XmlQualifiedName ST_integer = new XmlQualifiedName("integer", XmlSchema.Namespace);
internal static readonly XmlQualifiedName ST_decimal = new XmlQualifiedName("decimal", XmlSchema.Namespace);
internal static readonly XmlQualifiedName ST_float = new XmlQualifiedName("float", XmlSchema.Namespace);
internal static readonly XmlQualifiedName ST_double = new XmlQualifiedName("double", XmlSchema.Namespace);
internal static readonly XmlQualifiedName ST_duration = new XmlQualifiedName("duration", XmlSchema.Namespace);
internal static readonly XmlQualifiedName ST_dateTime = new XmlQualifiedName("dateTime", XmlSchema.Namespace);
internal static readonly XmlQualifiedName ST_time = new XmlQualifiedName("time", XmlSchema.Namespace);
internal static readonly XmlQualifiedName ST_date = new XmlQualifiedName("date", XmlSchema.Namespace);
internal static readonly XmlQualifiedName ST_gYearMonth = new XmlQualifiedName("gYearMonth", XmlSchema.Namespace);
internal static readonly XmlQualifiedName ST_string = new XmlQualifiedName("string", XmlSchema.Namespace);
internal static readonly XmlQualifiedName ST_anySimpleType = new XmlQualifiedName("anySimpleType", XmlSchema.Namespace);
internal static XmlQualifiedName[] SimpleTypes =
{
ST_boolean,
ST_byte,
ST_unsignedByte,
ST_short,
ST_unsignedShort,
ST_int,
ST_unsignedInt,
ST_long,
ST_unsignedLong,
ST_integer,
ST_decimal,
ST_float,
ST_double,
ST_duration,
ST_dateTime,
ST_time,
ST_date,
ST_gYearMonth,
ST_string
};
internal const short HC_ST_boolean = 0;
internal const short HC_ST_byte = 1;
internal const short HC_ST_unsignedByte = 2;
internal const short HC_ST_short = 3;
internal const short HC_ST_unsignedShort = 4;
internal const short HC_ST_int = 5;
internal const short HC_ST_unsignedInt = 6;
internal const short HC_ST_long = 7;
internal const short HC_ST_unsignedLong = 8;
internal const short HC_ST_integer = 9;
internal const short HC_ST_decimal = 10;
internal const short HC_ST_float = 11;
internal const short HC_ST_double = 12;
internal const short HC_ST_duration = 13;
internal const short HC_ST_dateTime = 14;
internal const short HC_ST_time = 15;
internal const short HC_ST_date = 16;
internal const short HC_ST_gYearMonth = 17;
internal const short HC_ST_string = 18;
internal const short HC_ST_Count = HC_ST_string + 1;
internal const int TF_boolean = 1 << HC_ST_boolean;
internal const int TF_byte = 1 << HC_ST_byte;
internal const int TF_unsignedByte = 1 << HC_ST_unsignedByte;
internal const int TF_short = 1 << HC_ST_short;
internal const int TF_unsignedShort = 1 << HC_ST_unsignedShort;
internal const int TF_int = 1 << HC_ST_int;
internal const int TF_unsignedInt = 1 << HC_ST_unsignedInt;
internal const int TF_long = 1 << HC_ST_long;
internal const int TF_unsignedLong = 1 << HC_ST_unsignedLong;
internal const int TF_integer = 1 << HC_ST_integer;
internal const int TF_decimal = 1 << HC_ST_decimal;
internal const int TF_float = 1 << HC_ST_float;
internal const int TF_double = 1 << HC_ST_double;
internal const int TF_duration = 1 << HC_ST_duration;
internal const int TF_dateTime = 1 << HC_ST_dateTime;
internal const int TF_time = 1 << HC_ST_time;
internal const int TF_date = 1 << HC_ST_date;
internal const int TF_gYearMonth = 1 << HC_ST_gYearMonth;
internal const int TF_string = 1 << HC_ST_string;
private XmlSchema? _rootSchema; //(XmlSchema) xsc[TargetNamespace];
private XmlSchemaSet? _schemaSet;
private XmlReader? _xtr;
private readonly NameTable _nametable;
private string? _targetNamespace;
private readonly XmlNamespaceManager _namespaceManager;
//private Hashtable schemas; //contains collection of schemas before they get added to the XmlSchemaSet xsc
//private bool bRefine = false; //indicates if we are going to infer or refine schema when InferSchema is called
private InferenceOption _occurrence = InferenceOption.Restricted;
private InferenceOption _typeInference = InferenceOption.Restricted;
/* internal struct ReplaceList
{
internal XmlSchemaObjectCollection col;
internal int position;
internal ReplaceList(XmlSchemaObjectCollection col, int position)
{
this.col = col;
this.position = position;
}
}*/
public enum InferenceOption
{
Restricted,
Relaxed
};
public InferenceOption Occurrence
{
get
{
return _occurrence;
}
set
{
_occurrence = value;
}
}
public InferenceOption TypeInference
{
get
{
return _typeInference;
}
set
{
_typeInference = value;
}
}
public XmlSchemaInference()
{
_nametable = new NameTable();
_namespaceManager = new XmlNamespaceManager(_nametable);
_namespaceManager.AddNamespace("xs", XmlSchema.Namespace);
}
public XmlSchemaSet InferSchema(XmlReader instanceDocument)
{
return InferSchema1(instanceDocument, new XmlSchemaSet(_nametable));
}
public XmlSchemaSet InferSchema(XmlReader instanceDocument, XmlSchemaSet schemas)
{
schemas ??= new XmlSchemaSet(_nametable);
return InferSchema1(instanceDocument, schemas);
}
internal XmlSchemaSet InferSchema1(XmlReader instanceDocument, XmlSchemaSet schemas)
{
ArgumentNullException.ThrowIfNull(instanceDocument);
_rootSchema = null;
_xtr = instanceDocument;
schemas.Compile();
_schemaSet = schemas;
//schemas = new Hashtable();
//while(xtr.Read())
while (_xtr.NodeType != XmlNodeType.Element && _xtr.Read()) ;
if (_xtr.NodeType == XmlNodeType.Element)
{
//Create and process the root element
_targetNamespace = _xtr.NamespaceURI;
if (_xtr.NamespaceURI == XmlSchema.Namespace)
{
throw new XmlSchemaInferenceException(SR.SchInf_schema, 0, 0);
}
XmlSchemaElement? xse = null;
foreach (XmlSchemaElement? elem in schemas.GlobalElements.Values)
{
if (elem!.Name == _xtr.LocalName && elem.QualifiedName.Namespace == _xtr.NamespaceURI)
{
_rootSchema = elem.Parent as XmlSchema;
xse = elem;
break;
}
}
if (_rootSchema == null)
{
//rootSchema = CreateXmlSchema(xtr.NamespaceURI);
AddElement(_xtr.LocalName, _xtr.Prefix, _xtr.NamespaceURI, null, null, -1);
}
else
{
//bRefine = true;
InferElement(xse!, false, _rootSchema);
}
/* foreach (ReplaceList listItem in schemaList)
{
if (listItem.position < listItem.col.Count)
{
XmlSchemaElement particle = listItem.col[listItem.position] as XmlSchemaElement;
if (particle != null && (particle.RefName.Namespace == XmlSchema.Namespace))
{
XmlSchemaAny any = new XmlSchemaAny();
if (particle.MaxOccurs != 1)
{
any.MaxOccurs = particle.MaxOccurs;
}
if (particle.MinOccurs != 1)
{
any.MinOccurs = particle.MinOccurs;
}
any.ProcessContents = XmlSchemaContentProcessing.Skip;
any.MinOccurs = decimal.Zero;
any.Namespace = particle.RefName.Namespace;
listItem.col[listItem.position] = any;
}
}
}*/
foreach (string? prefix in _namespaceManager)
{
if (!prefix!.Equals("xml") && !prefix.Equals("xmlns"))
{
string ns = _namespaceManager.LookupNamespace(_nametable.Get(prefix)!)!;
if (ns.Length != 0)
{ //Do not add xmlns=""
_rootSchema!.Namespaces.Add(prefix, ns);
}
}
}
Debug.Assert(_rootSchema != null, "rootSchema is null");
schemas.Reprocess(_rootSchema);
schemas.Compile();
//break;
}
else
{
throw new XmlSchemaInferenceException(SR.SchInf_NoElement, 0, 0);
}
return schemas;
}
private XmlSchemaAttribute AddAttribute(string localName, string prefix, string childURI, string attrValue, bool bCreatingNewType, XmlSchema parentSchema, XmlSchemaObjectCollection addLocation, XmlSchemaObjectTable compiledAttributes)
{
if (childURI == XmlSchema.Namespace)
{
throw new XmlSchemaInferenceException(SR.SchInf_schema, 0, 0);
}
XmlSchemaAttribute? xsa;
int AttributeType = -1;
XmlSchemaAttribute? returnedAttribute; //this value will change to attributeReference if childURI!= parentURI
XmlSchema? xs = null;
bool add = true;
Debug.Assert(compiledAttributes != null); //AttributeUses is never null
// First we need to look into the already compiled attributes
// (they come from the schemaset which we got on input)
// If there are none or we don't find it there, then we must search the list of attributes
// where we are going to add a new one (if it doesn't exist).
// This is necessary to avoid adding duplicate attribute declarations.
ICollection searchCollectionPrimary;
ICollection? searchCollectionSecondary;
if (compiledAttributes.Count > 0)
{
searchCollectionPrimary = compiledAttributes.Values;
searchCollectionSecondary = addLocation;
}
else
{
searchCollectionPrimary = addLocation;
searchCollectionSecondary = null;
}
if (childURI == XmlReservedNs.NsXml)
{
XmlSchemaAttribute? attributeReference;
//see if the reference exists
attributeReference = FindAttributeRef(searchCollectionPrimary, localName, childURI);
if (attributeReference == null && searchCollectionSecondary != null)
{
attributeReference = FindAttributeRef(searchCollectionSecondary, localName, childURI);
}
if (attributeReference == null)
{
attributeReference = new XmlSchemaAttribute();
attributeReference.RefName = new XmlQualifiedName(localName, childURI);
if (bCreatingNewType && this.Occurrence == InferenceOption.Restricted)
{
attributeReference.Use = XmlSchemaUse.Required;
}
else
{
attributeReference.Use = XmlSchemaUse.Optional;
}
addLocation.Add(attributeReference);
}
returnedAttribute = attributeReference;
}
else
{
if (childURI.Length == 0)
{
xs = parentSchema;
add = false;
}
else if (!_schemaSet!.Contains(childURI))
{
/*if (parentSchema.AttributeFormDefault = XmlSchemaForm.Unqualified && childURI.Length == 0)
{
xs = parentSchema;
add = false;
break;
}*/
xs = new XmlSchema();
xs.AttributeFormDefault = XmlSchemaForm.Unqualified;
xs.ElementFormDefault = XmlSchemaForm.Qualified;
if (childURI.Length != 0)
xs.TargetNamespace = childURI;
//schemas.Add(childURI, xs);
_schemaSet.Add(xs);
if (prefix.Length != 0 && !string.Equals(prefix, "xml", StringComparison.OrdinalIgnoreCase))
_namespaceManager.AddNamespace(prefix, childURI);
}
else
{
ArrayList? col = _schemaSet!.Schemas(childURI) as ArrayList;
if (col != null && col.Count > 0)
{
xs = col[0] as XmlSchema;
}
}
if (childURI!.Length != 0) //BUGBUG It need not be an attribute reference if there is a namespace, it can be attribute with attributeFormDefault = qualified
{
XmlSchemaAttribute? attributeReference;
//see if the reference exists
attributeReference = FindAttributeRef(searchCollectionPrimary, localName, childURI);
if (attributeReference == null & searchCollectionSecondary != null)
{
attributeReference = FindAttributeRef(searchCollectionSecondary!, localName, childURI);
}
if (attributeReference == null)
{
attributeReference = new XmlSchemaAttribute();
attributeReference.RefName = new XmlQualifiedName(localName, childURI);
if (bCreatingNewType && this.Occurrence == InferenceOption.Restricted)
{
attributeReference.Use = XmlSchemaUse.Required;
}
else
{
attributeReference.Use = XmlSchemaUse.Optional;
}
addLocation.Add(attributeReference);
}
returnedAttribute = attributeReference;
//see if the attribute exists on the global level
xsa = FindAttribute(xs!.Items, localName);
if (xsa == null)
{
xsa = new XmlSchemaAttribute();
xsa.Name = localName;
xsa.SchemaTypeName = RefineSimpleType(attrValue, ref AttributeType);
xsa.LineNumber = AttributeType; //we use LineNumber to store flags of valid types
xs.Items.Add(xsa);
}
else
{
if (xsa.Parent == null)
{
AttributeType = xsa.LineNumber; // we use LineNumber to store flags of valid types
}
else
{
AttributeType = GetSchemaType(xsa.SchemaTypeName);
xsa.Parent = null;
}
xsa.SchemaTypeName = RefineSimpleType(attrValue, ref AttributeType);
xsa.LineNumber = AttributeType; // we use LineNumber to store flags of valid types
}
}
else
{
xsa = FindAttribute(searchCollectionPrimary, localName);
if (xsa == null && searchCollectionSecondary != null)
{
xsa = FindAttribute(searchCollectionSecondary, localName);
}
if (xsa == null)
{
xsa = new XmlSchemaAttribute();
xsa.Name = localName;
xsa.SchemaTypeName = RefineSimpleType(attrValue, ref AttributeType);
xsa.LineNumber = AttributeType; // we use LineNumber to store flags of valid types
if (bCreatingNewType && this.Occurrence == InferenceOption.Restricted)
xsa.Use = XmlSchemaUse.Required;
else
xsa.Use = XmlSchemaUse.Optional;
addLocation.Add(xsa);
if (xs!.AttributeFormDefault != XmlSchemaForm.Unqualified)
{
xsa.Form = XmlSchemaForm.Unqualified;
}
}
else
{
if (xsa.Parent == null)
{
AttributeType = xsa.LineNumber; // we use LineNumber to store flags of valid types
}
else
{
AttributeType = GetSchemaType(xsa.SchemaTypeName);
xsa.Parent = null;
}
xsa.SchemaTypeName = RefineSimpleType(attrValue, ref AttributeType);
xsa.LineNumber = AttributeType; // we use LineNumber to store flags of valid types
}
returnedAttribute = xsa;
}
}
string? nullString = null;
if (add && childURI != parentSchema.TargetNamespace)
{
for (int i = 0; i < parentSchema.Includes.Count; ++i)
{
XmlSchemaImport? import = parentSchema.Includes[i] as XmlSchemaImport;
if (import == null)
{
continue;
}
if (import.Namespace == childURI)
{
add = false;
}
}
if (add)
{
XmlSchemaImport import = new XmlSchemaImport();
import.Schema = xs;
if (childURI.Length != 0)
{
nullString = childURI;
}
import.Namespace = nullString;
parentSchema.Includes.Add(import);
}
}
return returnedAttribute;
}
private XmlSchema CreateXmlSchema(string targetNS)
{
Debug.Assert(targetNS == null || targetNS.Length > 0, "targetns for schema is empty");
XmlSchema xs = new XmlSchema();
xs.AttributeFormDefault = XmlSchemaForm.Unqualified;
xs.ElementFormDefault = XmlSchemaForm.Qualified;
xs.TargetNamespace = targetNS;
_schemaSet!.Add(xs);
return xs;
}
private XmlSchemaElement AddElement(string localName, string prefix, string? childURI, XmlSchema? parentSchema, XmlSchemaObjectCollection? addLocation, int positionWithinCollection)
{
if (childURI == XmlSchema.Namespace)
{
throw new XmlSchemaInferenceException(SR.SchInf_schema, 0, 0);
}
XmlSchemaElement? xse;
XmlSchemaElement? returnedElement; //this value will change to elementReference if childURI!= parentURI
XmlSchema? xs;
bool bCreatingNewType = true;
if (childURI == string.Empty)
{
childURI = null;
}
// The new element belongs to the same ns as parent and addlocation is not null
if (parentSchema != null && childURI == parentSchema.TargetNamespace)
{
xse = new XmlSchemaElement();
xse.Name = localName;
xs = parentSchema;
if (xs.ElementFormDefault != XmlSchemaForm.Qualified && addLocation != null)
{
xse.Form = XmlSchemaForm.Qualified;
}
}
else if (_schemaSet!.Contains(childURI))
{
xse = this.FindGlobalElement(childURI, localName, out xs);
if (xse == null)
{
ArrayList? col = _schemaSet.Schemas(childURI) as ArrayList;
if (col != null && col.Count > 0)
{
xs = col[0] as XmlSchema;
}
xse = new XmlSchemaElement();
xse.Name = localName;
xs!.Items.Add(xse);
}
else
bCreatingNewType = false;
}
else
{
xs = CreateXmlSchema(childURI!);
if (prefix.Length != 0)
_namespaceManager.AddNamespace(prefix, childURI!);
xse = new XmlSchemaElement();
xse.Name = localName;
xs.Items.Add(xse); //add global element declaration only when creating new schema
}
if (parentSchema == null)
{
parentSchema = xs;
_rootSchema = parentSchema;
}
if (childURI != parentSchema!.TargetNamespace)
{
bool add = true;
for (int i = 0; i < parentSchema.Includes.Count; ++i)
{
XmlSchemaImport? import = parentSchema.Includes[i] as XmlSchemaImport;
if (import == null)
{
continue;
}
//Debug.WriteLine(import.Schema.TargetNamespace);
if (import.Namespace == childURI)
{
add = false;
}
}
if (add)
{
XmlSchemaImport import = new XmlSchemaImport();
import.Schema = xs;
import.Namespace = childURI;
parentSchema.Includes.Add(import);
}
}
returnedElement = xse;
if (addLocation != null)
{
if (childURI == parentSchema.TargetNamespace)
{
if (this.Occurrence == InferenceOption.Relaxed /*&& parentSchema.Items != addLocation*/)
{
xse.MinOccurs = 0;
}
if (positionWithinCollection == -1)
{
addLocation.Add(xse);
}
else
{
addLocation.Insert(positionWithinCollection, xse);
}
}
else
{
XmlSchemaElement elementReference = new XmlSchemaElement();
elementReference.RefName = new XmlQualifiedName(localName, childURI);
if (this.Occurrence == InferenceOption.Relaxed)
{
elementReference.MinOccurs = 0;
}
if (positionWithinCollection == -1)
{
addLocation.Add(elementReference);
}
else
{
addLocation.Insert(positionWithinCollection, elementReference);
}
returnedElement = elementReference;
/* if (childURI == XmlSchema.Namespace)
{
schemaList.Add(new ReplaceList(addLocation, positionWithinCollection));
}*/
}
}
InferElement(xse, bCreatingNewType, xs!);
return returnedElement;
}
/// <summary>
/// Sets type of the xse based on the currently read element.
/// If the type is already set, verifies that it matches the instance and if not, updates the type to validate the instance.
/// </summary>
/// <param name="xse">XmlSchemaElement corresponding to the element just read by the xtr XmlTextReader</param>
/// <param name="bCreatingNewType">true if the type is newly created, false if the type already existed and matches the current element name</param>
/// <param name="parentSchema">namespaceURI of the parent element. Used to distinguish if ref= should be used when parent is in different ns than child.</param>
internal void InferElement(XmlSchemaElement xse, bool bCreatingNewType, XmlSchema parentSchema)
{
bool bEmptyElement = _xtr!.IsEmptyElement;
int lastUsedSeqItem = -1;
Hashtable table = new Hashtable();
XmlSchemaType? schemaType = GetEffectiveSchemaType(xse, bCreatingNewType);
XmlSchemaComplexType? ct = schemaType as XmlSchemaComplexType;
//infer type based on content of the current element
if (_xtr.MoveToFirstAttribute())
{
ProcessAttributes(ref xse, schemaType, bCreatingNewType, parentSchema);
}
else
{
if (!bCreatingNewType && ct != null)
{ //if type already exists and can potentially have attributes
MakeExistingAttributesOptional(ct, null);
}
}
if (ct == null || ct == XmlSchemaComplexType.AnyType)
{ //It was null or simple type, after processing attributes, this might have been set
ct = xse.SchemaType as XmlSchemaComplexType;
}
//xse's type is set either to complex type if attributes exist or null
if (bEmptyElement) //<element attr="3232" />
{
if (!bCreatingNewType)
{
if (null != ct)
{
if (null != ct.Particle)
{
ct.Particle.MinOccurs = 0;
}
else if (null != ct.ContentModel)
{
XmlSchemaSimpleContentExtension sce = CheckSimpleContentExtension(ct);
sce.BaseTypeName = ST_string;
sce.LineNumber = TF_string;
}
}
else if (!xse.SchemaTypeName.IsEmpty)
{
xse.LineNumber = TF_string;
xse.SchemaTypeName = ST_string;
}
}
else
{
xse.LineNumber = TF_string;
//xse.SchemaTypeName = ST_string; //My change
}
return; //We are done processing this element - all attributes are already added
}
bool bWhiteSpace = false;
do
{
_xtr.Read();
if (_xtr.NodeType == XmlNodeType.Whitespace)
{
bWhiteSpace = true;
}
if (_xtr.NodeType == XmlNodeType.EntityReference)
{
throw new XmlSchemaInferenceException(SR.SchInf_entity, 0, 0);
}
} while ((!_xtr.EOF) && (_xtr.NodeType != XmlNodeType.EndElement) && (_xtr.NodeType != XmlNodeType.CDATA) && (_xtr.NodeType != XmlNodeType.Element) && (_xtr.NodeType != XmlNodeType.Text));
if (_xtr.NodeType == XmlNodeType.EndElement)
{
if (bWhiteSpace)
{
if (ct != null)
{
if (null != ct.ContentModel)
{
XmlSchemaSimpleContentExtension sce = CheckSimpleContentExtension(ct);
sce.BaseTypeName = ST_string;
sce.LineNumber = TF_string;
}
else if (bCreatingNewType)
{
//attributes exist, but both Particle and ContentModel == null - this must be complex type with simpleContent extension
XmlSchemaSimpleContent sc = new XmlSchemaSimpleContent();
ct.ContentModel = sc;
XmlSchemaSimpleContentExtension sce = new XmlSchemaSimpleContentExtension();
sc.Content = sce;
MoveAttributes(ct, sce, bCreatingNewType);
sce.BaseTypeName = ST_string;
sce.LineNumber = TF_string;
}
else
ct.IsMixed = true;
}
else
{
xse.SchemaTypeName = ST_string;
xse.LineNumber = TF_string;
}
}
if (bCreatingNewType)
{
xse.LineNumber = TF_string;
//xse.SchemaTypeName = ST_string; //my change
}
else
{
if (null != ct)
{
if (null != ct.Particle)
{
ct.Particle.MinOccurs = 0;
}
else if (null != ct.ContentModel)
{
XmlSchemaSimpleContentExtension sce = CheckSimpleContentExtension(ct);
sce.BaseTypeName = ST_string;
sce.LineNumber = TF_string;
}
}
else if (!xse.SchemaTypeName.IsEmpty)
{
xse.LineNumber = TF_string;
xse.SchemaTypeName = ST_string;
}
}
return; //<element attr="232"></element>
}
int iChildNumber = 0;
bool bCreatingNewSequence = false;
while (!_xtr.EOF && (_xtr.NodeType != XmlNodeType.EndElement))
{
bool bNextNodeAlreadyRead = false; //In some cases we have to look ahead one node. If true means that we did look ahead.
iChildNumber++;
if ((_xtr.NodeType == XmlNodeType.Text) || (_xtr.NodeType == XmlNodeType.CDATA)) //node can be simple type, complex with simple content or complex with mixed content
{
if (null != ct)
{
if (null != ct.Particle)
{
ct.IsMixed = true;
if (iChildNumber == 1)
{
//if this is the only child and other elements do not follow, we must set particle minOccurs="0"
do { _xtr.Read(); } while ((!_xtr.EOF) && ((_xtr.NodeType == XmlNodeType.CDATA) || (_xtr.NodeType == XmlNodeType.Text) || (_xtr.NodeType == XmlNodeType.Comment) || (_xtr.NodeType == XmlNodeType.ProcessingInstruction) || (_xtr.NodeType == XmlNodeType.Whitespace) || (_xtr.NodeType == XmlNodeType.SignificantWhitespace) || (_xtr.NodeType == XmlNodeType.XmlDeclaration)));
bNextNodeAlreadyRead = true;
if (_xtr.NodeType == XmlNodeType.EndElement)
ct.Particle.MinOccurs = decimal.Zero;
}
}
else if (null != ct.ContentModel)
{ //complexType with simpleContent
XmlSchemaSimpleContentExtension sce = CheckSimpleContentExtension(ct);
if ((_xtr.NodeType == XmlNodeType.Text) && (iChildNumber == 1))
{
int SimpleType = -1;
if (xse.Parent == null)
{
SimpleType = sce.LineNumber; // we use LineNumber to represent valid type flags
}
else
{
SimpleType = GetSchemaType(sce.BaseTypeName);
xse.Parent = null;
}
sce.BaseTypeName = RefineSimpleType(_xtr.Value, ref SimpleType);
sce.LineNumber = SimpleType; // we use LineNumber to represent valid type flags
}
else
{
sce.BaseTypeName = ST_string;
sce.LineNumber = TF_string;
}
}
else
{
//attributes exist, but both Particle and ContentModel == null - this must be complex type with simpleContent extension
XmlSchemaSimpleContent sc = new XmlSchemaSimpleContent();
ct.ContentModel = sc;
XmlSchemaSimpleContentExtension sce = new XmlSchemaSimpleContentExtension();
sc.Content = sce;
MoveAttributes(ct, sce, bCreatingNewType);
if (_xtr.NodeType == XmlNodeType.Text)
{
int TypeFlags;
if (!bCreatingNewType)
//previously this was empty element
TypeFlags = TF_string;
else
TypeFlags = -1;
sce.BaseTypeName = RefineSimpleType(_xtr.Value, ref TypeFlags);
sce.LineNumber = TypeFlags; // we use LineNumber to store flags of valid types
}
else
{
sce.BaseTypeName = ST_string;
sce.LineNumber = TF_string;
}
}
}
else
{ //node is currently empty or with SimpleType
//node will become simple type
if (iChildNumber > 1)
{
//more than one consecutive text nodes probably with PI in between
xse.SchemaTypeName = ST_string;
xse.LineNumber = TF_string; // we use LineNumber to store flags of valid types
}
else
{
int TypeFlags = -1;
if (bCreatingNewType)
if (_xtr.NodeType == XmlNodeType.Text)
{
xse.SchemaTypeName = RefineSimpleType(_xtr.Value, ref TypeFlags);
xse.LineNumber = TypeFlags; // we use LineNumber to store flags of valid types
}
else
{
xse.SchemaTypeName = ST_string;
xse.LineNumber = TF_string; // we use LineNumber to store flags of valid types
}
else if (_xtr.NodeType == XmlNodeType.Text)
{
if (xse.Parent == null)
{
TypeFlags = xse.LineNumber;
}
else
{
TypeFlags = GetSchemaType(xse.SchemaTypeName);
if (TypeFlags == -1 && xse.LineNumber == TF_string)
{ //Since schemaTypeName is not set for empty elements (<e></e>)
TypeFlags = TF_string;
}
xse.Parent = null;
}
xse.SchemaTypeName = RefineSimpleType(_xtr.Value, ref TypeFlags); //simple type
xse.LineNumber = TypeFlags; // we use LineNumber to store flags of valid types
}
else
{
xse.SchemaTypeName = ST_string;
xse.LineNumber = TF_string; // we use LineNumber to store flags of valid types
}
}
}
}
else if (_xtr.NodeType == XmlNodeType.Element)
{
XmlQualifiedName qname = new XmlQualifiedName(_xtr.LocalName, _xtr.NamespaceURI);
bool Maxoccursflag = false;
if (table.Contains(qname))
{
Maxoccursflag = true;
}
else
{
table.Add(qname, null);
}
if (ct == null)
{ // until now the element was empty or SimpleType - it now becomes complex type
ct = new XmlSchemaComplexType();
xse.SchemaType = ct;
if (!xse.SchemaTypeName.IsEmpty) //BUGBUG, This assumption is wrong
{
ct.IsMixed = true;
xse.SchemaTypeName = XmlQualifiedName.Empty;
}
}
if (ct.ContentModel != null)
{ //type was previously identified as simple content extension - we need to convert it to sequence
XmlSchemaSimpleContentExtension sce = CheckSimpleContentExtension(ct);
MoveAttributes(sce, ct);
ct.ContentModel = null;
ct.IsMixed = true;
if (ct.Particle != null)
throw new XmlSchemaInferenceException(SR.SchInf_particle, 0, 0);
ct.Particle = new XmlSchemaSequence();
bCreatingNewSequence = true;
AddElement(_xtr.LocalName, _xtr.Prefix, _xtr.NamespaceURI, parentSchema, ((XmlSchemaSequence)ct.Particle).Items, -1);
lastUsedSeqItem = 0;
if (!bCreatingNewType)
ct.Particle.MinOccurs = 0; //previously this was simple type so subelements did not exist
}
else if (ct.Particle == null)
{
ct.Particle = new XmlSchemaSequence();
bCreatingNewSequence = true;
AddElement(_xtr.LocalName, _xtr.Prefix, _xtr.NamespaceURI, parentSchema, ((XmlSchemaSequence)ct.Particle).Items, -1);
if (!bCreatingNewType)
{
((XmlSchemaSequence)ct.Particle).MinOccurs = decimal.Zero;
// subelement.MinOccurs = decimal.Zero;
}
lastUsedSeqItem = 0;
}
else
{
FindMatchingElement(bCreatingNewType || bCreatingNewSequence, _xtr, ct, ref lastUsedSeqItem, parentSchema, Maxoccursflag);
}
}
else if (_xtr.NodeType == XmlNodeType.Text)
{
if (ct == null)
throw new XmlSchemaInferenceException(SR.SchInf_ct, 0, 0);
ct.IsMixed = true;
}
do
{
if (_xtr.NodeType == XmlNodeType.EntityReference)
{
throw new XmlSchemaInferenceException(SR.SchInf_entity, 0, 0);
}
if (!bNextNodeAlreadyRead)
{
_xtr.Read();
}
else
{
bNextNodeAlreadyRead = false;
}
} while ((!_xtr.EOF) && (_xtr.NodeType != XmlNodeType.EndElement) && (_xtr.NodeType != XmlNodeType.CDATA) && (_xtr.NodeType != XmlNodeType.Element) && (_xtr.NodeType != XmlNodeType.Text));
}
if (lastUsedSeqItem != -1)
{
//Verify if all elements in a sequence exist, if not set MinOccurs=0
while (++lastUsedSeqItem < ((XmlSchemaSequence)ct!.Particle!).Items.Count)
{
if (((XmlSchemaSequence)ct.Particle).Items[lastUsedSeqItem].GetType() != typeof(XmlSchemaElement))
throw new XmlSchemaInferenceException(SR.SchInf_seq, 0, 0);
XmlSchemaElement subElement = (XmlSchemaElement)((XmlSchemaSequence)ct.Particle).Items[lastUsedSeqItem];
subElement.MinOccurs = 0;
}
}
}
private static XmlSchemaSimpleContentExtension CheckSimpleContentExtension(XmlSchemaComplexType ct)
{
XmlSchemaSimpleContent? sc = ct.ContentModel as XmlSchemaSimpleContent;
if (sc == null)
{
throw new XmlSchemaInferenceException(SR.SchInf_simplecontent, 0, 0);
}
XmlSchemaSimpleContentExtension? sce = sc.Content as XmlSchemaSimpleContentExtension;
if (sce == null)
{
throw new XmlSchemaInferenceException(SR.SchInf_extension, 0, 0);
}
return sce;
}
private XmlSchemaType? GetEffectiveSchemaType(XmlSchemaElement elem, bool bCreatingNewType)
{
XmlSchemaType? effectiveSchemaType = null;
if (!bCreatingNewType && elem.ElementSchemaType != null)
{
effectiveSchemaType = elem.ElementSchemaType;
}
else
{ //creating new type, hence look up pre-compiled info
Debug.Assert(elem.ElementDecl == null);
if (elem.SchemaType != null)
{
effectiveSchemaType = elem.SchemaType;
}
else if (elem.SchemaTypeName != XmlQualifiedName.Empty)
{
effectiveSchemaType =
_schemaSet!.GlobalTypes[elem.SchemaTypeName] as XmlSchemaType ??
(XmlSchemaType?)XmlSchemaType.GetBuiltInSimpleType(elem.SchemaTypeName) ??
(XmlSchemaType?)XmlSchemaType.GetBuiltInComplexType(elem.SchemaTypeName);
}
}
return effectiveSchemaType;
}
/// <summary>
/// Verifies that the current element has its corresponding element in the sequence and order is the same.
/// If the order is not the same, it changes the particle from Sequence to Sequence with Choice.
/// If there is more elements of the same kind in the sequence, sets maxOccurs to unbounded
/// </summary>
/// <param name="bCreatingNewType">True if this is a new type. This is important for setting minOccurs=0 for elements that did not exist in a particle.</param>
/// <param name="xtr">text reader positioned to the current element</param>
/// <param name="ct">complex type with Sequence or Choice Particle</param>
/// <param name="lastUsedSeqItem">ordinal number in the sequence to indicate current sequence position</param>
/// <param name="parentSchema">The parent schema.</param>
/// <param name="setMaxoccurs">Whether set max occurs.</param>
internal XmlSchemaElement FindMatchingElement(bool bCreatingNewType, XmlReader xtr, XmlSchemaComplexType ct, ref int lastUsedSeqItem, XmlSchema? parentSchema, bool setMaxoccurs)
{
if (xtr.NamespaceURI == XmlSchema.Namespace)
{
throw new XmlSchemaInferenceException(SR.SchInf_schema, 0, 0);
}
bool bItemNotUsedYet = ((lastUsedSeqItem == -1) ? true : false);
XmlSchemaObjectCollection minOccursCandidates = new XmlSchemaObjectCollection(); //elements that are skipped in the sequence and need minOccurs modified.
if (ct.Particle!.GetType() == typeof(XmlSchemaSequence))
{
string? childURI = xtr.NamespaceURI;
if (childURI.Length == 0)
{
childURI = null;
}
XmlSchemaSequence xss = (XmlSchemaSequence)ct.Particle;
if (xss.Items.Count < 1 && !bCreatingNewType)
{
lastUsedSeqItem = 0;
XmlSchemaElement e = AddElement(xtr.LocalName, xtr.Prefix, xtr.NamespaceURI, parentSchema, xss.Items, -1);
e.MinOccurs = 0;
return e;
}
if (xss.Items[0].GetType() == typeof(XmlSchemaChoice))
{ // <sequence minOccurs="0" maxOccurs="unbounded"><choice><element>...</choice></sequence>
XmlSchemaChoice xsch = (XmlSchemaChoice)xss.Items[0];
for (int i = 0; i < xsch.Items.Count; ++i)
{
XmlSchemaElement? el = xsch.Items[i] as XmlSchemaElement;
if (el == null)
{
throw new XmlSchemaInferenceException(SR.SchInf_UnknownParticle, 0, 0);
}
if ((el.Name == xtr.LocalName) && (parentSchema!.TargetNamespace == childURI))
{ // element is in the same namespace
InferElement(el, false, parentSchema);
SetMinMaxOccurs(el, setMaxoccurs);
return el;
}
else if ((el.RefName.Name == xtr.LocalName) && (el.RefName.Namespace == xtr.NamespaceURI))
{
XmlSchemaElement referencedElement = FindGlobalElement(childURI, xtr.LocalName, out parentSchema)!;
InferElement(referencedElement, false, parentSchema!);
SetMinMaxOccurs(el, setMaxoccurs);
return referencedElement;
}
}
XmlSchemaElement subElement = AddElement(xtr.LocalName, xtr.Prefix, xtr.NamespaceURI, parentSchema, xsch.Items, -1);
return subElement;
}
else
{ //this should be sequence of elements
int iSeqItem = 0; //iterator through schema sequence items
if (lastUsedSeqItem >= 0)
iSeqItem = lastUsedSeqItem;
XmlSchemaParticle? particle = xss.Items[iSeqItem] as XmlSchemaParticle;
XmlSchemaElement? el = particle as XmlSchemaElement;
if (el == null)
{
throw new XmlSchemaInferenceException(SR.SchInf_UnknownParticle, 0, 0);
}
if (el.Name == xtr.LocalName && parentSchema!.TargetNamespace == childURI)
{
if (!bItemNotUsedYet) //read: if item was already used one or more times
el.MaxOccurs = decimal.MaxValue; //set it to unbounded
lastUsedSeqItem = iSeqItem;
InferElement(el, false, parentSchema);
SetMinMaxOccurs(el, false);
return el;
}
else if (el.RefName.Name == xtr.LocalName && el.RefName.Namespace == xtr.NamespaceURI)
{
if (!bItemNotUsedYet) //read: if item was already used one or more times
el.MaxOccurs = decimal.MaxValue; //set it to unbounded
lastUsedSeqItem = iSeqItem;
XmlSchemaElement referencedElement = FindGlobalElement(childURI, xtr.LocalName, out parentSchema)!;
InferElement(referencedElement, false, parentSchema!);
SetMinMaxOccurs(el, false);
return el;
}
if (bItemNotUsedYet && el.MinOccurs != decimal.Zero)
minOccursCandidates.Add(el);
iSeqItem++;
while (iSeqItem < xss.Items.Count)
{
particle = xss.Items[iSeqItem] as XmlSchemaParticle;
el = particle as XmlSchemaElement;
if (el == null)
{
throw new XmlSchemaInferenceException(SR.SchInf_UnknownParticle, 0, 0);
}
if (el.Name == xtr.LocalName && parentSchema!.TargetNamespace == childURI)
{
lastUsedSeqItem = iSeqItem;
for (int i = 0; i < minOccursCandidates.Count; ++i)
{
((XmlSchemaElement)minOccursCandidates[i]).MinOccurs = decimal.Zero;
}
InferElement(el, false, parentSchema);
SetMinMaxOccurs(el, setMaxoccurs);
return el;
}
else if (el.RefName.Name == xtr.LocalName && el.RefName.Namespace == xtr.NamespaceURI)
{
lastUsedSeqItem = iSeqItem;
for (int i = 0; i < minOccursCandidates.Count; ++i)
{
((XmlSchemaElement)minOccursCandidates[i]).MinOccurs = decimal.Zero;
}
XmlSchemaElement referencedElement = FindGlobalElement(childURI, xtr.LocalName, out parentSchema)!;
InferElement(referencedElement!, false, parentSchema!);
SetMinMaxOccurs(el, setMaxoccurs);
return referencedElement;
}
minOccursCandidates.Add(el);
iSeqItem++;
}
//element not found in the sequence order, if it is found out of order change Sequence of elements to Sequence of Choices otherwise insert into sequence as optional
XmlSchemaElement? subElement;
XmlSchemaElement? actualElement = null;
//BUGBUG - is this logic correct - if there is a sequence of elements should they be int he parent's namespace.
if (parentSchema!.TargetNamespace == childURI)
{
subElement = FindElement(xss.Items, xtr.LocalName);
actualElement = subElement;
}
else
{
subElement = FindElementRef(xss.Items, xtr.LocalName, xtr.NamespaceURI);
if (subElement != null)
{
actualElement = FindGlobalElement(childURI, xtr.LocalName, out parentSchema);
}
}
if (null != subElement)
{
XmlSchemaChoice xsc = new XmlSchemaChoice();
xsc.MaxOccurs = decimal.MaxValue;
SetMinMaxOccurs(subElement, setMaxoccurs);
InferElement(actualElement!, false, parentSchema!);
for (int i = 0; i < xss.Items.Count; ++i)
{
xsc.Items.Add(CreateNewElementforChoice((XmlSchemaElement)xss.Items[i]));
}
xss.Items.Clear();
xss.Items.Add(xsc);
return subElement;
}
else
{
subElement = AddElement(xtr.LocalName, xtr.Prefix, xtr.NamespaceURI, parentSchema, xss.Items, ++lastUsedSeqItem);
if (!bCreatingNewType)
subElement.MinOccurs = decimal.Zero;
return subElement;
}
}
}
else
{
throw new XmlSchemaInferenceException(SR.SchInf_noseq, 0, 0);
}
}
internal void ProcessAttributes(ref XmlSchemaElement xse, XmlSchemaType? effectiveSchemaType, bool bCreatingNewType, XmlSchema parentSchema)
{
XmlSchemaObjectCollection attributesSeen = new XmlSchemaObjectCollection();
XmlSchemaComplexType? ct = effectiveSchemaType as XmlSchemaComplexType;
Debug.Assert(_xtr!.NodeType == XmlNodeType.Attribute);
do
{
if (_xtr.NamespaceURI == XmlSchema.Namespace)
{
throw new XmlSchemaInferenceException(SR.SchInf_schema, 0, 0);
}
if (_xtr.NamespaceURI == XmlReservedNs.NsXmlNs)
{
if (_xtr.Prefix == "xmlns")
_namespaceManager.AddNamespace(_xtr.LocalName, _xtr.Value);
}
else if (_xtr.NamespaceURI == XmlReservedNs.NsXsi)
{
string localName = _xtr.LocalName;
if (localName == "nil")
{
xse.IsNillable = true;
}
else if (localName != "type" && localName != "schemaLocation" && localName != "noNamespaceSchemaLocation")
{
throw new XmlSchemaInferenceException(SR.Sch_NotXsiAttribute, localName);
}
}
else
{
if (ct == null || ct == XmlSchemaComplexType.AnyType)
{
ct = new XmlSchemaComplexType();
xse.SchemaType = ct;
}
XmlSchemaAttribute? xsa;
//The earlier assumption of checking just schemaTypeName !Empty is not correct for schemas that are not generated by us, schemaTypeName can point to any complex type as well
//Check that it is a simple type by checking typeCode
//Switch to complex type simple content extension
if (effectiveSchemaType != null && effectiveSchemaType.Datatype != null && !xse.SchemaTypeName.IsEmpty)
{
//type was previously simple type, now it will become complex with simple type extension
Debug.Assert(ct != null);
XmlSchemaSimpleContent sc = new XmlSchemaSimpleContent();
ct.ContentModel = sc;
XmlSchemaSimpleContentExtension sce = new XmlSchemaSimpleContentExtension();
sc.Content = sce;
sce.BaseTypeName = xse.SchemaTypeName;
sce.LineNumber = xse.LineNumber;
xse.LineNumber = 0;
xse.SchemaTypeName = XmlQualifiedName.Empty; //re-set the name
}
Debug.Assert(ct != null); //either the user-defined type itself is a complex type or we switched from a simple type to a complex type
if (ct.ContentModel != null)
{
XmlSchemaSimpleContentExtension sce = CheckSimpleContentExtension(ct);
Debug.Assert(sce != null);
xsa = AddAttribute(_xtr.LocalName, _xtr.Prefix, _xtr.NamespaceURI, _xtr.Value, bCreatingNewType, parentSchema, sce.Attributes, ct.AttributeUses);
}
else //add attributes directly to complex type
{
xsa = AddAttribute(_xtr.LocalName, _xtr.Prefix, _xtr.NamespaceURI, _xtr.Value, bCreatingNewType, parentSchema, ct.Attributes, ct.AttributeUses);
}
if (xsa != null)
{
attributesSeen.Add(xsa);
}
}
} while (_xtr.MoveToNextAttribute());
if (!bCreatingNewType)
{
//make attributes that did not appear this time optional
if (ct != null)
{
MakeExistingAttributesOptional(ct, attributesSeen);
}
}
}
private static void MoveAttributes(XmlSchemaSimpleContentExtension scExtension, XmlSchemaComplexType ct)
{
//copy all attributes from the simple content to the complex type
//This is ok since when we move from complex type to simple content extension we copy from AttributeUses property
for (int i = 0; i < scExtension.Attributes.Count; ++i) //since simpleContent is being cleared
{
ct.Attributes.Add(scExtension.Attributes[i]);
}
}
private static void MoveAttributes(XmlSchemaComplexType ct, XmlSchemaSimpleContentExtension simpleContentExtension, bool bCreatingNewType)
{
//copy all attributes from the complex type to the simple content
ICollection sourceCollection;
if (!bCreatingNewType && ct.AttributeUses.Count > 0)
{
sourceCollection = ct.AttributeUses.Values;
}
else
{
sourceCollection = ct.Attributes;
}
foreach (XmlSchemaAttribute? attr in sourceCollection)
{
simpleContentExtension.Attributes.Add(attr!);
}
ct.Attributes.Clear(); //Clear from pre-compiled property, post compiled will be cleared on Re-process and Compile()
}
internal static XmlSchemaAttribute? FindAttribute(ICollection attributes, string attrName)
{
foreach (XmlSchemaObject? xsa in attributes)
{
XmlSchemaAttribute? schemaAttribute = xsa as XmlSchemaAttribute;
if (schemaAttribute != null)
{
if (schemaAttribute.Name == attrName)
{
return schemaAttribute;
}
}
}
return null;
}
internal XmlSchemaElement? FindGlobalElement(string? namespaceURI, string localName, out XmlSchema? parentSchema)
{
ICollection col = _schemaSet!.Schemas(namespaceURI);
XmlSchemaElement? xse;
parentSchema = null;
foreach (XmlSchema? schema in col)
{
xse = FindElement(schema!.Items, localName);
if (xse != null)
{
parentSchema = schema;
return xse;
}
}
return null;
}
internal static XmlSchemaElement? FindElement(XmlSchemaObjectCollection elements, string elementName)
{
for (int i = 0; i < elements.Count; ++i)
{
XmlSchemaElement? xse = elements[i] as XmlSchemaElement;
if (xse != null && xse.RefName != null)
{
if (xse.Name == elementName)
{
return xse;
}
}
}
return null;
}
internal static XmlSchemaAttribute? FindAttributeRef(ICollection attributes, string attributeName, string nsURI)
{
foreach (XmlSchemaObject? xsa in attributes)
{
XmlSchemaAttribute? schemaAttribute = xsa as XmlSchemaAttribute;
if (schemaAttribute != null)
{
if (schemaAttribute.RefName.Name == attributeName && schemaAttribute.RefName.Namespace == nsURI)
{
return schemaAttribute;
}
}
}
return null;
}
internal static XmlSchemaElement? FindElementRef(XmlSchemaObjectCollection elements, string elementName, string nsURI)
{
for (int i = 0; i < elements.Count; ++i)
{
XmlSchemaElement? xse = elements[i] as XmlSchemaElement;
if (xse != null && xse.RefName != null)
{
if (xse.RefName.Name == elementName && xse.RefName.Namespace == nsURI)
{
return xse;
}
}
}
return null;
}
internal static void MakeExistingAttributesOptional(XmlSchemaComplexType ct, XmlSchemaObjectCollection? attributesInInstance)
{
if (ct == null)
{
throw new XmlSchemaInferenceException(SR.SchInf_noct, 0, 0);
}
if (ct.ContentModel != null)
{
XmlSchemaSimpleContentExtension xssce = CheckSimpleContentExtension(ct);
SwitchUseToOptional(xssce.Attributes, attributesInInstance);
}
else
{ //either <xs:attribute> as child of xs:complexType or the attributes are within the content model
SwitchUseToOptional(ct.Attributes, attributesInInstance);
}
}
private static void SwitchUseToOptional(XmlSchemaObjectCollection attributes, XmlSchemaObjectCollection? attributesInInstance)
{
for (int i = 0; i < attributes.Count; ++i)
{
XmlSchemaAttribute? attr = attributes[i] as XmlSchemaAttribute;
if (attr != null)
{
if (attributesInInstance != null)
{
if (attr.RefName.Name.Length == 0)
{ //If the attribute is not present in this instance, make it optional
if (null == FindAttribute(attributesInInstance, attr.Name!))
{
attr.Use = XmlSchemaUse.Optional;
}
}
else
{
if (null == FindAttributeRef(attributesInInstance, attr.RefName.Name, attr.RefName.Namespace))
{
attr.Use = XmlSchemaUse.Optional;
}
}
}
else
{
attr.Use = XmlSchemaUse.Optional;
}
}
}
}
internal XmlQualifiedName RefineSimpleType(string s, ref int iTypeFlags)
{
bool bNeedsRangeCheck = false;
s = s.Trim();
if (iTypeFlags == TF_string || _typeInference == InferenceOption.Relaxed)
return ST_string;
iTypeFlags &= InferSimpleType(s, ref bNeedsRangeCheck);
if (iTypeFlags == TF_string)
return ST_string;
if (bNeedsRangeCheck)
{
if ((iTypeFlags & TF_byte) != 0)
{
try
{
XmlConvert.ToSByte(s);
//sbyte.Parse(s);
if ((iTypeFlags & TF_unsignedByte) != 0)
return ST_unsignedByte; //number is positive and fits byte -> it also fits unsignedByte
else
return ST_byte;
}
catch (FormatException)
{ }
catch (OverflowException)
{ }
iTypeFlags &= (~TF_byte);
}
if ((iTypeFlags & TF_unsignedByte) != 0)
{
try
{
XmlConvert.ToByte(s);
//byte.Parse(s);
return ST_unsignedByte;
}
catch (FormatException)
{ }
catch (OverflowException)
{ }
iTypeFlags &= (~TF_unsignedByte);
}
if ((iTypeFlags & TF_short) != 0)
{
try
{
XmlConvert.ToInt16(s);
//short.Parse(s);
if ((iTypeFlags & TF_unsignedShort) != 0)
return ST_unsignedShort; //number is positive and fits short -> it also fits unsignedShort
else
return ST_short;
}
catch (FormatException)
{ }
catch (OverflowException)
{ }
iTypeFlags &= (~TF_short);
}
if ((iTypeFlags & TF_unsignedShort) != 0)
{
try
{
XmlConvert.ToUInt16(s);
//ushort.Parse(s);
return ST_unsignedShort;
}
catch (FormatException)
{ }
catch (OverflowException)
{ }
iTypeFlags &= (~TF_unsignedShort);
}
if ((iTypeFlags & TF_int) != 0)
{
try
{
XmlConvert.ToInt32(s);
//int.Parse(s);
if ((iTypeFlags & TF_unsignedInt) != 0)
return ST_unsignedInt; //number is positive and fits int -> it also fits unsignedInt
else
return ST_int;
}
catch (FormatException)
{ }
catch (OverflowException)
{ }
iTypeFlags &= (~TF_int);
}
if ((iTypeFlags & TF_unsignedInt) != 0)
{
try
{
XmlConvert.ToUInt32(s);
//uint.Parse(s);
return ST_unsignedInt;
}
catch (FormatException)
{ }
catch (OverflowException)
{ }
iTypeFlags &= (~TF_unsignedInt);
}
if ((iTypeFlags & TF_long) != 0)
{
try
{
XmlConvert.ToInt64(s);
//long.Parse(s);
if ((iTypeFlags & TF_unsignedLong) != 0)
return ST_unsignedLong; //number is positive and fits long -> it also fits unsignedLong
else
return ST_long;
}
catch (FormatException)
{ }
catch (OverflowException)
{ }
iTypeFlags &= (~TF_long);
}
if ((iTypeFlags & TF_unsignedLong) != 0)
{
try
{
XmlConvert.ToUInt64(s);
//ulong.Parse(s);
return ST_unsignedLong;
}
catch (FormatException)
{ }
catch (OverflowException)
{ }
iTypeFlags &= (~TF_unsignedLong);
}
if ((iTypeFlags & TF_double) != 0)
{
try
{
double dbValue = XmlConvert.ToDouble(s);
if ((iTypeFlags & TF_integer) != 0)
return ST_integer;
else if ((iTypeFlags & TF_decimal) != 0)
return ST_decimal;
else
{
// The value fits into double, but it could be float as well
if ((iTypeFlags & TF_float) != 0)
{
// We used to default to float in this case, so try to fit it into float first
try
{
float flValue = XmlConvert.ToSingle(s);
// Compare the float and double values. We can't do simple value comparison
// as conversion from float to double introduces imprecissions which cause problems.
// Instead we will convert both back to string and compare the strings.
if (string.Equals(XmlConvert.ToString(flValue), XmlConvert.ToString(dbValue), StringComparison.OrdinalIgnoreCase))
{
// If we can convert the original string to the exact same value
// and it still fits into float then we treat it as float
return ST_float;
}
}
catch (FormatException)
{ }
catch (OverflowException)
{ }
}
iTypeFlags &= (~TF_float);
return ST_double;
}
}
catch (FormatException)
{ }
catch (OverflowException)
{ }
iTypeFlags &= (~TF_double);
}
if ((iTypeFlags & TF_float) != 0)
{
try
{
XmlConvert.ToSingle(s);
if ((iTypeFlags & TF_integer) != 0)
return ST_integer;
else if ((iTypeFlags & TF_decimal) != 0)
return ST_decimal;
else
return ST_float;
}
catch (FormatException) { }
catch (OverflowException) { }
iTypeFlags &= (~TF_float);
}
if ((iTypeFlags & TF_integer) != 0)
return ST_integer;
else if ((iTypeFlags & TF_decimal) != 0)
return ST_decimal;
else if (iTypeFlags == (TF_gYearMonth | TF_string))
{
try
{
XmlConvert.ToDateTime(s, XmlDateTimeSerializationMode.RoundtripKind);
return ST_gYearMonth;
}
catch (FormatException)
{ }
catch (OverflowException)
{ }
iTypeFlags = TF_string;
return ST_string;
}
else if (iTypeFlags == (TF_duration | TF_string))
{
try
{
XmlConvert.ToTimeSpan(s);
return ST_duration;
}
catch (FormatException)
{ }
catch (OverflowException)
{ }
iTypeFlags = TF_string;
return ST_string;
}
else if (iTypeFlags == (TF_boolean | TF_string))
{
return ST_boolean;
}
}
switch (iTypeFlags)
{
case TF_string:
return ST_string;
case TF_boolean:
return ST_boolean;
case TF_byte:
return ST_byte;
case TF_unsignedByte:
return ST_unsignedByte;
case TF_short:
return ST_short;
case TF_unsignedShort:
return ST_unsignedShort;
case TF_int:
return ST_int;
case TF_unsignedInt:
return ST_unsignedInt;
case TF_long:
return ST_long;
case TF_unsignedLong:
return ST_unsignedLong;
case TF_integer:
return ST_integer;
case TF_decimal:
return ST_decimal;
case TF_float:
return ST_float;
case TF_double:
return ST_double;
case TF_duration:
return ST_duration;
case TF_dateTime:
return ST_dateTime;
case TF_time:
return ST_time;
case TF_date:
return ST_date;
case TF_gYearMonth:
return ST_gYearMonth;
case TF_boolean | TF_string:
return ST_boolean;
case TF_dateTime | TF_string:
return ST_dateTime;
case TF_date | TF_string:
return ST_date;
case TF_time | TF_string:
return ST_time;
case TF_float | TF_double | TF_string:
return ST_float;
case TF_double | TF_string:
return ST_double;
default:
Debug.Fail("Expected type not matched");
return ST_string;
}
/* if (currentType == null)
return SimpleTypes[newType];
else
return SimpleTypes[ST_Map[newType,(short) ST_Codes[currentType]]];
*/
}
internal static int InferSimpleType(string s, ref bool bNeedsRangeCheck)
{
bool bNegative = false;
bool bPositive = false;
bool bDate = false;
bool bTime = false;
bool bMissingDay = false;
if (s.Length == 0) return TF_string;
int i = 0;
switch (s[i])
{
case 't':
case 'f':
if (s == "true")
return TF_boolean | TF_string;
else if (s == "false")
return TF_boolean | TF_string;
else
return TF_string;
case 'N': //try to match "NaN"
if (s == "NaN")
return TF_float | TF_double | TF_string;
else
return TF_string;
//else
case 'I': //try to match "INF"
INF:
if (s.AsSpan(i) is "INF")
return TF_float | TF_double | TF_string;
else return TF_string;
case '.': //try to match ".9999" decimal/float/double
FRACTION:
bNeedsRangeCheck = true;
i++;
if (i == s.Length)
{
if ((i == 1) || (i == 2 && (bPositive || bNegative))) //"." "-." "+."
return TF_string;
else
return TF_decimal | TF_float | TF_double | TF_string;
}
switch (s[i])
{
case 'e':
case 'E':
goto EXPONENT;
default:
if (char.IsAsciiDigit(s[i]))
goto DEC_PART;
else
return TF_string;
}
DEC_PART:
i++; if (i == s.Length) return TF_decimal | TF_float | TF_double | TF_string; //"9999.9" was matched
switch (s[i])
{
case 'e':
case 'E':
goto EXPONENT;
default:
if (char.IsAsciiDigit(s[i]))
goto DEC_PART;
else
return TF_string;
}
EXPONENT:
i++; if (i == s.Length) return TF_string;
switch (s[i])
{
case '+':
case '-':
goto E1;
default:
if (char.IsAsciiDigit(s[i]))
goto EXP_PART;
else
return TF_string;
}
E1:
i++; if (i == s.Length) return TF_string; //".9999e+" was matched
if (char.IsAsciiDigit(s[i]))
goto EXP_PART;
else
return TF_string; //".999e+X was matched
EXP_PART:
i++; if (i == s.Length) return TF_float | TF_double | TF_string; //".9999e+99" was matched
if (char.IsAsciiDigit(s[i])) //".9999e+9
goto EXP_PART;
else
return TF_string; //".9999e+999X" was matched
case '-':
bNegative = true;
i++; if (i == s.Length) return TF_string;
switch (s[i])
{
case 'I': //try to match "-INF"
goto INF;
case '.': //try to match "-.9999"
goto FRACTION;
case 'P':
goto DURATION;
default:
if (char.IsAsciiDigit(s[i])) //-9
goto NUMBER;
else return TF_string;
}
case '+':
bPositive = true;
i++; if (i == s.Length) return TF_string;
switch (s[i])
{
case '.': //try to match "+.9999"
goto FRACTION;
case 'P':
goto DURATION;
default:
if (char.IsAsciiDigit(s[i])) //"+9
goto NUMBER;
else return TF_string;
}
case 'P': //try to match duration
DURATION:
i++; if (i == s.Length) return TF_string;
switch (s[i])
{
case 'T':
goto D7;
default:
if (char.IsAsciiDigit(s[i])) //"P9"
goto D1;
else return TF_string;
}
D1:
i++; if (i == s.Length) return TF_string; //"P999" was matched
switch (s[i])
{
case 'Y':
goto D2;
case 'M':
goto D4;
case 'D':
goto D6;
default:
if (char.IsAsciiDigit(s[i]))
goto D1;
else
return TF_string;
}
D2:
i++;
if (i == s.Length)
{
bNeedsRangeCheck = true;
return TF_duration | TF_string; //"P999Y" was matched
}
switch (s[i])
{
case 'T':
goto D7;
default:
if (char.IsAsciiDigit(s[i]))
goto D3;
else
return TF_string;
}
D3:
i++; if (i == s.Length) return TF_string; //"P999Y9" was matched
switch (s[i])
{
case 'M':
goto D4;
case 'D':
goto D6;
default:
if (char.IsAsciiDigit(s[i]))
goto D3;
else
return TF_string;
}
D4:
i++;
if (i == s.Length)
{
bNeedsRangeCheck = true;
return TF_duration | TF_string; //"P999Y999M" was matched
}
switch (s[i])
{
case 'T':
goto D7;
default:
if (char.IsAsciiDigit(s[i]))
goto D5;
else
return TF_string;
}
D5:
i++; if (i == s.Length) return TF_string; //"P999Y999M9" was matched
switch (s[i])
{
case 'D':
goto D6;
default:
if (char.IsAsciiDigit(s[i]))
goto D5;
else
return TF_string;
}
D6:
i++;
if (i == s.Length)
{
bNeedsRangeCheck = true;
return TF_duration | TF_string; //"P999Y999M999D" was matched
}
switch (s[i])
{
case 'T':
goto D7;
default:
return TF_string;
}
D7:
i++; if (i == s.Length) return TF_string; //"P999Y999M9999DT" was matched
if (char.IsAsciiDigit(s[i]))
goto D8;
else
return TF_string;
D8:
i++; if (i == s.Length) return TF_string; //"___T9" was matched
switch (s[i])
{
case 'H':
goto D9;
case 'M':
goto D11;
case '.':
goto D13;
case 'S':
goto D15;
default:
if (char.IsAsciiDigit(s[i]))
goto D8;
else
return TF_string;
}
D9:
i++;
if (i == s.Length)
{
bNeedsRangeCheck = true;
return TF_duration | TF_string; //"___T999H" was matched
}
if (char.IsAsciiDigit(s[i]))
goto D10;
else
return TF_string;
D10:
i++; if (i == s.Length) return TF_string; //"___T999H9" was matched
switch (s[i])
{
case 'M':
goto D11;
case '.':
goto D13;
case 'S':
goto D15;
default:
if (char.IsAsciiDigit(s[i]))
goto D10;
else
return TF_string;
}
D11:
i++;
if (i == s.Length)
{
bNeedsRangeCheck = true;
return TF_duration | TF_string; //"___T999H999M" was matched
}
if (char.IsAsciiDigit(s[i]))
goto D12;
else
return TF_string;
D12:
i++; if (i == s.Length) return TF_string; //"___T999H999M9" was matched
switch (s[i])
{
case '.':
goto D13;
case 'S':
goto D15;
default:
if (char.IsAsciiDigit(s[i]))
goto D12;
else
return TF_string;
}
D13:
i++;
if (i == s.Length)
{
bNeedsRangeCheck = true;
return TF_duration | TF_string; //"___T999H999M999." was matched
}
if (char.IsAsciiDigit(s[i]))
goto D14;
else
return TF_string;
D14:
i++; if (i == s.Length) return TF_string; //"___T999H999M999.9" was matched
switch (s[i])
{
case 'S':
goto D15;
default:
if (char.IsAsciiDigit(s[i]))
goto D14;
else
return TF_string;
}
D15:
i++;
if (i == s.Length)
{
bNeedsRangeCheck = true;
return TF_duration | TF_string; //"___T999H999M999.999S" was matched
}
else return TF_string;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
NUMBER:
i++;
if (i == s.Length)
{
bNeedsRangeCheck = true;
if (bNegative || bPositive)
return TF_byte | TF_short | TF_int | TF_long | TF_integer | TF_decimal | TF_float | TF_double | TF_string; //"-9"
else
{
if (s == "0" || s == "1")
return TF_boolean | TF_byte | TF_short | TF_int | TF_long | TF_integer | TF_decimal | TF_float | TF_double |
TF_unsignedByte | TF_unsignedShort | TF_unsignedInt | TF_unsignedLong | TF_string;
else
return TF_byte | TF_short | TF_int | TF_long | TF_integer | TF_decimal | TF_float | TF_double |
TF_unsignedByte | TF_unsignedShort | TF_unsignedInt | TF_unsignedLong | TF_string;
}
}
switch (s[i])
{
case '.':
goto FRACTION;
case 'e':
case 'E':
bNeedsRangeCheck = true;
return TF_float | TF_double | TF_string;
default:
if (char.IsAsciiDigit(s[i]))
goto N2;
else
return TF_string;
}
N2:
i++;
if (i == s.Length)
{
bNeedsRangeCheck = true;
if (bNegative || bPositive)
return TF_byte | TF_short | TF_int | TF_long | TF_integer | TF_decimal | TF_float | TF_double | TF_string; //"-9"
else
return TF_byte | TF_short | TF_int | TF_long | TF_integer | TF_decimal | TF_float | TF_double |
TF_unsignedByte | TF_unsignedShort | TF_unsignedInt | TF_unsignedLong | TF_string;
}
switch (s[i])
{
case '.':
goto FRACTION;
case ':':
bTime = true;
goto MINUTE;
case 'e':
case 'E':
bNeedsRangeCheck = true;
return TF_float | TF_double | TF_string;
default:
if (char.IsAsciiDigit(s[i]))
goto N3;
else
return TF_string;
}
N3:
i++;
if (i == s.Length)
{
bNeedsRangeCheck = true; //three digits may not fit byte and unsignedByte
if (bNegative || bPositive)
return TF_byte | TF_short | TF_int | TF_long | TF_integer | TF_decimal | TF_float | TF_double | TF_string; //"-9"
else
return TF_byte | TF_short | TF_int | TF_long | TF_integer | TF_decimal | TF_float | TF_double |
TF_unsignedByte | TF_unsignedShort | TF_unsignedInt | TF_unsignedLong | TF_string;
}
switch (s[i])
{
case '.':
goto FRACTION;
case 'e':
case 'E':
bNeedsRangeCheck = true;
return TF_float | TF_double | TF_string;
default:
if (char.IsAsciiDigit(s[i]))
goto N4;
else
return TF_string;
}
N4:
i++;
if (i == s.Length)
{
bNeedsRangeCheck = true;
if (bNegative || bPositive)
return TF_byte | TF_short | TF_int | TF_long | TF_integer | TF_decimal | TF_float | TF_double | TF_string; //"-9"
else
return TF_byte | TF_short | TF_int | TF_long | TF_integer | TF_decimal | TF_float | TF_double |
TF_unsignedByte | TF_unsignedShort | TF_unsignedInt | TF_unsignedLong | TF_string;
}
switch (s[i])
{
case '-':
bDate = true;
goto DATE;
case '.':
goto FRACTION;
case 'e':
case 'E':
bNeedsRangeCheck = true;
return TF_float | TF_double | TF_string;
default:
if (char.IsAsciiDigit(s[i]))
goto N4;
else
return TF_string;
}
DATE:
i++; if (i == s.Length) return TF_string; //"9999-"
if (!char.IsAsciiDigit(s[i]))
return TF_string;
i++; if (i == s.Length) return TF_string; //"9999-9"
if (!char.IsAsciiDigit(s[i]))
return TF_string;
i++;
if (i == s.Length)
{
bNeedsRangeCheck = true;
return TF_gYearMonth | TF_string; //"9999-99"
}
switch (s[i])
{
case '-':
goto DAY;
case 'Z':
case 'z':
bMissingDay = true;
goto ZULU;
case '+':
bMissingDay = true;
goto ZONE_SHIFT;
default:
return TF_string;
}
DAY:
i++; if (i == s.Length) return TF_string; //"9999-99-"
if (!char.IsAsciiDigit(s[i]))
return TF_string;
i++; if (i == s.Length) return TF_string; //"9999-99-9"
if (!char.IsAsciiDigit(s[i]))
return TF_string;
i++; if (i == s.Length) return DateTime(s, bDate, bTime); //"9999-99-99"
switch (s[i])
{
case 'Z':
case 'z':
goto ZULU;
case '+':
case '-':
goto ZONE_SHIFT;
case 'T':
bTime = true;
goto TIME;
case ':':
bMissingDay = true;
goto ZONE_SHIFT_MINUTE;
default:
return TF_string;
}
ZULU:
i++;
if (i == s.Length)
{
if (bMissingDay)
{
bNeedsRangeCheck = true;
return TF_gYearMonth | TF_string;
}
else
{
return DateTime(s, bDate, bTime);
}
}
else
return TF_string;
ZONE_SHIFT:
i++; if (i == s.Length) return TF_string;
if (!char.IsAsciiDigit(s[i]))
return TF_string;
i++; if (i == s.Length) return TF_string;
if (!char.IsAsciiDigit(s[i]))
return TF_string;
i++; if (i == s.Length) return TF_string;
if (s[i] != ':')
return TF_string;
ZONE_SHIFT_MINUTE:
i++; if (i == s.Length) return TF_string;
if (!char.IsAsciiDigit(s[i]))
return TF_string;
i++; if (i == s.Length) return TF_string;
if (!char.IsAsciiDigit(s[i]))
return TF_string;
i++;
if (i == s.Length)
{
if (bMissingDay)
{
bNeedsRangeCheck = true;
return TF_gYearMonth | TF_string;
}
else
{
return DateTime(s, bDate, bTime);
}
}
else return TF_string;
TIME:
i++; if (i == s.Length) return TF_string;
if (!char.IsAsciiDigit(s[i]))
return TF_string;
i++; if (i == s.Length) return TF_string;
if (!char.IsAsciiDigit(s[i]))
return TF_string;
i++; if (i == s.Length) return TF_string;
if (s[i] != ':')
return TF_string;
MINUTE:
i++; if (i == s.Length) return TF_string;
if (!char.IsAsciiDigit(s[i]))
return TF_string;
i++; if (i == s.Length) return TF_string;
if (!char.IsAsciiDigit(s[i]))
return TF_string;
i++; if (i == s.Length) return TF_string;
if (s[i] != ':')
return TF_string;
i++; if (i == s.Length) return TF_string;
if (!char.IsAsciiDigit(s[i]))
return TF_string;
i++; if (i == s.Length) return TF_string;
if (!char.IsAsciiDigit(s[i]))
return TF_string;
i++; if (i == s.Length) return DateTime(s, bDate, bTime);
switch (s[i])
{
case 'Z':
case 'z':
goto ZULU;
case '+':
case '-':
goto ZONE_SHIFT;
case '.':
goto SECOND_FRACTION;
default:
return TF_string;
}
SECOND_FRACTION:
i++; if (i == s.Length) return TF_string;
if (!char.IsAsciiDigit(s[i]))
return TF_string;
FRACT_DIGITS:
i++; if (i == s.Length) return DateTime(s, bDate, bTime);
switch (s[i])
{
case 'Z':
case 'z':
goto ZULU;
case '+':
case '-':
goto ZONE_SHIFT;
default:
if (char.IsAsciiDigit(s[i]))
goto FRACT_DIGITS;
else
return TF_string;
}
default:
return TF_string;
}
}
internal static int DateTime(string s, bool bDate, bool bTime)
{
try
{
XmlConvert.ToDateTime(s, XmlDateTimeSerializationMode.RoundtripKind);
}
catch (FormatException)
{
return TF_string;
}
if (bDate && bTime)
return TF_dateTime | TF_string;
else if (bDate)
return TF_date | TF_string;
else if (bTime)
return TF_time | TF_string;
else
{
Debug.Fail("Expected date, time or dateTime");
return TF_string;
}
}
private XmlSchemaElement CreateNewElementforChoice(XmlSchemaElement copyElement)
{
XmlSchemaElement newElement = new XmlSchemaElement();
newElement.Annotation = copyElement.Annotation;
newElement.Block = copyElement.Block;
newElement.DefaultValue = copyElement.DefaultValue;
newElement.Final = copyElement.Final;
newElement.FixedValue = copyElement.FixedValue;
newElement.Form = copyElement.Form;
newElement.Id = copyElement.Id;
// newElement.IsAbstract = copyElement.IsAbstract;
if (copyElement.IsNillable)
{
newElement.IsNillable = copyElement.IsNillable;
}
newElement.LineNumber = copyElement.LineNumber;
newElement.LinePosition = copyElement.LinePosition;
newElement.Name = copyElement.Name;
newElement.Namespaces = copyElement.Namespaces;
newElement.RefName = copyElement.RefName;
newElement.SchemaType = copyElement.SchemaType;
newElement.SchemaTypeName = copyElement.SchemaTypeName;
newElement.SourceUri = copyElement.SourceUri;
newElement.SubstitutionGroup = copyElement.SubstitutionGroup;
newElement.UnhandledAttributes = copyElement.UnhandledAttributes;
if (copyElement.MinOccurs != decimal.One && this.Occurrence == InferenceOption.Relaxed)
{
newElement.MinOccurs = copyElement.MinOccurs;
}
if (copyElement.MaxOccurs != decimal.One)
{
newElement.MaxOccurs = copyElement.MaxOccurs;
}
return newElement;
}
private static int GetSchemaType(XmlQualifiedName qname)
{
if (qname == SimpleTypes[HC_ST_boolean])
{
return TF_boolean | TF_string;
}
if (qname == SimpleTypes[HC_ST_byte])
{
return TF_byte | TF_short | TF_int | TF_long | TF_integer | TF_decimal | TF_float | TF_double | TF_string;
}
if (qname == SimpleTypes[HC_ST_unsignedByte])
{
return TF_byte | TF_short | TF_int | TF_long | TF_integer | TF_decimal | TF_float | TF_double |
TF_unsignedByte | TF_unsignedShort | TF_unsignedInt | TF_unsignedLong | TF_string;
}
if (qname == SimpleTypes[HC_ST_short])
{
return TF_short | TF_int | TF_long | TF_integer | TF_decimal | TF_float | TF_double | TF_string;
}
if (qname == SimpleTypes[HC_ST_unsignedShort])
{
return TF_short | TF_int | TF_long | TF_integer | TF_decimal | TF_float | TF_double |
TF_unsignedShort | TF_unsignedInt | TF_unsignedLong | TF_string;
}
if (qname == SimpleTypes[HC_ST_int])
{
return TF_int | TF_long | TF_integer | TF_decimal | TF_float | TF_double | TF_string;
}
if (qname == SimpleTypes[HC_ST_unsignedInt])
{
return TF_int | TF_long | TF_integer | TF_decimal | TF_float | TF_double |
TF_unsignedInt | TF_unsignedLong | TF_string;
}
if (qname == SimpleTypes[HC_ST_long])
{
return TF_long | TF_integer | TF_decimal | TF_float | TF_double | TF_string;
}
if (qname == SimpleTypes[HC_ST_unsignedLong])
{
return TF_long | TF_integer | TF_decimal | TF_float | TF_double |
TF_unsignedLong | TF_string;
}
if (qname == SimpleTypes[HC_ST_integer])
{
return TF_integer | TF_decimal | TF_float | TF_double | TF_string;
}
if (qname == SimpleTypes[HC_ST_decimal])
{
return TF_decimal | TF_float | TF_double | TF_string;
}
if (qname == SimpleTypes[HC_ST_float])
{
return TF_float | TF_double | TF_string;
}
if (qname == SimpleTypes[HC_ST_double])
{
return TF_double | TF_string;
}
if (qname == SimpleTypes[HC_ST_duration])
{
return TF_duration | TF_string;
}
if (qname == SimpleTypes[HC_ST_dateTime])
{
return TF_dateTime | TF_string;
}
if (qname == SimpleTypes[HC_ST_time])
{
return TF_time | TF_string;
}
if (qname == SimpleTypes[HC_ST_date])
{
return TF_date;
}
if (qname == SimpleTypes[HC_ST_gYearMonth])
{
return TF_gYearMonth;
}
if (qname == SimpleTypes[HC_ST_string])
{
return TF_string;
}
if (qname == null || qname.IsEmpty)
{
return -1;
}
throw new XmlSchemaInferenceException(SR.SchInf_schematype, 0, 0);
}
internal void SetMinMaxOccurs(XmlSchemaElement el, bool setMaxOccurs)
{
if (this.Occurrence == InferenceOption.Relaxed)
{
if (setMaxOccurs || el.MaxOccurs > 1)
{
el.MaxOccurs = decimal.MaxValue; //set it to unbounded
}
el.MinOccurs = 0;
}
else if (el.MinOccurs > 1)
{
el.MinOccurs = 1;
}
}
}
}
|