XmlSchemaExporter.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442
  1. //
  2. // System.Xml.Serialization.XmlSchemaExporter
  3. //
  4. // Author:
  5. // Tim Coleman ([email protected])
  6. //
  7. // Copyright (C) Tim Coleman, 2002
  8. //
  9. using System.Xml;
  10. using System.Xml.Schema;
  11. using System.Collections;
  12. namespace System.Xml.Serialization {
  13. public class XmlSchemaExporter {
  14. #region Fields
  15. XmlSchemas schemas;
  16. Hashtable exportedMaps;
  17. #endregion
  18. #region Constructors
  19. public XmlSchemaExporter (XmlSchemas schemas)
  20. {
  21. this.schemas = schemas;
  22. }
  23. #endregion // Constructors
  24. #region Methods
  25. [MonoTODO]
  26. public string ExportAnyType (string ns)
  27. {
  28. throw new NotImplementedException ();
  29. }
  30. public void ExportMembersMapping (XmlMembersMapping xmlMembersMapping)
  31. {
  32. exportedMaps = new Hashtable ();
  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. exportedMaps = new Hashtable ();
  54. XmlSchema schema = GetSchema (null);
  55. XmlTypeMapElementInfo einfo = new XmlTypeMapElementInfo (null, xmlTypeMapping.TypeData);
  56. einfo.Namespace = "";
  57. einfo.ElementName = xmlTypeMapping.ElementName;
  58. einfo.MappedType = xmlTypeMapping;
  59. einfo.IsNullable = false;
  60. AddSchemaElement (schema.Items, schema, einfo, false);
  61. CompileSchemas ();
  62. }
  63. void ExportClassSchema (XmlTypeMapping map)
  64. {
  65. if (IsMapExported (map)) return;
  66. SetMapExported (map);
  67. XmlSchema schema = GetSchema (map.Namespace);
  68. XmlSchemaComplexType stype = new XmlSchemaComplexType ();
  69. stype.Name = map.ElementName;
  70. schema.Items.Add (stype);
  71. if (map.BaseMap != null)
  72. {
  73. XmlSchemaComplexContent cstype = new XmlSchemaComplexContent ();
  74. cstype.IsMixed = true;
  75. XmlSchemaComplexContentExtension ext = new XmlSchemaComplexContentExtension ();
  76. ext.BaseTypeName = new XmlQualifiedName (map.BaseMap.XmlType, map.BaseMap.Namespace);
  77. cstype.Content = ext;
  78. stype.ContentModel = cstype;
  79. XmlSchemaSequence particle;
  80. XmlSchemaAnyAttribute anyAttribute;
  81. ExportMembersMapSchema (schema, (ClassMap)map.ObjectMap, map.BaseMap, ext.Attributes, out particle, out anyAttribute);
  82. ext.Particle = particle;
  83. ext.AnyAttribute = anyAttribute;
  84. ImportNamespace (schema, map.BaseMap.Namespace);
  85. ExportClassSchema (map.BaseMap);
  86. }
  87. else
  88. {
  89. XmlSchemaSequence particle;
  90. XmlSchemaAnyAttribute anyAttribute;
  91. ExportMembersMapSchema (schema, (ClassMap)map.ObjectMap, map.BaseMap, stype.Attributes, out particle, out anyAttribute);
  92. stype.Particle = particle;
  93. stype.AnyAttribute = anyAttribute;
  94. stype.IsMixed = true;
  95. }
  96. }
  97. void ExportMembersMapSchema (XmlSchema schema, ClassMap map, XmlTypeMapping baseMap, XmlSchemaObjectCollection outAttributes, out XmlSchemaSequence particle, out XmlSchemaAnyAttribute anyAttribute)
  98. {
  99. particle = null;
  100. XmlSchemaSequence seq = new XmlSchemaSequence ();
  101. ICollection members = map.ElementMembers;
  102. if (members != null)
  103. {
  104. foreach (XmlTypeMapMemberElement member in members)
  105. {
  106. if (baseMap != null && DefinedInBaseMap (baseMap, member)) continue;
  107. Type memType = member.GetType();
  108. if (memType == typeof(XmlTypeMapMemberFlatList))
  109. {
  110. AddSchemaArrayElement (seq.Items, schema, member.ElementInfo);
  111. }
  112. else if (memType == typeof(XmlTypeMapMemberAnyElement))
  113. {
  114. AddSchemaArrayElement (seq.Items, schema, member.ElementInfo);
  115. }
  116. else if (memType == typeof(XmlTypeMapMemberAnyAttribute))
  117. {
  118. // Ignore
  119. }
  120. else if (memType == typeof(XmlTypeMapMemberElement))
  121. {
  122. XmlSchemaElement selem = (XmlSchemaElement) AddSchemaElement (seq.Items, schema, (XmlTypeMapElementInfo) member.ElementInfo [0], true);
  123. if (selem != null && member.DefaultValue != System.DBNull.Value)
  124. selem.DefaultValue = XmlCustomFormatter.ToXmlString (member.TypeData, member.DefaultValue);
  125. }
  126. else
  127. {
  128. AddSchemaElement (seq.Items, schema, (XmlTypeMapElementInfo) member.ElementInfo [0], true);
  129. }
  130. }
  131. }
  132. if (seq.Items.Count > 0)
  133. particle = seq;
  134. // Write attributes
  135. ICollection attributes = map.AttributeMembers;
  136. if (attributes != null)
  137. {
  138. foreach (XmlTypeMapMemberAttribute attr in attributes)
  139. outAttributes.Add (GetSchemaAttribute (schema, attr));
  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.Namespace);
  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.Namespace);;
  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.Namespace);;
  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, XmlTypeMapMemberElement 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. if (selem.MinOccursString == string.Empty) selem.MinOccursString = "0";
  296. if (selem.MaxOccursString == string.Empty) 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.IsMixed = true;
  339. stype.Name = map.ElementName;
  340. schema.Items.Add (stype);
  341. ListMap lmap = (ListMap) map.ObjectMap;
  342. XmlSchemaSequence seq = new XmlSchemaSequence ();
  343. XmlSchemaParticle spart = AddSchemaArrayElement (seq.Items, schema, lmap.ItemInfo);
  344. if (spart is XmlSchemaChoice)
  345. stype.Particle = spart;
  346. else
  347. stype.Particle = seq;
  348. }
  349. bool IsMapExported (XmlTypeMapping map)
  350. {
  351. if (exportedMaps.Contains (map)) return true;
  352. if (map.TypeData.Type == typeof(object)) return true;
  353. return false;
  354. }
  355. void SetMapExported (XmlTypeMapping map)
  356. {
  357. exportedMaps.Add (map,map);
  358. }
  359. void CompileSchemas ()
  360. {
  361. foreach (XmlSchema sc in schemas)
  362. sc.Compile (null);
  363. }
  364. XmlSchema GetSchema (string ns)
  365. {
  366. XmlSchema schema = schemas [ns];
  367. if (schema == null)
  368. {
  369. schema = new XmlSchema ();
  370. schema.TargetNamespace = ns;
  371. schema.ElementFormDefault = XmlSchemaForm.Qualified;
  372. schemas.Add (schema);
  373. }
  374. return schema;
  375. }
  376. #endregion // Methods
  377. }
  378. }