1 //
2 // System.Xml.Serialization.XmlSchemaExporter
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 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 //
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 //
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31 
32 using System.Xml;
33 using System.Xml.Schema;
34 using System.Collections;
35 
36 namespace System.Xml.Serialization {
37 	public class XmlSchemaExporter {
38 
39 		#region Fields
40 
41 		XmlSchemas schemas;
42 		Hashtable exportedMaps = new Hashtable();
43 		Hashtable exportedElements = new Hashtable();
44 		bool encodedFormat = false;
45 		XmlDocument xmlDoc;
46 
47 		#endregion
48 
49 		#region Constructors
50 
XmlSchemaExporter(XmlSchemas schemas)51 		public XmlSchemaExporter (XmlSchemas schemas)
52 		{
53 			this.schemas = schemas;
54 		}
55 
XmlSchemaExporter(XmlSchemas schemas, bool encodedFormat)56 		internal XmlSchemaExporter (XmlSchemas schemas, bool encodedFormat)
57 		{
58 			this.encodedFormat = encodedFormat;
59 			this.schemas = schemas;
60 		}
61 
62 		#endregion // Constructors
63 
64 		#region Methods
65 
66 		[MonoTODO]
ExportAnyType(string ns)67 		public string ExportAnyType (string ns)
68 		{
69 			throw new NotImplementedException ();
70 		}
71 
72 		[MonoNotSupported("")]
ExportAnyType(XmlMembersMapping members)73 		public string ExportAnyType (XmlMembersMapping members)
74 		{
75 			throw new NotImplementedException ();
76 		}
77 
ExportMembersMapping(XmlMembersMapping xmlMembersMapping)78 		public void ExportMembersMapping (XmlMembersMapping xmlMembersMapping)
79 		{
80 			ExportMembersMapping (xmlMembersMapping, true);
81 		}
82 
83 		public
ExportMembersMapping(XmlMembersMapping xmlMembersMapping, bool exportEnclosingType)84 		void ExportMembersMapping (XmlMembersMapping xmlMembersMapping, bool exportEnclosingType)
85 		{
86 			ClassMap cmap = (ClassMap) xmlMembersMapping.ObjectMap;
87 
88 			if (xmlMembersMapping.HasWrapperElement && exportEnclosingType)
89 			{
90 				XmlSchema schema = GetSchema (xmlMembersMapping.Namespace);
91 				XmlSchemaComplexType stype = new XmlSchemaComplexType ();
92 
93 				XmlSchemaSequence particle;
94 				XmlSchemaAnyAttribute anyAttribute;
95 				ExportMembersMapSchema (schema, cmap, null, stype.Attributes, out particle, out anyAttribute);
96 				stype.Particle = particle;
97 				stype.AnyAttribute = anyAttribute;
98 
99 				if (encodedFormat)
100 				{
101 					stype.Name = xmlMembersMapping.ElementName;
102 					schema.Items.Add (stype);
103 				}
104 				else
105 				{
106 					XmlSchemaElement selem = new XmlSchemaElement ();
107 					selem.Name = xmlMembersMapping.ElementName;
108 					selem.SchemaType = stype;
109 					schema.Items.Add (selem);
110 				}
111 			}
112 			else
113 			{
114 				ICollection members = cmap.ElementMembers;
115 				if (members != null)
116 				{
117 					foreach (XmlTypeMapMemberElement member in members)
118 					{
119 						if (member is XmlTypeMapMemberAnyElement && member.TypeData.IsListType)
120 						{
121 							XmlSchema mschema = GetSchema (xmlMembersMapping.Namespace);
122 							XmlSchemaParticle par = GetSchemaArrayElement (mschema, member.ElementInfo);
123 							if (par is XmlSchemaAny)
124 							{
125 								XmlSchemaComplexType ct = FindComplexType (mschema.Items, "any");
126 								if (ct != null) continue;
127 
128 								ct = new XmlSchemaComplexType ();
129 								ct.Name = "any";
130 								ct.IsMixed = true;
131 								XmlSchemaSequence seq = new XmlSchemaSequence ();
132 								ct.Particle = seq;
133 								seq.Items.Add (par);
134 								mschema.Items.Add (ct);
135 								continue;
136 							}
137 						}
138 
139 
140 						XmlTypeMapElementInfo einfo = (XmlTypeMapElementInfo) member.ElementInfo [0];
141 						XmlSchema schema;
142 
143 						if (encodedFormat)
144 						{
145 							schema = GetSchema (xmlMembersMapping.Namespace);
146 							ImportNamespace (schema, XmlSerializer.EncodingNamespace);
147 						}
148 						else
149 							schema = GetSchema (einfo.Namespace);
150 
151 
152 						XmlSchemaElement exe = FindElement (schema.Items, einfo.ElementName);
153 						XmlSchemaElement elem;
154 
155 						XmlSchemaObjectContainer container = null;
156 						// In encoded format, the schema elements are not needed
157 						if (!encodedFormat)
158 							container = new XmlSchemaObjectContainer (schema);
159 
160 						Type memType = member.GetType();
161 						if (member is XmlTypeMapMemberFlatList)
162 							throw new InvalidOperationException ("Unwrapped arrays not supported as parameters");
163 						else if (memType == typeof(XmlTypeMapMemberElement))
164 							elem = (XmlSchemaElement) GetSchemaElement (schema,
165 								einfo, member.DefaultValue, false, container);
166 						else
167 							elem = (XmlSchemaElement) GetSchemaElement (schema,
168 								einfo, false, container);
169 
170 						if (exe != null)
171 						{
172 							if (exe.SchemaTypeName.Equals (elem.SchemaTypeName))
173 								schema.Items.Remove (elem);
174 							else
175 							{
176 								string s = "The XML element named '" + einfo.ElementName + "' ";
177 								s += "from namespace '" + schema.TargetNamespace + "' references distinct types " + elem.SchemaTypeName.Name + " and " + exe.SchemaTypeName.Name + ". ";
178 								s += "Use XML attributes to specify another XML name or namespace for the element or types.";
179 								throw new InvalidOperationException (s);
180 							}
181 						}
182 					}
183 				}
184 			}
185 
186 			CompileSchemas ();
187 		}
188 
189 		[MonoTODO]
ExportTypeMapping(XmlMembersMapping xmlMembersMapping)190 		public XmlQualifiedName ExportTypeMapping (XmlMembersMapping xmlMembersMapping)
191 		{
192 			throw new NotImplementedException ();
193 		}
194 
ExportTypeMapping(XmlTypeMapping xmlTypeMapping)195 		public void ExportTypeMapping (XmlTypeMapping xmlTypeMapping)
196 		{
197 			if (!xmlTypeMapping.IncludeInSchema) return;
198 			if (IsElementExported (xmlTypeMapping)) return;
199 
200 			if (encodedFormat)
201 			{
202 				ExportClassSchema (xmlTypeMapping);
203 				XmlSchema schema = GetSchema (xmlTypeMapping.XmlTypeNamespace);
204 				ImportNamespace (schema, XmlSerializer.EncodingNamespace);
205 			}
206 			else
207 			{
208 				XmlSchema schema = GetSchema (xmlTypeMapping.Namespace);
209 				XmlTypeMapElementInfo einfo = new XmlTypeMapElementInfo (null, xmlTypeMapping.TypeData);
210 				einfo.Namespace = xmlTypeMapping.Namespace;
211 				einfo.ElementName = xmlTypeMapping.ElementName;
212 				if (xmlTypeMapping.TypeData.IsComplexType)
213 					einfo.MappedType = xmlTypeMapping;
214 				einfo.IsNullable = xmlTypeMapping.IsNullable;
215 				GetSchemaElement (schema, einfo, false, new XmlSchemaObjectContainer (schema));
216 				SetElementExported (xmlTypeMapping);
217 			}
218 
219 			CompileSchemas ();
220 		}
221 
ExportXmlSerializableSchema(XmlSchema currentSchema, XmlSerializableMapping map)222 		void ExportXmlSerializableSchema (XmlSchema currentSchema, XmlSerializableMapping map)
223 		{
224 	        if (IsMapExported (map)) return;
225 	        SetMapExported (map);
226 
227 	        if (map.Schema == null) return;
228 
229 			string targetNs = map.Schema.TargetNamespace;
230 	        XmlSchema existingSchema = schemas [targetNs];
231 	        if (existingSchema == null)
232 	        {
233 				schemas.Add (map.Schema);
234 				ImportNamespace (currentSchema, targetNs);
235 	        }
236 	        else if (existingSchema != map.Schema && !CanBeDuplicated (existingSchema, map.Schema))
237 	        {
238 				throw new InvalidOperationException("The namespace '" + targetNs +"' defined by the class '" + map.TypeFullName + "' is a duplicate.");
239 	        }
240 		}
241 
CanBeDuplicated(XmlSchema existingSchema, XmlSchema schema)242 		private static bool CanBeDuplicated (XmlSchema existingSchema, XmlSchema schema)
243 		{
244 			if(XmlSchemas.IsDataSet (existingSchema) && XmlSchemas.IsDataSet (schema)
245 				&& existingSchema.Id == schema.Id)
246 				return true;
247 			return false;
248 		}
249 
ExportClassSchema(XmlTypeMapping map)250 		void ExportClassSchema (XmlTypeMapping map)
251 		{
252 			if (IsMapExported (map)) return;
253 			SetMapExported (map);
254 
255 			if (map.TypeData.Type == typeof(object))
256 			{
257 				foreach (XmlTypeMapping dmap in map.DerivedTypes)
258 					if (dmap.TypeData.SchemaType == SchemaTypes.Class) ExportClassSchema (dmap);
259 				return;
260 			}
261 
262 			XmlSchema schema = GetSchema (map.XmlTypeNamespace);
263 			XmlSchemaComplexType stype = new XmlSchemaComplexType ();
264 			stype.Name = map.XmlType;
265 			schema.Items.Add (stype);
266 
267 			ClassMap cmap = (ClassMap)map.ObjectMap;
268 
269 			if (cmap.HasSimpleContent)
270 			{
271 				XmlSchemaSimpleContent simple = new XmlSchemaSimpleContent ();
272 				stype.ContentModel = simple;
273 				XmlSchemaSimpleContentExtension ext = new XmlSchemaSimpleContentExtension ();
274 				simple.Content = ext;
275 				XmlSchemaSequence particle;
276 				XmlSchemaAnyAttribute anyAttribute;
277 				ExportMembersMapSchema (schema, cmap, map.BaseMap, ext.Attributes, out particle, out anyAttribute);
278 				ext.AnyAttribute = anyAttribute;
279 				if (map.BaseMap == null)
280 					ext.BaseTypeName = cmap.SimpleContentBaseType;
281 				else {
282 					ext.BaseTypeName = new XmlQualifiedName (map.BaseMap.XmlType, map.BaseMap.XmlTypeNamespace);
283 					ImportNamespace (schema, map.BaseMap.XmlTypeNamespace);
284 					ExportClassSchema (map.BaseMap);
285 				}
286 			}
287 			else if (map.BaseMap != null && map.BaseMap.IncludeInSchema)
288 			{
289 				XmlSchemaComplexContent cstype = new XmlSchemaComplexContent ();
290 				XmlSchemaComplexContentExtension ext = new XmlSchemaComplexContentExtension ();
291 				ext.BaseTypeName = new XmlQualifiedName (map.BaseMap.XmlType, map.BaseMap.XmlTypeNamespace);
292 				cstype.Content = ext;
293 				stype.ContentModel = cstype;
294 
295 				XmlSchemaSequence particle;
296 				XmlSchemaAnyAttribute anyAttribute;
297 				ExportMembersMapSchema (schema, cmap, map.BaseMap, ext.Attributes, out particle, out anyAttribute);
298 				ext.Particle = particle;
299 				ext.AnyAttribute = anyAttribute;
300 				stype.IsMixed = HasMixedContent (map);
301 				cstype.IsMixed = BaseHasMixedContent (map);
302 
303 				ImportNamespace (schema, map.BaseMap.XmlTypeNamespace);
304 				ExportClassSchema (map.BaseMap);
305 			}
306 			else
307 			{
308 				XmlSchemaSequence particle;
309 				XmlSchemaAnyAttribute anyAttribute;
310 				ExportMembersMapSchema (schema, cmap, map.BaseMap, stype.Attributes, out particle, out anyAttribute);
311 				stype.Particle = particle;
312 				stype.AnyAttribute = anyAttribute;
313 				stype.IsMixed = cmap.XmlTextCollector != null;
314 			}
315 
316 			foreach (XmlTypeMapping dmap in map.DerivedTypes)
317 				if (dmap.TypeData.SchemaType == SchemaTypes.Class) ExportClassSchema (dmap);
318 		}
319 
BaseHasMixedContent(XmlTypeMapping map)320 		bool BaseHasMixedContent (XmlTypeMapping map)
321 		{
322 			ClassMap cmap = (ClassMap)map.ObjectMap;
323 			return (cmap.XmlTextCollector != null && (map.BaseMap != null && DefinedInBaseMap (map.BaseMap, cmap.XmlTextCollector)));
324 		}
325 
HasMixedContent(XmlTypeMapping map)326 		bool HasMixedContent (XmlTypeMapping map)
327 		{
328 			ClassMap cmap = (ClassMap)map.ObjectMap;
329 			return (cmap.XmlTextCollector != null && (map.BaseMap == null || !DefinedInBaseMap (map.BaseMap, cmap.XmlTextCollector)));
330 		}
331 
ExportMembersMapSchema(XmlSchema schema, ClassMap map, XmlTypeMapping baseMap, XmlSchemaObjectCollection outAttributes, out XmlSchemaSequence particle, out XmlSchemaAnyAttribute anyAttribute)332 		void ExportMembersMapSchema (XmlSchema schema, ClassMap map, XmlTypeMapping baseMap, XmlSchemaObjectCollection outAttributes, out XmlSchemaSequence particle, out XmlSchemaAnyAttribute anyAttribute)
333 		{
334 			particle = null;
335 			XmlSchemaSequence seq = new XmlSchemaSequence ();
336 
337 			ICollection members = map.ElementMembers;
338 			if (members != null && !map.HasSimpleContent)
339 			{
340 				foreach (XmlTypeMapMemberElement member in members)
341 				{
342 					if (baseMap != null && DefinedInBaseMap (baseMap, member)) continue;
343 
344 					Type memType = member.GetType();
345 					if (memType == typeof(XmlTypeMapMemberFlatList))
346 					{
347 						XmlSchemaParticle part = GetSchemaArrayElement (schema, member.ElementInfo);
348 						if (part != null) seq.Items.Add (part);
349 					}
350 					else if (memType == typeof(XmlTypeMapMemberAnyElement))
351 					{
352 						seq.Items.Add (GetSchemaArrayElement (schema, member.ElementInfo));
353 					}
354 					else if (memType == typeof(XmlTypeMapMemberElement))
355 					{
356 						GetSchemaElement (schema, (XmlTypeMapElementInfo) member.ElementInfo [0],
357 							member.DefaultValue, true, new XmlSchemaObjectContainer (seq));
358 					}
359 					else
360 					{
361 						GetSchemaElement (schema, (XmlTypeMapElementInfo) member.ElementInfo[0],
362 							true, new XmlSchemaObjectContainer (seq));
363 					}
364 				}
365 			}
366 
367 			if (seq.Items.Count > 0)
368 				particle = seq;
369 
370 			// Write attributes
371 
372 			ICollection attributes = map.AttributeMembers;
373 			if (attributes != null)
374 			{
375 				foreach (XmlTypeMapMemberAttribute attr in attributes) {
376 					if (baseMap != null && DefinedInBaseMap (baseMap, attr)) continue;
377 					outAttributes.Add (GetSchemaAttribute (schema, attr, true));
378 				}
379 			}
380 
381 			XmlTypeMapMember anyAttrMember = map.DefaultAnyAttributeMember;
382 			if (anyAttrMember != null)
383 				anyAttribute = new XmlSchemaAnyAttribute ();
384 			else
385 				anyAttribute = null;
386 		}
387 
FindElement(XmlSchemaObjectCollection col, string name)388 		XmlSchemaElement FindElement (XmlSchemaObjectCollection col, string name)
389 		{
390 			foreach (XmlSchemaObject ob in col)
391 			{
392 				XmlSchemaElement elem = ob as XmlSchemaElement;
393 				if (elem != null && elem.Name == name) return elem;
394 			}
395 			return null;
396 		}
397 
FindComplexType(XmlSchemaObjectCollection col, string name)398 		XmlSchemaComplexType FindComplexType (XmlSchemaObjectCollection col, string name)
399 		{
400 			foreach (XmlSchemaObject ob in col)
401 			{
402 				XmlSchemaComplexType ctype = ob as XmlSchemaComplexType;
403 				if (ctype != null && ctype.Name == name) return ctype;
404 			}
405 			return null;
406 		}
407 
GetSchemaAttribute(XmlSchema currentSchema, XmlTypeMapMemberAttribute attinfo, bool isTypeMember)408 		XmlSchemaAttribute GetSchemaAttribute (XmlSchema currentSchema, XmlTypeMapMemberAttribute attinfo, bool isTypeMember)
409 		{
410 			XmlSchemaAttribute sat = new XmlSchemaAttribute ();
411 			if (attinfo.DefaultValue != System.DBNull.Value) {
412 				sat.DefaultValue = ExportDefaultValue (attinfo.TypeData,
413 					attinfo.MappedType, attinfo.DefaultValue);
414 			} else {
415 				if (!attinfo.IsOptionalValueType && attinfo.TypeData.IsValueType)
416 					sat.Use = XmlSchemaUse.Required;
417 			}
418 
419 			ImportNamespace (currentSchema, attinfo.Namespace);
420 
421 			XmlSchema memberSchema;
422 			if (attinfo.Namespace.Length == 0 && attinfo.Form != XmlSchemaForm.Qualified)
423 				memberSchema = currentSchema;
424 			else
425 				memberSchema = GetSchema (attinfo.Namespace);
426 
427 			if (currentSchema == memberSchema || encodedFormat)
428 			{
429 				sat.Name = attinfo.AttributeName;
430 				if (isTypeMember) sat.Form = attinfo.Form;
431 				if (attinfo.TypeData.SchemaType == SchemaTypes.Enum)
432 				{
433 					ImportNamespace (currentSchema, attinfo.DataTypeNamespace);
434 					ExportEnumSchema (attinfo.MappedType);
435 					sat.SchemaTypeName = new XmlQualifiedName (attinfo.TypeData.XmlType, attinfo.DataTypeNamespace);
436 				}
437 				else if (attinfo.TypeData.SchemaType == SchemaTypes.Array && TypeTranslator.IsPrimitive (attinfo.TypeData.ListItemType))
438 				{
439 					sat.SchemaType = GetSchemaSimpleListType (attinfo.TypeData);
440 				}
441 				else
442 					sat.SchemaTypeName = new XmlQualifiedName (attinfo.TypeData.XmlType, attinfo.DataTypeNamespace);;
443 			}
444 			else
445 			{
446 				sat.RefName = new XmlQualifiedName (attinfo.AttributeName, attinfo.Namespace);
447 				foreach (XmlSchemaObject ob in memberSchema.Items)
448 					if (ob is XmlSchemaAttribute && ((XmlSchemaAttribute)ob).Name == attinfo.AttributeName)
449 						return sat;
450 
451 				memberSchema.Items.Add (GetSchemaAttribute (memberSchema, attinfo, false));
452 			}
453 			return sat;
454 		}
455 
GetSchemaElement(XmlSchema currentSchema, XmlTypeMapElementInfo einfo, bool isTypeMember)456 		XmlSchemaParticle GetSchemaElement (XmlSchema currentSchema, XmlTypeMapElementInfo einfo, bool isTypeMember)
457 		{
458 			return GetSchemaElement (currentSchema, einfo, System.DBNull.Value,
459 				isTypeMember, (XmlSchemaObjectContainer) null);
460 		}
461 
GetSchemaElement(XmlSchema currentSchema, XmlTypeMapElementInfo einfo, bool isTypeMember, XmlSchemaObjectContainer container)462 		XmlSchemaParticle GetSchemaElement (XmlSchema currentSchema, XmlTypeMapElementInfo einfo, bool isTypeMember, XmlSchemaObjectContainer container)
463 		{
464 			return GetSchemaElement (currentSchema, einfo, System.DBNull.Value, isTypeMember, container);
465 		}
466 
GetSchemaElement(XmlSchema currentSchema, XmlTypeMapElementInfo einfo, object defaultValue, bool isTypeMember, XmlSchemaObjectContainer container)467 		XmlSchemaParticle GetSchemaElement (XmlSchema currentSchema, XmlTypeMapElementInfo einfo, object defaultValue, bool isTypeMember, XmlSchemaObjectContainer container)
468 		{
469 			if (einfo.IsTextElement) return null;
470 
471 			if (einfo.IsUnnamedAnyElement)
472 			{
473 				XmlSchemaAny any = new XmlSchemaAny ();
474 				any.MinOccurs = 0;
475 				any.MaxOccurs = 1;
476 				if (container != null)
477 					container.Items.Add (any);
478 				return any;
479 			}
480 
481 			XmlSchemaElement selem = new XmlSchemaElement ();
482 			selem.IsNillable = einfo.IsNullable;
483 			if (container != null)
484 				container.Items.Add (selem);
485 
486 			if (isTypeMember)
487 			{
488 				selem.MaxOccurs = 1;
489 				selem.MinOccurs = einfo.IsNullable ? 1 : 0;
490 
491 				if ((defaultValue == DBNull.Value && einfo.TypeData.IsValueType && einfo.Member != null && !einfo.Member.IsOptionalValueType) || encodedFormat)
492  					selem.MinOccurs = 1;
493 			}
494 
495 			XmlSchema memberSchema = null;
496 
497 			if (!encodedFormat)
498 			{
499 				memberSchema = GetSchema (einfo.Namespace);
500 				ImportNamespace (currentSchema, einfo.Namespace);
501 			}
502 
503 			if (currentSchema == memberSchema || encodedFormat || !isTypeMember)
504 			{
505 				if (isTypeMember) selem.IsNillable = einfo.IsNullable;
506 				selem.Name = einfo.ElementName;
507 
508 				if (defaultValue != System.DBNull.Value)
509 					selem.DefaultValue = ExportDefaultValue (einfo.TypeData,
510 						einfo.MappedType, defaultValue);
511 
512 				if (einfo.Form != XmlSchemaForm.Qualified)
513 					selem.Form = einfo.Form;
514 
515 				switch (einfo.TypeData.SchemaType)
516 				{
517 					case SchemaTypes.XmlNode:
518 						selem.SchemaType = GetSchemaXmlNodeType ();
519 						break;
520 
521 					case SchemaTypes.XmlSerializable:
522 						SetSchemaXmlSerializableType (einfo.MappedType as XmlSerializableMapping, selem);
523 						ExportXmlSerializableSchema (currentSchema, einfo.MappedType as XmlSerializableMapping);
524 						break;
525 
526 					case SchemaTypes.Enum:
527 						selem.SchemaTypeName = new XmlQualifiedName (einfo.MappedType.XmlType, einfo.MappedType.XmlTypeNamespace);
528 						ImportNamespace (currentSchema, einfo.MappedType.XmlTypeNamespace);
529 						ExportEnumSchema (einfo.MappedType);
530 						break;
531 
532 					case SchemaTypes.Array:
533 						XmlQualifiedName atypeName = ExportArraySchema (einfo.MappedType, currentSchema.TargetNamespace);
534 						selem.SchemaTypeName = atypeName;
535 						ImportNamespace (currentSchema, atypeName.Namespace);
536 						break;
537 
538 					case SchemaTypes.Class:
539 						if (einfo.MappedType.TypeData.Type != typeof(object)) {
540 							selem.SchemaTypeName = new XmlQualifiedName (einfo.MappedType.XmlType, einfo.MappedType.XmlTypeNamespace);
541 							ImportNamespace (currentSchema, einfo.MappedType.XmlTypeNamespace);
542 						}
543 						else if (encodedFormat)
544 							selem.SchemaTypeName = new XmlQualifiedName (einfo.MappedType.XmlType, einfo.MappedType.XmlTypeNamespace);
545 
546 						ExportClassSchema (einfo.MappedType);
547 						break;
548 
549 					case SchemaTypes.Primitive:
550 						selem.SchemaTypeName = new XmlQualifiedName (einfo.TypeData.XmlType, einfo.DataTypeNamespace);
551 						if (!einfo.TypeData.IsXsdType) {
552 							ImportNamespace (currentSchema, einfo.MappedType.XmlTypeNamespace);
553 							ExportDerivedSchema (einfo.MappedType);
554 						}
555 						break;
556 				}
557 			}
558 			else
559 			{
560 				selem.RefName = new XmlQualifiedName (einfo.ElementName, einfo.Namespace);
561 				foreach (XmlSchemaObject ob in memberSchema.Items)
562 					if (ob is XmlSchemaElement && ((XmlSchemaElement)ob).Name == einfo.ElementName)
563 						return selem;
564 
565 				GetSchemaElement (memberSchema, einfo, defaultValue, false,
566 					new XmlSchemaObjectContainer (memberSchema));
567 			}
568 			return selem;
569 		}
570 
ImportNamespace(XmlSchema schema, string ns)571 		void ImportNamespace (XmlSchema schema, string ns)
572 		{
573 			if (ns == null || ns.Length == 0 ||
574 				ns == schema.TargetNamespace || ns == XmlSchema.Namespace) return;
575 
576 			foreach (XmlSchemaObject sob in schema.Includes)
577 				if ((sob is XmlSchemaImport) && ((XmlSchemaImport)sob).Namespace == ns) return;
578 
579 			XmlSchemaImport imp = new XmlSchemaImport ();
580 			imp.Namespace = ns;
581 			schema.Includes.Add (imp);
582 		}
583 
DefinedInBaseMap(XmlTypeMapping map, XmlTypeMapMember member)584 		bool DefinedInBaseMap (XmlTypeMapping map, XmlTypeMapMember member)
585 		{
586 			if (((ClassMap)map.ObjectMap).FindMember (member.Name) != null)
587 				return true;
588 			else if (map.BaseMap != null)
589 				return DefinedInBaseMap (map.BaseMap, member);
590 			else
591 				return false;
592 		}
593 
GetSchemaXmlNodeType()594 		XmlSchemaType GetSchemaXmlNodeType ()
595 		{
596 			XmlSchemaComplexType stype = new XmlSchemaComplexType ();
597 			stype.IsMixed = true;
598 			XmlSchemaSequence seq = new XmlSchemaSequence ();
599 			seq.Items.Add (new XmlSchemaAny ());
600 			stype.Particle = seq;
601 			return stype;
602 		}
603 
SetSchemaXmlSerializableType(XmlSerializableMapping map, XmlSchemaElement elem)604 		void SetSchemaXmlSerializableType (XmlSerializableMapping map, XmlSchemaElement elem)
605 		{
606 			if (map.SchemaType != null && map.Schema != null) {
607 				elem.SchemaType = map.SchemaType;
608 				return;
609 			}
610 
611 			if (map.SchemaType == null && map.SchemaTypeName != null) {
612 				elem.SchemaTypeName = map.SchemaTypeName;
613 				elem.Name = map.SchemaTypeName.Name;
614 				return;
615 			}
616 			XmlSchemaComplexType stype = new XmlSchemaComplexType ();
617 			XmlSchemaSequence seq = new XmlSchemaSequence ();
618 			if (map.Schema == null) {
619 				XmlSchemaElement selem = new XmlSchemaElement ();
620 				selem.RefName = new XmlQualifiedName ("schema",XmlSchema.Namespace);
621 				seq.Items.Add (selem);
622 				seq.Items.Add (new XmlSchemaAny ());
623 			} else {
624 				XmlSchemaAny any = new XmlSchemaAny ();
625 				any.Namespace = map.Schema.TargetNamespace;
626 				seq.Items.Add (any);
627 			}
628 			stype.Particle = seq;
629 			elem.SchemaType = stype;
630 		}
631 
GetSchemaSimpleListType(TypeData typeData)632 		XmlSchemaSimpleType GetSchemaSimpleListType (TypeData typeData)
633 		{
634 			XmlSchemaSimpleType stype = new XmlSchemaSimpleType ();
635 			XmlSchemaSimpleTypeList list = new XmlSchemaSimpleTypeList ();
636 			TypeData itemTypeData = TypeTranslator.GetTypeData (typeData.ListItemType);
637 			list.ItemTypeName = new XmlQualifiedName (itemTypeData.XmlType, XmlSchema.Namespace);
638 			stype.Content = list;
639 			return stype;
640 		}
641 
GetSchemaArrayElement(XmlSchema currentSchema, XmlTypeMapElementInfoList infos)642 		XmlSchemaParticle GetSchemaArrayElement (XmlSchema currentSchema, XmlTypeMapElementInfoList infos)
643 		{
644 			int numInfos = infos.Count;
645 			if (numInfos > 0 && ((XmlTypeMapElementInfo)infos[0]).IsTextElement) numInfos--;
646 			if (numInfos == 0) return null;
647 
648 			if (numInfos == 1)
649 			{
650 				XmlSchemaParticle selem = GetSchemaElement (currentSchema, (XmlTypeMapElementInfo) infos[infos.Count-1], true);
651 				selem.MinOccursString = "0";
652 				selem.MaxOccursString = "unbounded";
653 				return selem;
654 			}
655 			else
656 			{
657 				XmlSchemaChoice schoice = new XmlSchemaChoice ();
658 				schoice.MinOccursString = "0";
659 				schoice.MaxOccursString = "unbounded";
660 				foreach (XmlTypeMapElementInfo einfo in infos)
661 				{
662 					if (einfo.IsTextElement) continue;
663 					schoice.Items.Add (GetSchemaElement (currentSchema, einfo, true));
664 				}
665 				return schoice;
666 			}
667 		}
668 
ExportDefaultValue(TypeData typeData, XmlTypeMapping map, object defaultValue)669 		string ExportDefaultValue (TypeData typeData, XmlTypeMapping map, object defaultValue)
670 		{
671 			if (typeData.SchemaType == SchemaTypes.Enum) {
672 				EnumMap enumMap = (EnumMap) map.ObjectMap;
673 				// get corresponding xml name
674 				return enumMap.GetXmlName (map.TypeFullName, defaultValue);
675 		}
676 			return XmlCustomFormatter.ToXmlString (typeData, defaultValue);
677 		}
678 
ExportDerivedSchema(XmlTypeMapping map)679 		void ExportDerivedSchema(XmlTypeMapping map) {
680 			if (IsMapExported (map)) return;
681 			SetMapExported (map);
682 
683 			XmlSchema schema = GetSchema (map.XmlTypeNamespace);
684 			for (int i = 0; i < schema.Items.Count; i++) {
685 			        XmlSchemaSimpleType item = schema.Items [i] as XmlSchemaSimpleType;
686 			        if (item != null && item.Name == map.ElementName)
687 			                return;
688 			}
689 			XmlSchemaSimpleType stype = new XmlSchemaSimpleType ();
690 			stype.Name = map.ElementName;
691 			schema.Items.Add (stype);
692 
693 			XmlSchemaSimpleTypeRestriction rest = new XmlSchemaSimpleTypeRestriction ();
694 			rest.BaseTypeName = new XmlQualifiedName (map.TypeData.MappedType.XmlType, XmlSchema.Namespace);
695 			XmlSchemaPatternFacet facet = map.TypeData.XmlSchemaPatternFacet;
696 			if (facet != null)
697 				rest.Facets.Add(facet);
698 			stype.Content = rest;
699 		}
700 
ExportEnumSchema(XmlTypeMapping map)701 		void ExportEnumSchema (XmlTypeMapping map)
702 		{
703 			if (IsMapExported (map)) return;
704 			SetMapExported (map);
705 
706 			XmlSchema schema = GetSchema (map.XmlTypeNamespace);
707 			XmlSchemaSimpleType stype = new XmlSchemaSimpleType ();
708 			stype.Name = map.ElementName;
709 			schema.Items.Add (stype);
710 
711 			XmlSchemaSimpleTypeRestriction rest = new XmlSchemaSimpleTypeRestriction ();
712 			rest.BaseTypeName = new XmlQualifiedName ("string",XmlSchema.Namespace);
713 			EnumMap emap = (EnumMap) map.ObjectMap;
714 
715 			foreach (EnumMap.EnumMapMember emem in emap.Members)
716 			{
717 				XmlSchemaEnumerationFacet ef = new XmlSchemaEnumerationFacet ();
718 				ef.Value = emem.XmlName;
719 				rest.Facets.Add (ef);
720 			}
721 
722 			if (emap.IsFlags) {
723 				XmlSchemaSimpleTypeList slist = new XmlSchemaSimpleTypeList ();
724 				XmlSchemaSimpleType restrictionType = new XmlSchemaSimpleType ();
725 				restrictionType.Content = rest;
726 				slist.ItemType = restrictionType;
727 				stype.Content = slist;
728 			} else {
729 				stype.Content = rest;
730 			}
731 		}
732 
ExportArraySchema(XmlTypeMapping map, string defaultNamespace)733 		XmlQualifiedName ExportArraySchema (XmlTypeMapping map, string defaultNamespace)
734 		{
735 			ListMap lmap = (ListMap) map.ObjectMap;
736 
737 			if (encodedFormat)
738 			{
739 				string name, ns, schemaNs;
740 				lmap.GetArrayType (-1, out name, out ns);
741 				if (ns == XmlSchema.Namespace) schemaNs = defaultNamespace;
742 				else schemaNs = ns;
743 
744 				if (IsMapExported (map)) return new XmlQualifiedName (lmap.GetSchemaArrayName (), schemaNs);
745 				SetMapExported (map);
746 
747 				XmlSchema schema = GetSchema (schemaNs);
748 				XmlSchemaComplexType stype = new XmlSchemaComplexType ();
749 				stype.Name = lmap.GetSchemaArrayName ();
750 				schema.Items.Add (stype);
751 
752 				XmlSchemaComplexContent content = new XmlSchemaComplexContent();
753 				content.IsMixed = false;
754 				stype.ContentModel = content;
755 
756 				XmlSchemaComplexContentRestriction rest = new XmlSchemaComplexContentRestriction ();
757 				content.Content = rest;
758 				rest.BaseTypeName = new XmlQualifiedName ("Array", XmlSerializer.EncodingNamespace);
759 				XmlSchemaAttribute at = new XmlSchemaAttribute ();
760 				rest.Attributes.Add (at);
761 				at.RefName = new XmlQualifiedName ("arrayType", XmlSerializer.EncodingNamespace);
762 
763 				XmlAttribute arrayType = Document.CreateAttribute ("arrayType", XmlSerializer.WsdlNamespace);
764 				arrayType.Value = ns + (ns != "" ? ":" : "") + name;
765 				at.UnhandledAttributes = new XmlAttribute [] { arrayType };
766 				ImportNamespace (schema, XmlSerializer.WsdlNamespace);
767 
768 				XmlTypeMapElementInfo einfo = (XmlTypeMapElementInfo) lmap.ItemInfo[0];
769 				if (einfo.MappedType != null)
770 				{
771 					switch (einfo.TypeData.SchemaType)
772 					{
773 						case SchemaTypes.Enum:
774 							ExportEnumSchema (einfo.MappedType);
775 							break;
776 						case SchemaTypes.Array:
777 							ExportArraySchema (einfo.MappedType, schemaNs);
778 							break;
779 						case SchemaTypes.Class:
780 							ExportClassSchema (einfo.MappedType);
781 							break;
782 					}
783 				}
784 
785 				return new XmlQualifiedName (lmap.GetSchemaArrayName (), schemaNs);
786 			}
787 			else
788 			{
789 				if (IsMapExported (map)) return new XmlQualifiedName (map.XmlType, map.XmlTypeNamespace);
790 
791 				SetMapExported (map);
792 				XmlSchema schema = GetSchema (map.XmlTypeNamespace);
793 				XmlSchemaComplexType stype = new XmlSchemaComplexType ();
794 				stype.Name = map.ElementName;
795 				schema.Items.Add (stype);
796 
797 				XmlSchemaParticle spart = GetSchemaArrayElement (schema, lmap.ItemInfo);
798 				if (spart is XmlSchemaChoice)
799 					stype.Particle = spart;
800 				else
801 				{
802 					XmlSchemaSequence seq = new XmlSchemaSequence ();
803 					seq.Items.Add (spart);
804 					stype.Particle = seq;
805 				}
806 
807 				return new XmlQualifiedName (map.XmlType, map.XmlTypeNamespace);
808 			}
809 		}
810 
811 		XmlDocument Document
812 		{
813 			get
814 			{
815 				if (xmlDoc == null) xmlDoc = new XmlDocument ();
816 				return xmlDoc;
817 			}
818 		}
819 
IsMapExported(XmlTypeMapping map)820 		bool IsMapExported (XmlTypeMapping map)
821 		{
822 			if (exportedMaps.ContainsKey (GetMapKey(map))) return true;
823 			return false;
824 		}
825 
SetMapExported(XmlTypeMapping map)826 		void SetMapExported (XmlTypeMapping map)
827 		{
828 			exportedMaps [GetMapKey(map)] = map;
829 		}
830 
IsElementExported(XmlTypeMapping map)831 		bool IsElementExported (XmlTypeMapping map)
832 		{
833 			if (exportedElements.ContainsKey (GetMapKey(map))) return true;
834 			if (map.TypeData.Type == typeof(object)) return true;
835 			return false;
836 		}
837 
SetElementExported(XmlTypeMapping map)838 		void SetElementExported (XmlTypeMapping map)
839 		{
840 			exportedElements [GetMapKey(map)] = map;
841 		}
842 
GetMapKey(XmlTypeMapping map)843 		string GetMapKey (XmlTypeMapping map)
844 		{
845 			// Don't use type name for array types, since we can have different
846 			// classes that represent the same array type (for example
847 			// StringCollection and string[]).
848 
849 			if (map.TypeData.IsListType)
850 				return GetArrayKeyName (map.TypeData) + " " + map.XmlType + " " + map.XmlTypeNamespace;
851 			else
852 				return map.TypeData.FullTypeName + " " + map.XmlType + " " + map.XmlTypeNamespace;
853 		}
854 
GetArrayKeyName(TypeData td)855 		string GetArrayKeyName (TypeData td)
856 		{
857 			TypeData etd = td.ListItemTypeData;
858 			return "*arrayof*" + (etd.IsListType ? GetArrayKeyName (etd) : etd.FullTypeName);
859 		}
860 
CompileSchemas()861 		void CompileSchemas ()
862 		{
863 //			foreach (XmlSchema sc in schemas)
864 //				sc.Compile (null);
865 		}
866 
GetSchema(string ns)867 		XmlSchema GetSchema (string ns)
868 		{
869 			XmlSchema schema = schemas [ns];
870 			if (schema == null)
871 			{
872 				schema = new XmlSchema ();
873 				if (ns != null && ns.Length > 0)
874 					schema.TargetNamespace = ns;
875 				if (!encodedFormat)
876 					schema.ElementFormDefault = XmlSchemaForm.Qualified;
877 				schemas.Add (schema);
878 			}
879 			return schema;
880 		}
881 
882 		#endregion // Methods
883 
884 		private class XmlSchemaObjectContainer
885 		{
886 			private readonly XmlSchemaObject _xmlSchemaObject;
887 
XmlSchemaObjectContainer(XmlSchema schema)888 			public XmlSchemaObjectContainer (XmlSchema schema)
889 			{
890 				_xmlSchemaObject = schema;
891 			}
892 
XmlSchemaObjectContainer(XmlSchemaGroupBase group)893 			public XmlSchemaObjectContainer (XmlSchemaGroupBase group)
894 			{
895 				_xmlSchemaObject = group;
896 			}
897 
898 			public XmlSchemaObjectCollection Items {
899 				get {
900 					if (_xmlSchemaObject is XmlSchema) {
901 						return ((XmlSchema) _xmlSchemaObject).Items;
902 					} else {
903 						return ((XmlSchemaGroupBase) _xmlSchemaObject).Items;
904 					}
905 				}
906 			}
907 		}
908 	}
909 }
910