XmlSchemaImporter.cs 49 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401
  1. //
  2. // System.Xml.Serialization.XmlSchemaImporter
  3. //
  4. // Author:
  5. // Tim Coleman ([email protected])
  6. // Lluis Sanchez Gual ([email protected])
  7. //
  8. // Copyright (C) Tim Coleman, 2002
  9. //
  10. using System.Xml;
  11. using System.Xml.Schema;
  12. using System.Collections;
  13. namespace System.Xml.Serialization {
  14. public class XmlSchemaImporter {
  15. #region Fields
  16. XmlSchemas schemas;
  17. CodeIdentifiers typeIdentifiers;
  18. CodeIdentifiers elemIdentifiers = new CodeIdentifiers ();
  19. Hashtable mappedTypes = new Hashtable ();
  20. Hashtable dataMappedTypes = new Hashtable ();
  21. Queue pendingMaps = new Queue ();
  22. Hashtable sharedAnonymousTypes = new Hashtable ();
  23. bool encodedFormat = false;
  24. XmlReflectionImporter auxXmlRefImporter;
  25. SoapReflectionImporter auxSoapRefImporter;
  26. Hashtable forcedBaseTypes;
  27. static readonly XmlQualifiedName anyType = new XmlQualifiedName ("anyType",XmlSchema.Namespace);
  28. static readonly XmlQualifiedName arrayType = new XmlQualifiedName ("Array",XmlSerializer.EncodingNamespace);
  29. static readonly XmlQualifiedName arrayTypeRefName = new XmlQualifiedName ("arrayType",XmlSerializer.EncodingNamespace);
  30. const string XmlNamespace = "http://www.w3.org/XML/1998/namespace";
  31. XmlSchemaElement anyElement = null;
  32. class MapFixup
  33. {
  34. public XmlTypeMapping Map;
  35. public XmlSchemaComplexType SchemaType;
  36. public XmlQualifiedName TypeName;
  37. }
  38. #endregion
  39. #region Constructors
  40. public XmlSchemaImporter (XmlSchemas schemas)
  41. {
  42. this.schemas = schemas;
  43. typeIdentifiers = new CodeIdentifiers ();
  44. }
  45. public XmlSchemaImporter (XmlSchemas schemas, CodeIdentifiers typeIdentifiers)
  46. : this (schemas)
  47. {
  48. this.typeIdentifiers = typeIdentifiers;
  49. }
  50. internal bool UseEncodedFormat
  51. {
  52. get { return encodedFormat; }
  53. set { encodedFormat = value; }
  54. }
  55. #endregion // Constructors
  56. #region Methods
  57. [MonoTODO]
  58. public XmlMembersMapping ImportAnyType (XmlQualifiedName typeName, string elementName)
  59. {
  60. throw new NotImplementedException ();
  61. }
  62. public XmlTypeMapping ImportDerivedTypeMapping (XmlQualifiedName name, Type baseType)
  63. {
  64. return ImportDerivedTypeMapping (name, baseType, true);
  65. }
  66. public XmlTypeMapping ImportDerivedTypeMapping (XmlQualifiedName name, Type baseType, bool baseTypeCanBeIndirect)
  67. {
  68. XmlQualifiedName qname;
  69. XmlSchemaType stype;
  70. if (encodedFormat)
  71. {
  72. qname = name;
  73. stype = schemas.Find (name, typeof (XmlSchemaComplexType)) as XmlSchemaComplexType;
  74. if (stype == null) throw new InvalidOperationException ("Schema type '" + name + "' not found or not valid");
  75. }
  76. else
  77. {
  78. if (!LocateElement (name, out qname, out stype)) return null;
  79. }
  80. XmlTypeMapping map = GetRegisteredTypeMapping (qname);
  81. if (map != null) return map;
  82. RegisterForcedBaseType (qname, baseType);
  83. map = CreateTypeMapping (qname, SchemaTypes.Class, name);
  84. map.Documentation = GetDocumentation (stype);
  85. RegisterMapFixup (map, qname, (XmlSchemaComplexType)stype);
  86. BuildPendingMaps ();
  87. return map;
  88. }
  89. [MonoTODO]
  90. public XmlTypeMapping ImportDerivedTypeMapping (XmlQualifiedName name, bool baseTypeCanBeIndirect)
  91. {
  92. throw new NotImplementedException ();
  93. }
  94. public XmlMembersMapping ImportMembersMapping (XmlQualifiedName name)
  95. {
  96. XmlSchemaElement elem = (XmlSchemaElement) schemas.Find (name, typeof (XmlSchemaElement));
  97. if (elem == null) throw new InvalidOperationException ("Schema element '" + name + "' not found or not valid");
  98. XmlSchemaComplexType stype;
  99. if (elem.SchemaType != null)
  100. {
  101. stype = elem.SchemaType as XmlSchemaComplexType;
  102. }
  103. else
  104. {
  105. if (elem.SchemaTypeName.IsEmpty) return null;
  106. if (elem.SchemaTypeName.Namespace == XmlSchema.Namespace) return null;
  107. object type = schemas.Find (elem.SchemaTypeName, typeof (XmlSchemaComplexType));
  108. if (type == null) throw new InvalidOperationException ("Schema type '" + elem.SchemaTypeName + "' not found");
  109. stype = type as XmlSchemaComplexType;
  110. }
  111. if (stype == null)
  112. throw new InvalidOperationException ("Schema element '" + name + "' not found or not valid");
  113. XmlMemberMapping[] mapping = ImportMembersMappingComposite (stype, name);
  114. return new XmlMembersMapping (name.Name, name.Namespace, mapping);
  115. }
  116. public XmlMembersMapping ImportMembersMapping (XmlQualifiedName[] names)
  117. {
  118. XmlMemberMapping[] mapping = new XmlMemberMapping [names.Length];
  119. for (int n=0; n<names.Length; n++)
  120. {
  121. XmlSchemaElement elem = (XmlSchemaElement) schemas.Find (names[n], typeof (XmlSchemaElement));
  122. if (elem == null) throw new InvalidOperationException ("Schema element '" + names[n] + "' not found");
  123. XmlQualifiedName typeQName = new XmlQualifiedName ("Message", names[n].Namespace);
  124. TypeData td = GetElementTypeData (typeQName, elem);
  125. mapping[n] = ImportMemberMapping (elem.Name, typeQName.Namespace, td);
  126. }
  127. BuildPendingMaps ();
  128. return new XmlMembersMapping (mapping);
  129. }
  130. public XmlMembersMapping ImportEncodedMembersMapping (string name, string ns, SoapSchemaMember[] members, bool hasWrapperElement)
  131. {
  132. XmlMemberMapping[] mapping = new XmlMemberMapping [members.Length];
  133. for (int n=0; n<members.Length; n++)
  134. {
  135. TypeData td = GetTypeData (members[n].MemberType, null);
  136. mapping[n] = ImportMemberMapping (members[n].MemberName, members[n].MemberType.Namespace, td);
  137. }
  138. BuildPendingMaps ();
  139. return new XmlMembersMapping (name, ns, hasWrapperElement, false, mapping);
  140. }
  141. public XmlMembersMapping ImportEncodedMembersMapping (string name, string ns, SoapSchemaMember member)
  142. {
  143. XmlSchemaComplexType stype = schemas.Find (member.MemberType, typeof (XmlSchemaComplexType)) as XmlSchemaComplexType;
  144. if (stype == null) throw new InvalidOperationException ("Schema type '" + member.MemberType + "' not found or not valid");
  145. XmlMemberMapping[] mapping = ImportMembersMappingComposite (stype, member.MemberType);
  146. return new XmlMembersMapping (name, ns, mapping);
  147. }
  148. public XmlMemberMapping[] ImportMembersMappingComposite (XmlSchemaComplexType stype, XmlQualifiedName refer)
  149. {
  150. if (stype.Particle == null)
  151. return new XmlMemberMapping [0];
  152. ClassMap cmap = new ClassMap ();
  153. XmlSchemaSequence seq = stype.Particle as XmlSchemaSequence;
  154. if (seq == null) throw new InvalidOperationException ("Schema element '" + refer + "' cannot be imported as XmlMembersMapping");
  155. CodeIdentifiers classIds = new CodeIdentifiers ();
  156. ImportParticleComplexContent (refer, cmap, seq, classIds, false);
  157. BuildPendingMaps ();
  158. int n = 0;
  159. XmlMemberMapping[] mapping = new XmlMemberMapping [cmap.AllMembers.Count];
  160. foreach (XmlTypeMapMember mapMem in cmap.AllMembers)
  161. mapping[n++] = new XmlMemberMapping (mapMem.Name, refer.Namespace, mapMem, encodedFormat);
  162. return mapping;
  163. }
  164. XmlMemberMapping ImportMemberMapping (string name, string ns, TypeData type)
  165. {
  166. XmlTypeMapMemberElement mapMem = new XmlTypeMapMemberElement ();
  167. mapMem.Name = name;
  168. mapMem.TypeData = type;
  169. mapMem.ElementInfo.Add (CreateElementInfo (ns, mapMem, name, type, true));
  170. return new XmlMemberMapping (name, ns, mapMem, encodedFormat);
  171. }
  172. [MonoTODO]
  173. public XmlMembersMapping ImportMembersMapping (XmlQualifiedName[] names, Type baseType, bool baseTypeCanBeIndirect)
  174. {
  175. throw new NotImplementedException ();
  176. }
  177. public XmlTypeMapping ImportTypeMapping (XmlQualifiedName name)
  178. {
  179. XmlQualifiedName qname;
  180. XmlSchemaType stype;
  181. if (!LocateElement (name, out qname, out stype)) return null;
  182. XmlTypeMapping map = GetRegisteredTypeMapping (qname);
  183. if (map != null) return map;
  184. map = CreateTypeMapping (qname, SchemaTypes.Class, name);
  185. map.Documentation = GetDocumentation (stype);
  186. RegisterMapFixup (map, qname, (XmlSchemaComplexType)stype);
  187. BuildPendingMaps ();
  188. return map;
  189. }
  190. bool LocateElement (XmlQualifiedName name, out XmlQualifiedName qname, out XmlSchemaType stype)
  191. {
  192. qname = null;
  193. stype = null;
  194. XmlSchemaElement elem = (XmlSchemaElement) schemas.Find (name, typeof (XmlSchemaElement));
  195. if (elem == null) return false;
  196. // The root element must be an element with complex type
  197. if (elem.SchemaType != null)
  198. {
  199. stype = elem.SchemaType;
  200. qname = name;
  201. }
  202. else
  203. {
  204. if (elem.SchemaTypeName.IsEmpty) return false;
  205. if (elem.SchemaTypeName.Namespace == XmlSchema.Namespace) return false;
  206. object type = schemas.Find (elem.SchemaTypeName, typeof (XmlSchemaComplexType));
  207. if (type == null) type = schemas.Find (elem.SchemaTypeName, typeof (XmlSchemaSimpleType));
  208. if (type == null) throw new InvalidOperationException ("Schema type '" + elem.SchemaTypeName + "' not found");
  209. stype = (XmlSchemaType) type;
  210. qname = stype.QualifiedName;
  211. }
  212. if (stype is XmlSchemaSimpleType) return false;
  213. return true;
  214. }
  215. public XmlTypeMapping ImportType (XmlQualifiedName name, XmlQualifiedName root)
  216. {
  217. XmlTypeMapping map = GetRegisteredTypeMapping (name);
  218. if (map != null) return map;
  219. XmlSchemaType type = (XmlSchemaType) schemas.Find (name, typeof (XmlSchemaComplexType));
  220. if (type == null) type = (XmlSchemaType) schemas.Find (name, typeof (XmlSchemaSimpleType));
  221. if (type == null)
  222. {
  223. if (name.Namespace == XmlSerializer.EncodingNamespace)
  224. throw new InvalidOperationException ("Referenced type '" + name + "' valid only for encoded SOAP");
  225. else
  226. throw new InvalidOperationException ("Referenced type '" + name + "' not found");
  227. }
  228. return ImportType (name, type, root);
  229. }
  230. XmlTypeMapping ImportType (XmlQualifiedName name, XmlSchemaType stype, XmlQualifiedName root)
  231. {
  232. XmlTypeMapping map = GetRegisteredTypeMapping (name);
  233. if (map != null) return map;
  234. if (stype is XmlSchemaComplexType)
  235. return ImportClassComplexType (name, (XmlSchemaComplexType) stype, root);
  236. else if (stype is XmlSchemaSimpleType)
  237. return ImportClassSimpleType (name, (XmlSchemaSimpleType) stype, root);
  238. throw new NotSupportedException ("Schema type not supported: " + stype.GetType ());
  239. }
  240. XmlTypeMapping ImportClassComplexType (XmlQualifiedName typeQName, XmlSchemaComplexType stype, XmlQualifiedName root)
  241. {
  242. XmlTypeMapping map;
  243. // The need for fixups: If the complex type is an array, then to get the type of the
  244. // array we need first to get the type of the items of the array.
  245. // But if one of the item types or its children has a referece to this type array,
  246. // then we enter in an infinite loop. This does not happen with class types because
  247. // the class map is registered before parsing the children. We can't do the same
  248. // with the array type because to register the array map we need the type of the array.
  249. if (CanBeArray (typeQName, stype))
  250. {
  251. TypeData typeData;
  252. ListMap listMap = BuildArrayMap (typeQName, stype, out typeData);
  253. if (listMap != null)
  254. {
  255. map = CreateArrayTypeMapping (typeQName, typeData);
  256. map.ObjectMap = listMap;
  257. return map;
  258. }
  259. // After all, it is not an array. Create a class map then.
  260. }
  261. else if (CanBeAnyElement (stype))
  262. {
  263. return GetTypeMapping (TypeTranslator.GetTypeData(typeof(XmlElement)));
  264. }
  265. else if (CanBeIXmlSerializable (stype))
  266. {
  267. return GetTypeMapping (TypeTranslator.GetTypeData(typeof(object)));
  268. }
  269. // Register the map right now but do not build it,
  270. // This will avoid loops.
  271. map = CreateTypeMapping (typeQName, SchemaTypes.Class, root);
  272. map.Documentation = GetDocumentation (stype);
  273. RegisterMapFixup (map, typeQName, stype);
  274. return map;
  275. }
  276. void RegisterMapFixup (XmlTypeMapping map, XmlQualifiedName typeQName, XmlSchemaComplexType stype)
  277. {
  278. MapFixup fixup = new MapFixup ();
  279. fixup.Map = map;
  280. fixup.SchemaType = stype;
  281. fixup.TypeName = typeQName;
  282. pendingMaps.Enqueue (fixup);
  283. }
  284. void BuildPendingMaps ()
  285. {
  286. while (pendingMaps.Count > 0) {
  287. MapFixup fixup = (MapFixup) pendingMaps.Dequeue ();
  288. if (fixup.Map.ObjectMap == null) {
  289. BuildClassMap (fixup.Map, fixup.TypeName, fixup.SchemaType);
  290. if (fixup.Map.ObjectMap == null) pendingMaps.Enqueue (fixup);
  291. }
  292. }
  293. }
  294. void BuildPendingMap (XmlTypeMapping map)
  295. {
  296. if (map.ObjectMap != null) return;
  297. foreach (MapFixup fixup in pendingMaps)
  298. {
  299. if (fixup.Map == map) {
  300. BuildClassMap (fixup.Map, fixup.TypeName, fixup.SchemaType);
  301. return;
  302. }
  303. }
  304. throw new InvalidOperationException ("Can't complete map of type " + map.XmlType + " : " + map.Namespace);
  305. }
  306. void BuildClassMap (XmlTypeMapping map, XmlQualifiedName typeQName, XmlSchemaComplexType stype)
  307. {
  308. CodeIdentifiers classIds = new CodeIdentifiers();
  309. classIds.AddReserved (map.TypeData.TypeName);
  310. ClassMap cmap = new ClassMap ();
  311. map.ObjectMap = cmap;
  312. bool isMixed = stype.IsMixed;
  313. if (stype.Particle != null)
  314. {
  315. if (HasForcedBaseType (typeQName))
  316. ImportForcedDerivedType (map, typeQName, ref isMixed);
  317. ImportParticleComplexContent (typeQName, cmap, stype.Particle, classIds, isMixed);
  318. }
  319. else
  320. {
  321. if (stype.ContentModel is XmlSchemaSimpleContent) {
  322. ImportSimpleContent (typeQName, map, (XmlSchemaSimpleContent)stype.ContentModel, classIds, isMixed);
  323. }
  324. else if (stype.ContentModel is XmlSchemaComplexContent) {
  325. ImportComplexContent (typeQName, map, (XmlSchemaComplexContent)stype.ContentModel, classIds, isMixed);
  326. }
  327. }
  328. ImportAttributes (typeQName, cmap, stype.Attributes, stype.AnyAttribute, classIds);
  329. ImportExtensionTypes (typeQName);
  330. }
  331. void ImportAttributes (XmlQualifiedName typeQName, ClassMap cmap, XmlSchemaObjectCollection atts, XmlSchemaAnyAttribute anyat, CodeIdentifiers classIds)
  332. {
  333. if (anyat != null)
  334. {
  335. XmlTypeMapMemberAnyAttribute member = new XmlTypeMapMemberAnyAttribute ();
  336. member.Name = classIds.AddUnique ("AnyAttribute", member);
  337. member.TypeData = TypeTranslator.GetTypeData (typeof(XmlAttribute[]));
  338. cmap.AddMember (member);
  339. }
  340. foreach (XmlSchemaObject at in atts)
  341. {
  342. if (at is XmlSchemaAttribute)
  343. {
  344. string ns;
  345. XmlSchemaAttribute attr = (XmlSchemaAttribute)at;
  346. XmlSchemaAttribute refAttr = GetRefAttribute (typeQName, attr, out ns);
  347. XmlTypeMapMemberAttribute member = new XmlTypeMapMemberAttribute ();
  348. member.Name = classIds.AddUnique (CodeIdentifier.MakeValid (refAttr.Name), member);
  349. member.Documentation = GetDocumentation (attr);
  350. member.AttributeName = refAttr.Name;
  351. member.Namespace = ns;
  352. member.Form = refAttr.Form;
  353. member.TypeData = GetAttributeTypeData (typeQName, attr);
  354. if (refAttr.DefaultValue != null) member.DefaultValue = XmlCustomFormatter.FromXmlString (member.TypeData, refAttr.DefaultValue);
  355. if (member.TypeData.IsComplexType)
  356. member.MappedType = GetTypeMapping (member.TypeData);
  357. cmap.AddMember (member);
  358. }
  359. else if (at is XmlSchemaAttributeGroupRef)
  360. {
  361. XmlSchemaAttributeGroupRef gref = (XmlSchemaAttributeGroupRef)at;
  362. XmlSchemaAttributeGroup grp = (XmlSchemaAttributeGroup) schemas.Find (gref.RefName, typeof(XmlSchemaAttributeGroup));
  363. ImportAttributes (typeQName, cmap, grp.Attributes, grp.AnyAttribute, classIds);
  364. }
  365. }
  366. }
  367. ListMap BuildArrayMap (XmlQualifiedName typeQName, XmlSchemaComplexType stype, out TypeData arrayTypeData)
  368. {
  369. if (encodedFormat)
  370. {
  371. XmlSchemaComplexContent content = stype.ContentModel as XmlSchemaComplexContent;
  372. XmlSchemaComplexContentRestriction rest = content.Content as XmlSchemaComplexContentRestriction;
  373. XmlSchemaAttribute arrayTypeAt = FindArrayAttribute (rest.Attributes);
  374. XmlAttribute[] uatts = arrayTypeAt.UnhandledAttributes;
  375. if (uatts == null || uatts.Length == 0) throw new InvalidOperationException ("arrayType attribute not specified in array declaration: " + typeQName);
  376. XmlAttribute xat = null;
  377. foreach (XmlAttribute at in uatts)
  378. if (at.LocalName == "arrayType" && at.NamespaceURI == XmlSerializer.WsdlNamespace)
  379. { xat = at; break; }
  380. if (xat == null)
  381. throw new InvalidOperationException ("arrayType attribute not specified in array declaration: " + typeQName);
  382. string name, ns, dims;
  383. TypeTranslator.ParseArrayType (xat.Value, out name, out ns, out dims);
  384. return BuildEncodedArrayMap (name + dims, ns, out arrayTypeData);
  385. }
  386. else
  387. {
  388. ClassMap cmap = new ClassMap ();
  389. CodeIdentifiers classIds = new CodeIdentifiers();
  390. ImportParticleComplexContent (typeQName, cmap, stype.Particle, classIds, false);
  391. XmlTypeMapMemberFlatList list = (cmap.AllMembers.Count == 1) ? cmap.AllMembers[0] as XmlTypeMapMemberFlatList : null;
  392. if (list != null && list.ChoiceMember == null)
  393. {
  394. arrayTypeData = list.TypeData;
  395. return list.ListMap;
  396. }
  397. else
  398. {
  399. arrayTypeData = null;
  400. return null;
  401. }
  402. }
  403. }
  404. ListMap BuildEncodedArrayMap (string type, string ns, out TypeData arrayTypeData)
  405. {
  406. ListMap map = new ListMap ();
  407. int i = type.LastIndexOf ("[");
  408. if (i == -1) throw new InvalidOperationException ("Invalid arrayType value: " + type);
  409. if (type.IndexOf (",",i) != -1) throw new InvalidOperationException ("Multidimensional arrays are not supported");
  410. string itemType = type.Substring (0,i);
  411. TypeData itemTypeData;
  412. if (itemType.IndexOf ("[") != -1)
  413. {
  414. ListMap innerListMap = BuildEncodedArrayMap (itemType, ns, out itemTypeData);
  415. int dims = itemType.Split ('[').Length - 1;
  416. string name = TypeTranslator.GetArrayName (type, dims);
  417. XmlQualifiedName qname = new XmlQualifiedName (name, ns);
  418. XmlTypeMapping tmap = CreateArrayTypeMapping (qname, itemTypeData);
  419. tmap.ObjectMap = innerListMap;
  420. }
  421. else
  422. {
  423. itemTypeData = GetTypeData (new XmlQualifiedName (itemType, ns), null);
  424. }
  425. arrayTypeData = itemTypeData.ListTypeData;
  426. map.ItemInfo = new XmlTypeMapElementInfoList();
  427. map.ItemInfo.Add (CreateElementInfo ("", null, "Item", itemTypeData, true));
  428. return map;
  429. }
  430. XmlSchemaAttribute FindArrayAttribute (XmlSchemaObjectCollection atts)
  431. {
  432. foreach (object ob in atts)
  433. {
  434. XmlSchemaAttribute att = ob as XmlSchemaAttribute;
  435. if (att != null && att.RefName == arrayTypeRefName) return att;
  436. XmlSchemaAttributeGroupRef gref = ob as XmlSchemaAttributeGroupRef;
  437. if (gref != null)
  438. {
  439. XmlSchemaAttributeGroup grp = (XmlSchemaAttributeGroup) schemas.Find (gref.RefName, typeof(XmlSchemaAttributeGroup));
  440. att = FindArrayAttribute (grp.Attributes);
  441. if (att != null) return att;
  442. }
  443. }
  444. return null;
  445. }
  446. void ImportParticleComplexContent (XmlQualifiedName typeQName, ClassMap cmap, XmlSchemaParticle particle, CodeIdentifiers classIds, bool isMixed)
  447. {
  448. ImportParticleContent (typeQName, cmap, particle, classIds, false, ref isMixed);
  449. if (isMixed)
  450. {
  451. XmlTypeMapMemberFlatList member = new XmlTypeMapMemberFlatList ();
  452. member.Name = classIds.AddUnique ("Text", member);
  453. member.TypeData = TypeTranslator.GetTypeData (typeof(string[]));
  454. member.ElementInfo.Add (CreateTextElementInfo (typeQName.Namespace, member, member.TypeData.ListItemTypeData));
  455. member.IsXmlTextCollector = true;
  456. member.ListMap = new ListMap ();
  457. member.ListMap.ItemInfo = member.ElementInfo;
  458. cmap.AddMember (member);
  459. }
  460. }
  461. void ImportParticleContent (XmlQualifiedName typeQName, ClassMap cmap, XmlSchemaParticle particle, CodeIdentifiers classIds, bool multiValue, ref bool isMixed)
  462. {
  463. if (particle is XmlSchemaGroupRef)
  464. particle = GetRefGroupParticle ((XmlSchemaGroupRef)particle);
  465. if (particle.MaxOccurs > 1) multiValue = true;
  466. if (particle is XmlSchemaSequence) {
  467. ImportSequenceContent (typeQName, cmap, ((XmlSchemaSequence)particle).Items, classIds, multiValue, ref isMixed);
  468. }
  469. else if (particle is XmlSchemaChoice) {
  470. if (((XmlSchemaChoice)particle).Items.Count == 1)
  471. ImportSequenceContent (typeQName, cmap, ((XmlSchemaChoice)particle).Items, classIds, multiValue, ref isMixed);
  472. else
  473. ImportChoiceContent (typeQName, cmap, (XmlSchemaChoice)particle, classIds, multiValue);
  474. }
  475. else if (particle is XmlSchemaAll) {
  476. ImportSequenceContent (typeQName, cmap, ((XmlSchemaAll)particle).Items, classIds, multiValue, ref isMixed);
  477. }
  478. }
  479. void ImportSequenceContent (XmlQualifiedName typeQName, ClassMap cmap, XmlSchemaObjectCollection items, CodeIdentifiers classIds, bool multiValue, ref bool isMixed)
  480. {
  481. foreach (XmlSchemaObject item in items)
  482. {
  483. XmlTypeMapMember mapMember;
  484. if (item is XmlSchemaElement)
  485. {
  486. string ns;
  487. XmlSchemaElement elem = (XmlSchemaElement) item;
  488. TypeData typeData = GetElementTypeData (typeQName, elem);
  489. XmlSchemaElement refElem = GetRefElement (typeQName, elem, out ns);
  490. if (elem.MaxOccurs == 1 && !multiValue)
  491. {
  492. XmlTypeMapMemberElement member = null;
  493. if (typeData.SchemaType != SchemaTypes.Array)
  494. {
  495. member = new XmlTypeMapMemberElement ();
  496. if (refElem.DefaultValue != null) member.DefaultValue = XmlCustomFormatter.FromXmlString (typeData, refElem.DefaultValue);
  497. }
  498. else if (GetTypeMapping (typeData).IsSimpleType)
  499. {
  500. // It is a simple list (space separated list).
  501. // Since this is not supported, map as a single item value
  502. // TODO: improve this
  503. member = new XmlTypeMapMemberElement ();
  504. typeData = typeData.ListItemTypeData;
  505. }
  506. else
  507. member = new XmlTypeMapMemberList ();
  508. member.Name = classIds.AddUnique(CodeIdentifier.MakeValid(refElem.Name), member);
  509. member.Documentation = GetDocumentation (elem);
  510. member.TypeData = typeData;
  511. member.ElementInfo.Add (CreateElementInfo (ns, member, refElem.Name, typeData, refElem.IsNillable));
  512. cmap.AddMember (member);
  513. }
  514. else
  515. {
  516. XmlTypeMapMemberFlatList member = new XmlTypeMapMemberFlatList ();
  517. member.ListMap = new ListMap ();
  518. member.Name = classIds.AddUnique(CodeIdentifier.MakeValid(refElem.Name), member);
  519. member.Documentation = GetDocumentation (elem);
  520. member.TypeData = typeData.ListTypeData;
  521. member.ElementInfo.Add (CreateElementInfo (ns, member, refElem.Name, typeData, refElem.IsNillable));
  522. member.ListMap.ItemInfo = member.ElementInfo;
  523. cmap.AddMember (member);
  524. }
  525. }
  526. else if (item is XmlSchemaAny)
  527. {
  528. XmlSchemaAny elem = (XmlSchemaAny) item;
  529. XmlTypeMapMemberAnyElement member = new XmlTypeMapMemberAnyElement ();
  530. member.Name = classIds.AddUnique ("Any", member);
  531. member.Documentation = GetDocumentation (elem);
  532. Type ctype;
  533. if (elem.MaxOccurs > 1 || multiValue)
  534. ctype = isMixed ? typeof(XmlNode[]) : typeof(XmlElement[]);
  535. else
  536. ctype = isMixed ? typeof(XmlNode) : typeof(XmlElement);
  537. member.TypeData = TypeTranslator.GetTypeData (ctype);
  538. XmlTypeMapElementInfo einfo = new XmlTypeMapElementInfo (member, member.TypeData);
  539. einfo.IsUnnamedAnyElement = true;
  540. member.ElementInfo.Add (einfo);
  541. if (isMixed)
  542. {
  543. einfo = CreateTextElementInfo (typeQName.Namespace, member, member.TypeData);
  544. member.ElementInfo.Add (einfo);
  545. member.IsXmlTextCollector = true;
  546. isMixed = false; //Allow only one XmlTextAttribute
  547. }
  548. cmap.AddMember (member);
  549. }
  550. else if (item is XmlSchemaParticle) {
  551. ImportParticleContent (typeQName, cmap, (XmlSchemaParticle)item, classIds, multiValue, ref isMixed);
  552. }
  553. }
  554. }
  555. void ImportChoiceContent (XmlQualifiedName typeQName, ClassMap cmap, XmlSchemaChoice choice, CodeIdentifiers classIds, bool multiValue)
  556. {
  557. XmlTypeMapElementInfoList choices = new XmlTypeMapElementInfoList ();
  558. multiValue = ImportChoices (typeQName, null, choices, choice.Items) || multiValue;
  559. if (choices.Count == 0) return;
  560. if (choice.MaxOccurs > 1) multiValue = true;
  561. XmlTypeMapMemberElement member;
  562. if (multiValue)
  563. {
  564. member = new XmlTypeMapMemberFlatList ();
  565. member.Name = classIds.AddUnique ("Items", member);
  566. ListMap listMap = new ListMap ();
  567. listMap.ItemInfo = choices;
  568. ((XmlTypeMapMemberFlatList)member).ListMap = listMap;
  569. }
  570. else
  571. {
  572. member = new XmlTypeMapMemberElement ();
  573. member.Name = classIds.AddUnique ("Item", member);
  574. }
  575. // If all choices have the same type, use that type for the member.
  576. // If not use System.Object.
  577. // If there are at least two choices with the same type, use a choice
  578. // identifier attribute
  579. TypeData typeData = null;
  580. bool twoEqual = false;
  581. bool allEqual = true;
  582. Hashtable types = new Hashtable ();
  583. foreach (XmlTypeMapElementInfo einfo in choices)
  584. {
  585. if (types.ContainsKey (einfo.TypeData)) twoEqual = true;
  586. else types.Add (einfo.TypeData, einfo);
  587. TypeData choiceType = einfo.TypeData;
  588. if (choiceType.SchemaType == SchemaTypes.Class)
  589. {
  590. // When comparing class types, use the most generic class in the
  591. // inheritance hierarchy
  592. XmlTypeMapping choiceMap = GetTypeMapping (choiceType);
  593. BuildPendingMap (choiceMap);
  594. while (choiceMap.BaseMap != null) {
  595. choiceMap = choiceMap.BaseMap;
  596. BuildPendingMap (choiceMap);
  597. choiceType = choiceMap.TypeData;
  598. }
  599. }
  600. if (typeData == null) typeData = choiceType;
  601. else if (typeData != choiceType) allEqual = false;
  602. }
  603. if (!allEqual)
  604. typeData = TypeTranslator.GetTypeData (typeof(object));
  605. if (twoEqual)
  606. {
  607. // Create the choice member
  608. XmlTypeMapMemberElement choiceMember = new XmlTypeMapMemberElement ();
  609. choiceMember.Name = classIds.AddUnique (member.Name + "ElementName", choiceMember);
  610. member.ChoiceMember = choiceMember.Name;
  611. // Create the choice enum
  612. XmlTypeMapping enumMap = CreateTypeMapping (new XmlQualifiedName (member.Name + "ChoiceType", typeQName.Namespace), SchemaTypes.Enum, null);
  613. CodeIdentifiers codeIdents = new CodeIdentifiers ();
  614. EnumMap.EnumMapMember[] members = new EnumMap.EnumMapMember [choices.Count];
  615. for (int n=0; n<choices.Count; n++)
  616. {
  617. XmlTypeMapElementInfo it =(XmlTypeMapElementInfo) choices[n];
  618. string xmlName = (it.Namespace != null && it.Namespace != "") ? it.Namespace + ":" + it.ElementName : it.ElementName;
  619. string enumName = codeIdents.AddUnique (CodeIdentifier.MakeValid (it.ElementName), it);
  620. members [n] = new EnumMap.EnumMapMember (xmlName, enumName);
  621. }
  622. enumMap.ObjectMap = new EnumMap (members, false);
  623. choiceMember.TypeData = multiValue ? enumMap.TypeData.ListTypeData : enumMap.TypeData;
  624. choiceMember.ElementInfo.Add (CreateElementInfo (typeQName.Namespace, choiceMember, choiceMember.Name, choiceMember.TypeData, false));
  625. cmap.AddMember (choiceMember);
  626. }
  627. if (multiValue)
  628. typeData = typeData.ListTypeData;
  629. member.ElementInfo = choices;
  630. member.Documentation = GetDocumentation (choice);
  631. member.TypeData = typeData;
  632. cmap.AddMember (member);
  633. }
  634. bool ImportChoices (XmlQualifiedName typeQName, XmlTypeMapMember member, XmlTypeMapElementInfoList choices, XmlSchemaObjectCollection items)
  635. {
  636. bool multiValue = false;
  637. foreach (XmlSchemaObject titem in items)
  638. {
  639. XmlSchemaObject item = titem;
  640. if (item is XmlSchemaGroupRef)
  641. item = GetRefGroupParticle ((XmlSchemaGroupRef)item);
  642. if (item is XmlSchemaElement)
  643. {
  644. string ns;
  645. XmlSchemaElement elem = (XmlSchemaElement) item;
  646. TypeData typeData = GetElementTypeData (typeQName, elem);
  647. XmlSchemaElement refElem = GetRefElement (typeQName, elem, out ns);
  648. choices.Add (CreateElementInfo (ns, member, refElem.Name, typeData, refElem.IsNillable));
  649. if (elem.MaxOccurs > 1) multiValue = true;
  650. }
  651. else if (item is XmlSchemaAny)
  652. {
  653. XmlTypeMapElementInfo einfo = new XmlTypeMapElementInfo (member, TypeTranslator.GetTypeData(typeof(XmlElement)));
  654. einfo.IsUnnamedAnyElement = true;
  655. choices.Add (einfo);
  656. }
  657. else if (item is XmlSchemaChoice) {
  658. multiValue = ImportChoices (typeQName, member, choices, ((XmlSchemaChoice)item).Items) || multiValue;
  659. }
  660. else if (item is XmlSchemaSequence) {
  661. multiValue = ImportChoices (typeQName, member, choices, ((XmlSchemaSequence)item).Items) || multiValue;
  662. }
  663. }
  664. return multiValue;
  665. }
  666. void ImportSimpleContent (XmlQualifiedName typeQName, XmlTypeMapping map, XmlSchemaSimpleContent content, CodeIdentifiers classIds, bool isMixed)
  667. {
  668. ClassMap cmap = (ClassMap)map.ObjectMap;
  669. XmlQualifiedName qname = GetContentBaseType (content.Content);
  670. XmlTypeMapMemberElement member = new XmlTypeMapMemberElement ();
  671. member.Name = classIds.AddUnique("Value", member);
  672. member.TypeData = FindBuiltInType (qname);
  673. member.ElementInfo.Add (CreateTextElementInfo (typeQName.Namespace, member, member.TypeData));
  674. member.IsXmlTextCollector = true;
  675. cmap.AddMember (member);
  676. XmlSchemaSimpleContentExtension ext = content.Content as XmlSchemaSimpleContentExtension;
  677. if (ext != null)
  678. ImportAttributes (typeQName, cmap, ext.Attributes, ext.AnyAttribute, classIds);
  679. }
  680. TypeData FindBuiltInType (XmlQualifiedName qname)
  681. {
  682. if (qname.Namespace == XmlSchema.Namespace)
  683. return TypeTranslator.GetPrimitiveTypeData (qname.Name);
  684. XmlSchemaComplexType ct = (XmlSchemaComplexType) schemas.Find (qname, typeof(XmlSchemaComplexType));
  685. if (ct != null)
  686. {
  687. XmlSchemaSimpleContent sc = ct.ContentModel as XmlSchemaSimpleContent;
  688. if (sc == null) throw new InvalidOperationException ("Invalid schema");
  689. return FindBuiltInType (GetContentBaseType (sc.Content));
  690. }
  691. XmlSchemaSimpleType st = (XmlSchemaSimpleType) schemas.Find (qname, typeof(XmlSchemaSimpleType));
  692. if (st != null)
  693. return FindBuiltInType (qname, st);
  694. throw new InvalidOperationException ("Definition of type " + qname + " not found");
  695. }
  696. TypeData FindBuiltInType (XmlQualifiedName qname, XmlSchemaSimpleType st)
  697. {
  698. if (CanBeEnum (st))
  699. return ImportType (qname, null).TypeData;
  700. if (st.Content is XmlSchemaSimpleTypeRestriction) {
  701. return FindBuiltInType (GetContentBaseType (st.Content));
  702. }
  703. else if (st.Content is XmlSchemaSimpleTypeList) {
  704. return FindBuiltInType (GetContentBaseType (st.Content)).ListTypeData;
  705. }
  706. else if (st.Content is XmlSchemaSimpleTypeUnion)
  707. {
  708. // Check if all types of the union are equal. If not, then will use anyType.
  709. XmlSchemaSimpleTypeUnion uni = (XmlSchemaSimpleTypeUnion) st.Content;
  710. TypeData utype = null;
  711. // Anonymous types are unique
  712. if (uni.BaseTypes.Count != 0 && uni.MemberTypes.Length != 0)
  713. return FindBuiltInType (anyType);
  714. foreach (XmlQualifiedName mt in uni.MemberTypes)
  715. {
  716. TypeData qn = FindBuiltInType (mt);
  717. if (utype != null && qn != utype) return FindBuiltInType (anyType);
  718. else utype = qn;
  719. }
  720. return utype;
  721. }
  722. else
  723. return null;
  724. }
  725. XmlQualifiedName GetContentBaseType (XmlSchemaObject ob)
  726. {
  727. if (ob is XmlSchemaSimpleContentExtension)
  728. return ((XmlSchemaSimpleContentExtension)ob).BaseTypeName;
  729. else if (ob is XmlSchemaSimpleContentRestriction)
  730. return ((XmlSchemaSimpleContentRestriction)ob).BaseTypeName;
  731. else if (ob is XmlSchemaSimpleTypeRestriction)
  732. return ((XmlSchemaSimpleTypeRestriction)ob).BaseTypeName;
  733. else if (ob is XmlSchemaSimpleTypeList)
  734. return ((XmlSchemaSimpleTypeList)ob).ItemTypeName;
  735. else
  736. return null;
  737. }
  738. void ImportComplexContent (XmlQualifiedName typeQName, XmlTypeMapping map, XmlSchemaComplexContent content, CodeIdentifiers classIds, bool isMixed)
  739. {
  740. ClassMap cmap = (ClassMap)map.ObjectMap;
  741. XmlQualifiedName qname;
  742. XmlSchemaComplexContentExtension ext = content.Content as XmlSchemaComplexContentExtension;
  743. if (ext != null) qname = ext.BaseTypeName;
  744. else qname = ((XmlSchemaComplexContentRestriction)content.Content).BaseTypeName;
  745. if (HasForcedBaseType (typeQName))
  746. RegisterForcedBaseType (qname, GetForcedBaseType (typeQName));
  747. // Add base map members to this map
  748. XmlTypeMapping baseMap = ImportType (qname, null);
  749. BuildPendingMap (baseMap);
  750. ClassMap baseClassMap = (ClassMap)baseMap.ObjectMap;
  751. foreach (XmlTypeMapMember member in baseClassMap.AllMembers)
  752. cmap.AddMember (member);
  753. if (baseClassMap.XmlTextCollector != null) isMixed = false;
  754. else if (content.IsMixed) isMixed = true;
  755. map.BaseMap = baseMap;
  756. baseMap.DerivedTypes.Add (map);
  757. if (ext != null) {
  758. // Add the members of this map
  759. if (ext.Particle != null)
  760. ImportParticleComplexContent (typeQName, cmap, ext.Particle, classIds, isMixed);
  761. ImportAttributes (typeQName, cmap, ext.Attributes, ext.AnyAttribute, classIds);
  762. }
  763. else {
  764. if (isMixed) ImportParticleComplexContent (typeQName, cmap, null, classIds, true);
  765. }
  766. }
  767. public void ImportForcedDerivedType (XmlTypeMapping map, XmlQualifiedName qname, ref bool isMixed)
  768. {
  769. ClassMap cmap = (ClassMap)map.ObjectMap;
  770. XmlTypeMapping baseMap;
  771. Type baseType = GetForcedBaseType (qname);
  772. if (encodedFormat)
  773. {
  774. if (auxXmlRefImporter == null) auxXmlRefImporter = new XmlReflectionImporter ();
  775. baseMap = auxXmlRefImporter.ImportTypeMapping (baseType);
  776. }
  777. else
  778. {
  779. if (auxSoapRefImporter == null) auxSoapRefImporter = new SoapReflectionImporter ();
  780. baseMap = auxSoapRefImporter.ImportTypeMapping (baseType);
  781. }
  782. ClassMap baseClassMap = (ClassMap)baseMap.ObjectMap;
  783. foreach (XmlTypeMapMember member in baseClassMap.AllMembers)
  784. cmap.AddMember (member);
  785. if (baseClassMap.XmlTextCollector != null) isMixed = false;
  786. map.BaseMap = baseMap;
  787. baseMap.DerivedTypes.Add (map);
  788. }
  789. void ImportExtensionTypes (XmlQualifiedName qname)
  790. {
  791. foreach (XmlSchema schema in schemas) {
  792. foreach (XmlSchemaObject sob in schema.Items)
  793. {
  794. XmlSchemaComplexType sct = sob as XmlSchemaComplexType;
  795. if (sct != null && sct.ContentModel is XmlSchemaComplexContent) {
  796. XmlQualifiedName exqname;
  797. XmlSchemaComplexContentExtension ext = sct.ContentModel.Content as XmlSchemaComplexContentExtension;
  798. if (ext != null) exqname = ext.BaseTypeName;
  799. else exqname = ((XmlSchemaComplexContentRestriction)sct.ContentModel.Content).BaseTypeName;
  800. if (exqname == qname)
  801. ImportType (new XmlQualifiedName (sct.Name, schema.TargetNamespace), sct, null);
  802. }
  803. }
  804. }
  805. }
  806. XmlTypeMapping ImportClassSimpleType (XmlQualifiedName typeQName, XmlSchemaSimpleType stype, XmlQualifiedName root)
  807. {
  808. if (CanBeEnum (stype))
  809. {
  810. // Create an enum map
  811. CodeIdentifiers codeIdents = new CodeIdentifiers ();
  812. XmlSchemaSimpleTypeRestriction rest = (XmlSchemaSimpleTypeRestriction)stype.Content;
  813. XmlTypeMapping enumMap = CreateTypeMapping (typeQName, SchemaTypes.Enum, null);
  814. enumMap.Documentation = GetDocumentation (stype);
  815. codeIdents.AddReserved (enumMap.TypeData.TypeName);
  816. EnumMap.EnumMapMember[] members = new EnumMap.EnumMapMember [rest.Facets.Count];
  817. for (int n=0; n<rest.Facets.Count; n++)
  818. {
  819. XmlSchemaEnumerationFacet enu = (XmlSchemaEnumerationFacet) rest.Facets[n];
  820. string enumName = codeIdents.AddUnique(CodeIdentifier.MakeValid (enu.Value), enu);
  821. members [n] = new EnumMap.EnumMapMember (enu.Value, enumName);
  822. members [n].Documentation = GetDocumentation (enu);
  823. }
  824. enumMap.ObjectMap = new EnumMap (members, false);
  825. enumMap.IsSimpleType = true;
  826. return enumMap;
  827. }
  828. if (stype.Content is XmlSchemaSimpleTypeList)
  829. {
  830. XmlSchemaSimpleTypeList slist = (XmlSchemaSimpleTypeList)stype.Content;
  831. TypeData arrayTypeData = FindBuiltInType (slist.ItemTypeName, stype);
  832. ListMap listMap = new ListMap ();
  833. listMap.ItemInfo = new XmlTypeMapElementInfoList ();
  834. listMap.ItemInfo.Add (CreateElementInfo (typeQName.Namespace, null, "Item", arrayTypeData.ListItemTypeData, false));
  835. XmlTypeMapping map = CreateArrayTypeMapping (typeQName, arrayTypeData);
  836. map.ObjectMap = listMap;
  837. map.IsSimpleType = true;
  838. return map;
  839. }
  840. // It is an extension of a primitive or known type
  841. TypeData typeData = FindBuiltInType (typeQName, stype);
  842. return GetTypeMapping (typeData);
  843. }
  844. bool CanBeEnum (XmlSchemaSimpleType stype)
  845. {
  846. if (stype.Content is XmlSchemaSimpleTypeRestriction)
  847. {
  848. XmlSchemaSimpleTypeRestriction rest = (XmlSchemaSimpleTypeRestriction)stype.Content;
  849. foreach (object ob in rest.Facets)
  850. if (!(ob is XmlSchemaEnumerationFacet)) return false;
  851. return true;
  852. }
  853. return false;
  854. }
  855. bool CanBeArray (XmlQualifiedName typeQName, XmlSchemaComplexType stype)
  856. {
  857. if (encodedFormat)
  858. {
  859. XmlSchemaComplexContent content = stype.ContentModel as XmlSchemaComplexContent;
  860. if (content == null) return false;
  861. XmlSchemaComplexContentRestriction rest = content.Content as XmlSchemaComplexContentRestriction;
  862. if (rest == null) return false;
  863. return rest.BaseTypeName == arrayType;
  864. }
  865. else
  866. {
  867. if (stype.Attributes.Count > 0 || stype.AnyAttribute != null) return false;
  868. else return !stype.IsMixed && CanBeArray (typeQName, stype.Particle, false);
  869. }
  870. }
  871. bool CanBeArray (XmlQualifiedName typeQName, XmlSchemaParticle particle, bool multiValue)
  872. {
  873. // To be an array, there can't be a direct child of type typeQName
  874. if (particle == null) return false;
  875. multiValue = multiValue || particle.MaxOccurs > 1;
  876. if (particle is XmlSchemaGroupRef)
  877. return CanBeArray (typeQName, GetRefGroupParticle ((XmlSchemaGroupRef)particle), multiValue);
  878. if (particle is XmlSchemaElement)
  879. {
  880. XmlSchemaElement elem = (XmlSchemaElement)particle;
  881. if (!elem.RefName.IsEmpty)
  882. return CanBeArray (typeQName, FindRefElement (elem), multiValue);
  883. else
  884. return multiValue && !typeQName.Equals (((XmlSchemaElement)particle).SchemaTypeName);
  885. }
  886. if (particle is XmlSchemaAny)
  887. return multiValue;
  888. if (particle is XmlSchemaSequence)
  889. {
  890. XmlSchemaSequence seq = particle as XmlSchemaSequence;
  891. if (seq.Items.Count != 1) return false;
  892. return CanBeArray (typeQName, (XmlSchemaParticle)seq.Items[0], multiValue);
  893. }
  894. if (particle is XmlSchemaChoice)
  895. {
  896. // Can be array if all choices have different types
  897. ArrayList types = new ArrayList ();
  898. if(!CheckChoiceType (typeQName, particle, types, ref multiValue)) return false;
  899. return multiValue;
  900. }
  901. return false;
  902. }
  903. bool CheckChoiceType (XmlQualifiedName typeQName, XmlSchemaParticle particle, ArrayList types, ref bool multiValue)
  904. {
  905. XmlQualifiedName type = null;
  906. multiValue = multiValue || particle.MaxOccurs > 1;
  907. if (particle is XmlSchemaGroupRef)
  908. return CheckChoiceType (typeQName, GetRefGroupParticle ((XmlSchemaGroupRef)particle), types, ref multiValue);
  909. if (particle is XmlSchemaElement) {
  910. string ns;
  911. XmlSchemaElement elem = (XmlSchemaElement)particle;
  912. XmlSchemaElement refElem = GetRefElement (typeQName, elem, out ns);
  913. if (refElem.SchemaType != null) return true;
  914. type = refElem.SchemaTypeName;
  915. }
  916. else if (particle is XmlSchemaAny) {
  917. type = anyType;
  918. }
  919. else if (particle is XmlSchemaSequence)
  920. {
  921. XmlSchemaSequence seq = particle as XmlSchemaSequence;
  922. foreach (XmlSchemaParticle par in seq.Items)
  923. if (!CheckChoiceType (typeQName, par, types, ref multiValue)) return false;
  924. return true;
  925. }
  926. else if (particle is XmlSchemaChoice)
  927. {
  928. foreach (XmlSchemaParticle choice in ((XmlSchemaChoice)particle).Items)
  929. if (!CheckChoiceType (typeQName, choice, types, ref multiValue)) return false;
  930. return true;
  931. }
  932. if (typeQName.Equals (type)) return false;
  933. // For primitive types, compare using CLR types, since several
  934. // xml types can be mapped to a single CLR type
  935. string t;
  936. if (type.Namespace == XmlSchema.Namespace)
  937. t = TypeTranslator.GetPrimitiveTypeData (type.Name).FullTypeName + ":" + type.Namespace;
  938. else
  939. t = type.Name + ":" + type.Namespace;
  940. if (types.Contains (t)) return false;
  941. types.Add (t);
  942. return true;
  943. }
  944. bool CanBeAnyElement (XmlSchemaComplexType stype)
  945. {
  946. XmlSchemaSequence seq = stype.Particle as XmlSchemaSequence;
  947. return (seq != null) && (seq.Items.Count == 1) && (seq.Items[0] is XmlSchemaAny);
  948. }
  949. bool CanBeIXmlSerializable (XmlSchemaComplexType stype)
  950. {
  951. XmlSchemaSequence seq = stype.Particle as XmlSchemaSequence;
  952. if (seq == null) return false;
  953. if (seq.Items.Count != 2) return false;
  954. XmlSchemaElement elem = seq.Items[0] as XmlSchemaElement;
  955. if (elem == null) return false;
  956. if (elem.RefName != new XmlQualifiedName ("schema",XmlSchema.Namespace)) return false;
  957. return (seq.Items[1] is XmlSchemaAny);
  958. }
  959. void RegisterForcedBaseType (XmlQualifiedName tname, Type type)
  960. {
  961. if (forcedBaseTypes == null) forcedBaseTypes = new Hashtable ();
  962. forcedBaseTypes [tname] = type;
  963. }
  964. bool HasForcedBaseType (XmlQualifiedName tname)
  965. {
  966. if (forcedBaseTypes == null) return false;
  967. return forcedBaseTypes.ContainsKey (tname);
  968. }
  969. Type GetForcedBaseType (XmlQualifiedName tname)
  970. {
  971. if (forcedBaseTypes == null) return null;
  972. return (Type) forcedBaseTypes [tname];
  973. }
  974. XmlTypeMapElementInfo CreateElementInfo (string ns, XmlTypeMapMember member, string name, TypeData typeData, bool isNillable)
  975. {
  976. XmlTypeMapElementInfo einfo = new XmlTypeMapElementInfo (member, typeData);
  977. einfo.ElementName = name;
  978. einfo.Namespace = ns;
  979. einfo.IsNullable = isNillable;
  980. if (einfo.TypeData.IsComplexType)
  981. einfo.MappedType = GetTypeMapping (typeData);
  982. return einfo;
  983. }
  984. XmlTypeMapElementInfo CreateTextElementInfo (string ns, XmlTypeMapMember member, TypeData typeData)
  985. {
  986. XmlTypeMapElementInfo einfo = new XmlTypeMapElementInfo (member, typeData);
  987. einfo.IsTextElement = true;
  988. einfo.WrappedElement = false;
  989. if (typeData.IsComplexType)
  990. einfo.MappedType = GetTypeMapping (typeData);
  991. return einfo;
  992. }
  993. XmlTypeMapping CreateTypeMapping (XmlQualifiedName typeQName, SchemaTypes schemaType, XmlQualifiedName root)
  994. {
  995. string typeName = CodeIdentifier.MakeValid (typeQName.Name);
  996. typeName = typeIdentifiers.AddUnique (typeName, null);
  997. TypeData typeData = new TypeData (typeName, typeName, typeName, schemaType, null);
  998. XmlQualifiedName elemName = (root != null) ? root : typeQName;
  999. XmlTypeMapping map = new XmlTypeMapping (elemName.Name, elemName.Namespace, typeData, typeQName.Name, typeQName.Namespace);
  1000. map.IncludeInSchema = true;
  1001. mappedTypes [typeQName] = map;
  1002. dataMappedTypes [typeData] = map;
  1003. return map;
  1004. }
  1005. XmlTypeMapping CreateArrayTypeMapping (XmlQualifiedName typeQName, TypeData arrayTypeData)
  1006. {
  1007. XmlTypeMapping map;
  1008. if (encodedFormat) map = new XmlTypeMapping ("Array", XmlSerializer.EncodingNamespace, arrayTypeData, "Array", XmlSerializer.EncodingNamespace);
  1009. else map = new XmlTypeMapping (arrayTypeData.XmlType, typeQName.Namespace, arrayTypeData, arrayTypeData.XmlType, typeQName.Namespace);
  1010. map.IncludeInSchema = true;
  1011. mappedTypes [typeQName] = map;
  1012. dataMappedTypes [arrayTypeData] = map;
  1013. return map;
  1014. }
  1015. XmlSchemaElement GetRefElement (XmlQualifiedName typeQName, XmlSchemaElement elem, out string ns)
  1016. {
  1017. if (!elem.RefName.IsEmpty)
  1018. {
  1019. ns = elem.RefName.Namespace;
  1020. return FindRefElement (elem);
  1021. }
  1022. else
  1023. {
  1024. ns = typeQName.Namespace;
  1025. return elem;
  1026. }
  1027. }
  1028. XmlSchemaAttribute GetRefAttribute (XmlQualifiedName typeQName, XmlSchemaAttribute attr, out string ns)
  1029. {
  1030. if (!attr.RefName.IsEmpty)
  1031. {
  1032. ns = attr.RefName.Namespace;
  1033. return FindRefAttribute (attr.RefName);
  1034. }
  1035. else
  1036. {
  1037. ns = typeQName.Namespace;
  1038. return attr;
  1039. }
  1040. }
  1041. TypeData GetElementTypeData (XmlQualifiedName typeQName, XmlSchemaElement elem)
  1042. {
  1043. bool sharedAnnType = false;
  1044. XmlQualifiedName root = null;
  1045. if (!elem.RefName.IsEmpty) {
  1046. XmlSchemaElement refElem = FindRefElement (elem);
  1047. if (refElem == null) throw new InvalidOperationException ("Global element not found: " + elem.RefName);
  1048. root = elem.RefName;
  1049. elem = refElem;
  1050. sharedAnnType = true;
  1051. }
  1052. if (!elem.SchemaTypeName.IsEmpty) return GetTypeData (elem.SchemaTypeName, root);
  1053. else if (elem.SchemaType == null) return TypeTranslator.GetTypeData (typeof(object));
  1054. else return GetTypeData (elem.SchemaType, typeQName, elem.Name, sharedAnnType, root);
  1055. }
  1056. TypeData GetAttributeTypeData (XmlQualifiedName typeQName, XmlSchemaAttribute attr)
  1057. {
  1058. bool sharedAnnType = false;
  1059. if (!attr.RefName.IsEmpty) {
  1060. XmlSchemaAttribute refAtt = FindRefAttribute (attr.RefName);
  1061. if (refAtt == null) throw new InvalidOperationException ("Global attribute not found: " + attr.RefName);
  1062. attr = refAtt;
  1063. sharedAnnType = true;
  1064. }
  1065. if (!attr.SchemaTypeName.IsEmpty) return GetTypeData (attr.SchemaTypeName, null);
  1066. else return GetTypeData (attr.SchemaType, typeQName, attr.Name, sharedAnnType, null);
  1067. }
  1068. TypeData GetTypeData (XmlQualifiedName typeQName, XmlQualifiedName root)
  1069. {
  1070. if (typeQName.Namespace == XmlSchema.Namespace)
  1071. return TypeTranslator.GetPrimitiveTypeData (typeQName.Name);
  1072. return ImportType (typeQName, root).TypeData;
  1073. }
  1074. TypeData GetTypeData (XmlSchemaType stype, XmlQualifiedName typeQNname, string propertyName, bool sharedAnnType, XmlQualifiedName root)
  1075. {
  1076. string baseName;
  1077. if (sharedAnnType)
  1078. {
  1079. // Anonymous types defined in root elements or attributes can be shared among all elements that
  1080. // reference this root element or attribute
  1081. TypeData std = sharedAnonymousTypes [stype] as TypeData;
  1082. if (std != null) return std;
  1083. baseName = propertyName;
  1084. }
  1085. else
  1086. baseName = typeQNname.Name + typeIdentifiers.MakeRightCase (propertyName);
  1087. baseName = elemIdentifiers.AddUnique (baseName, stype);
  1088. XmlQualifiedName newName;
  1089. newName = new XmlQualifiedName (baseName, typeQNname.Namespace);
  1090. XmlTypeMapping map = ImportType (newName, stype, root);
  1091. if (sharedAnnType) sharedAnonymousTypes [stype] = map.TypeData;
  1092. return map.TypeData;
  1093. }
  1094. XmlTypeMapping GetTypeMapping (TypeData typeData)
  1095. {
  1096. XmlTypeMapping map = (XmlTypeMapping) dataMappedTypes [typeData];
  1097. if (map != null) return map;
  1098. if (map == null && typeData.IsListType)
  1099. {
  1100. // Create an array map for the type
  1101. XmlTypeMapping itemMap = GetTypeMapping (typeData.ListItemTypeData);
  1102. map = new XmlTypeMapping (typeData.XmlType, itemMap.Namespace, typeData, typeData.XmlType, itemMap.Namespace);
  1103. map.IncludeInSchema = true;
  1104. ListMap listMap = new ListMap ();
  1105. listMap.ItemInfo = new XmlTypeMapElementInfoList();
  1106. listMap.ItemInfo.Add (CreateElementInfo (itemMap.Namespace, null, typeData.ListItemTypeData.XmlType, typeData.ListItemTypeData, false));
  1107. map.ObjectMap = listMap;
  1108. mappedTypes [new XmlQualifiedName(map.ElementName, map.Namespace)] = map;
  1109. dataMappedTypes [typeData] = map;
  1110. return map;
  1111. }
  1112. else if (typeData.SchemaType == SchemaTypes.Primitive || typeData.Type == typeof(object) || typeof(XmlNode).IsAssignableFrom(typeData.Type))
  1113. {
  1114. map = new XmlTypeMapping (typeData.XmlType, XmlSchema.Namespace, typeData, typeData.XmlType, XmlSchema.Namespace);
  1115. map.IncludeInSchema = false;
  1116. dataMappedTypes [typeData] = map;
  1117. return map;
  1118. }
  1119. throw new InvalidOperationException ("Map for type " + typeData.TypeName + " not found");
  1120. }
  1121. XmlTypeMapping GetRegisteredTypeMapping (XmlQualifiedName typeQName)
  1122. {
  1123. return (XmlTypeMapping) mappedTypes [typeQName];
  1124. }
  1125. XmlSchemaParticle GetRefGroupParticle (XmlSchemaGroupRef refGroup)
  1126. {
  1127. XmlSchemaGroup grp = (XmlSchemaGroup) schemas.Find (refGroup.RefName, typeof (XmlSchemaGroup));
  1128. return grp.Particle;
  1129. }
  1130. XmlSchemaElement FindRefElement (XmlSchemaElement elem)
  1131. {
  1132. if (elem.RefName.Namespace == XmlSchema.Namespace)
  1133. {
  1134. if (anyElement != null) return anyElement;
  1135. anyElement = new XmlSchemaElement ();
  1136. anyElement.Name = "any";
  1137. anyElement.SchemaTypeName = anyType;
  1138. return anyElement;
  1139. }
  1140. return (XmlSchemaElement) schemas.Find (elem.RefName, typeof(XmlSchemaElement));
  1141. }
  1142. XmlSchemaAttribute FindRefAttribute (XmlQualifiedName refName)
  1143. {
  1144. if (refName.Namespace == XmlNamespace)
  1145. {
  1146. XmlSchemaAttribute at = new XmlSchemaAttribute ();
  1147. at.Name = refName.Name;
  1148. at.SchemaTypeName = new XmlQualifiedName ("string",XmlSchema.Namespace);
  1149. return at;
  1150. }
  1151. return (XmlSchemaAttribute) schemas.Find (refName, typeof(XmlSchemaAttribute));
  1152. }
  1153. string GetDocumentation (XmlSchemaAnnotated elem)
  1154. {
  1155. string res = "";
  1156. XmlSchemaAnnotation anot = elem.Annotation;
  1157. if (anot == null || anot.Items == null) return null;
  1158. foreach (object ob in anot.Items)
  1159. {
  1160. XmlSchemaDocumentation doc = ob as XmlSchemaDocumentation;
  1161. if (doc != null && doc.Markup != null && doc.Markup.Length > 0) {
  1162. if (res != string.Empty) res += "\n";
  1163. foreach (XmlNode node in doc.Markup)
  1164. res += node.Value;
  1165. }
  1166. }
  1167. return res;
  1168. }
  1169. #endregion // Methods
  1170. }
  1171. }