2 // XmlSchemaInference.cs
5 // Atsushi Enomoto <atsushi@ximian.com>
7 // Copyright (C)2004 Novell Inc.
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 using System.Collections;
36 using System.Xml.Schema;
38 using QName = System.Xml.XmlQualifiedName;
39 using Form = System.Xml.Schema.XmlSchemaForm;
40 using Use = System.Xml.Schema.XmlSchemaUse;
41 using SOMList = System.Xml.Schema.XmlSchemaObjectCollection;
42 using SOMObject = System.Xml.Schema.XmlSchemaObject;
43 using Import = System.Xml.Schema.XmlSchemaImport;
44 using Element = System.Xml.Schema.XmlSchemaElement;
45 using Attr = System.Xml.Schema.XmlSchemaAttribute;
46 using AttrGroup = System.Xml.Schema.XmlSchemaAttributeGroup;
47 using AttrGroupRef = System.Xml.Schema.XmlSchemaAttributeGroupRef;
48 using SimpleType = System.Xml.Schema.XmlSchemaSimpleType;
49 using ComplexType = System.Xml.Schema.XmlSchemaComplexType;
50 using SimpleModel = System.Xml.Schema.XmlSchemaSimpleContent;
51 using SimpleExt = System.Xml.Schema.XmlSchemaSimpleContentExtension;
52 using SimpleRst = System.Xml.Schema.XmlSchemaSimpleContentRestriction;
53 using ComplexModel = System.Xml.Schema.XmlSchemaComplexContent;
54 using ComplexExt = System.Xml.Schema.XmlSchemaComplexContentExtension;
55 using ComplexRst = System.Xml.Schema.XmlSchemaComplexContentRestriction;
56 using SimpleTypeRst = System.Xml.Schema.XmlSchemaSimpleTypeRestriction;
57 using SimpleList = System.Xml.Schema.XmlSchemaSimpleTypeList;
58 using SimpleUnion = System.Xml.Schema.XmlSchemaSimpleTypeUnion;
59 using SchemaFacet = System.Xml.Schema.XmlSchemaFacet;
60 using LengthFacet = System.Xml.Schema.XmlSchemaLengthFacet;
61 using MinLengthFacet = System.Xml.Schema.XmlSchemaMinLengthFacet;
62 using Particle = System.Xml.Schema.XmlSchemaParticle;
63 using Sequence = System.Xml.Schema.XmlSchemaSequence;
64 using Choice = System.Xml.Schema.XmlSchemaChoice;
67 namespace System.Xml.Schema
69 [MonoTODO ("merge primitive types; infer gYearMonth too; in some cases sequence should contain element whose minOccurs=0 (no obvious rules right now); reject some non-supported schema components")]
70 public sealed class XmlSchemaInference
72 public enum InferenceOption {
77 InferenceOption occurrence = InferenceOption.Restricted;
78 InferenceOption typeInference = InferenceOption.Restricted;
80 public XmlSchemaInference ()
84 public InferenceOption Occurrence {
85 get { return occurrence; }
86 set { occurrence = value; }
89 public InferenceOption TypeInference {
90 get { return TypeInference; }
91 set { typeInference = value; }
94 public XmlSchemaSet InferSchema (XmlReader xmlReader)
96 return InferSchema (xmlReader, new XmlSchemaSet ());
99 public XmlSchemaSet InferSchema (XmlReader xmlReader,
100 XmlSchemaSet schemas)
102 return XsdInference.Process (xmlReader, schemas,
103 occurrence == InferenceOption.Relaxed,
104 typeInference == InferenceOption.Relaxed);
110 public static XmlSchemaSet Process (XmlReader xmlReader,
111 XmlSchemaSet schemas,
113 bool laxTypeInference)
115 XsdInference impl = new XsdInference (xmlReader,
116 schemas, laxOccurrence, laxTypeInference);
121 public const string NamespaceXml =
122 "http://www.w3.org/XML/1998/namespace";
124 public const string NamespaceXmlns =
125 "http://www.w3.org/2000/xmlns/";
127 public const string XdtNamespace =
128 "http://www.w3.org/2003/11/xpath-datatypes";
130 static readonly QName QNameString = new QName (
131 "string", XmlSchema.Namespace);
133 static readonly QName QNameBoolean = new QName (
134 "boolean", XmlSchema.Namespace);
136 static readonly QName QNameAnyType = new QName (
137 "anyType", XmlSchema.Namespace);
139 static readonly QName QNameByte = new QName (
140 "byte", XmlSchema.Namespace);
142 static readonly QName QNameUByte = new QName (
143 "unsignedByte", XmlSchema.Namespace);
145 static readonly QName QNameShort = new QName (
146 "short", XmlSchema.Namespace);
148 static readonly QName QNameUShort = new QName (
149 "unsignedShort", XmlSchema.Namespace);
151 static readonly QName QNameInt = new QName (
152 "int", XmlSchema.Namespace);
154 static readonly QName QNameUInt = new QName (
155 "unsignedInt", XmlSchema.Namespace);
157 static readonly QName QNameLong = new QName (
158 "long", XmlSchema.Namespace);
160 static readonly QName QNameULong = new QName (
161 "unsignedLong", XmlSchema.Namespace);
163 static readonly QName QNameDecimal = new QName (
164 "decimal", XmlSchema.Namespace);
166 static readonly QName QNameUDecimal = new QName (
167 "unsignedDecimal", XmlSchema.Namespace);
169 static readonly QName QNameDouble = new QName (
170 "double", XmlSchema.Namespace);
172 static readonly QName QNameFloat = new QName (
173 "float", XmlSchema.Namespace);
175 static readonly QName QNameDateTime = new QName (
176 "dateTime", XmlSchema.Namespace);
178 static readonly QName QNameDuration = new QName (
179 "duration", XmlSchema.Namespace);
182 XmlSchemaSet schemas;
184 bool laxTypeInference;
186 Hashtable newElements = new Hashtable ();
187 Hashtable newAttributes = new Hashtable ();
189 private XsdInference (XmlReader xmlReader,
190 XmlSchemaSet schemas,
192 bool laxTypeInference)
194 this.source = xmlReader;
195 this.schemas = schemas;
196 this.laxOccurrence = laxOccurrence;
197 this.laxTypeInference = laxTypeInference;
202 // XmlSchemaSet need to be compiled.
205 // move to top-level element
206 source.MoveToContent ();
207 int depth = source.Depth;
208 if (source.NodeType != XmlNodeType.Element)
209 throw new ArgumentException ("Argument XmlReader content is expected to be an element.");
211 QName qname = new QName (source.LocalName,
212 source.NamespaceURI);
213 Element el = GetGlobalElement (qname);
215 el = CreateGlobalElement (qname);
216 InferElement (el, qname.Namespace, true);
219 InferElement (el, qname.Namespace, false);
221 // FIXME: compile again.
222 // foreach (XmlSchema schema in schemas.Schemas ())
223 // schemas.Reprocess (schema);
226 private void AddImport (string current, string import)
228 foreach (XmlSchema schema in schemas.Schemas (current)) {
230 foreach (XmlSchemaExternal e in schema.Includes) {
231 Import imp = e as Import;
233 imp.Namespace == import)
238 Import newimp = new Import ();
239 newimp.Namespace = import;
240 schema.Includes.Add (newimp);
244 private void IncludeXmlAttributes ()
246 if (schemas.Schemas (NamespaceXml).Count == 0)
247 // FIXME: do it from resources.
248 schemas.Add (NamespaceXml,
249 "http://www.w3.org/2001/xml.xsd");
252 private void InferElement (Element el, string ns, bool isNew)
254 // Quick check for reference to another definition
255 // (i.e. element ref='...' that should be redirected)
256 if (el.RefName != QName.Empty) {
257 Element body = GetGlobalElement (el.RefName);
259 body = CreateElement (el.RefName);
260 InferElement (body, ns, true);
263 InferElement (body, ns, isNew);
268 if (source.MoveToFirstAttribute ()) {
269 InferAttributes (el, ns, isNew);
270 source.MoveToElement ();
274 if (source.IsEmptyElement) {
275 InferAsEmptyElement (el, ns, isNew);
277 source.MoveToContent ();
280 InferContent (el, ns, isNew);
281 source.ReadEndElement ();
283 if (el.SchemaType == null &&
284 el.SchemaTypeName == QName.Empty)
285 el.SchemaTypeName = QNameString;
288 #region Attribute Inference
290 private Hashtable CollectAttrTable (SOMList attList)
292 // get attribute definition table.
293 Hashtable table = new Hashtable ();
294 foreach (XmlSchemaObject obj in attList) {
295 Attr attr = obj as Attr;
297 throw Error (obj, String.Format ("Attribute inference only supports direct attribute definition. {0} is not supported.", obj.GetType ()));
298 if (attr.RefName != QName.Empty)
299 table.Add (attr.RefName, attr);
301 table.Add (new QName (attr.Name, ""),
307 private void InferAttributes (Element el, string ns, bool isNew)
309 // Now this element is going to have complexType.
310 // It currently not, then we have to replace it.
311 ComplexType ct = null;
312 SOMList attList = null;
313 Hashtable table = null;
316 switch (source.NamespaceURI) {
318 if (schemas.Schemas (
319 NamespaceXml) .Count == 0)
320 IncludeXmlAttributes ();
322 case XmlSchema.InstanceNamespace:
323 if (source.LocalName == "nil")
324 el.IsNillable = true;
325 // all other xsi:* atts are ignored
331 ct = ToComplexType (el);
332 attList = GetAttributes (ct);
333 table = CollectAttrTable (attList);
335 QName attrName = new QName (
336 source.LocalName, source.NamespaceURI);
337 Attr attr = table [attrName] as Attr;
339 attList.Add (InferNewAttribute (
340 attrName, isNew, ns));
342 table.Remove (attrName);
343 if (attr.RefName != null &&
344 attr.RefName != QName.Empty)
345 continue; // just a reference
346 InferMergedAttribute (attr);
348 } while (source.MoveToNextAttribute ());
350 // mark all attr definitions that did not appear
353 foreach (Attr attr in table.Values)
354 attr.Use = Use.Optional;
357 private XmlSchemaAttribute InferNewAttribute (
358 QName attrName, bool isNewTypeDefinition, string ns)
361 bool mergedRequired = false;
362 if (attrName.Namespace.Length > 0) {
363 // global attribute; might be already defined.
364 attr = GetGlobalAttribute (attrName) as Attr;
366 attr = CreateGlobalAttribute (attrName);
367 attr.SchemaTypeName =
368 InferSimpleType (source.Value);
370 InferMergedAttribute (attr);
372 attr.Use == Use.Required;
375 attr.RefName = attrName;
376 AddImport (ns, attrName.Namespace);
380 attr.Name = attrName.Name;
381 attr.SchemaTypeName =
382 InferSimpleType (source.Value);
384 if (!laxOccurrence &&
385 (isNewTypeDefinition || mergedRequired))
386 attr.Use = Use.Required;
388 attr.Use = Use.Optional;
393 // validate string value agains attr and
394 // if invalid, then relax the type.
395 private void InferMergedAttribute (Attr attr)
397 attr.SchemaTypeName = InferMergedType (source.Value,
398 attr.SchemaTypeName);
399 attr.SchemaType = null;
402 private QName InferMergedType (string value, QName typeName)
404 // examine value against specified type and
405 // if unacceptable, then return a relaxed type.
407 SimpleType st = XmlSchemaType.GetBuiltInSimpleType (
409 if (st == null) // non-primitive type => see above.
413 st.Datatype.ParseValue (value,
415 source as IXmlNamespaceResolver);
418 st = st.BaseXmlSchemaType as XmlSchemaSimpleType;
419 typeName = st != null ? st.QualifiedName : QName.Empty;
421 } while (typeName != QName.Empty);
425 private SOMList GetAttributes (ComplexType ct)
427 if (ct.ContentModel == null)
428 return ct.Attributes;
430 SimpleModel sc = ct.ContentModel as SimpleModel;
432 SimpleExt sce = sc.Content as SimpleExt;
434 return sce.Attributes;
435 SimpleRst scr = sc.Content as SimpleRst;
437 return scr.Attributes;
439 throw Error (sc, "Invalid simple content model.");
441 ComplexModel cc = ct.ContentModel as ComplexModel;
443 ComplexExt cce = cc.Content as ComplexExt;
445 return cce.Attributes;
446 ComplexRst ccr = cc.Content as ComplexRst;
448 return ccr.Attributes;
450 throw Error (cc, "Invalid simple content model.");
452 throw Error (cc, "Invalid complexType. Should not happen.");
455 private ComplexType ToComplexType (Element el)
457 QName name = el.SchemaTypeName;
458 XmlSchemaType type = el.SchemaType;
460 // 1. element type is complex.
461 ComplexType ct = type as ComplexType;
465 // 2. reference to global complexType.
466 XmlSchemaType globalType = schemas.GlobalTypes [name]
468 ct = globalType as ComplexType;
472 ct = new ComplexType ();
474 el.SchemaTypeName = QName.Empty;
476 // 3. base type name is xs:anyType or no specification.
477 // <xs:complexType />
478 if (name == QNameAnyType)
480 else if (type == null && name == QName.Empty)
483 SimpleModel sc = new SimpleModel ();
484 ct.ContentModel = sc;
486 // 4. type is simpleType
487 // -> extension of existing simple type.
488 SimpleType st = type as SimpleType;
490 SimpleRst scr = new SimpleRst ();
496 SimpleExt sce = new SimpleExt ();
499 // 5. type name points to primitive type
500 // -> simple extension of a primitive type
501 st = XmlSchemaType.GetBuiltInSimpleType (name);
503 sce.BaseTypeName = name;
507 // 6. type name points to global simpleType.
508 st = globalType as SimpleType;
510 sce.BaseTypeName = name;
514 throw Error (el, "Unexpected schema component that contains simpleTypeName that could not be resolved.");
521 private void InferAsEmptyElement (Element el, string ns,
524 ComplexType ct = el.SchemaType as ComplexType;
527 ct.ContentModel as SimpleModel;
529 ToEmptiableSimpleContent (sm, isNew);
533 ComplexModel cm = ct.ContentModel
536 ToEmptiableComplexContent (cm, isNew);
540 if (ct.Particle != null)
541 ct.Particle.MinOccurs = 0;
544 SimpleType st = el.SchemaType as SimpleType;
546 st = MakeBaseTypeAsEmptiable (st);
547 switch (st.QualifiedName.Namespace) {
548 case XmlSchema.Namespace:
550 el.SchemaTypeName = st.QualifiedName;
559 private SimpleType MakeBaseTypeAsEmptiable (SimpleType st)
561 switch (st.QualifiedName.Namespace) {
562 case XmlSchema.Namespace:
564 // If a primitive type
565 return XmlSchemaType.GetBuiltInSimpleType (
568 SimpleTypeRst str = st.Content as SimpleTypeRst;
571 foreach (SchemaFacet f in str.Facets) {
572 if (f is LengthFacet ||
573 f is MinLengthFacet) {
575 al = new ArrayList ();
579 foreach (SchemaFacet f in al)
580 str.Facets.Remove (f);
581 if (str.BaseType != null)
583 MakeBaseTypeAsEmptiable (st);
585 // It might have a reference to an
586 // external simple type, but there is
587 // no assurance that any of those
588 // external types allow an empty
589 // string. So just set base type as
591 str.BaseTypeName = QNameString;
592 } // union/list can have empty string value.
597 private void ToEmptiableSimpleContent (
598 SimpleModel sm, bool isNew)
600 SimpleExt se = sm.Content as SimpleExt;
602 se.BaseTypeName = QNameString;
604 SimpleRst sr = sm.Content
607 throw Error (sm, "Invalid simple content model was passed.");
608 sr.BaseTypeName = QNameString;
613 private void ToEmptiableComplexContent (
614 ComplexModel cm, bool isNew)
616 ComplexExt ce = cm.Content
619 if (ce.Particle != null)
620 ce.Particle.MinOccurs = 0;
621 else if (ce.BaseTypeName != null &&
622 ce.BaseTypeName != QName.Empty &&
623 ce.BaseTypeName != QNameAnyType)
624 throw Error (ce, "Complex type content extension has a reference to an external component that is not supported.");
627 ComplexRst cr = cm.Content
630 throw Error (cm, "Invalid complex content model was passed.");
631 if (cr.Particle != null)
632 cr.Particle.MinOccurs = 0;
633 else if (cr.BaseTypeName != null &&
634 cr.BaseTypeName != QName.Empty &&
635 cr.BaseTypeName != QNameAnyType)
636 throw Error (cr, "Complex type content extension has a reference to an external component that is not supported.");
640 private void InferContent (Element el, string ns, bool isNew)
643 source.MoveToContent ();
644 switch (source.NodeType) {
645 case XmlNodeType.EndElement:
646 InferAsEmptyElement (el, ns, isNew);
648 case XmlNodeType.Element:
649 InferComplexContent (el, ns, isNew);
651 case XmlNodeType.Text:
652 case XmlNodeType.CDATA:
653 case XmlNodeType.SignificantWhitespace:
654 InferTextContent (el, isNew);
655 source.MoveToContent ();
656 if (source.NodeType == XmlNodeType.Element)
657 goto case XmlNodeType.Element;
659 case XmlNodeType.Whitespace:
660 InferContent (el, ns, isNew); // skip and retry
665 private void InferComplexContent (Element el, string ns,
668 ComplexType ct = ToComplexType (el);
669 ToComplexContentType (ct);
672 bool consumed = false;
675 switch (source.NodeType) {
676 case XmlNodeType.Element:
677 Sequence s = PopulateSequence (ct);
678 Choice c = s.Items.Count > 0 ?
679 s.Items [0] as Choice :
684 ProcessSequence (ct, s, ns,
688 source.MoveToContent ();
690 case XmlNodeType.Text:
691 case XmlNodeType.CDATA:
692 case XmlNodeType.SignificantWhitespace:
694 source.ReadString ();
695 source.MoveToContent ();
697 case XmlNodeType.EndElement:
699 case XmlNodeType.None:
700 throw new NotImplementedException ("Internal Error: Should not happen.");
705 private void InferTextContent (Element el, bool isNew)
707 string value = source.ReadString ();
708 if (el.SchemaType == null) {
709 if (el.SchemaTypeName == QName.Empty) {
710 // no type information -> infer type
720 switch (el.SchemaTypeName.Namespace) {
721 case XmlSchema.Namespace:
723 // existing primitive type
724 el.SchemaTypeName = InferMergedType (
725 value, el.SchemaTypeName);
728 ComplexType ct = schemas.GlobalTypes [
731 // If it is complex, then just set
732 // mixed='true' (type cannot be set.)
733 // If it is simple, then we cannot
734 // make sure that string value is
735 // valid. So just set as xs:string.
739 el.SchemaTypeName = QNameString;
745 SimpleType st = el.SchemaType as SimpleType;
747 // If simple, then (described above)
748 el.SchemaType = null;
749 el.SchemaTypeName = QNameString;
754 ComplexType ect = el.SchemaType as ComplexType;
756 SimpleModel sm = ect.ContentModel as SimpleModel;
764 SimpleExt se = sm.Content as SimpleExt;
766 se.BaseTypeName = InferMergedType (value,
768 SimpleRst sr = sm.Content as SimpleRst;
770 sr.BaseTypeName = InferMergedType (value,
776 private void MarkAsMixed (ComplexType ct)
778 ComplexModel cm = ct.ContentModel as ComplexModel;
789 private void ProcessLax (Choice c, string ns)
791 foreach (Particle p in c.Items) {
792 Element el = p as Element;
794 throw Error (c, String.Format ("Target schema item contains unacceptable particle {0}. Only element is allowed here."));
795 if (ElementMatches (el, ns)) {
796 InferElement (el, ns, false);
800 // append a new element particle to lax term.
801 Element nel = new Element ();
802 if (source.NamespaceURI == ns)
803 nel.Name = source.LocalName;
805 nel.RefName = new QName (source.LocalName,
806 source.NamespaceURI);
807 AddImport (ns, source.NamespaceURI);
809 InferElement (nel, source.NamespaceURI, true);
813 private bool ElementMatches (Element el, string ns)
815 bool matches = false;
816 if (el.RefName != QName.Empty) {
817 if (el.RefName.Name == source.LocalName &&
818 el.RefName.Namespace ==
822 else if (el.Name == source.LocalName &&
823 ns == source.NamespaceURI)
828 private void ProcessSequence (ComplexType ct, Sequence s,
829 string ns, ref int position, ref bool consumed,
832 for (int i = 0; i < position; i++) {
833 Element iel = s.Items [i] as Element;
834 if (ElementMatches (iel, ns)) {
835 // Sequence element type violation
836 // might happen (might not, but we
837 // cannot backtrack here). So switch
838 // to sequence of choice* here.
839 ProcessLax (ToSequenceOfChoice (s), ns);
844 if (s.Items.Count <= position) {
845 QName name = new QName (source.LocalName,
846 source.NamespaceURI);
847 Element nel = CreateElement (name);
850 InferElement (nel, ns, true);
851 if (ns == name.Namespace)
854 Element re = new Element ();
858 AddImport (ns, name.Namespace);
864 Element el = s.Items [position] as Element;
866 throw Error (s, String.Format ("Target complex type content sequence has an unacceptable type of particle {0}", s.Items [position]));
867 bool matches = ElementMatches (el, ns);
870 el.MaxOccursString = "unbounded";
871 InferElement (el, source.NamespaceURI, false);
872 source.MoveToContent ();
873 switch (source.NodeType) {
874 case XmlNodeType.None:
875 if (source.NodeType ==
877 goto case XmlNodeType.Element;
878 else if (source.NodeType ==
879 XmlNodeType.EndElement)
880 goto case XmlNodeType.EndElement;
882 case XmlNodeType.Element:
883 ProcessSequence (ct, s, ns, ref position,
884 ref consumed, isNew);
886 case XmlNodeType.Text:
887 case XmlNodeType.CDATA:
888 case XmlNodeType.SignificantWhitespace:
890 source.ReadString ();
891 goto case XmlNodeType.None;
892 case XmlNodeType.Whitespace:
893 source.ReadString ();
894 goto case XmlNodeType.None;
895 case XmlNodeType.EndElement:
906 ProcessSequence (ct, s, ns,
907 ref position, ref consumed,
911 ProcessLax (ToSequenceOfChoice (s), ns);
915 // Note that it does not return the changed sequence.
916 private Choice ToSequenceOfChoice (Sequence s)
918 Choice c = new Choice ();
921 c.MaxOccursString = "unbounded";
922 foreach (Particle p in s.Items)
929 // It makes complexType not to have Simple content model.
930 private void ToComplexContentType (ComplexType type)
932 SimpleModel sm = type.ContentModel as SimpleModel;
936 SOMList atts = GetAttributes (type);
937 foreach (SOMObject o in atts)
938 type.Attributes.Add (o);
939 // FIXME: need to copy AnyAttribute.
940 // (though not considered right now)
941 type.ContentModel = null;
945 private Sequence PopulateSequence (ComplexType ct)
947 Particle p = PopulateParticle (ct);
948 Sequence s = p as Sequence;
952 throw Error (ct, String.Format ("Target complexType contains unacceptable type of particle {0}", p));
955 private Sequence CreateSequence ()
957 Sequence s = new Sequence ();
963 private Particle PopulateParticle (ComplexType ct)
965 if (ct.ContentModel == null) {
966 if (ct.Particle == null)
967 ct.Particle = CreateSequence ();
970 ComplexModel cm = ct.ContentModel as ComplexModel;
972 ComplexExt ce = cm.Content as ComplexExt;
974 if (ce.Particle == null)
975 ce.Particle = CreateSequence ();
978 ComplexRst cr = cm.Content as ComplexRst;
980 if (cr.Particle == null)
981 cr.Particle = CreateSequence ();
985 throw Error (ct, "Schema inference internal error. The complexType should have been converted to have a complex content.");
992 // primitive type inference.
993 // When running lax type inference, it just returns xs:string.
994 private QName InferSimpleType (string value)
996 if (laxTypeInference)
1000 // 0 and 1 are not infered as byte unlike MS.XSDInfer
1005 return QNameBoolean;
1008 long dec = XmlConvert.ToInt64 (value);
1009 if (byte.MinValue <= dec && dec <= byte.MaxValue)
1011 if (sbyte.MinValue <= dec && dec <= sbyte.MaxValue)
1013 if (ushort.MinValue <= dec && dec <= ushort.MaxValue)
1015 if (short.MinValue <= dec && dec <= short.MaxValue)
1017 if (uint.MinValue <= dec && dec <= uint.MaxValue)
1019 if (int.MinValue <= dec && dec <= int.MaxValue)
1022 } catch (Exception) {
1025 XmlConvert.ToUInt64 (value);
1027 } catch (Exception) {
1030 XmlConvert.ToDecimal (value);
1031 return QNameDecimal;
1032 } catch (Exception) {
1035 double dbl = XmlConvert.ToDouble (value);
1036 if (float.MinValue <= dbl &&
1037 dbl <= float.MaxValue)
1041 } catch (Exception) {
1044 // FIXME: also try DateTimeSerializationMode
1046 XmlConvert.ToDateTime (value);
1047 return QNameDateTime;
1048 } catch (Exception) {
1051 XmlConvert.ToTimeSpan (value);
1052 return QNameDuration;
1053 } catch (Exception) {
1064 private Element GetGlobalElement (QName name)
1066 Element el = newElements [name] as Element;
1068 el = schemas.GlobalElements [name] as Element;
1072 private Attr GetGlobalAttribute (QName name)
1074 Attr a = newElements [name] as Attr;
1076 a = schemas.GlobalAttributes [name] as Attr;
1080 private Element CreateElement (QName name)
1082 Element el = new Element ();
1083 el.Name = name.Name;
1087 private Element CreateGlobalElement (QName name)
1089 Element el = CreateElement (name);
1090 XmlSchema schema = PopulateSchema (name.Namespace);
1091 schema.Items.Add (el);
1092 newElements.Add (name, el);
1096 private Attr CreateGlobalAttribute (QName name)
1098 Attr attr = new Attr ();
1099 XmlSchema schema = PopulateSchema (name.Namespace);
1100 attr.Name = name.Name;
1101 schema.Items.Add (attr);
1102 newAttributes.Add (name, attr);
1106 // Note that the return value never assures that all the
1107 // components in the parameter ns must reside in it.
1108 private XmlSchema PopulateSchema (string ns)
1110 ICollection list = schemas.Schemas (ns);
1111 if (list.Count > 0) {
1112 IEnumerator e = list.GetEnumerator ();
1114 return (XmlSchema) e.Current;
1116 XmlSchema s = new XmlSchema ();
1117 if (ns != null && ns.Length > 0)
1118 s.TargetNamespace = ns;
1119 s.ElementFormDefault = Form.Qualified;
1120 s.AttributeFormDefault = Form.Unqualified;
1125 private XmlSchemaInferenceException Error (
1126 XmlSchemaObject sourceObj,
1129 // This override is mainly for schema component error.
1130 return Error (sourceObj, false, message);
1133 private XmlSchemaInferenceException Error (
1134 XmlSchemaObject sourceObj,
1138 string msg = String.Concat (
1141 String.Format (". Related schema component is {0}",
1142 sourceObj.SourceUri,
1143 sourceObj.LineNumber,
1144 sourceObj.LinePosition) :
1147 String.Format (". {0}", source.BaseURI) :
1150 IXmlLineInfo li = source as IXmlLineInfo;
1151 if (useReader && li != null)
1152 return new XmlSchemaInferenceException (
1153 msg, null, li.LineNumber,
1156 return new XmlSchemaInferenceException (msg);