XmlSchemaExporter.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  1. //
  2. // System.Xml.Serialization.XmlSchemaExporter
  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 XmlSchemaExporter {
  15. #region Fields
  16. XmlSchemas schemas;
  17. Hashtable exportedMaps = new Hashtable();
  18. #endregion
  19. #region Constructors
  20. public XmlSchemaExporter (XmlSchemas schemas)
  21. {
  22. this.schemas = schemas;
  23. }
  24. #endregion // Constructors
  25. #region Methods
  26. [MonoTODO]
  27. public string ExportAnyType (string ns)
  28. {
  29. throw new NotImplementedException ();
  30. }
  31. public void ExportMembersMapping (XmlMembersMapping xmlMembersMapping)
  32. {
  33. XmlSchema schema = GetSchema (xmlMembersMapping.Namespace);
  34. XmlSchemaElement selem = new XmlSchemaElement ();
  35. selem.Name = xmlMembersMapping.ElementName;
  36. schema.Items.Add (selem);
  37. XmlSchemaComplexType stype = new XmlSchemaComplexType ();
  38. XmlSchemaSequence particle;
  39. XmlSchemaAnyAttribute anyAttribute;
  40. ExportMembersMapSchema (schema, (ClassMap)xmlMembersMapping.ObjectMap, null, stype.Attributes, out particle, out anyAttribute);
  41. stype.Particle = particle;
  42. stype.AnyAttribute = anyAttribute;
  43. selem.SchemaType = stype;
  44. CompileSchemas ();
  45. }
  46. [MonoTODO]
  47. public XmlQualifiedName ExportTypeMapping (XmlMembersMapping xmlMembersMapping)
  48. {
  49. throw new NotImplementedException ();
  50. }
  51. public void ExportTypeMapping (XmlTypeMapping xmlTypeMapping)
  52. {
  53. XmlSchema schema = GetSchema (null);
  54. XmlTypeMapElementInfo einfo = new XmlTypeMapElementInfo (null, xmlTypeMapping.TypeData);
  55. einfo.Namespace = xmlTypeMapping.Namespace;
  56. einfo.ElementName = xmlTypeMapping.ElementName;
  57. einfo.MappedType = xmlTypeMapping;
  58. einfo.IsNullable = false;
  59. AddSchemaElement (schema.Items, schema, einfo, false);
  60. // CompileSchemas ();
  61. }
  62. void ExportClassSchema (XmlTypeMapping map)
  63. {
  64. if (IsMapExported (map)) return;
  65. SetMapExported (map);
  66. XmlSchema schema = GetSchema (map.XmlTypeNamespace);
  67. XmlSchemaComplexType stype = new XmlSchemaComplexType ();
  68. stype.Name = map.XmlType;
  69. schema.Items.Add (stype);
  70. if (map.BaseMap != null)
  71. {
  72. XmlSchemaComplexContent cstype = new XmlSchemaComplexContent ();
  73. XmlSchemaComplexContentExtension ext = new XmlSchemaComplexContentExtension ();
  74. ext.BaseTypeName = new XmlQualifiedName (map.BaseMap.XmlType, map.BaseMap.XmlTypeNamespace);
  75. cstype.Content = ext;
  76. stype.ContentModel = cstype;
  77. XmlSchemaSequence particle;
  78. XmlSchemaAnyAttribute anyAttribute;
  79. ExportMembersMapSchema (schema, (ClassMap)map.ObjectMap, map.BaseMap, ext.Attributes, out particle, out anyAttribute);
  80. ext.Particle = particle;
  81. ext.AnyAttribute = anyAttribute;
  82. ImportNamespace (schema, map.BaseMap.Namespace);
  83. ExportClassSchema (map.BaseMap);
  84. }
  85. else
  86. {
  87. XmlSchemaSequence particle;
  88. XmlSchemaAnyAttribute anyAttribute;
  89. ExportMembersMapSchema (schema, (ClassMap)map.ObjectMap, map.BaseMap, stype.Attributes, out particle, out anyAttribute);
  90. stype.Particle = particle;
  91. stype.AnyAttribute = anyAttribute;
  92. stype.IsMixed = ((ClassMap)map.ObjectMap).XmlTextCollector != null;
  93. }
  94. }
  95. void ExportMembersMapSchema (XmlSchema schema, ClassMap map, XmlTypeMapping baseMap, XmlSchemaObjectCollection outAttributes, out XmlSchemaSequence particle, out XmlSchemaAnyAttribute anyAttribute)
  96. {
  97. particle = null;
  98. XmlSchemaSequence seq = new XmlSchemaSequence ();
  99. ICollection members = map.ElementMembers;
  100. if (members != null)
  101. {
  102. foreach (XmlTypeMapMemberElement member in members)
  103. {
  104. if (baseMap != null && DefinedInBaseMap (baseMap, member)) continue;
  105. Type memType = member.GetType();
  106. if (memType == typeof(XmlTypeMapMemberFlatList))
  107. {
  108. AddSchemaArrayElement (seq.Items, schema, member.ElementInfo);
  109. }
  110. else if (memType == typeof(XmlTypeMapMemberAnyElement))
  111. {
  112. AddSchemaArrayElement (seq.Items, schema, member.ElementInfo);
  113. }
  114. else if (memType == typeof(XmlTypeMapMemberAnyAttribute))
  115. {
  116. // Ignore
  117. }
  118. else if (memType == typeof(XmlTypeMapMemberElement))
  119. {
  120. XmlSchemaElement selem = (XmlSchemaElement) AddSchemaElement (seq.Items, schema, (XmlTypeMapElementInfo) member.ElementInfo [0], true);
  121. if (selem != null && member.DefaultValue != System.DBNull.Value)
  122. selem.DefaultValue = XmlCustomFormatter.ToXmlString (member.TypeData, member.DefaultValue);
  123. }
  124. else
  125. {
  126. AddSchemaElement (seq.Items, schema, (XmlTypeMapElementInfo) member.ElementInfo [0], true);
  127. }
  128. }
  129. }
  130. if (seq.Items.Count > 0)
  131. particle = seq;
  132. // Write attributes
  133. ICollection attributes = map.AttributeMembers;
  134. if (attributes != null)
  135. {
  136. foreach (XmlTypeMapMemberAttribute attr in attributes) {
  137. if (baseMap != null && DefinedInBaseMap (baseMap, attr)) continue;
  138. outAttributes.Add (GetSchemaAttribute (schema, attr));
  139. }
  140. }
  141. XmlTypeMapMember anyAttrMember = map.DefaultAnyAttributeMember;
  142. if (anyAttrMember != null)
  143. anyAttribute = new XmlSchemaAnyAttribute ();
  144. else
  145. anyAttribute = null;
  146. }
  147. XmlSchemaAttribute GetSchemaAttribute (XmlSchema currentSchema, XmlTypeMapMemberAttribute attinfo)
  148. {
  149. XmlSchemaAttribute sat = new XmlSchemaAttribute ();
  150. if (attinfo.DefaultValue != System.DBNull.Value) sat.DefaultValue = XmlCustomFormatter.ToXmlString (attinfo.TypeData, attinfo.DefaultValue);
  151. ImportNamespace (currentSchema, attinfo.Namespace);
  152. XmlSchema memberSchema = GetSchema (attinfo.Namespace);
  153. if (currentSchema == memberSchema)
  154. {
  155. sat.Name = attinfo.AttributeName;
  156. if (attinfo.TypeData.SchemaType == SchemaTypes.Enum)
  157. {
  158. ExportEnumSchema (attinfo.MappedType);
  159. sat.SchemaTypeName = new XmlQualifiedName (attinfo.TypeData.XmlType, attinfo.DataTypeNamespace);;
  160. }
  161. else if (attinfo.TypeData.SchemaType == SchemaTypes.Array && TypeTranslator.IsPrimitive (attinfo.TypeData.ListItemType))
  162. {
  163. sat.SchemaType = GetSchemaSimpleListType (attinfo.TypeData);
  164. }
  165. else
  166. sat.SchemaTypeName = new XmlQualifiedName (attinfo.TypeData.XmlType, attinfo.DataTypeNamespace);;
  167. }
  168. else
  169. {
  170. sat.RefName = new XmlQualifiedName (attinfo.AttributeName, attinfo.Namespace);
  171. memberSchema.Items.Add (GetSchemaAttribute (memberSchema, attinfo));
  172. }
  173. return sat;
  174. }
  175. XmlSchemaParticle AddSchemaElement (XmlSchemaObjectCollection destcol, XmlSchema currentSchema, XmlTypeMapElementInfo einfo, bool isTypeMember)
  176. {
  177. if (einfo.IsTextElement) return null;
  178. if (einfo.IsUnnamedAnyElement)
  179. {
  180. XmlSchemaAny any = new XmlSchemaAny ();
  181. any.MinOccurs = 0;
  182. any.MaxOccurs = 1;
  183. destcol.Add (any);
  184. return any;
  185. }
  186. XmlSchemaElement selem = new XmlSchemaElement ();
  187. destcol.Add (selem);
  188. if (isTypeMember)
  189. {
  190. selem.MaxOccurs = 1;
  191. selem.MinOccurs = einfo.IsNullable ? 1 : 0;
  192. if (einfo.TypeData.Type.IsPrimitive && einfo.TypeData.Type != typeof(string) ||
  193. einfo.TypeData.Type.IsEnum)
  194. selem.MinOccurs = 1;
  195. }
  196. XmlSchema memberSchema = GetSchema (einfo.Namespace);
  197. ImportNamespace (currentSchema, einfo.Namespace);
  198. if (currentSchema == memberSchema)
  199. {
  200. if (isTypeMember) selem.IsNillable = einfo.IsNullable;
  201. selem.Name = einfo.ElementName;
  202. XmlQualifiedName typeName = new XmlQualifiedName (einfo.TypeData.XmlType, einfo.DataTypeNamespace);
  203. switch (einfo.TypeData.SchemaType)
  204. {
  205. case SchemaTypes.XmlNode:
  206. selem.SchemaType = GetSchemaXmlNodeType ();
  207. break;
  208. case SchemaTypes.XmlSerializable:
  209. selem.SchemaType = GetSchemaXmlSerializableType ();
  210. break;
  211. case SchemaTypes.Enum:
  212. selem.SchemaTypeName = new XmlQualifiedName (einfo.MappedType.XmlType, einfo.MappedType.XmlTypeNamespace);
  213. ImportNamespace (currentSchema, einfo.MappedType.Namespace);
  214. ExportEnumSchema (einfo.MappedType);
  215. break;
  216. case SchemaTypes.Array:
  217. selem.SchemaTypeName = new XmlQualifiedName (einfo.MappedType.XmlType, einfo.MappedType.XmlTypeNamespace);;
  218. ImportNamespace (currentSchema, einfo.MappedType.Namespace);
  219. ExportArraySchema (einfo.MappedType);
  220. break;
  221. case SchemaTypes.Class:
  222. if (einfo.MappedType.TypeData.Type != typeof(object)) {
  223. selem.SchemaTypeName = new XmlQualifiedName (einfo.MappedType.XmlType, einfo.MappedType.XmlTypeNamespace);;
  224. ImportNamespace (currentSchema, einfo.MappedType.Namespace);
  225. ExportClassSchema (einfo.MappedType);
  226. }
  227. break;
  228. case SchemaTypes.Primitive:
  229. selem.SchemaTypeName = new XmlQualifiedName (einfo.TypeData.XmlType, einfo.DataTypeNamespace);;
  230. break;
  231. }
  232. }
  233. else
  234. {
  235. selem.RefName = new XmlQualifiedName (einfo.ElementName, einfo.Namespace);
  236. AddSchemaElement (memberSchema.Items, memberSchema, einfo, false);
  237. }
  238. return selem;
  239. }
  240. void ImportNamespace (XmlSchema schema, string ns)
  241. {
  242. if (ns == "" || ns == schema.TargetNamespace) return;
  243. foreach (XmlSchemaObject sob in schema.Includes)
  244. if ((sob is XmlSchemaImport) && ((XmlSchemaImport)sob).Namespace == ns) return;
  245. XmlSchemaImport imp = new XmlSchemaImport ();
  246. imp.Namespace = ns;
  247. schema.Includes.Add (imp);
  248. }
  249. bool DefinedInBaseMap (XmlTypeMapping map, XmlTypeMapMember member)
  250. {
  251. if (((ClassMap)map.ObjectMap).FindMember (member.Name) != null)
  252. return true;
  253. else if (map.BaseMap != null)
  254. return DefinedInBaseMap (map.BaseMap, member);
  255. else
  256. return false;
  257. }
  258. XmlSchemaType GetSchemaXmlNodeType ()
  259. {
  260. XmlSchemaComplexType stype = new XmlSchemaComplexType ();
  261. stype.IsMixed = true;
  262. XmlSchemaSequence seq = new XmlSchemaSequence ();
  263. seq.Items.Add (new XmlSchemaAny ());
  264. stype.Particle = seq;
  265. return stype;
  266. }
  267. XmlSchemaType GetSchemaXmlSerializableType ()
  268. {
  269. XmlSchemaComplexType stype = new XmlSchemaComplexType ();
  270. XmlSchemaSequence seq = new XmlSchemaSequence ();
  271. XmlSchemaElement selem = new XmlSchemaElement ();
  272. selem.RefName = new XmlQualifiedName ("schema",XmlSchema.Namespace);
  273. seq.Items.Add (selem);
  274. seq.Items.Add (new XmlSchemaAny ());
  275. stype.Particle = seq;
  276. return stype;
  277. }
  278. XmlSchemaSimpleType GetSchemaSimpleListType (TypeData typeData)
  279. {
  280. XmlSchemaSimpleType stype = new XmlSchemaSimpleType ();
  281. XmlSchemaSimpleTypeList list = new XmlSchemaSimpleTypeList ();
  282. TypeData itemTypeData = TypeTranslator.GetTypeData (typeData.ListItemType);
  283. list.ItemTypeName = new XmlQualifiedName (itemTypeData.XmlType, XmlSchema.Namespace);
  284. stype.Content = list;
  285. return stype;
  286. }
  287. XmlSchemaParticle AddSchemaArrayElement (XmlSchemaObjectCollection destcol, XmlSchema currentSchema, XmlTypeMapElementInfoList infos)
  288. {
  289. int numInfos = infos.Count;
  290. if (numInfos > 0 && ((XmlTypeMapElementInfo)infos[0]).IsTextElement) numInfos--;
  291. if (numInfos == 0) return null;
  292. if (numInfos == 1)
  293. {
  294. XmlSchemaParticle selem = AddSchemaElement (destcol, currentSchema, (XmlTypeMapElementInfo) infos[infos.Count-1], true);
  295. selem.MinOccursString = "0";
  296. selem.MaxOccursString = "unbounded";
  297. return selem;
  298. }
  299. else
  300. {
  301. XmlSchemaChoice schoice = new XmlSchemaChoice ();
  302. destcol.Add (schoice);
  303. schoice.MinOccursString = "0";
  304. schoice.MaxOccursString = "unbounded";
  305. foreach (XmlTypeMapElementInfo einfo in infos)
  306. {
  307. if (einfo.IsTextElement) continue;
  308. AddSchemaElement (schoice.Items, currentSchema, einfo, true);
  309. }
  310. return schoice;
  311. }
  312. }
  313. void ExportEnumSchema (XmlTypeMapping map)
  314. {
  315. if (IsMapExported (map)) return;
  316. SetMapExported (map);
  317. XmlSchema schema = GetSchema (map.Namespace);
  318. XmlSchemaSimpleType stype = new XmlSchemaSimpleType ();
  319. stype.Name = map.ElementName;
  320. schema.Items.Add (stype);
  321. XmlSchemaSimpleTypeRestriction rest = new XmlSchemaSimpleTypeRestriction ();
  322. rest.BaseTypeName = new XmlQualifiedName ("string",XmlSchema.Namespace);
  323. EnumMap emap = (EnumMap) map.ObjectMap;
  324. foreach (EnumMap.EnumMapMember emem in emap.Members)
  325. {
  326. XmlSchemaEnumerationFacet ef = new XmlSchemaEnumerationFacet ();
  327. ef.Value = emem.XmlName;
  328. rest.Facets.Add (ef);
  329. }
  330. stype.Content = rest;
  331. }
  332. void ExportArraySchema (XmlTypeMapping map)
  333. {
  334. if (IsMapExported (map)) return;
  335. SetMapExported (map);
  336. XmlSchema schema = GetSchema (map.Namespace);
  337. XmlSchemaComplexType stype = new XmlSchemaComplexType ();
  338. stype.Name = map.ElementName;
  339. schema.Items.Add (stype);
  340. ListMap lmap = (ListMap) map.ObjectMap;
  341. XmlSchemaSequence seq = new XmlSchemaSequence ();
  342. XmlSchemaParticle spart = AddSchemaArrayElement (seq.Items, schema, lmap.ItemInfo);
  343. if (spart is XmlSchemaChoice)
  344. stype.Particle = spart;
  345. else
  346. stype.Particle = seq;
  347. }
  348. bool IsMapExported (XmlTypeMapping map)
  349. {
  350. if (exportedMaps.Contains (map)) return true;
  351. if (map.TypeData.Type == typeof(object)) return true;
  352. return false;
  353. }
  354. void SetMapExported (XmlTypeMapping map)
  355. {
  356. exportedMaps.Add (map,map);
  357. }
  358. void CompileSchemas ()
  359. {
  360. // foreach (XmlSchema sc in schemas)
  361. // sc.Compile (null);
  362. }
  363. XmlSchema GetSchema (string ns)
  364. {
  365. XmlSchema schema = schemas [ns];
  366. if (schema == null)
  367. {
  368. schema = new XmlSchema ();
  369. schema.TargetNamespace = ns;
  370. schema.ElementFormDefault = XmlSchemaForm.Qualified;
  371. schemas.Add (schema);
  372. }
  373. return schema;
  374. }
  375. #endregion // Methods
  376. }
  377. }