PageRenderTime 34ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/mcs/class/System.XML/System.Xml.Serialization/XmlSchemaImporter.cs

https://bitbucket.org/danipen/mono
C# | 1965 lines | 1552 code | 304 blank | 109 comment | 482 complexity | 86c182ba08f4e9a2790ec657b48d12dc MD5 | raw file
Possible License(s): Unlicense, Apache-2.0, LGPL-2.0, MPL-2.0-no-copyleft-exception, CC-BY-SA-3.0, GPL-2.0
  1. //
  2. // System.Xml.Serialization.XmlSchemaImporter
  3. //
  4. // Author:
  5. // Tim Coleman (tim@timcoleman.com)
  6. // Lluis Sanchez Gual (lluis@ximian.com)
  7. //
  8. // Copyright (C) Tim Coleman, 2002
  9. //
  10. //
  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:
  18. //
  19. // The above copyright notice and this permission notice shall be
  20. // included in all copies or substantial portions of the Software.
  21. //
  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.
  29. //
  30. using System.Xml;
  31. #if !TARGET_JVM && !MOBILE
  32. using System.CodeDom.Compiler;
  33. #endif
  34. using System.Xml.Schema;
  35. using System.Collections;
  36. #if NET_2_0 && CONFIGURATION_DEP
  37. using System.Configuration;
  38. using System.Xml.Serialization.Configuration;
  39. #endif
  40. namespace System.Xml.Serialization
  41. {
  42. public class XmlSchemaImporter
  43. #if NET_2_0 && !MOBILE
  44. : SchemaImporter
  45. #endif
  46. {
  47. #region Fields
  48. XmlSchemas schemas;
  49. CodeIdentifiers typeIdentifiers;
  50. CodeIdentifiers elemIdentifiers = new CodeIdentifiers ();
  51. Hashtable mappedTypes = new Hashtable ();
  52. Hashtable primitiveDerivedMappedTypes = new Hashtable ();
  53. Hashtable dataMappedTypes = new Hashtable ();
  54. Queue pendingMaps = new Queue ();
  55. Hashtable sharedAnonymousTypes = new Hashtable ();
  56. bool encodedFormat = false;
  57. XmlReflectionImporter auxXmlRefImporter;
  58. SoapReflectionImporter auxSoapRefImporter;
  59. bool anyTypeImported;
  60. // CodeGenerationOptions options;
  61. static readonly XmlQualifiedName anyType = new XmlQualifiedName ("anyType",XmlSchema.Namespace);
  62. static readonly XmlQualifiedName arrayType = new XmlQualifiedName ("Array",XmlSerializer.EncodingNamespace);
  63. static readonly XmlQualifiedName arrayTypeRefName = new XmlQualifiedName ("arrayType",XmlSerializer.EncodingNamespace);
  64. const string XmlNamespace = "http://www.w3.org/XML/1998/namespace";
  65. XmlSchemaElement anyElement = null;
  66. class MapFixup
  67. {
  68. public XmlTypeMapping Map;
  69. public XmlSchemaComplexType SchemaType;
  70. public XmlQualifiedName TypeName;
  71. }
  72. #endregion
  73. #region Constructors
  74. public XmlSchemaImporter (XmlSchemas schemas)
  75. {
  76. this.schemas = schemas;
  77. typeIdentifiers = new CodeIdentifiers ();
  78. InitializeExtensions ();
  79. }
  80. public XmlSchemaImporter (XmlSchemas schemas, CodeIdentifiers typeIdentifiers)
  81. : this (schemas)
  82. {
  83. this.typeIdentifiers = typeIdentifiers;
  84. }
  85. #if !TARGET_JVM && !MOBILE
  86. [MonoTODO]
  87. public XmlSchemaImporter (XmlSchemas schemas, CodeGenerationOptions options, CodeDomProvider codeProvider, ImportContext context)
  88. {
  89. this.schemas = schemas;
  90. // this.options = options;
  91. if (context != null) {
  92. typeIdentifiers = context.TypeIdentifiers;
  93. InitSharedData (context);
  94. }
  95. else
  96. typeIdentifiers = new CodeIdentifiers ();
  97. InitializeExtensions ();
  98. }
  99. [MonoTODO]
  100. public XmlSchemaImporter (XmlSchemas schemas, CodeGenerationOptions options, ImportContext context)
  101. {
  102. this.schemas = schemas;
  103. // this.options = options;
  104. if (context != null) {
  105. typeIdentifiers = context.TypeIdentifiers;
  106. InitSharedData (context);
  107. }
  108. else
  109. typeIdentifiers = new CodeIdentifiers ();
  110. InitializeExtensions ();
  111. }
  112. [MonoTODO]
  113. public XmlSchemaImporter (XmlSchemas schemas, CodeIdentifiers typeIdentifiers, CodeGenerationOptions options)
  114. {
  115. this.typeIdentifiers = typeIdentifiers;
  116. this.schemas = schemas;
  117. // this.options = options;
  118. InitializeExtensions ();
  119. }
  120. void InitSharedData (ImportContext context)
  121. {
  122. if (context.ShareTypes) {
  123. mappedTypes = context.MappedTypes;
  124. dataMappedTypes = context.DataMappedTypes;
  125. sharedAnonymousTypes = context.SharedAnonymousTypes;
  126. }
  127. }
  128. #endif
  129. internal bool UseEncodedFormat
  130. {
  131. get { return encodedFormat; }
  132. set { encodedFormat = value; }
  133. }
  134. #endregion // Constructors
  135. #region Methods
  136. void InitializeExtensions ()
  137. {
  138. #if NET_2_0 && CONFIGURATION_DEP
  139. SerializationSectionGroup root = ConfigurationManager.GetSection ("system.xml.serialization") as SerializationSectionGroup;
  140. if (root == null)
  141. return;
  142. foreach (SchemaImporterExtensionElement element in
  143. root.SchemaImporterExtensions.SchemaImporterExtensions)
  144. Extensions.Add (element.Name, element.Type);
  145. #endif
  146. }
  147. public XmlMembersMapping ImportAnyType (XmlQualifiedName typeName, string elementName)
  148. {
  149. if (typeName == XmlQualifiedName.Empty)
  150. {
  151. XmlTypeMapMemberAnyElement mapMem = new XmlTypeMapMemberAnyElement ();
  152. mapMem.Name = typeName.Name;
  153. mapMem.TypeData = TypeTranslator.GetTypeData(typeof(XmlNode));
  154. mapMem.ElementInfo.Add (CreateElementInfo (typeName.Namespace, mapMem, typeName.Name, mapMem.TypeData, true, XmlSchemaForm.None, -1));
  155. XmlMemberMapping[] mm = new XmlMemberMapping [1];
  156. mm[0] = new XmlMemberMapping (typeName.Name, typeName.Namespace, mapMem, encodedFormat);
  157. return new XmlMembersMapping (mm);
  158. }
  159. else
  160. {
  161. XmlSchemaComplexType stype = (XmlSchemaComplexType) schemas.Find (typeName, typeof (XmlSchemaComplexType));
  162. if (stype == null)
  163. throw new InvalidOperationException ("Referenced type '" + typeName + "' not found");
  164. if (!CanBeAnyElement (stype))
  165. throw new InvalidOperationException ("The type '" + typeName + "' is not valid for a collection of any elements");
  166. ClassMap cmap = new ClassMap ();
  167. CodeIdentifiers classIds = new CodeIdentifiers ();
  168. bool isMixed = stype.IsMixed;
  169. ImportSequenceContent (typeName, cmap, ((XmlSchemaSequence) stype.Particle).Items, classIds, false, ref isMixed);
  170. XmlTypeMapMemberAnyElement mapMem = (XmlTypeMapMemberAnyElement) cmap.AllMembers[0];
  171. mapMem.Name = typeName.Name;
  172. XmlMemberMapping[] mm = new XmlMemberMapping [1];
  173. mm[0] = new XmlMemberMapping (typeName.Name, typeName.Namespace, mapMem, encodedFormat);
  174. return new XmlMembersMapping (mm);
  175. }
  176. }
  177. public XmlTypeMapping ImportDerivedTypeMapping (XmlQualifiedName name, Type baseType)
  178. {
  179. return ImportDerivedTypeMapping (name, baseType, true);
  180. }
  181. public XmlTypeMapping ImportDerivedTypeMapping (XmlQualifiedName name, Type baseType, bool baseTypeCanBeIndirect)
  182. {
  183. XmlQualifiedName qname;
  184. XmlSchemaType stype;
  185. if (encodedFormat)
  186. {
  187. qname = name;
  188. stype = schemas.Find (name, typeof (XmlSchemaComplexType)) as XmlSchemaComplexType;
  189. if (stype == null) throw new InvalidOperationException ("Schema type '" + name + "' not found or not valid");
  190. }
  191. else
  192. {
  193. if (!LocateElement (name, out qname, out stype))
  194. return null;
  195. }
  196. XmlTypeMapping map = GetRegisteredTypeMapping (qname, baseType);
  197. if (map != null)
  198. {
  199. // If the type has already been imported, make sure that the map
  200. // has the requested base type
  201. SetMapBaseType (map, baseType);
  202. map.UpdateRoot (name);
  203. return map;
  204. }
  205. map = CreateTypeMapping (qname, SchemaTypes.Class, name);
  206. if (stype != null) {
  207. map.Documentation = GetDocumentation (stype);
  208. RegisterMapFixup (map, qname, (XmlSchemaComplexType)stype);
  209. } else {
  210. ClassMap cmap = new ClassMap ();
  211. CodeIdentifiers classIds = new CodeIdentifiers ();
  212. map.ObjectMap = cmap;
  213. AddTextMember (qname, cmap, classIds);
  214. }
  215. BuildPendingMaps ();
  216. SetMapBaseType (map, baseType);
  217. return map;
  218. }
  219. void SetMapBaseType (XmlTypeMapping map, Type baseType)
  220. {
  221. // This method sets the base type for a given map.
  222. // If the map already inherits from this type, it does nothing.
  223. // Fiirst of all, check if the map already inherits from baseType
  224. XmlTypeMapping topMap = null;
  225. while (map != null)
  226. {
  227. if (map.TypeData.Type == baseType)
  228. return;
  229. topMap = map;
  230. map = map.BaseMap;
  231. }
  232. // Does not have the requested base type.
  233. // Then, get/create a map for that base type.
  234. XmlTypeMapping baseMap = ReflectType (baseType);
  235. // Add this map as a derived map of the base map
  236. topMap.BaseMap = baseMap;
  237. baseMap.DerivedTypes.Add (topMap);
  238. baseMap.DerivedTypes.AddRange (topMap.DerivedTypes);
  239. // Now add the base type fields to all derived maps
  240. ClassMap baseClassMap = (ClassMap)baseMap.ObjectMap;
  241. ClassMap cmap = (ClassMap)topMap.ObjectMap;
  242. foreach (XmlTypeMapMember member in baseClassMap.AllMembers)
  243. cmap.AddMember (member);
  244. foreach (XmlTypeMapping derivedMap in topMap.DerivedTypes)
  245. {
  246. cmap = (ClassMap)derivedMap.ObjectMap;
  247. foreach (XmlTypeMapMember member in baseClassMap.AllMembers)
  248. cmap.AddMember (member);
  249. }
  250. }
  251. public XmlMembersMapping ImportMembersMapping (XmlQualifiedName name)
  252. {
  253. XmlSchemaElement elem = (XmlSchemaElement) schemas.Find (name, typeof (XmlSchemaElement));
  254. if (elem == null) throw new InvalidOperationException ("Schema element '" + name + "' not found or not valid");
  255. XmlSchemaComplexType stype;
  256. if (elem.SchemaType != null)
  257. {
  258. stype = elem.SchemaType as XmlSchemaComplexType;
  259. }
  260. else
  261. {
  262. if (elem.SchemaTypeName.IsEmpty) return null;
  263. object type = schemas.Find (elem.SchemaTypeName, typeof (XmlSchemaComplexType));
  264. if (type == null) {
  265. if (IsPrimitiveTypeNamespace (elem.SchemaTypeName.Namespace)) return null;
  266. throw new InvalidOperationException ("Schema type '" + elem.SchemaTypeName + "' not found");
  267. }
  268. stype = type as XmlSchemaComplexType;
  269. }
  270. if (stype == null)
  271. throw new InvalidOperationException ("Schema element '" + name + "' not found or not valid");
  272. XmlMemberMapping[] mapping = ImportMembersMappingComposite (stype, name);
  273. return new XmlMembersMapping (name.Name, name.Namespace, mapping);
  274. }
  275. public XmlMembersMapping ImportMembersMapping (XmlQualifiedName[] names)
  276. {
  277. XmlMemberMapping[] mapping = new XmlMemberMapping [names.Length];
  278. for (int n=0; n<names.Length; n++)
  279. {
  280. XmlSchemaElement elem = (XmlSchemaElement) schemas.Find (names[n], typeof (XmlSchemaElement));
  281. if (elem == null) throw new InvalidOperationException ("Schema element '" + names[n] + "' not found");
  282. XmlQualifiedName typeQName = new XmlQualifiedName ("Message", names[n].Namespace);
  283. XmlTypeMapping tmap;
  284. TypeData td = GetElementTypeData (typeQName, elem, names[n], out tmap);
  285. mapping[n] = ImportMemberMapping (elem.Name, typeQName.Namespace, elem.IsNillable, td, tmap, n);
  286. }
  287. BuildPendingMaps ();
  288. return new XmlMembersMapping (mapping);
  289. }
  290. #if NET_2_0
  291. [MonoTODO]
  292. public XmlMembersMapping ImportMembersMapping (string name, string ns, SoapSchemaMember[] members)
  293. {
  294. throw new NotImplementedException ();
  295. }
  296. public XmlTypeMapping ImportSchemaType (XmlQualifiedName typeName)
  297. {
  298. return ImportSchemaType (typeName, typeof (object));
  299. }
  300. public XmlTypeMapping ImportSchemaType (XmlQualifiedName typeName, Type baseType)
  301. {
  302. return ImportSchemaType (typeName, typeof (object), false);
  303. }
  304. [MonoTODO ("baseType and baseTypeCanBeIndirect are ignored")]
  305. public XmlTypeMapping ImportSchemaType (XmlQualifiedName typeName, Type baseType, bool baseTypeCanBeIndirect)
  306. {
  307. XmlSchemaType stype =
  308. (XmlSchemaType) schemas.Find (typeName, typeof (XmlSchemaComplexType)) ??
  309. (XmlSchemaType) schemas.Find (typeName, typeof (XmlSchemaSimpleType));
  310. return ImportTypeCommon (typeName, typeName, stype, true);
  311. }
  312. #endif
  313. internal XmlMembersMapping ImportEncodedMembersMapping (string name, string ns, SoapSchemaMember[] members, bool hasWrapperElement)
  314. {
  315. XmlMemberMapping[] mapping = new XmlMemberMapping [members.Length];
  316. for (int n=0; n<members.Length; n++)
  317. {
  318. TypeData td = GetTypeData (members[n].MemberType, null, false); // FIXME: isNullable could be true?
  319. XmlTypeMapping tmap = GetTypeMapping (td);
  320. mapping[n] = ImportMemberMapping (members[n].MemberName, members[n].MemberType.Namespace, true, td, tmap, n);
  321. }
  322. BuildPendingMaps ();
  323. return new XmlMembersMapping (name, ns, hasWrapperElement, false, mapping);
  324. }
  325. internal XmlMembersMapping ImportEncodedMembersMapping (string name, string ns, SoapSchemaMember member)
  326. {
  327. XmlSchemaComplexType stype = schemas.Find (member.MemberType, typeof (XmlSchemaComplexType)) as XmlSchemaComplexType;
  328. if (stype == null) throw new InvalidOperationException ("Schema type '" + member.MemberType + "' not found or not valid");
  329. XmlMemberMapping[] mapping = ImportMembersMappingComposite (stype, member.MemberType);
  330. return new XmlMembersMapping (name, ns, mapping);
  331. }
  332. XmlMemberMapping[] ImportMembersMappingComposite (XmlSchemaComplexType stype, XmlQualifiedName refer)
  333. {
  334. if (stype.Particle == null)
  335. return new XmlMemberMapping [0];
  336. ClassMap cmap = new ClassMap ();
  337. XmlSchemaSequence seq = stype.Particle as XmlSchemaSequence;
  338. if (seq == null) throw new InvalidOperationException ("Schema element '" + refer + "' cannot be imported as XmlMembersMapping");
  339. CodeIdentifiers classIds = new CodeIdentifiers ();
  340. ImportParticleComplexContent (refer, cmap, seq, classIds, false);
  341. ImportAttributes (refer, cmap, stype.Attributes, stype.AnyAttribute, classIds);
  342. BuildPendingMaps ();
  343. int n = 0;
  344. XmlMemberMapping[] mapping = new XmlMemberMapping [cmap.AllMembers.Count];
  345. foreach (XmlTypeMapMember mapMem in cmap.AllMembers)
  346. mapping[n++] = new XmlMemberMapping (mapMem.Name, refer.Namespace, mapMem, encodedFormat);
  347. return mapping;
  348. }
  349. XmlMemberMapping ImportMemberMapping (string name, string ns, bool isNullable, TypeData type, XmlTypeMapping emap, int order)
  350. {
  351. XmlTypeMapMemberElement mapMem;
  352. if (type.IsListType)
  353. mapMem = new XmlTypeMapMemberList ();
  354. else
  355. mapMem = new XmlTypeMapMemberElement ();
  356. mapMem.Name = name;
  357. mapMem.TypeData = type;
  358. mapMem.ElementInfo.Add (CreateElementInfo (ns, mapMem, name, type, isNullable, XmlSchemaForm.None, emap, order));
  359. return new XmlMemberMapping (name, ns, mapMem, encodedFormat);
  360. }
  361. [MonoTODO]
  362. public XmlMembersMapping ImportMembersMapping (XmlQualifiedName[] names, Type baseType, bool baseTypeCanBeIndirect)
  363. {
  364. throw new NotImplementedException ();
  365. }
  366. public XmlTypeMapping ImportTypeMapping (XmlQualifiedName name)
  367. {
  368. XmlQualifiedName qname;
  369. XmlSchemaType stype;
  370. XmlSchemaElement elem = (XmlSchemaElement) schemas.Find (name, typeof (XmlSchemaElement));
  371. if (!LocateElement (elem, out qname, out stype))
  372. throw new InvalidOperationException (String.Format ("'{0}' is missing.", name));
  373. return ImportTypeCommon (name, qname, stype, elem.IsNillable);
  374. }
  375. // FIXME: name and qname are confusing. Rename one either
  376. // (name is in schema itself, qname is for actual processing.
  377. // For example simple types have qname as in xsd namespace.)
  378. private XmlTypeMapping ImportTypeCommon (XmlQualifiedName name, XmlQualifiedName qname, XmlSchemaType stype, bool isNullable)
  379. {
  380. if (stype == null) {
  381. if (qname == anyType) {
  382. // Importing anyType.
  383. XmlTypeMapping xmap = GetTypeMapping (TypeTranslator.GetTypeData (typeof (object)));
  384. // This also means, all complexTypes
  385. // are imported as well.
  386. BuildPendingMaps ();
  387. return xmap;
  388. } else {
  389. // Importing a primitive type
  390. TypeData td = TypeTranslator.GetPrimitiveTypeData (qname.Name);
  391. return ReflectType (td, name.Namespace);
  392. }
  393. }
  394. XmlTypeMapping map = GetRegisteredTypeMapping (qname);
  395. if (map != null) return map;
  396. if (stype is XmlSchemaSimpleType)
  397. return ImportClassSimpleType (stype.QualifiedName, (XmlSchemaSimpleType) stype, name);
  398. map = CreateTypeMapping (qname, SchemaTypes.Class, name);
  399. map.Documentation = GetDocumentation (stype);
  400. map.IsNullable = isNullable;
  401. RegisterMapFixup (map, qname, (XmlSchemaComplexType)stype);
  402. BuildPendingMaps ();
  403. return map;
  404. }
  405. bool LocateElement (XmlQualifiedName name, out XmlQualifiedName qname, out XmlSchemaType stype)
  406. {
  407. XmlSchemaElement elem = (XmlSchemaElement) schemas.Find (name, typeof (XmlSchemaElement));
  408. return LocateElement (elem, out qname, out stype);
  409. }
  410. bool LocateElement (XmlSchemaElement elem, out XmlQualifiedName qname, out XmlSchemaType stype)
  411. {
  412. qname = null;
  413. stype = null;
  414. if (elem == null) return false;
  415. // The root element must be an element with complex type
  416. if (elem.SchemaType != null)
  417. {
  418. stype = elem.SchemaType;
  419. qname = elem.QualifiedName;
  420. }
  421. else if (elem.ElementType == XmlSchemaComplexType.AnyType)
  422. {
  423. qname = anyType;
  424. return true;
  425. }
  426. else
  427. {
  428. if (elem.SchemaTypeName.IsEmpty) return false;
  429. object type = schemas.Find (elem.SchemaTypeName, typeof (XmlSchemaComplexType));
  430. if (type == null) type = schemas.Find (elem.SchemaTypeName, typeof (XmlSchemaSimpleType));
  431. if (type == null) {
  432. if (IsPrimitiveTypeNamespace (elem.SchemaTypeName.Namespace)) {
  433. qname = elem.SchemaTypeName;
  434. return true;
  435. }
  436. throw new InvalidOperationException ("Schema type '" + elem.SchemaTypeName + "' not found");
  437. }
  438. stype = (XmlSchemaType) type;
  439. qname = stype.QualifiedName;
  440. XmlSchemaType btype = stype.BaseSchemaType as XmlSchemaType;
  441. if (btype != null && btype.QualifiedName == elem.SchemaTypeName)
  442. throw new InvalidOperationException ("Cannot import schema for type '" + elem.SchemaTypeName.Name + "' from namespace '" + elem.SchemaTypeName.Namespace + "'. Redefine not supported");
  443. }
  444. //if (stype is XmlSchemaSimpleType) return false;
  445. return true;
  446. }
  447. XmlTypeMapping ImportType (XmlQualifiedName name, XmlQualifiedName root, bool throwOnError)
  448. {
  449. XmlTypeMapping map = GetRegisteredTypeMapping (name);
  450. if (map != null) {
  451. map.UpdateRoot (root);
  452. return map;
  453. }
  454. XmlSchemaType type = (XmlSchemaType) schemas.Find (name, typeof (XmlSchemaComplexType));
  455. if (type == null) type = (XmlSchemaType) schemas.Find (name, typeof (XmlSchemaSimpleType));
  456. if (type == null)
  457. {
  458. if (throwOnError) {
  459. if (name.Namespace == XmlSerializer.EncodingNamespace)
  460. throw new InvalidOperationException ("Referenced type '" + name + "' valid only for encoded SOAP.");
  461. else
  462. throw new InvalidOperationException ("Referenced type '" + name + "' not found.");
  463. } else
  464. return null;
  465. }
  466. return ImportType (name, type, root);
  467. }
  468. XmlTypeMapping ImportClass (XmlQualifiedName name)
  469. {
  470. XmlTypeMapping map = ImportType (name, null, true);
  471. if (map.TypeData.SchemaType == SchemaTypes.Class) return map;
  472. XmlSchemaComplexType stype = schemas.Find (name, typeof (XmlSchemaComplexType)) as XmlSchemaComplexType;
  473. return CreateClassMap (name, stype, new XmlQualifiedName (map.ElementName, map.Namespace));
  474. }
  475. XmlTypeMapping ImportType (XmlQualifiedName name, XmlSchemaType stype, XmlQualifiedName root)
  476. {
  477. XmlTypeMapping map = GetRegisteredTypeMapping (name);
  478. if (map != null) {
  479. XmlSchemaComplexType ct = stype as XmlSchemaComplexType;
  480. if (map.TypeData.SchemaType != SchemaTypes.Class || ct == null || !CanBeArray (name, ct)) {
  481. map.UpdateRoot (root);
  482. return map;
  483. }
  484. // The map was initially imported as a class, but it turns out that it is an
  485. // array. It has to be imported now as array.
  486. }
  487. if (stype is XmlSchemaComplexType)
  488. return ImportClassComplexType (name, (XmlSchemaComplexType) stype, root);
  489. else if (stype is XmlSchemaSimpleType)
  490. return ImportClassSimpleType (name, (XmlSchemaSimpleType) stype, root);
  491. throw new NotSupportedException ("Schema type not supported: " + stype.GetType ());
  492. }
  493. XmlTypeMapping ImportClassComplexType (XmlQualifiedName typeQName, XmlSchemaComplexType stype, XmlQualifiedName root)
  494. {
  495. // The need for fixups: If the complex type is an array, then to get the type of the
  496. // array we need first to get the type of the items of the array.
  497. // But if one of the item types or its children has a referece to this type array,
  498. // then we enter in an infinite loop. This does not happen with class types because
  499. // the class map is registered before parsing the children. We can't do the same
  500. // with the array type because to register the array map we need the type of the array.
  501. if (CanBeArray (typeQName, stype))
  502. {
  503. TypeData typeData;
  504. ListMap listMap = BuildArrayMap (typeQName, stype, out typeData);
  505. if (listMap != null)
  506. {
  507. XmlTypeMapping map = CreateArrayTypeMapping (typeQName, typeData);
  508. map.ObjectMap = listMap;
  509. return map;
  510. }
  511. // After all, it is not an array. Create a class map then.
  512. }
  513. else if (CanBeIXmlSerializable (stype))
  514. {
  515. return ImportXmlSerializableMapping (typeQName.Namespace);
  516. }
  517. // Register the map right now but do not build it,
  518. // This will avoid loops.
  519. return CreateClassMap (typeQName, stype, root);
  520. }
  521. XmlTypeMapping CreateClassMap (XmlQualifiedName typeQName, XmlSchemaComplexType stype, XmlQualifiedName root)
  522. {
  523. XmlTypeMapping map = CreateTypeMapping (typeQName, SchemaTypes.Class, root);
  524. map.Documentation = GetDocumentation (stype);
  525. RegisterMapFixup (map, typeQName, stype);
  526. return map;
  527. }
  528. ArrayList fixup_registered_types = new ArrayList ();
  529. void RegisterMapFixup (XmlTypeMapping map, XmlQualifiedName typeQName, XmlSchemaComplexType stype)
  530. {
  531. // This check is introduced for bug #650117, but might be too wide to catch erroneous cases...
  532. if (fixup_registered_types.Contains (stype))
  533. throw new InvalidOperationException (String.Format ("Circular dependency for schema type {0} in namespace {1}", map.ElementName, map.Namespace));
  534. fixup_registered_types.Add (stype);
  535. MapFixup fixup = new MapFixup ();
  536. fixup.Map = map;
  537. fixup.SchemaType = stype;
  538. fixup.TypeName = typeQName;
  539. pendingMaps.Enqueue (fixup);
  540. }
  541. void BuildPendingMaps ()
  542. {
  543. while (pendingMaps.Count > 0) {
  544. MapFixup fixup = (MapFixup) pendingMaps.Dequeue ();
  545. if (fixup.Map.ObjectMap == null) {
  546. BuildClassMap (fixup.Map, fixup.TypeName, fixup.SchemaType);
  547. if (fixup.Map.ObjectMap == null) pendingMaps.Enqueue (fixup);
  548. }
  549. }
  550. }
  551. void BuildPendingMap (XmlTypeMapping map)
  552. {
  553. if (map.ObjectMap != null) return;
  554. foreach (MapFixup fixup in pendingMaps)
  555. {
  556. if (fixup.Map == map) {
  557. BuildClassMap (fixup.Map, fixup.TypeName, fixup.SchemaType);
  558. return;
  559. }
  560. }
  561. throw new InvalidOperationException ("Can't complete map of type " + map.XmlType + " : " + map.Namespace);
  562. }
  563. void BuildClassMap (XmlTypeMapping map, XmlQualifiedName typeQName, XmlSchemaComplexType stype)
  564. {
  565. CodeIdentifiers classIds = new CodeIdentifiers();
  566. classIds.AddReserved (map.TypeData.TypeName);
  567. ClassMap cmap = new ClassMap ();
  568. map.ObjectMap = cmap;
  569. bool isMixed = stype.IsMixed;
  570. if (stype.Particle != null)
  571. ImportParticleComplexContent (typeQName, cmap, stype.Particle, classIds, isMixed);
  572. else
  573. {
  574. if (stype.ContentModel is XmlSchemaSimpleContent) {
  575. ImportSimpleContent (typeQName, map, (XmlSchemaSimpleContent)stype.ContentModel, classIds, isMixed);
  576. }
  577. else if (stype.ContentModel is XmlSchemaComplexContent) {
  578. ImportComplexContent (typeQName, map, (XmlSchemaComplexContent)stype.ContentModel, classIds, isMixed);
  579. }
  580. }
  581. ImportAttributes (typeQName, cmap, stype.Attributes, stype.AnyAttribute, classIds);
  582. ImportExtensionTypes (typeQName);
  583. if (isMixed) AddTextMember (typeQName, cmap, classIds);
  584. AddObjectDerivedMap (map);
  585. }
  586. void ImportAttributes (XmlQualifiedName typeQName, ClassMap cmap, XmlSchemaObjectCollection atts, XmlSchemaAnyAttribute anyat, CodeIdentifiers classIds)
  587. {
  588. atts = CollectAttributeUsesNonOverlap (atts, cmap);
  589. if (anyat != null)
  590. {
  591. XmlTypeMapMemberAnyAttribute member = new XmlTypeMapMemberAnyAttribute ();
  592. member.Name = classIds.AddUnique ("AnyAttribute", member);
  593. member.TypeData = TypeTranslator.GetTypeData (typeof(XmlAttribute[]));
  594. cmap.AddMember (member);
  595. }
  596. foreach (XmlSchemaObject at in atts)
  597. {
  598. if (at is XmlSchemaAttribute)
  599. {
  600. string ns;
  601. XmlSchemaAttribute attr = (XmlSchemaAttribute)at;
  602. XmlSchemaAttribute refAttr = GetRefAttribute (typeQName, attr, out ns);
  603. XmlTypeMapMemberAttribute member = new XmlTypeMapMemberAttribute ();
  604. member.Name = classIds.AddUnique (CodeIdentifier.MakeValid (refAttr.Name), member);
  605. member.Documentation = GetDocumentation (attr);
  606. member.AttributeName = refAttr.Name;
  607. member.Namespace = ns;
  608. member.Form = refAttr.Form;
  609. member.TypeData = GetAttributeTypeData (typeQName, attr);
  610. if (refAttr.DefaultValue != null)
  611. member.DefaultValue = ImportDefaultValue (member.TypeData, refAttr.DefaultValue);
  612. else if (member.TypeData.IsValueType)
  613. member.IsOptionalValueType = (refAttr.ValidatedUse != XmlSchemaUse.Required);
  614. if (member.TypeData.IsComplexType)
  615. member.MappedType = GetTypeMapping (member.TypeData);
  616. cmap.AddMember (member);
  617. }
  618. else if (at is XmlSchemaAttributeGroupRef)
  619. {
  620. XmlSchemaAttributeGroupRef gref = (XmlSchemaAttributeGroupRef)at;
  621. XmlSchemaAttributeGroup grp = FindRefAttributeGroup (gref.RefName);
  622. ImportAttributes (typeQName, cmap, grp.Attributes, grp.AnyAttribute, classIds);
  623. }
  624. }
  625. }
  626. // Attributes might be redefined, so there is an existing attribute for the same name, skip it.
  627. // FIXME: this is nothing more than just a hack.
  628. // Basically it should use
  629. // XmlSchemaComplexType.AttributeUses.
  630. XmlSchemaObjectCollection CollectAttributeUsesNonOverlap (
  631. XmlSchemaObjectCollection src, ClassMap map)
  632. {
  633. XmlSchemaObjectCollection atts = new XmlSchemaObjectCollection ();
  634. foreach (XmlSchemaAttribute a in src)
  635. if (map.GetAttribute (a.QualifiedName.Name, a.QualifiedName.Namespace) == null)
  636. atts.Add (a);
  637. return atts;
  638. }
  639. ListMap BuildArrayMap (XmlQualifiedName typeQName, XmlSchemaComplexType stype, out TypeData arrayTypeData)
  640. {
  641. if (encodedFormat)
  642. {
  643. XmlSchemaComplexContent content = stype.ContentModel as XmlSchemaComplexContent;
  644. XmlSchemaComplexContentRestriction rest = content.Content as XmlSchemaComplexContentRestriction;
  645. XmlSchemaAttribute arrayTypeAt = FindArrayAttribute (rest.Attributes);
  646. if (arrayTypeAt != null)
  647. {
  648. XmlAttribute[] uatts = arrayTypeAt.UnhandledAttributes;
  649. if (uatts == null || uatts.Length == 0) throw new InvalidOperationException ("arrayType attribute not specified in array declaration: " + typeQName);
  650. XmlAttribute xat = null;
  651. foreach (XmlAttribute at in uatts)
  652. if (at.LocalName == "arrayType" && at.NamespaceURI == XmlSerializer.WsdlNamespace)
  653. { xat = at; break; }
  654. if (xat == null)
  655. throw new InvalidOperationException ("arrayType attribute not specified in array declaration: " + typeQName);
  656. string name, ns, dims;
  657. TypeTranslator.ParseArrayType (xat.Value, out name, out ns, out dims);
  658. return BuildEncodedArrayMap (name + dims, ns, out arrayTypeData);
  659. }
  660. else
  661. {
  662. XmlSchemaElement elem = null;
  663. XmlSchemaSequence seq = rest.Particle as XmlSchemaSequence;
  664. if (seq != null && seq.Items.Count == 1)
  665. elem = seq.Items[0] as XmlSchemaElement;
  666. else {
  667. XmlSchemaAll all = rest.Particle as XmlSchemaAll;
  668. if (all != null && all.Items.Count == 1)
  669. elem = all.Items[0] as XmlSchemaElement;
  670. }
  671. if (elem == null)
  672. throw new InvalidOperationException ("Unknown array format");
  673. return BuildEncodedArrayMap (elem.SchemaTypeName.Name + "[]", elem.SchemaTypeName.Namespace, out arrayTypeData);
  674. }
  675. }
  676. else
  677. {
  678. ClassMap cmap = new ClassMap ();
  679. CodeIdentifiers classIds = new CodeIdentifiers();
  680. ImportParticleComplexContent (typeQName, cmap, stype.Particle, classIds, stype.IsMixed);
  681. XmlTypeMapMemberFlatList list = (cmap.AllMembers.Count == 1) ? cmap.AllMembers[0] as XmlTypeMapMemberFlatList : null;
  682. if (list != null && list.ChoiceMember == null)
  683. {
  684. arrayTypeData = list.TypeData;
  685. return list.ListMap;
  686. }
  687. else
  688. {
  689. arrayTypeData = null;
  690. return null;
  691. }
  692. }
  693. }
  694. ListMap BuildEncodedArrayMap (string type, string ns, out TypeData arrayTypeData)
  695. {
  696. ListMap map = new ListMap ();
  697. int i = type.LastIndexOf ("[");
  698. if (i == -1) throw new InvalidOperationException ("Invalid arrayType value: " + type);
  699. if (type.IndexOf (",",i) != -1) throw new InvalidOperationException ("Multidimensional arrays are not supported");
  700. string itemType = type.Substring (0,i);
  701. TypeData itemTypeData;
  702. if (itemType.IndexOf ("[") != -1)
  703. {
  704. ListMap innerListMap = BuildEncodedArrayMap (itemType, ns, out itemTypeData);
  705. int dims = itemType.Split ('[').Length - 1;
  706. string name = TypeTranslator.GetArrayName (type, dims);
  707. XmlQualifiedName qname = new XmlQualifiedName (name, ns);
  708. XmlTypeMapping tmap = CreateArrayTypeMapping (qname, itemTypeData);
  709. tmap.ObjectMap = innerListMap;
  710. }
  711. else
  712. {
  713. itemTypeData = GetTypeData (new XmlQualifiedName (itemType, ns), null, false);
  714. }
  715. arrayTypeData = itemTypeData.ListTypeData;
  716. map.ItemInfo = new XmlTypeMapElementInfoList();
  717. map.ItemInfo.Add (CreateElementInfo ("", null, "Item", itemTypeData, true, XmlSchemaForm.None, -1));
  718. return map;
  719. }
  720. XmlSchemaAttribute FindArrayAttribute (XmlSchemaObjectCollection atts)
  721. {
  722. foreach (object ob in atts)
  723. {
  724. XmlSchemaAttribute att = ob as XmlSchemaAttribute;
  725. if (att != null && att.RefName == arrayTypeRefName) return att;
  726. XmlSchemaAttributeGroupRef gref = ob as XmlSchemaAttributeGroupRef;
  727. if (gref != null)
  728. {
  729. XmlSchemaAttributeGroup grp = FindRefAttributeGroup (gref.RefName);
  730. att = FindArrayAttribute (grp.Attributes);
  731. if (att != null) return att;
  732. }
  733. }
  734. return null;
  735. }
  736. void ImportParticleComplexContent (XmlQualifiedName typeQName, ClassMap cmap, XmlSchemaParticle particle, CodeIdentifiers classIds, bool isMixed)
  737. {
  738. ImportParticleContent (typeQName, cmap, particle, classIds, false, ref isMixed);
  739. if (isMixed) AddTextMember (typeQName, cmap, classIds);
  740. }
  741. void AddTextMember (XmlQualifiedName typeQName, ClassMap cmap, CodeIdentifiers classIds)
  742. {
  743. if (cmap.XmlTextCollector == null)
  744. {
  745. XmlTypeMapMemberFlatList member = new XmlTypeMapMemberFlatList ();
  746. member.Name = classIds.AddUnique ("Text", member);
  747. member.TypeData = TypeTranslator.GetTypeData (typeof(string[]));
  748. member.ElementInfo.Add (CreateTextElementInfo (typeQName.Namespace, member, member.TypeData.ListItemTypeData));
  749. member.IsXmlTextCollector = true;
  750. member.ListMap = new ListMap ();
  751. member.ListMap.ItemInfo = member.ElementInfo;
  752. cmap.AddMember (member);
  753. }
  754. }
  755. void ImportParticleContent (XmlQualifiedName typeQName, ClassMap cmap, XmlSchemaParticle particle, CodeIdentifiers classIds, bool multiValue, ref bool isMixed)
  756. {
  757. if (particle == null) return;
  758. if (particle is XmlSchemaGroupRef)
  759. particle = GetRefGroupParticle ((XmlSchemaGroupRef)particle);
  760. if (particle.MaxOccurs > 1) multiValue = true;
  761. if (particle is XmlSchemaSequence) {
  762. ImportSequenceContent (typeQName, cmap, ((XmlSchemaSequence)particle).Items, classIds, multiValue, ref isMixed);
  763. }
  764. else if (particle is XmlSchemaChoice) {
  765. if (((XmlSchemaChoice)particle).Items.Count == 1)
  766. ImportSequenceContent (typeQName, cmap, ((XmlSchemaChoice)particle).Items, classIds, multiValue, ref isMixed);
  767. else
  768. ImportChoiceContent (typeQName, cmap, (XmlSchemaChoice)particle, classIds, multiValue);
  769. }
  770. else if (particle is XmlSchemaAll) {
  771. ImportSequenceContent (typeQName, cmap, ((XmlSchemaAll)particle).Items, classIds, multiValue, ref isMixed);
  772. }
  773. }
  774. void ImportSequenceContent (XmlQualifiedName typeQName, ClassMap cmap, XmlSchemaObjectCollection items, CodeIdentifiers classIds, bool multiValue, ref bool isMixed)
  775. {
  776. foreach (XmlSchemaObject item in items)
  777. {
  778. if (item is XmlSchemaElement)
  779. {
  780. string ns;
  781. XmlSchemaElement elem = (XmlSchemaElement) item;
  782. XmlTypeMapping emap;
  783. TypeData typeData = GetElementTypeData (typeQName, elem, null, out emap);
  784. XmlSchemaElement refElem = GetRefElement (typeQName, elem, out ns);
  785. if (elem.MaxOccurs == 1 && !multiValue)
  786. {
  787. XmlTypeMapMemberElement member = null;
  788. if (typeData.SchemaType != SchemaTypes.Array)
  789. {
  790. member = new XmlTypeMapMemberElement ();
  791. if (refElem.DefaultValue != null) member.DefaultValue = ImportDefaultValue (typeData, refElem.DefaultValue);
  792. }
  793. else if (GetTypeMapping (typeData).IsSimpleType)
  794. {
  795. // It is a simple list (space separated list).
  796. // Since this is not supported, map as a single item value
  797. member = new XmlTypeMapMemberElement ();
  798. #if NET_2_0
  799. // In MS.NET those types are mapped to a string
  800. typeData = TypeTranslator.GetTypeData(typeof(string));
  801. #else
  802. typeData = typeData.ListItemTypeData;
  803. #endif
  804. }
  805. else
  806. member = new XmlTypeMapMemberList ();
  807. if (elem.MinOccurs == 0 && typeData.IsValueType)
  808. member.IsOptionalValueType = true;
  809. member.Name = classIds.AddUnique(CodeIdentifier.MakeValid(refElem.Name), member);
  810. member.Documentation = GetDocumentation (elem);
  811. member.TypeData = typeData;
  812. member.ElementInfo.Add (CreateElementInfo (ns, member, refElem.Name, typeData, refElem.IsNillable, refElem.Form, emap, items.IndexOf (item)));
  813. cmap.AddMember (member);
  814. }
  815. else
  816. {
  817. XmlTypeMapMemberFlatList member = new XmlTypeMapMemberFlatList ();
  818. member.ListMap = new ListMap ();
  819. member.Name = classIds.AddUnique(CodeIdentifier.MakeValid(refElem.Name), member);
  820. member.Documentation = GetDocumentation (elem);
  821. member.TypeData = typeData.ListTypeData;
  822. member.ElementInfo.Add (CreateElementInfo (ns, member, refElem.Name, typeData, refElem.IsNillable, refElem.Form, emap, items.IndexOf (item)));
  823. member.ListMap.ItemInfo = member.ElementInfo;
  824. cmap.AddMember (member);
  825. }
  826. }
  827. else if (item is XmlSchemaAny)
  828. {
  829. XmlSchemaAny elem = (XmlSchemaAny) item;
  830. XmlTypeMapMemberAnyElement member = new XmlTypeMapMemberAnyElement ();
  831. member.Name = classIds.AddUnique ("Any", member);
  832. member.Documentation = GetDocumentation (elem);
  833. Type ctype;
  834. if (elem.MaxOccurs != 1 || multiValue)
  835. ctype = isMixed ? typeof(XmlNode[]) : typeof(XmlElement[]);
  836. else
  837. ctype = isMixed ? typeof(XmlNode) : typeof(XmlElement);
  838. member.TypeData = TypeTranslator.GetTypeData (ctype);
  839. XmlTypeMapElementInfo einfo = new XmlTypeMapElementInfo (member, member.TypeData);
  840. einfo.IsUnnamedAnyElement = true;
  841. member.ElementInfo.Add (einfo);
  842. if (isMixed)
  843. {
  844. einfo = CreateTextElementInfo (typeQName.Namespace, member, member.TypeData);
  845. member.ElementInfo.Add (einfo);
  846. member.IsXmlTextCollector = true;
  847. isMixed = false; //Allow only one XmlTextAttribute
  848. }
  849. cmap.AddMember (member);
  850. }
  851. else if (item is XmlSchemaParticle) {
  852. ImportParticleContent (typeQName, cmap, (XmlSchemaParticle)item, classIds, multiValue, ref isMixed);
  853. }
  854. }
  855. }
  856. object ImportDefaultValue (TypeData typeData, string value)
  857. {
  858. if (typeData.SchemaType == SchemaTypes.Enum) {
  859. XmlTypeMapping map = GetTypeMapping (typeData);
  860. EnumMap emap = (EnumMap) map.ObjectMap;
  861. string res = emap.GetEnumName (map.TypeFullName, value);
  862. if (res == null) throw new InvalidOperationException ("'" + value + "' is not a valid enumeration value");
  863. return res;
  864. } else
  865. return XmlCustomFormatter.FromXmlString (typeData, value);
  866. }
  867. void ImportChoiceContent (XmlQualifiedName typeQName, ClassMap cmap, XmlSchemaChoice choice, CodeIdentifiers classIds, bool multiValue)
  868. {
  869. XmlTypeMapElementInfoList choices = new XmlTypeMapElementInfoList ();
  870. multiValue = ImportChoices (typeQName, null, choices, choice.Items) || multiValue;
  871. if (choices.Count == 0) return;
  872. if (choice.MaxOccurs > 1) multiValue = true;
  873. XmlTypeMapMemberElement member;
  874. if (multiValue)
  875. {
  876. member = new XmlTypeMapMemberFlatList ();
  877. member.Name = classIds.AddUnique ("Items", member);
  878. ListMap listMap = new ListMap ();
  879. listMap.ItemInfo = choices;
  880. ((XmlTypeMapMemberFlatList)member).ListMap = listMap;
  881. }
  882. else
  883. {
  884. member = new XmlTypeMapMemberElement ();
  885. member.Name = classIds.AddUnique ("Item", member);
  886. }
  887. // If all choices have the same type, use that type for the member.
  888. // If not use System.Object.
  889. // If there are at least two choices with the same type, use a choice
  890. // identifier attribute
  891. TypeData typeData = null;
  892. bool twoEqual = false;
  893. bool allEqual = true;
  894. Hashtable types = new Hashtable ();
  895. for (int n = choices.Count - 1; n >= 0; n--)
  896. {
  897. XmlTypeMapElementInfo einfo = (XmlTypeMapElementInfo) choices [n];
  898. // In some complex schemas, we may end up with several options
  899. // with the same name. It is better to ignore the extra options
  900. // than to crash. It's the best we can do, and btw it works
  901. // better than in MS.NET.
  902. if (cmap.GetElement (einfo.ElementName, einfo.Namespace, einfo.ExplicitOrder) != null ||
  903. choices.IndexOfElement (einfo.ElementName, einfo.Namespace) != n)
  904. {
  905. choices.RemoveAt (n);
  906. continue;
  907. }
  908. if (types.ContainsKey (einfo.TypeData)) twoEqual = true;
  909. else types.Add (einfo.TypeData, einfo);
  910. TypeData choiceType = einfo.TypeData;
  911. if (choiceType.SchemaType == SchemaTypes.Class)
  912. {
  913. // When comparing class types, use the most generic class in the
  914. // inheritance hierarchy
  915. XmlTypeMapping choiceMap = GetTypeMapping (choiceType);
  916. BuildPendingMap (choiceMap);
  917. while (choiceMap.BaseMap != null) {
  918. choiceMap = choiceMap.BaseMap;
  919. BuildPendingMap (choiceMap);
  920. choiceType = choiceMap.TypeData;
  921. }
  922. }
  923. if (typeData == null) typeData = choiceType;
  924. else if (typeData != choiceType) allEqual = false;
  925. }
  926. if (!allEqual)
  927. typeData = TypeTranslator.GetTypeData (typeof(object));
  928. if (twoEqual)
  929. {
  930. // Create the choice member
  931. XmlTypeMapMemberElement choiceMember = new XmlTypeMapMemberElement ();
  932. choiceMember.Ignore = true;
  933. choiceMember.Name = classIds.AddUnique (member.Name + "ElementName", choiceMember);
  934. member.ChoiceMember = choiceMember.Name;
  935. // Create the choice enum
  936. XmlTypeMapping enumMap = CreateTypeMapping (new XmlQualifiedName (member.Name + "ChoiceType", typeQName.Namespace), SchemaTypes.Enum, null);
  937. enumMap.IncludeInSchema = false;
  938. CodeIdentifiers codeIdents = new CodeIdentifiers ();
  939. EnumMap.EnumMapMember[] members = new EnumMap.EnumMapMember [choices.Count];
  940. for (int n=0; n<choices.Count; n++)
  941. {
  942. XmlTypeMapElementInfo it =(XmlTypeMapElementInfo) choices[n];
  943. bool extraNs = (it.Namespace != null && it.Namespace != "" && it.Namespace != typeQName.Namespace);
  944. string xmlName = extraNs ? it.Namespace + ":" + it.ElementName : it.ElementName;
  945. string enumName = codeIdents.AddUnique (CodeIdentifier.MakeValid (it.ElementName), it);
  946. members [n] = new EnumMap.EnumMapMember (xmlName, enumName);
  947. }
  948. enumMap.ObjectMap = new EnumMap (members, false);
  949. choiceMember.TypeData = multiValue ? enumMap.TypeData.ListTypeData : enumMap.TypeData;
  950. choiceMember.ElementInfo.Add (CreateElementInfo (typeQName.Namespace, choiceMember, choiceMember.Name, choiceMember.TypeData, false, XmlSchemaForm.None, -1));
  951. cmap.AddMember (choiceMember);
  952. }
  953. if (typeData == null)
  954. return;
  955. if (multiValue)
  956. typeData = typeData.ListTypeData;
  957. member.ElementInfo = choices;
  958. member.Documentation = GetDocumentation (choice);
  959. member.TypeData = typeData;
  960. cmap.AddMember (member);
  961. }
  962. bool ImportChoices (XmlQualifiedName typeQName, XmlTypeMapMember member, XmlTypeMapElementInfoList choices, XmlSchemaObjectCollection items)
  963. {
  964. bool multiValue = false;
  965. foreach (XmlSchemaObject titem in items)
  966. {
  967. XmlSchemaObject item = titem;
  968. if (item is XmlSchemaGroupRef)
  969. item = GetRefGroupParticle ((XmlSchemaGroupRef)item);
  970. if (item is XmlSchemaElement)
  971. {
  972. string ns;
  973. XmlSchemaElement elem = (XmlSchemaElement) item;
  974. XmlTypeMapping emap;
  975. TypeData typeData = GetElementTypeData (typeQName, elem, null, out emap);
  976. XmlSchemaElement refElem = GetRefElement (typeQName, elem, out ns);
  977. choices.Add (CreateElementInfo (ns, member, refElem.Name, typeData, refElem.IsNillable, refElem.Form, emap, -1));
  978. if (elem.MaxOccurs > 1) multiValue = true;
  979. }
  980. else if (item is XmlSchemaAny)
  981. {
  982. XmlTypeMapElementInfo einfo = new XmlTypeMapElementInfo (member, TypeTranslator.GetTypeData(typeof(XmlElement)));
  983. einfo.IsUnnamedAnyElement = true;
  984. choices.Add (einfo);
  985. }
  986. else if (item is XmlSchemaChoice) {
  987. multiValue = ImportChoices (typeQName, member, choices, ((XmlSchemaChoice)item).Items) || multiValue;
  988. }
  989. else if (item is XmlSchemaSequence) {
  990. multiValue = ImportChoices (typeQName, member, choices, ((XmlSchemaSequence)item).Items) || multiValue;
  991. }
  992. }
  993. return multiValue;
  994. }
  995. void ImportSimpleContent (XmlQualifiedName typeQName, XmlTypeMapping map, XmlSchemaSimpleContent content, CodeIdentifiers classIds, bool isMixed)
  996. {
  997. XmlSchemaSimpleContentExtension ext = content.Content as XmlSchemaSimpleContentExtension;
  998. ClassMap cmap = (ClassMap)map.ObjectMap;
  999. XmlQualifiedName qname = GetContentBaseType (content.Content);
  1000. TypeData simpleType = null;
  1001. if (!IsPrimitiveTypeNamespace (qname.Namespace))
  1002. {
  1003. // Add base map members to this map
  1004. XmlTypeMapping baseMap = ImportType (qname, null, true);
  1005. BuildPendingMap (baseMap);
  1006. if (baseMap.IsSimpleType) {
  1007. simpleType = baseMap.TypeData;
  1008. } else {
  1009. ClassMap baseClassMap = (ClassMap)baseMap.ObjectMap;
  1010. foreach (XmlTypeMapMember member in baseClassMap.AllMembers)
  1011. cmap.AddMember (member);
  1012. map.BaseMap = baseMap;
  1013. baseMap.DerivedTypes.Add (map);
  1014. }
  1015. }
  1016. else
  1017. simpleType = FindBuiltInType (qname);
  1018. if (simpleType != null) {
  1019. XmlTypeMapMemberElement member = new XmlTypeMapMemberElement ();
  1020. member.Name = classIds.AddUnique("Value", member);
  1021. member.TypeData = simpleType;
  1022. member.ElementInfo.Add (CreateTextElementInfo (typeQName.Namespace, member, member.TypeData));
  1023. member.IsXmlTextCollector = true;
  1024. cmap.AddMember (member);
  1025. }
  1026. if (ext != null)
  1027. ImportAttributes (typeQName, cmap, ext.Attributes, ext.AnyAttribute, classIds);
  1028. }
  1029. TypeData FindBuiltInType (XmlQualifiedName qname)
  1030. {
  1031. XmlSchemaComplexType ct = (XmlSchemaComplexType) schemas.Find (qname, typeof(XmlSchemaComplexType));
  1032. if (ct != null)
  1033. {
  1034. XmlSchemaSimpleContent sc = ct.ContentModel as XmlSchemaSimpleContent;
  1035. if (sc == null) throw new InvalidOperationException ("Invalid schema");
  1036. return FindBuiltInType (GetContentBaseType (sc.Content));
  1037. }
  1038. XmlSchemaSimpleType st = (XmlSchemaSimpleType) schemas.Find (qname, typeof(XmlSchemaSimpleType));
  1039. if (st != null)
  1040. return FindBuiltInType (qname, st);
  1041. if (IsPrimitiveTypeNamespace (qname.Namespace))
  1042. return TypeTranslator.GetPrimitiveTypeData (qname.Name);
  1043. throw new InvalidOperationException ("Definition of type '" + qname + "' not found");
  1044. }
  1045. TypeData FindBuiltInType (XmlQualifiedName qname, XmlSchemaSimpleType st)
  1046. {
  1047. if (CanBeEnum (st) && qname != null)
  1048. return ImportType (qname, null, true).TypeData;
  1049. if (st.Content is XmlSchemaSimpleTypeRestriction) {
  1050. XmlSchemaSimpleTypeRestriction rest = (XmlSchemaSimpleTypeRestriction) st.Content;
  1051. XmlQualifiedName bn = GetContentBaseType (rest);
  1052. if (bn == XmlQualifiedName.Empty && rest.BaseType != null)
  1053. return FindBuiltInType (qname, rest.BaseType);
  1054. else
  1055. return FindBuiltInType (bn);
  1056. }
  1057. else if (st.Content is XmlSchemaSimpleTypeList) {
  1058. return FindBuiltInType (GetContentBaseType (st.Content)).ListTypeData;
  1059. }
  1060. else if (st.Content is XmlSchemaSimpleTypeUnion) {
  1061. // MS.NET always import simple unions as string
  1062. return FindBuiltInType (new XmlQualifiedName ("string", XmlSchema.Namespace));
  1063. }
  1064. else
  1065. return null;
  1066. }
  1067. XmlQualifiedName GetContentBaseType (XmlSchemaObject ob)
  1068. {
  1069. if (ob is XmlSchemaSimpleContentExtension)
  1070. return ((XmlSchemaSimpleContentExtension)ob).BaseTypeName;
  1071. else if (ob is XmlSchemaSimpleContentRestriction)
  1072. return ((XmlSchemaSimpleContentRestriction)ob).BaseTypeName;
  1073. else if (ob is XmlSchemaSimpleTypeRestriction)
  1074. return ((XmlSchemaSimpleTypeRestriction)ob).BaseTypeName;
  1075. else if (ob is XmlSchemaSimpleTypeList)
  1076. return ((XmlSchemaSimpleTypeList)ob).ItemTypeName;
  1077. else
  1078. return null;
  1079. }
  1080. void ImportComplexContent (XmlQualifiedName typeQName, XmlTypeMapping map, XmlSchemaComplexContent content, CodeIdentifiers classIds, bool isMixed)
  1081. {
  1082. ClassMap cmap = (ClassMap)map.ObjectMap;
  1083. XmlQualifiedName qname;
  1084. XmlSchemaComplexContentExtension ext = content.Content as XmlSchemaComplexContentExtension;
  1085. if (ext != null) qname = ext.BaseTypeName;
  1086. else qname = ((XmlSchemaComplexContentRestriction)content.Content).BaseTypeName;
  1087. if (qname == typeQName)
  1088. throw new InvalidOperationException ("Cannot import schema for type '" + typeQName.Name + "' from namespace '" + typeQName.Namespace + "'. Redefine not supported");
  1089. // Add base map members to this map
  1090. XmlTypeMapping baseMap = ImportClass (qname);
  1091. BuildPendingMap (baseMap);
  1092. ClassMap baseClassMap = (ClassMap)baseMap.ObjectMap;
  1093. foreach (XmlTypeMapMember member in baseClassMap.AllMembers)
  1094. cmap.AddMember (member);
  1095. if (baseClassMap.XmlTextCollector != null) isMixed = false;
  1096. else if (content.IsMixed) isMixed = true;
  1097. map.BaseMap = baseMap;
  1098. baseMap.DerivedTypes.Add (map);
  1099. if (ext != null) {
  1100. // Add the members of this map
  1101. ImportParticleComplexContent (typeQName, cmap, ext.Particle, classIds, isMixed);
  1102. ImportAttributes (typeQName, cmap, ext.Attributes, ext.AnyAttribute, classIds);
  1103. }
  1104. else {
  1105. if (isMixed) ImportParticleComplexContent (typeQName, cmap, null, classIds, true);
  1106. }
  1107. }
  1108. void ImportExtensionTypes (XmlQualifiedName qname)
  1109. {
  1110. foreach (XmlSchema schema in schemas) {
  1111. foreach (XmlSchemaObject sob in schema.Items)
  1112. {
  1113. XmlSchemaComplexType sct = sob as XmlSchemaComplexType;
  1114. if (sct != null && sct.ContentModel is XmlSchemaComplexContent) {
  1115. XmlQualifiedName exqname;
  1116. XmlSchemaComplexContentExtension ext = sct.ContentModel.Content as XmlSchemaComplexContentExtension;
  1117. if (ext != null) exqname = ext.BaseTypeName;
  1118. else exqname = ((XmlSchemaComplexContentRestriction)sct.ContentModel.Content).BaseTypeName;
  1119. if (exqname == qname)
  1120. ImportType (new XmlQualifiedName (sct.Name, schema.TargetNamespace), sct, null);
  1121. }
  1122. }
  1123. }
  1124. }
  1125. XmlTypeMapping ImportClassSimpleType (XmlQualifiedName typeQName, XmlSchemaSimpleType stype, XmlQualifiedName root)
  1126. {
  1127. if (CanBeEnum (stype))
  1128. {
  1129. // Create an enum map
  1130. CodeIdentifiers codeIdents = new CodeIdentifiers ();
  1131. XmlTypeMapping enumMap = CreateTypeMapping (typeQName, SchemaTypes.Enum, root);
  1132. enumMap.Documentation = GetDocumentation (stype);
  1133. bool isFlags = false;
  1134. if (stype.Content is XmlSchemaSimpleTypeList) {
  1135. stype = ((XmlSchemaSimpleTypeList)stype.Content).ItemType;
  1136. isFlags = true;
  1137. }
  1138. XmlSchemaSimpleTypeRestriction rest = (XmlSchemaSimpleTypeRestriction)stype.Content;
  1139. codeIdents.AddReserved (enumMap.TypeData.TypeName);
  1140. EnumMap.EnumMapMember[] members = new EnumMap.EnumMapMember [rest.Facets.Count];
  1141. for (int n=0; n<rest.Facets.Count; n++)
  1142. {
  1143. XmlSchemaEnumerationFacet enu = (XmlSchemaEnumerationFacet) rest.Facets[n];
  1144. string enumName = codeIdents.AddUnique(CodeIdentifier.MakeValid (enu.Value), enu);
  1145. members [n] = new EnumMap.EnumMapMember (enu.Value, enumName);
  1146. members [n].Documentation = GetDocumentation (enu);
  1147. }
  1148. enumMap.ObjectMap = new EnumMap (members, isFlags);
  1149. enumMap.IsSimpleType = true;
  1150. return enumMap;
  1151. }
  1152. if (stype.Content is XmlSchemaSimpleTypeList)
  1153. {
  1154. XmlSchemaSimpleTypeList slist = (XmlSchemaSimpleTypeList)stype.Content;
  1155. TypeData arrayTypeData = FindBuiltInType (slist.ItemTypeName, stype);
  1156. ListMap listMap = new ListMap ();
  1157. listMap.ItemInfo = new XmlTypeMapElementInfoList ();
  1158. listMap.ItemInfo.Add (CreateElementInfo (typeQName.Namespace, null, "Item", arrayTypeData.ListItemTypeData, false, XmlSchemaForm.None, -1));
  1159. XmlTypeMapping map = CreateArrayTypeMapping (typeQName, arrayTypeData);
  1160. map.ObjectMap = listMap;
  1161. map.IsSimpleType = true;
  1162. return map;
  1163. }
  1164. // It is an extension of a primitive or known type
  1165. TypeData typeData = FindBuiltInType (typeQName, stype);
  1166. XmlTypeMapping rmap = GetTypeMapping (typeData);
  1167. // The resulting map must be a simple type. It needs to be explicitely set for arrays
  1168. rmap.IsSimpleType = true;
  1169. return rmap;
  1170. }
  1171. bool CanBeEnum (XmlSchemaSimpleType stype)
  1172. {
  1173. if (stype.Content is XmlSchemaSimpleTypeRestriction)
  1174. {
  1175. XmlSchemaSimpleTypeRestriction rest = (XmlSchemaSimpleTypeRestriction)stype.Content;
  1176. if (rest.Facets.Count == 0) return false;
  1177. foreach (object ob in rest.Facets)
  1178. if (!(ob is XmlSchemaEnumerationFacet)) return false;
  1179. return true;
  1180. }
  1181. else if (stype.Content is XmlSchemaSimpleTypeList)
  1182. {
  1183. XmlSchemaSimpleTypeList list = (XmlSchemaSimpleTypeList) stype.Content;
  1184. return (list.ItemType != null && CanBeEnum (list.ItemType));
  1185. }
  1186. return false;
  1187. }
  1188. bool CanBeArray (XmlQualifiedName typeQName, XmlSchemaComplexType stype)
  1189. {
  1190. if (encodedFormat)
  1191. {
  1192. XmlSchemaComplexContent content = stype.ContentModel as XmlSchemaComplexContent;
  1193. if (content == null) return false;
  1194. XmlSchemaComplexContentRestriction rest = content.Content as XmlSchemaComplexContentRestriction;
  1195. if (rest == null) return false;
  1196. return rest.BaseTypeName == arrayType;
  1197. }
  1198. else
  1199. {
  1200. if (stype.Attributes.Count > 0 || stype.AnyAttribute != null) return false;
  1201. else return !stype.IsMixed && CanBeArray (typeQName, stype.Particle, false);
  1202. }
  1203. }
  1204. bool CanBeArray (XmlQualifiedName typeQName, XmlSchemaParticle particle, bool multiValue)
  1205. {
  1206. // To be an array, there can't be a direct child of type typeQName
  1207. if (particle == null) return false;
  1208. multiValue = multiValue || particle.MaxOccurs > 1;
  1209. if (particle is XmlSchemaGroupRef)
  1210. return CanBeArray (typeQName, GetRefGroupParticle ((XmlSchemaGroupRef)particle), multiValue);
  1211. if (particle is XmlSchemaElement)
  1212. {
  1213. XmlSchemaElement elem = (XmlSchemaElement)particle;
  1214. if (!elem.RefName.IsEmpty)
  1215. return CanBeArray (typeQName, FindRefElement (elem), multiValue);
  1216. else
  1217. return multiValue && !typeQName.Equals (((XmlSchemaElement)particle).SchemaTypeName);
  1218. }
  1219. if (particle is XmlSchemaAny)
  1220. return multiValue;
  1221. if (particle is XmlSchemaSequence)
  1222. {
  1223. XmlSchemaSequence seq = particle as XmlSchemaSequence;
  1224. if (seq.Items.Count != 1) return false;
  1225. return CanBeArray (typeQName, (XmlSchemaParticle)seq.Items[0], multiValue);
  1226. }
  1227. if (particle is XmlSchemaChoice)
  1228. {
  1229. // Can be array if all choices have different types
  1230. ArrayList types = new ArrayList ();
  1231. if(!CheckChoiceType (typeQName, particle, types, ref multiValue)) return false;
  1232. return multiValue;
  1233. }
  1234. return false;
  1235. }
  1236. bool CheckChoiceType (XmlQualifiedName typeQName, XmlSchemaParticle particle, ArrayList types, ref bool multiValue)
  1237. {
  1238. XmlQualifiedName type = null;
  1239. multiValue = multiValue || particle.MaxOccurs > 1;
  1240. if (particle is XmlSchemaGroupRef)
  1241. return CheckChoiceType (typeQName, GetRefGroupParticle ((XmlSchemaGroupRef)particle), types, ref multiValue);
  1242. if (particle is XmlSchemaElement) {
  1243. string ns;
  1244. XmlSchemaElement elem = (XmlSchemaElement)particle;
  1245. XmlSchemaElement refElem = GetRefElement (typeQName, elem, out ns);
  1246. if (refElem.SchemaType != null) return true;
  1247. type = refElem.SchemaTypeName;
  1248. }
  1249. else if (particle is XmlSchemaAny) {
  1250. type = anyType;
  1251. }
  1252. else if (particle is XmlSchemaSequence)
  1253. {
  1254. XmlSchemaSequence seq = particle as XmlSchemaSequence;
  1255. foreach (XmlSchemaParticle par in seq.Items)
  1256. if (!CheckChoiceType (typeQName, par, types, ref multiValue)) return false;
  1257. return true;
  1258. }
  1259. else if (particle is XmlSchemaChoice)
  1260. {
  1261. foreach (XmlSchemaParticle choice in ((XmlSchemaChoice)particle).Items)
  1262. if (!CheckChoiceType (typeQName, choice, types, ref multiValue)) return false;
  1263. return true;
  1264. }
  1265. if (typeQName.Equals (type)) return false;
  1266. // For primitive types, compare using CLR types, since several
  1267. // xml types can be mapped to a single CLR type
  1268. string t;
  1269. if (IsPrimitiveTypeNamespace (type.Namespace))
  1270. t = TypeTranslator.GetPrimitiveTypeData (type.Name).FullTypeName + ":" + type.Namespace;
  1271. else
  1272. t = type.Name + ":" + type.Namespace;
  1273. if (types.Contains (t)) return false;
  1274. types.Add (t);
  1275. return true;
  1276. }
  1277. bool CanBeAnyElement (XmlSchemaComplexType stype)
  1278. {
  1279. XmlSchemaSequence seq = stype.Particle as XmlSchemaSequence;
  1280. return (seq != null) && (seq.Items.Count == 1) && (seq.Items[0] is XmlSchemaAny);
  1281. }
  1282. Type GetAnyElementType (XmlSchemaComplexType stype)
  1283. {
  1284. XmlSchemaSequence seq = stype.Particle as XmlSchemaSequence;
  1285. if ((seq == null) || (seq.Items.Count != 1) || !(seq.Items[0] is XmlSchemaAny))
  1286. return null;
  1287. if (encodedFormat)
  1288. return typeof(object);
  1289. XmlSchemaAny any = seq.Items[0] as XmlSchemaAny;
  1290. if (any.MaxOccurs == 1)
  1291. {
  1292. if (stype.IsMixed)
  1293. return typeof(XmlNode);
  1294. else
  1295. return typeof(XmlElement);
  1296. }
  1297. else
  1298. {
  1299. if (stype.IsMixed)
  1300. return typeof(XmlNode[]);
  1301. else
  1302. return typeof(XmlElement[]);
  1303. }
  1304. }
  1305. bool CanBeIXmlSerializable (XmlSchemaComplexType stype)
  1306. {
  1307. XmlSchemaSequence seq = stype.Particle as XmlSchemaSequence;
  1308. if (seq == null) return false;
  1309. if (seq.Items.Count != 2) return false;
  1310. XmlSchemaElement elem = seq.Items[0] as XmlSchemaElement;
  1311. if (elem == null) return false;
  1312. if (elem.RefName != new XmlQualifiedName ("schema",XmlSchema.Namespace)) return false;
  1313. return (seq.Items[1] is XmlSchemaAny);
  1314. }
  1315. XmlTypeMapping ImportXmlSerializableMapping (string ns)
  1316. {
  1317. XmlQualifiedName qname = new XmlQualifiedName ("System.Data.DataSet",ns);
  1318. XmlTypeMapping map = GetRegisteredTypeMapping (qname);
  1319. if (map != null) return map;
  1320. TypeData typeData = new TypeData ("System.Data.DataSet", "System.Data.DataSet", "System.Data.DataSet", SchemaTypes.XmlSerializable, null);
  1321. map = new XmlTypeMapping ("System.Data.DataSet", "", typeData, "System.Data.DataSet", ns);
  1322. map.IncludeInSchema = true;
  1323. RegisterTypeMapping (qname, typeData, map);
  1324. return map;
  1325. }
  1326. XmlTypeMapElementInfo CreateElementInfo (string ns, XmlTypeMapMember member, string name, TypeData typeData, bool isNillable, XmlSchemaForm form, int order)
  1327. {
  1328. if (typeData.IsComplexType)
  1329. return CreateElementInfo (ns, member, name, typeData, isNillable, form, GetTypeMapping (typeData), order);
  1330. else
  1331. return CreateElementInfo (ns, member, name, typeData, isNillable, form, null, order);
  1332. }
  1333. XmlTypeMapElementInfo CreateElementInfo (string ns, XmlTypeMapMember member, string name, TypeData typeData, bool isNillable, XmlSchemaForm form, XmlTypeMapping emap, int order)
  1334. {
  1335. XmlTypeMapElementInfo einfo = new XmlTypeMapElementInfo (member, typeData);
  1336. einfo.ElementName = name;
  1337. einfo.Namespace = ns;
  1338. einfo.IsNullable = isNillable;
  1339. einfo.Form = GetForm (form, ns, true);
  1340. if (typeData.IsComplexType)
  1341. einfo.MappedType = emap;
  1342. einfo.ExplicitOrder = order;
  1343. return einfo;
  1344. }
  1345. XmlSchemaForm GetForm (XmlSchemaForm form, string ns, bool forElement)
  1346. {
  1347. // Returns the schema form for an element or attribute, taking
  1348. // into account the schema defaults. If the form has not been explicitly
  1349. // set and there is no default, use Unqualified as default.
  1350. if (form != XmlSchemaForm.None)
  1351. return form;
  1352. XmlSchema s = schemas [ns];
  1353. if (s == null)
  1354. return XmlSchemaForm.Unqualified;
  1355. XmlSchemaForm schemaForm = forElement ? s.ElementFormDefault : s.AttributeFormDefault;
  1356. if (schemaForm != XmlSchemaForm.None)
  1357. return schemaForm;
  1358. else
  1359. return XmlSchemaForm.Unqualified;
  1360. }
  1361. XmlTypeMapElementInfo CreateTextElementInfo (string ns, XmlTypeMapMember member, TypeData typeData)
  1362. {
  1363. XmlTypeMapElementInfo einfo = new XmlTypeMapElementInfo (member, typeData);
  1364. einfo.IsTextElement = true;
  1365. einfo.WrappedElement = false;
  1366. if (typeData.IsComplexType)
  1367. einfo.MappedType = GetTypeMapping (typeData);
  1368. return einfo;
  1369. }
  1370. XmlTypeMapping CreateTypeMapping (XmlQualifiedName typeQName, SchemaTypes schemaType, XmlQualifiedName root)
  1371. {
  1372. string typeName = CodeIdentifier.MakeValid (typeQName.Name);
  1373. typeName = typeIdentifiers.AddUnique (typeName, null);
  1374. TypeData typeData = new TypeData (typeName, typeName, typeName, schemaType, null);
  1375. string rootElem;
  1376. string rootNs;
  1377. if (root != null) {
  1378. rootElem = root.Name;
  1379. rootNs = root.Namespace;
  1380. }
  1381. else {
  1382. rootElem = typeQName.Name;
  1383. rootNs = "";
  1384. }
  1385. XmlTypeMapping map = new XmlTypeMapping (rootElem, rootNs, typeData, typeQName.Name, typeQName.Namespace);
  1386. map.IncludeInSchema = true;
  1387. RegisterTypeMapping (typeQName, typeData, map);
  1388. return map;
  1389. }
  1390. XmlTypeMapping CreateArrayTypeMapping (XmlQualifiedName typeQName, TypeData arrayTypeData)
  1391. {
  1392. XmlTypeMapping map;
  1393. if (encodedFormat) map = new XmlTypeMapping ("Array", XmlSerializer.EncodingNamespace, arrayTypeData, "Array", XmlSerializer.EncodingNamespace);
  1394. else map = new XmlTypeMapping (arrayTypeData.XmlType, typeQName.Namespace, arrayTypeData, arrayTypeData.XmlType, typeQName.Namespace);
  1395. map.IncludeInSchema = true;
  1396. RegisterTypeMapping (typeQName, arrayTypeData, map);
  1397. return map;
  1398. }
  1399. XmlSchemaElement GetRefElement (XmlQualifiedName typeQName, XmlSchemaElement elem, out string ns)
  1400. {
  1401. if (!elem.RefName.IsEmpty)
  1402. {
  1403. ns = elem.RefName.Namespace;
  1404. return FindRefElement (elem);
  1405. }
  1406. else
  1407. {
  1408. ns = typeQName.Namespace;
  1409. return elem;
  1410. }
  1411. }
  1412. XmlSchemaAttribute GetRefAttribute (XmlQualifiedName typeQName, XmlSchemaAttribute attr, out string ns)
  1413. {
  1414. if (!attr.RefName.IsEmpty)
  1415. {
  1416. ns = attr.RefName.Namespace;
  1417. XmlSchemaAttribute at = FindRefAttribute (attr.RefName);
  1418. if (at == null) throw new InvalidOperationException ("The attribute " + attr.RefName + " is missing");
  1419. return at;
  1420. }
  1421. else
  1422. {
  1423. ns = attr.ParentIsSchema ? typeQName.Namespace : String.Empty;
  1424. return attr;
  1425. }
  1426. }
  1427. TypeData GetElementTypeData (XmlQualifiedName typeQName, XmlSchemaElement elem, XmlQualifiedName root, out XmlTypeMapping map)
  1428. {
  1429. bool sharedAnnType = false;
  1430. map = null;
  1431. if (!elem.RefName.IsEmpty) {
  1432. XmlSchemaElement refElem = FindRefElement (elem);
  1433. if (refElem == null) throw new InvalidOperationException ("Global element not found: " + elem.RefName);
  1434. root = elem.RefName;
  1435. elem = refElem;
  1436. sharedAnnType = true;
  1437. }
  1438. TypeData td;
  1439. if (!elem.SchemaTypeName.IsEmpty) {
  1440. td = GetTypeData (elem.SchemaTypeName, root, elem.IsNillable);
  1441. map = GetRegisteredTypeMapping (td);
  1442. }
  1443. else if (elem.SchemaType == null)
  1444. td = TypeTranslator.GetTypeData (typeof(object));
  1445. else
  1446. td = GetTypeData (elem.SchemaType, typeQName, elem.Name, sharedAnnType, root);
  1447. if (map == null && td.IsComplexType)
  1448. map = GetTypeMapping (td);
  1449. return td;
  1450. }
  1451. TypeData GetAttributeTypeData (XmlQualifiedName typeQName, XmlSchemaAttribute attr)
  1452. {
  1453. bool sharedAnnType = false;
  1454. if (!attr.RefName.IsEmpty) {
  1455. XmlSchemaAttribute refAtt = FindRefAttribute (attr.RefName);
  1456. if (refAtt == null) throw new InvalidOperationException ("Global attribute not found: " + attr.RefName);
  1457. attr = refAtt;
  1458. sharedAnnType = true;
  1459. }
  1460. if (!attr.SchemaTypeName.IsEmpty) return GetTypeData (attr.SchemaTypeName, null, false);
  1461. if (attr.SchemaType == null) return TypeTranslator.GetTypeData (typeof(string));
  1462. else return GetTypeData (attr.SchemaType, typeQName, attr.Name, sharedAnnType, null);
  1463. }
  1464. TypeData GetTypeData (XmlQualifiedName typeQName, XmlQualifiedName root, bool isNullable)
  1465. {
  1466. if (IsPrimitiveTypeNamespace (typeQName.Namespace)) {
  1467. XmlTypeMapping map = ImportType (typeQName, root, false);
  1468. if (map != null) return map.TypeData;
  1469. else return TypeTranslator.GetPrimitiveTypeData (typeQName.Name, isNullable);
  1470. }
  1471. if (encodedFormat && typeQName.Namespace == "")
  1472. return TypeTranslator.GetPrimitiveTypeData (typeQName.Name);
  1473. return ImportType (typeQName, root, true).TypeData;
  1474. }
  1475. TypeData GetTypeData (XmlSchemaType stype, XmlQualifiedName typeQNname, string propertyName, bool sharedAnnType, XmlQualifiedName root)
  1476. {
  1477. string baseName;
  1478. if (sharedAnnType)
  1479. {
  1480. // Anonymous types defined in root elements or attributes can be shared among all elements that
  1481. // reference this root element or attribute
  1482. TypeData std = sharedAnonymousTypes [stype] as TypeData;
  1483. if (std != null) return std;
  1484. baseName = propertyName;
  1485. }
  1486. else
  1487. baseName = typeQNname.Name + typeIdentifiers.MakeRightCase (propertyName);
  1488. baseName = elemIdentifiers.AddUnique (baseName, stype);
  1489. XmlQualifiedName newName;
  1490. newName = new XmlQualifiedName (baseName, typeQNname.Namespace);
  1491. XmlTypeMapping map = ImportType (newName, stype, root);
  1492. if (sharedAnnType) sharedAnonymousTypes [stype] = map.TypeData;
  1493. return map.TypeData;
  1494. }
  1495. XmlTypeMapping GetTypeMapping (TypeData typeData)
  1496. {
  1497. if (typeData.Type == typeof(object) && !anyTypeImported)
  1498. ImportAllObjectTypes ();
  1499. XmlTypeMapping map = GetRegisteredTypeMapping (typeData);
  1500. if (map != null) return map;
  1501. if (typeData.IsListType)
  1502. {
  1503. // Create an array map for the type
  1504. XmlTypeMapping itemMap = GetTypeMapping (typeData.ListItemTypeData);
  1505. map = new XmlTypeMapping (typeData.XmlType, itemMap.Namespace, typeData, typeData.XmlType, itemMap.Namespace);
  1506. map.IncludeInSchema = true;
  1507. ListMap listMap = new ListMap ();
  1508. listMap.ItemInfo = new XmlTypeMapElementInfoList();
  1509. listMap.ItemInfo.Add (CreateElementInfo (itemMap.Namespace, null, typeData.ListItemTypeData.XmlType, typeData.ListItemTypeData, false, XmlSchemaForm.None, -1));
  1510. map.ObjectMap = listMap;
  1511. RegisterTypeMapping (new XmlQualifiedName(map.ElementName, map.Namespace), typeData, map);
  1512. return map;
  1513. }
  1514. else if (typeData.SchemaType == SchemaTypes.Primitive || typeData.Type == typeof(object) || typeof(XmlNode).IsAssignableFrom(typeData.Type))
  1515. {
  1516. return CreateSystemMap (typeData);
  1517. }
  1518. throw new InvalidOperationException ("Map for type " + typeData.TypeName + " not found");
  1519. }
  1520. void AddObjectDerivedMap (XmlTypeMapping map)
  1521. {
  1522. TypeData typeData = TypeTranslator.GetTypeData (typeof(object));
  1523. XmlTypeMapping omap = GetRegisteredTypeMapping (typeData);
  1524. if (omap == null)
  1525. omap = CreateSystemMap (typeData);
  1526. omap.DerivedTypes.Add (map);
  1527. }
  1528. XmlTypeMapping CreateSystemMap (TypeData typeData)
  1529. {
  1530. XmlTypeMapping map = new XmlTypeMapping (typeData.XmlType, XmlSchema.Namespace, typeData, typeData.XmlType, XmlSchema.Namespace);
  1531. map.IncludeInSchema = false;
  1532. map.ObjectMap = new ClassMap ();
  1533. dataMappedTypes [typeData] = map;
  1534. return map;
  1535. }
  1536. void ImportAllObjectTypes ()
  1537. {
  1538. // All complex types are subtypes of anyType, so all of them
  1539. // must also be imported
  1540. anyTypeImported = true;
  1541. foreach (XmlSchema schema in schemas) {
  1542. foreach (XmlSchemaObject sob in schema.Items)
  1543. {
  1544. XmlSchemaComplexType sct = sob as XmlSchemaComplexType;
  1545. if (sct != null)
  1546. ImportType (new XmlQualifiedName (sct.Name, schema.TargetNamespace), sct, null);
  1547. }
  1548. }
  1549. }
  1550. XmlTypeMapping GetRegisteredTypeMapping (XmlQualifiedName typeQName, Type baseType)
  1551. {
  1552. // Primitive types with a forced base class are stored in a different table.
  1553. // In this way it is possible to have two maps for primitive types: one with
  1554. // the forced base class (returned by ImportDerivedTypeMapping) and one
  1555. // with the regular primitive map.
  1556. if (IsPrimitiveTypeNamespace (typeQName.Namespace))
  1557. return (XmlTypeMapping) primitiveDerivedMappedTypes [typeQName];
  1558. else
  1559. return (XmlTypeMapping) mappedTypes [typeQName];
  1560. }
  1561. XmlTypeMapping GetRegisteredTypeMapping (XmlQualifiedName typeQName)
  1562. {
  1563. return (XmlTypeMapping) mappedTypes [typeQName];
  1564. }
  1565. XmlTypeMapping GetRegisteredTypeMapping (TypeData typeData)
  1566. {
  1567. return (XmlTypeMapping) dataMappedTypes [typeData];
  1568. }
  1569. void RegisterTypeMapping (XmlQualifiedName qname, TypeData typeData, XmlTypeMapping map)
  1570. {
  1571. // Primitive types with a forced base class are stored in a different table.
  1572. // In this way it is possible to have two maps for primitive types: one with
  1573. // the forced base class (returned by ImportDerivedTypeMapping) and one
  1574. // with the regular primitive map.
  1575. dataMappedTypes [typeData] = map;
  1576. if (IsPrimitiveTypeNamespace (qname.Namespace) && !map.IsSimpleType)
  1577. primitiveDerivedMappedTypes [qname] = map;
  1578. else
  1579. mappedTypes [qname] = map;
  1580. }
  1581. XmlSchemaParticle GetRefGroupParticle (XmlSchemaGroupRef refGroup)
  1582. {
  1583. XmlSchemaGroup grp = (XmlSchemaGroup) schemas.Find (refGroup.RefName, typeof (XmlSchemaGroup));
  1584. return grp.Particle;
  1585. }
  1586. XmlSchemaElement FindRefElement (XmlSchemaElement elem)
  1587. {
  1588. XmlSchemaElement refelem = (XmlSchemaElement) schemas.Find (elem.RefName, typeof(XmlSchemaElement));
  1589. if (refelem != null) return refelem;
  1590. if (IsPrimitiveTypeNamespace (elem.RefName.Namespace))
  1591. {
  1592. if (anyElement != null) return anyElement;
  1593. anyElement = new XmlSchemaElement ();
  1594. anyElement.Name = "any";
  1595. anyElement.SchemaTypeName = anyType;
  1596. return anyElement;
  1597. } else
  1598. return null;
  1599. }
  1600. XmlSchemaAttribute FindRefAttribute (XmlQualifiedName refName)
  1601. {
  1602. if (refName.Namespace == XmlNamespace)
  1603. {
  1604. XmlSchemaAttribute at = new XmlSchemaAttribute ();
  1605. at.Name = refName.Name;
  1606. at.SchemaTypeName = new XmlQualifiedName ("string",XmlSchema.Namespace);
  1607. return at;
  1608. }
  1609. return (XmlSchemaAttribute) schemas.Find (refName, typeof(XmlSchemaAttribute));
  1610. }
  1611. XmlSchemaAttributeGroup FindRefAttributeGroup (XmlQualifiedName refName)
  1612. {
  1613. XmlSchemaAttributeGroup grp = (XmlSchemaAttributeGroup) schemas.Find (refName, typeof(XmlSchemaAttributeGroup));
  1614. foreach (XmlSchemaObject at in grp.Attributes)
  1615. {
  1616. if (at is XmlSchemaAttributeGroupRef && ((XmlSchemaAttributeGroupRef)at).RefName == refName)
  1617. throw new InvalidOperationException ("Cannot import attribute group '" + refName.Name + "' from namespace '" + refName.Namespace + "'. Redefine not supported");
  1618. }
  1619. return grp;
  1620. }
  1621. XmlTypeMapping ReflectType (Type type)
  1622. {
  1623. TypeData typeData = TypeTranslator.GetTypeData (type);
  1624. return ReflectType (typeData, (string) null);
  1625. }
  1626. XmlTypeMapping ReflectType (TypeData typeData, string ns)
  1627. {
  1628. if (!encodedFormat)
  1629. {
  1630. if (auxXmlRefImporter == null) auxXmlRefImporter = new XmlReflectionImporter ();
  1631. return auxXmlRefImporter.ImportTypeMapping (typeData, ns);
  1632. }
  1633. else
  1634. {
  1635. if (auxSoapRefImporter == null) auxSoapRefImporter = new SoapReflectionImporter ();
  1636. return auxSoapRefImporter.ImportTypeMapping (typeData, ns);
  1637. }
  1638. }
  1639. string GetDocumentation (XmlSchemaAnnotated elem)
  1640. {
  1641. string res = "";
  1642. XmlSchemaAnnotation anot = elem.Annotation;
  1643. if (anot == null || anot.Items == null) return null;
  1644. foreach (object ob in anot.Items)
  1645. {
  1646. XmlSchemaDocumentation doc = ob as XmlSchemaDocumentation;
  1647. if (doc != null && doc.Markup != null && doc.Markup.Length > 0) {
  1648. if (res != string.Empty) res += "\n";
  1649. foreach (XmlNode node in doc.Markup)
  1650. res += node.Value;
  1651. }
  1652. }
  1653. return res;
  1654. }
  1655. bool IsPrimitiveTypeNamespace (string ns)
  1656. {
  1657. return (ns == XmlSchema.Namespace) || (encodedFormat && ns == XmlSerializer.EncodingNamespace);
  1658. }
  1659. #endregion // Methods
  1660. }
  1661. }