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
71 // - merge primitive types
72 // - infer gYearMonth too
73 // - in some cases sequence should contain element whose minOccurs=0
74 // (no obvious rules right now)
75 // - reject some non-supported schema components
76 public sealed class XmlSchemaInference
78 public enum InferenceOption {
83 InferenceOption occurrence = InferenceOption.Restricted;
84 InferenceOption typeInference = InferenceOption.Restricted;
86 public XmlSchemaInference ()
90 public InferenceOption Occurrence {
91 get { return occurrence; }
92 set { occurrence = value; }
95 public InferenceOption TypeInference {
96 get { return TypeInference; }
97 set { typeInference = value; }
100 public XmlSchemaSet InferSchema (XmlReader xmlReader)
102 return InferSchema (xmlReader, new XmlSchemaSet ());
105 public XmlSchemaSet InferSchema (XmlReader xmlReader,
106 XmlSchemaSet schemas)
108 return XsdInference.Process (xmlReader, schemas,
109 occurrence == InferenceOption.Relaxed,
110 typeInference == InferenceOption.Relaxed);
116 public static XmlSchemaSet Process (XmlReader xmlReader,
117 XmlSchemaSet schemas,
119 bool laxTypeInference)
121 XsdInference impl = new XsdInference (xmlReader,
122 schemas, laxOccurrence, laxTypeInference);
127 public const string NamespaceXml =
128 "http://www.w3.org/XML/1998/namespace";
130 public const string NamespaceXmlns =
131 "http://www.w3.org/2000/xmlns/";
133 public const string XdtNamespace =
134 "http://www.w3.org/2003/11/xpath-datatypes";
136 static readonly QName QNameString = new QName (
137 "string", XmlSchema.Namespace);
139 static readonly QName QNameBoolean = new QName (
140 "boolean", XmlSchema.Namespace);
142 static readonly QName QNameAnyType = new QName (
143 "anyType", XmlSchema.Namespace);
145 static readonly QName QNameByte = new QName (
146 "byte", XmlSchema.Namespace);
148 static readonly QName QNameUByte = new QName (
149 "unsignedByte", XmlSchema.Namespace);
151 static readonly QName QNameShort = new QName (
152 "short", XmlSchema.Namespace);
154 static readonly QName QNameUShort = new QName (
155 "unsignedShort", XmlSchema.Namespace);
157 static readonly QName QNameInt = new QName (
158 "int", XmlSchema.Namespace);
160 static readonly QName QNameUInt = new QName (
161 "unsignedInt", XmlSchema.Namespace);
163 static readonly QName QNameLong = new QName (
164 "long", XmlSchema.Namespace);
166 static readonly QName QNameULong = new QName (
167 "unsignedLong", XmlSchema.Namespace);
169 static readonly QName QNameDecimal = new QName (
170 "decimal", XmlSchema.Namespace);
172 static readonly QName QNameUDecimal = new QName (
173 "unsignedDecimal", XmlSchema.Namespace);
175 static readonly QName QNameDouble = new QName (
176 "double", XmlSchema.Namespace);
178 static readonly QName QNameFloat = new QName (
179 "float", XmlSchema.Namespace);
181 static readonly QName QNameDateTime = new QName (
182 "dateTime", XmlSchema.Namespace);
184 static readonly QName QNameDuration = new QName (
185 "duration", XmlSchema.Namespace);
188 XmlSchemaSet schemas;
190 bool laxTypeInference;
192 Hashtable newElements = new Hashtable ();
193 Hashtable newAttributes = new Hashtable ();
195 private XsdInference (XmlReader xmlReader,
196 XmlSchemaSet schemas,
198 bool laxTypeInference)
200 this.source = xmlReader;
201 this.schemas = schemas;
202 this.laxOccurrence = laxOccurrence;
203 this.laxTypeInference = laxTypeInference;
208 // XmlSchemaSet need to be compiled.
211 // move to top-level element
212 source.MoveToContent ();
213 int depth = source.Depth;
214 if (source.NodeType != XmlNodeType.Element)
215 throw new ArgumentException ("Argument XmlReader content is expected to be an element.");
217 QName qname = new QName (source.LocalName,
218 source.NamespaceURI);
219 Element el = GetGlobalElement (qname);
221 el = CreateGlobalElement (qname);
222 InferElement (el, qname.Namespace, true);
225 InferElement (el, qname.Namespace, false);
227 // FIXME: compile again.
228 // foreach (XmlSchema schema in schemas.Schemas ())
229 // schemas.Reprocess (schema);
232 private void AddImport (string current, string import)
234 foreach (XmlSchema schema in schemas.Schemas (current)) {
236 foreach (XmlSchemaExternal e in schema.Includes) {
237 Import imp = e as Import;
239 imp.Namespace == import)
244 Import newimp = new Import ();
245 newimp.Namespace = import;
246 schema.Includes.Add (newimp);
250 private void IncludeXmlAttributes ()
252 if (schemas.Schemas (NamespaceXml).Count == 0)
253 // FIXME: do it from resources.
254 schemas.Add (NamespaceXml,
255 "http://www.w3.org/2001/xml.xsd");
258 private void InferElement (Element el, string ns, bool isNew)
260 // Quick check for reference to another definition
261 // (i.e. element ref='...' that should be redirected)
262 if (el.RefName != QName.Empty) {
263 Element body = GetGlobalElement (el.RefName);
265 body = CreateElement (el.RefName);
266 InferElement (body, ns, true);
269 InferElement (body, ns, isNew);
274 if (source.MoveToFirstAttribute ()) {
275 InferAttributes (el, ns, isNew);
276 source.MoveToElement ();
280 if (source.IsEmptyElement) {
281 InferAsEmptyElement (el, ns, isNew);
283 source.MoveToContent ();
286 InferContent (el, ns, isNew);
287 source.ReadEndElement ();
289 if (el.SchemaType == null &&
290 el.SchemaTypeName == QName.Empty)
291 el.SchemaTypeName = QNameString;
294 #region Attribute Inference
296 private Hashtable CollectAttrTable (SOMList attList)
298 // get attribute definition table.
299 Hashtable table = new Hashtable ();
300 foreach (XmlSchemaObject obj in attList) {
301 Attr attr = obj as Attr;
303 throw Error (obj, String.Format ("Attribute inference only supports direct attribute definition. {0} is not supported.", obj.GetType ()));
304 if (attr.RefName != QName.Empty)
305 table.Add (attr.RefName, attr);
307 table.Add (new QName (attr.Name, ""),
313 private void InferAttributes (Element el, string ns, bool isNew)
315 // Now this element is going to have complexType.
316 // It currently not, then we have to replace it.
317 ComplexType ct = null;
318 SOMList attList = null;
319 Hashtable table = null;
322 switch (source.NamespaceURI) {
324 if (schemas.Schemas (
325 NamespaceXml) .Count == 0)
326 IncludeXmlAttributes ();
328 case XmlSchema.InstanceNamespace:
329 if (source.LocalName == "nil")
330 el.IsNillable = true;
331 // all other xsi:* atts are ignored
337 ct = ToComplexType (el);
338 attList = GetAttributes (ct);
339 table = CollectAttrTable (attList);
341 QName attrName = new QName (
342 source.LocalName, source.NamespaceURI);
343 Attr attr = table [attrName] as Attr;
345 attList.Add (InferNewAttribute (
346 attrName, isNew, ns));
348 table.Remove (attrName);
349 if (attr.RefName != null &&
350 attr.RefName != QName.Empty)
351 continue; // just a reference
352 InferMergedAttribute (attr);
354 } while (source.MoveToNextAttribute ());
356 // mark all attr definitions that did not appear
359 foreach (Attr attr in table.Values)
360 attr.Use = Use.Optional;
363 private XmlSchemaAttribute InferNewAttribute (
364 QName attrName, bool isNewTypeDefinition, string ns)
367 bool mergedRequired = false;
368 if (attrName.Namespace.Length > 0) {
369 // global attribute; might be already defined.
370 attr = GetGlobalAttribute (attrName) as Attr;
372 attr = CreateGlobalAttribute (attrName);
373 attr.SchemaTypeName =
374 InferSimpleType (source.Value);
376 InferMergedAttribute (attr);
378 attr.Use == Use.Required;
381 attr.RefName = attrName;
382 AddImport (ns, attrName.Namespace);
386 attr.Name = attrName.Name;
387 attr.SchemaTypeName =
388 InferSimpleType (source.Value);
390 if (!laxOccurrence &&
391 (isNewTypeDefinition || mergedRequired))
392 attr.Use = Use.Required;
394 attr.Use = Use.Optional;
399 // validate string value agains attr and
400 // if invalid, then relax the type.
401 private void InferMergedAttribute (Attr attr)
403 attr.SchemaTypeName = InferMergedType (source.Value,
404 attr.SchemaTypeName);
405 attr.SchemaType = null;
408 private QName InferMergedType (string value, QName typeName)
410 // examine value against specified type and
411 // if unacceptable, then return a relaxed type.
413 SimpleType st = XmlSchemaType.GetBuiltInSimpleType (
415 if (st == null) // non-primitive type => see above.
419 st.Datatype.ParseValue (value,
421 source as IXmlNamespaceResolver);
424 st = st.BaseXmlSchemaType as XmlSchemaSimpleType;
425 typeName = st != null ? st.QualifiedName : QName.Empty;
427 } while (typeName != QName.Empty);
431 private SOMList GetAttributes (ComplexType ct)
433 if (ct.ContentModel == null)
434 return ct.Attributes;
436 SimpleModel sc = ct.ContentModel as SimpleModel;
438 SimpleExt sce = sc.Content as SimpleExt;
440 return sce.Attributes;
441 SimpleRst scr = sc.Content as SimpleRst;
443 return scr.Attributes;
445 throw Error (sc, "Invalid simple content model.");
447 ComplexModel cc = ct.ContentModel as ComplexModel;
449 ComplexExt cce = cc.Content as ComplexExt;
451 return cce.Attributes;
452 ComplexRst ccr = cc.Content as ComplexRst;
454 return ccr.Attributes;
456 throw Error (cc, "Invalid simple content model.");
458 throw Error (cc, "Invalid complexType. Should not happen.");
461 private ComplexType ToComplexType (Element el)
463 QName name = el.SchemaTypeName;
464 XmlSchemaType type = el.SchemaType;
466 // 1. element type is complex.
467 ComplexType ct = type as ComplexType;
471 // 2. reference to global complexType.
472 XmlSchemaType globalType = schemas.GlobalTypes [name]
474 ct = globalType as ComplexType;
478 ct = new ComplexType ();
480 el.SchemaTypeName = QName.Empty;
482 // 3. base type name is xs:anyType or no specification.
483 // <xs:complexType />
484 if (name == QNameAnyType)
486 else if (type == null && name == QName.Empty)
489 SimpleModel sc = new SimpleModel ();
490 ct.ContentModel = sc;
492 // 4. type is simpleType
493 // -> extension of existing simple type.
494 SimpleType st = type as SimpleType;
496 SimpleRst scr = new SimpleRst ();
502 SimpleExt sce = new SimpleExt ();
505 // 5. type name points to primitive type
506 // -> simple extension of a primitive type
507 st = XmlSchemaType.GetBuiltInSimpleType (name);
509 sce.BaseTypeName = name;
513 // 6. type name points to global simpleType.
514 st = globalType as SimpleType;
516 sce.BaseTypeName = name;
520 throw Error (el, "Unexpected schema component that contains simpleTypeName that could not be resolved.");
527 private void InferAsEmptyElement (Element el, string ns,
530 ComplexType ct = el.SchemaType as ComplexType;
533 ct.ContentModel as SimpleModel;
535 ToEmptiableSimpleContent (sm, isNew);
539 ComplexModel cm = ct.ContentModel
542 ToEmptiableComplexContent (cm, isNew);
546 if (ct.Particle != null)
547 ct.Particle.MinOccurs = 0;
550 SimpleType st = el.SchemaType as SimpleType;
552 st = MakeBaseTypeAsEmptiable (st);
553 switch (st.QualifiedName.Namespace) {
554 case XmlSchema.Namespace:
556 el.SchemaTypeName = st.QualifiedName;
565 private SimpleType MakeBaseTypeAsEmptiable (SimpleType st)
567 switch (st.QualifiedName.Namespace) {
568 case XmlSchema.Namespace:
570 // If a primitive type
571 return XmlSchemaType.GetBuiltInSimpleType (
574 SimpleTypeRst str = st.Content as SimpleTypeRst;
577 foreach (SchemaFacet f in str.Facets) {
578 if (f is LengthFacet ||
579 f is MinLengthFacet) {
581 al = new ArrayList ();
585 foreach (SchemaFacet f in al)
586 str.Facets.Remove (f);
587 if (str.BaseType != null)
589 MakeBaseTypeAsEmptiable (st);
591 // It might have a reference to an
592 // external simple type, but there is
593 // no assurance that any of those
594 // external types allow an empty
595 // string. So just set base type as
597 str.BaseTypeName = QNameString;
598 } // union/list can have empty string value.
603 private void ToEmptiableSimpleContent (
604 SimpleModel sm, bool isNew)
606 SimpleExt se = sm.Content as SimpleExt;
608 se.BaseTypeName = QNameString;
610 SimpleRst sr = sm.Content
613 throw Error (sm, "Invalid simple content model was passed.");
614 sr.BaseTypeName = QNameString;
619 private void ToEmptiableComplexContent (
620 ComplexModel cm, bool isNew)
622 ComplexExt ce = cm.Content
625 if (ce.Particle != null)
626 ce.Particle.MinOccurs = 0;
627 else if (ce.BaseTypeName != null &&
628 ce.BaseTypeName != QName.Empty &&
629 ce.BaseTypeName != QNameAnyType)
630 throw Error (ce, "Complex type content extension has a reference to an external component that is not supported.");
633 ComplexRst cr = cm.Content
636 throw Error (cm, "Invalid complex content model was passed.");
637 if (cr.Particle != null)
638 cr.Particle.MinOccurs = 0;
639 else if (cr.BaseTypeName != null &&
640 cr.BaseTypeName != QName.Empty &&
641 cr.BaseTypeName != QNameAnyType)
642 throw Error (cr, "Complex type content extension has a reference to an external component that is not supported.");
646 private void InferContent (Element el, string ns, bool isNew)
649 source.MoveToContent ();
650 switch (source.NodeType) {
651 case XmlNodeType.EndElement:
652 InferAsEmptyElement (el, ns, isNew);
654 case XmlNodeType.Element:
655 InferComplexContent (el, ns, isNew);
657 case XmlNodeType.Text:
658 case XmlNodeType.CDATA:
659 case XmlNodeType.SignificantWhitespace:
660 InferTextContent (el, isNew);
661 source.MoveToContent ();
662 if (source.NodeType == XmlNodeType.Element)
663 goto case XmlNodeType.Element;
665 case XmlNodeType.Whitespace:
666 InferContent (el, ns, isNew); // skip and retry
671 private void InferComplexContent (Element el, string ns,
674 ComplexType ct = ToComplexType (el);
675 ToComplexContentType (ct);
678 bool consumed = false;
681 switch (source.NodeType) {
682 case XmlNodeType.Element:
683 Sequence s = PopulateSequence (ct);
684 Choice c = s.Items.Count > 0 ?
685 s.Items [0] as Choice :
690 ProcessSequence (ct, s, ns,
694 source.MoveToContent ();
696 case XmlNodeType.Text:
697 case XmlNodeType.CDATA:
698 case XmlNodeType.SignificantWhitespace:
700 source.ReadString ();
701 source.MoveToContent ();
703 case XmlNodeType.EndElement:
705 case XmlNodeType.None:
706 throw new NotImplementedException ("Internal Error: Should not happen.");
711 private void InferTextContent (Element el, bool isNew)
713 string value = source.ReadString ();
714 if (el.SchemaType == null) {
715 if (el.SchemaTypeName == QName.Empty) {
716 // no type information -> infer type
726 switch (el.SchemaTypeName.Namespace) {
727 case XmlSchema.Namespace:
729 // existing primitive type
730 el.SchemaTypeName = InferMergedType (
731 value, el.SchemaTypeName);
734 ComplexType ct = schemas.GlobalTypes [
737 // If it is complex, then just set
738 // mixed='true' (type cannot be set.)
739 // If it is simple, then we cannot
740 // make sure that string value is
741 // valid. So just set as xs:string.
745 el.SchemaTypeName = QNameString;
751 SimpleType st = el.SchemaType as SimpleType;
753 // If simple, then (described above)
754 el.SchemaType = null;
755 el.SchemaTypeName = QNameString;
760 ComplexType ect = el.SchemaType as ComplexType;
762 SimpleModel sm = ect.ContentModel as SimpleModel;
770 SimpleExt se = sm.Content as SimpleExt;
772 se.BaseTypeName = InferMergedType (value,
774 SimpleRst sr = sm.Content as SimpleRst;
776 sr.BaseTypeName = InferMergedType (value,
782 private void MarkAsMixed (ComplexType ct)
784 ComplexModel cm = ct.ContentModel as ComplexModel;
795 private void ProcessLax (Choice c, string ns)
797 foreach (Particle p in c.Items) {
798 Element el = p as Element;
800 throw Error (c, String.Format ("Target schema item contains unacceptable particle {0}. Only element is allowed here."));
801 if (ElementMatches (el, ns)) {
802 InferElement (el, ns, false);
806 // append a new element particle to lax term.
807 Element nel = new Element ();
808 if (source.NamespaceURI == ns)
809 nel.Name = source.LocalName;
811 nel.RefName = new QName (source.LocalName,
812 source.NamespaceURI);
813 AddImport (ns, source.NamespaceURI);
815 InferElement (nel, source.NamespaceURI, true);
819 private bool ElementMatches (Element el, string ns)
821 bool matches = false;
822 if (el.RefName != QName.Empty) {
823 if (el.RefName.Name == source.LocalName &&
824 el.RefName.Namespace ==
828 else if (el.Name == source.LocalName &&
829 ns == source.NamespaceURI)
834 private void ProcessSequence (ComplexType ct, Sequence s,
835 string ns, ref int position, ref bool consumed,
838 for (int i = 0; i < position; i++) {
839 Element iel = s.Items [i] as Element;
840 if (ElementMatches (iel, ns)) {
841 // Sequence element type violation
842 // might happen (might not, but we
843 // cannot backtrack here). So switch
844 // to sequence of choice* here.
845 ProcessLax (ToSequenceOfChoice (s), ns);
850 if (s.Items.Count <= position) {
851 QName name = new QName (source.LocalName,
852 source.NamespaceURI);
853 Element nel = CreateElement (name);
856 InferElement (nel, ns, true);
857 if (ns == name.Namespace)
860 Element re = new Element ();
864 AddImport (ns, name.Namespace);
870 Element el = s.Items [position] as Element;
872 throw Error (s, String.Format ("Target complex type content sequence has an unacceptable type of particle {0}", s.Items [position]));
873 bool matches = ElementMatches (el, ns);
876 el.MaxOccursString = "unbounded";
877 InferElement (el, source.NamespaceURI, false);
878 source.MoveToContent ();
879 switch (source.NodeType) {
880 case XmlNodeType.None:
881 if (source.NodeType ==
883 goto case XmlNodeType.Element;
884 else if (source.NodeType ==
885 XmlNodeType.EndElement)
886 goto case XmlNodeType.EndElement;
888 case XmlNodeType.Element:
889 ProcessSequence (ct, s, ns, ref position,
890 ref consumed, isNew);
892 case XmlNodeType.Text:
893 case XmlNodeType.CDATA:
894 case XmlNodeType.SignificantWhitespace:
896 source.ReadString ();
897 goto case XmlNodeType.None;
898 case XmlNodeType.Whitespace:
899 source.ReadString ();
900 goto case XmlNodeType.None;
901 case XmlNodeType.EndElement:
912 ProcessSequence (ct, s, ns,
913 ref position, ref consumed,
917 ProcessLax (ToSequenceOfChoice (s), ns);
921 // Note that it does not return the changed sequence.
922 private Choice ToSequenceOfChoice (Sequence s)
924 Choice c = new Choice ();
927 c.MaxOccursString = "unbounded";
928 foreach (Particle p in s.Items)
935 // It makes complexType not to have Simple content model.
936 private void ToComplexContentType (ComplexType type)
938 SimpleModel sm = type.ContentModel as SimpleModel;
942 SOMList atts = GetAttributes (type);
943 foreach (SOMObject o in atts)
944 type.Attributes.Add (o);
945 // FIXME: need to copy AnyAttribute.
946 // (though not considered right now)
947 type.ContentModel = null;
951 private Sequence PopulateSequence (ComplexType ct)
953 Particle p = PopulateParticle (ct);
954 Sequence s = p as Sequence;
958 throw Error (ct, String.Format ("Target complexType contains unacceptable type of particle {0}", p));
961 private Sequence CreateSequence ()
963 Sequence s = new Sequence ();
969 private Particle PopulateParticle (ComplexType ct)
971 if (ct.ContentModel == null) {
972 if (ct.Particle == null)
973 ct.Particle = CreateSequence ();
976 ComplexModel cm = ct.ContentModel as ComplexModel;
978 ComplexExt ce = cm.Content as ComplexExt;
980 if (ce.Particle == null)
981 ce.Particle = CreateSequence ();
984 ComplexRst cr = cm.Content as ComplexRst;
986 if (cr.Particle == null)
987 cr.Particle = CreateSequence ();
991 throw Error (ct, "Schema inference internal error. The complexType should have been converted to have a complex content.");
998 // primitive type inference.
999 // When running lax type inference, it just returns xs:string.
1000 private QName InferSimpleType (string value)
1002 if (laxTypeInference)
1006 // 0 and 1 are not infered as byte unlike MS.XSDInfer
1011 return QNameBoolean;
1014 long dec = XmlConvert.ToInt64 (value);
1015 if (byte.MinValue <= dec && dec <= byte.MaxValue)
1017 if (sbyte.MinValue <= dec && dec <= sbyte.MaxValue)
1019 if (ushort.MinValue <= dec && dec <= ushort.MaxValue)
1021 if (short.MinValue <= dec && dec <= short.MaxValue)
1023 if (uint.MinValue <= dec && dec <= uint.MaxValue)
1025 if (int.MinValue <= dec && dec <= int.MaxValue)
1028 } catch (Exception) {
1031 XmlConvert.ToUInt64 (value);
1033 } catch (Exception) {
1036 XmlConvert.ToDecimal (value);
1037 return QNameDecimal;
1038 } catch (Exception) {
1041 double dbl = XmlConvert.ToDouble (value);
1042 if (float.MinValue <= dbl &&
1043 dbl <= float.MaxValue)
1047 } catch (Exception) {
1050 // FIXME: also try DateTimeSerializationMode
1052 XmlConvert.ToDateTime (value);
1053 return QNameDateTime;
1054 } catch (Exception) {
1057 XmlConvert.ToTimeSpan (value);
1058 return QNameDuration;
1059 } catch (Exception) {
1070 private Element GetGlobalElement (QName name)
1072 Element el = newElements [name] as Element;
1074 el = schemas.GlobalElements [name] as Element;
1078 private Attr GetGlobalAttribute (QName name)
1080 Attr a = newElements [name] as Attr;
1082 a = schemas.GlobalAttributes [name] as Attr;
1086 private Element CreateElement (QName name)
1088 Element el = new Element ();
1089 el.Name = name.Name;
1093 private Element CreateGlobalElement (QName name)
1095 Element el = CreateElement (name);
1096 XmlSchema schema = PopulateSchema (name.Namespace);
1097 schema.Items.Add (el);
1098 newElements.Add (name, el);
1102 private Attr CreateGlobalAttribute (QName name)
1104 Attr attr = new Attr ();
1105 XmlSchema schema = PopulateSchema (name.Namespace);
1106 attr.Name = name.Name;
1107 schema.Items.Add (attr);
1108 newAttributes.Add (name, attr);
1112 // Note that the return value never assures that all the
1113 // components in the parameter ns must reside in it.
1114 private XmlSchema PopulateSchema (string ns)
1116 ICollection list = schemas.Schemas (ns);
1117 if (list.Count > 0) {
1118 IEnumerator e = list.GetEnumerator ();
1120 return (XmlSchema) e.Current;
1122 XmlSchema s = new XmlSchema ();
1123 if (ns != null && ns.Length > 0)
1124 s.TargetNamespace = ns;
1125 s.ElementFormDefault = Form.Qualified;
1126 s.AttributeFormDefault = Form.Unqualified;
1131 private XmlSchemaInferenceException Error (
1132 XmlSchemaObject sourceObj,
1135 // This override is mainly for schema component error.
1136 return Error (sourceObj, false, message);
1139 private XmlSchemaInferenceException Error (
1140 XmlSchemaObject sourceObj,
1144 string msg = String.Concat (
1147 String.Format (". Related schema component is {0}",
1148 sourceObj.SourceUri,
1149 sourceObj.LineNumber,
1150 sourceObj.LinePosition) :
1153 String.Format (". {0}", source.BaseURI) :
1156 IXmlLineInfo li = source as IXmlLineInfo;
1157 if (useReader && li != null)
1158 return new XmlSchemaInferenceException (
1159 msg, null, li.LineNumber,
1162 return new XmlSchemaInferenceException (msg);