1 //------------------------------------------------------------------------------
2 // <copyright file="XmlSchema.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 // <owner current="true" primary="true">[....]</owner>
6 //------------------------------------------------------------------------------
8 namespace System.Xml.Schema {
10 public class XmlSchema : XmlSchemaObject
12 //Empty XmlSchema class to enable backward compatibility of interface method IXmlSerializable.GetSchema()
13 //Add private ctor to prevent constructing of this class
18 using System.Collections;
19 using System.ComponentModel;
20 using System.Xml.Serialization;
21 using System.Threading;
22 using System.Diagnostics;
24 /// <include file='doc\XmlSchema.uex' path='docs/doc[@for="XmlSchema"]/*' />
26 /// <para>[To be supplied.]</para>
28 [XmlRoot("schema", Namespace=XmlSchema.Namespace)]
29 public class XmlSchema : XmlSchemaObject {
31 /// <include file='doc\XmlSchema.uex' path='docs/doc[@for="XmlSchema.Namespace"]/*' />
33 /// <para>[To be supplied.]</para>
35 public const string Namespace = XmlReservedNs.NsXs;
36 /// <include file='doc\XmlSchema.uex' path='docs/doc[@for="XmlSchema.InstanceNamespace"]/*' />
38 /// <para>[To be supplied.]</para>
40 public const string InstanceNamespace = XmlReservedNs.NsXsi;
42 XmlSchemaForm attributeFormDefault = XmlSchemaForm.None;
43 XmlSchemaForm elementFormDefault = XmlSchemaForm.None;
44 XmlSchemaDerivationMethod blockDefault = XmlSchemaDerivationMethod.None;
45 XmlSchemaDerivationMethod finalDefault = XmlSchemaDerivationMethod.None;
48 XmlSchemaObjectCollection includes = new XmlSchemaObjectCollection();
49 XmlSchemaObjectCollection items = new XmlSchemaObjectCollection();
51 XmlAttribute[] moreAttributes;
54 bool isCompiled = false;
55 bool isCompiledBySet = false;
56 bool isPreprocessed = false;
57 bool isRedefined = false;
59 XmlSchemaObjectTable attributes;
60 XmlSchemaObjectTable attributeGroups = new XmlSchemaObjectTable();
61 XmlSchemaObjectTable elements = new XmlSchemaObjectTable();
62 XmlSchemaObjectTable types = new XmlSchemaObjectTable();
63 XmlSchemaObjectTable groups = new XmlSchemaObjectTable();
64 XmlSchemaObjectTable notations = new XmlSchemaObjectTable();
65 XmlSchemaObjectTable identityConstraints = new XmlSchemaObjectTable();
67 static int globalIdCounter = -1;
68 ArrayList importedSchemas;
69 ArrayList importedNamespaces;
71 int schemaId = -1; //Not added to a set
74 Hashtable ids = new Hashtable();
76 XmlNameTable nameTable;
78 /// <include file='doc\XmlSchema.uex' path='docs/doc[@for="XmlSchema.XmlSchema"]/*' />
80 /// <para>[To be supplied.]</para>
84 /// <include file='doc\XmlSchema.uex' path='docs/doc[@for="XmlSchema.Read"]/*' />
86 /// <para>[To be supplied.]</para>
88 public static XmlSchema Read(TextReader reader, ValidationEventHandler validationEventHandler) {
89 return Read(new XmlTextReader(reader), validationEventHandler);
92 /// <include file='doc\XmlSchema.uex' path='docs/doc[@for="XmlSchema.Read1"]/*' />
94 /// <para>[To be supplied.]</para>
96 public static XmlSchema Read(Stream stream, ValidationEventHandler validationEventHandler) {
97 return Read(new XmlTextReader(stream), validationEventHandler);
100 /// <include file='doc\XmlSchema.uex' path='docs/doc[@for="XmlSchema.Read2"]/*' />
102 /// <para>[To be supplied.]</para>
104 public static XmlSchema Read(XmlReader reader, ValidationEventHandler validationEventHandler) {
105 XmlNameTable nameTable = reader.NameTable;
106 Parser parser = new Parser(SchemaType.XSD, nameTable, new SchemaNames(nameTable), validationEventHandler);
108 parser.Parse(reader, null);
110 catch(XmlSchemaException e) {
111 if (validationEventHandler != null) {
112 validationEventHandler(null, new ValidationEventArgs(e));
119 return parser.XmlSchema;
122 /// <include file='doc\XmlSchema.uex' path='docs/doc[@for="XmlSchema.Write"]/*' />
124 /// <para>[To be supplied.]</para>
126 public void Write(Stream stream) {
130 /// <include file='doc\XmlSchema.uex' path='docs/doc[@for="XmlSchema.Write1"]/*' />
132 /// <para>[To be supplied.]</para>
134 public void Write(Stream stream, XmlNamespaceManager namespaceManager) {
135 XmlTextWriter xmlWriter = new XmlTextWriter(stream, null);
136 xmlWriter.Formatting = Formatting.Indented;
137 Write(xmlWriter, namespaceManager);
140 /// <include file='doc\XmlSchema.uex' path='docs/doc[@for="XmlSchema.Write2"]/*' />
142 /// <para>[To be supplied.]</para>
144 public void Write(TextWriter writer) {
148 /// <include file='doc\XmlSchema.uex' path='docs/doc[@for="XmlSchema.Write3"]/*' />
150 /// <para>[To be supplied.]</para>
152 public void Write(TextWriter writer, XmlNamespaceManager namespaceManager) {
153 XmlTextWriter xmlWriter = new XmlTextWriter(writer);
154 xmlWriter.Formatting = Formatting.Indented;
155 Write(xmlWriter, namespaceManager);
158 /// <include file='doc\XmlSchema.uex' path='docs/doc[@for="XmlSchema.Write4"]/*' />
160 /// <para>[To be supplied.]</para>
162 public void Write(XmlWriter writer) {
166 /// <include file='doc\XmlSchema.uex' path='docs/doc[@for="XmlSchema.Write5"]/*' />
168 /// <para>[To be supplied.]</para>
170 public void Write(XmlWriter writer, XmlNamespaceManager namespaceManager) {
171 XmlSerializer serializer = new XmlSerializer(typeof(XmlSchema));
172 XmlSerializerNamespaces ns;
174 if (namespaceManager != null) {
175 ns = new XmlSerializerNamespaces();
176 bool ignoreXS = false;
177 if (this.Namespaces != null) { //User may have set both nsManager and Namespaces property on the XmlSchema object
178 ignoreXS = this.Namespaces.Namespaces["xs"] != null || this.Namespaces.Namespaces.ContainsValue(XmlReservedNs.NsXs);
181 if (!ignoreXS && namespaceManager.LookupPrefix(XmlReservedNs.NsXs) == null &&
182 namespaceManager.LookupNamespace("xs") == null ) {
183 ns.Add("xs", XmlReservedNs.NsXs);
185 foreach(string prefix in namespaceManager) {
186 if (prefix != "xml" && prefix != "xmlns") {
187 ns.Add(prefix, namespaceManager.LookupNamespace(prefix));
191 } else if (this.Namespaces != null && this.Namespaces.Count > 0) {
192 Hashtable serializerNS = this.Namespaces.Namespaces;
193 if (serializerNS["xs"] == null && !serializerNS.ContainsValue(XmlReservedNs.NsXs)) { //Prefix xs not defined AND schema namespace not already mapped to a prefix
194 serializerNS.Add("xs", XmlReservedNs.NsXs);
196 ns = this.Namespaces;
199 ns = new XmlSerializerNamespaces();
200 ns.Add("xs", XmlSchema.Namespace);
201 if (targetNs != null && targetNs.Length != 0) {
202 ns.Add("tns", targetNs);
205 serializer.Serialize(writer, this, ns);
208 /// <include file='doc\XmlSchema.uex' path='docs/doc[@for="XmlSchema.Compile"]/*' />
210 /// <para>[To be supplied.]</para>
212 [Obsolete("Use System.Xml.Schema.XmlSchemaSet for schema compilation and validation. http://go.microsoft.com/fwlink/?linkid=14202")]
213 public void Compile(ValidationEventHandler validationEventHandler) {
214 SchemaInfo sInfo = new SchemaInfo();
215 sInfo.SchemaType = SchemaType.XSD;
216 CompileSchema(null, System.Xml.XmlConfiguration.XmlReaderSection.CreateDefaultResolver(), sInfo, null, validationEventHandler, NameTable, false);
219 /// <include file='doc\XmlSchema.uex' path='docs/doc[@for="XmlSchema.Compileq"]/*' />
221 /// <para>[To be supplied.]</para>
223 [Obsolete("Use System.Xml.Schema.XmlSchemaSet for schema compilation and validation. http://go.microsoft.com/fwlink/?linkid=14202")]
224 public void Compile(ValidationEventHandler validationEventHandler, XmlResolver resolver) {
225 SchemaInfo sInfo = new SchemaInfo();
226 sInfo.SchemaType = SchemaType.XSD;
227 CompileSchema(null, resolver, sInfo, null, validationEventHandler, NameTable, false);
230 #pragma warning disable 618
231 internal bool CompileSchema(XmlSchemaCollection xsc, XmlResolver resolver, SchemaInfo schemaInfo, string ns, ValidationEventHandler validationEventHandler, XmlNameTable nameTable, bool CompileContentModel) {
233 //Need to lock here to prevent multi-threading problems when same schema is added to set and compiled
236 SchemaCollectionPreprocessor prep = new SchemaCollectionPreprocessor(nameTable, null, validationEventHandler);
237 prep.XmlResolver = resolver;
238 if (!prep.Execute(this, ns, true, xsc)) {
243 SchemaCollectionCompiler compiler = new SchemaCollectionCompiler(nameTable, validationEventHandler);
244 isCompiled = compiler.Execute(this, schemaInfo, CompileContentModel);
245 this.SetIsCompiled(isCompiled);
250 #pragma warning restore 618
252 internal void CompileSchemaInSet(XmlNameTable nameTable, ValidationEventHandler eventHandler, XmlSchemaCompilationSettings compilationSettings) {
253 Debug.Assert(this.isPreprocessed);
254 Compiler setCompiler = new Compiler(nameTable, eventHandler, null, compilationSettings);
255 setCompiler.Prepare(this, true);
256 this.isCompiledBySet = setCompiler.Compile();
259 /// <include file='doc\XmlSchema.uex' path='docs/doc[@for="XmlSchema.AttributeFormDefault"]/*' />
261 /// <para>[To be supplied.]</para>
263 [XmlAttribute("attributeFormDefault"), DefaultValue(XmlSchemaForm.None)]
264 public XmlSchemaForm AttributeFormDefault {
265 get { return attributeFormDefault; }
266 set { attributeFormDefault = value; }
269 /// <include file='doc\XmlSchema.uex' path='docs/doc[@for="XmlSchema.BlockDefault"]/*' />
271 /// <para>[To be supplied.]</para>
273 [XmlAttribute("blockDefault"), DefaultValue(XmlSchemaDerivationMethod.None)]
274 public XmlSchemaDerivationMethod BlockDefault {
275 get { return blockDefault; }
276 set { blockDefault = value; }
279 /// <include file='doc\XmlSchema.uex' path='docs/doc[@for="XmlSchema.FinalDefault"]/*' />
281 /// <para>[To be supplied.]</para>
283 [XmlAttribute("finalDefault"), DefaultValue(XmlSchemaDerivationMethod.None)]
284 public XmlSchemaDerivationMethod FinalDefault {
285 get { return finalDefault; }
286 set { finalDefault = value; }
289 /// <include file='doc\XmlSchema.uex' path='docs/doc[@for="XmlSchema.ElementFormDefault"]/*' />
291 /// <para>[To be supplied.]</para>
293 [XmlAttribute("elementFormDefault"), DefaultValue(XmlSchemaForm.None)]
294 public XmlSchemaForm ElementFormDefault {
295 get { return elementFormDefault; }
296 set { elementFormDefault = value; }
299 /// <include file='doc\XmlSchema.uex' path='docs/doc[@for="XmlSchema.TargetNamespace"]/*' />
301 /// <para>[To be supplied.]</para>
303 [XmlAttribute("targetNamespace", DataType="anyURI")]
304 public string TargetNamespace {
305 get { return targetNs; }
306 set { targetNs = value; }
309 /// <include file='doc\XmlSchema.uex' path='docs/doc[@for="XmlSchema.Version"]/*' />
311 /// <para>[To be supplied.]</para>
313 [XmlAttribute("version", DataType="token")]
314 public string Version {
315 get { return version; }
316 set { version = value; }
319 /// <include file='doc\XmlSchema.uex' path='docs/doc[@for="XmlSchema.Includes"]/*' />
321 /// <para>[To be supplied.]</para>
323 [XmlElement("include", typeof(XmlSchemaInclude)),
324 XmlElement("import", typeof(XmlSchemaImport)),
325 XmlElement("redefine", typeof(XmlSchemaRedefine))]
326 public XmlSchemaObjectCollection Includes {
327 get { return includes; }
330 /// <include file='doc\XmlSchema.uex' path='docs/doc[@for="XmlSchema.Items"]/*' />
332 /// <para>[To be supplied.]</para>
334 [XmlElement("annotation", typeof(XmlSchemaAnnotation)),
335 XmlElement("attribute", typeof(XmlSchemaAttribute)),
336 XmlElement("attributeGroup", typeof(XmlSchemaAttributeGroup)),
337 XmlElement("complexType", typeof(XmlSchemaComplexType)),
338 XmlElement("simpleType", typeof(XmlSchemaSimpleType)),
339 XmlElement("element", typeof(XmlSchemaElement)),
340 XmlElement("group", typeof(XmlSchemaGroup)),
341 XmlElement("notation", typeof(XmlSchemaNotation))]
342 public XmlSchemaObjectCollection Items {
343 get { return items; }
347 /// <include file='doc\XmlSchema.uex' path='docs/doc[@for="XmlSchema.IsCompiled"]/*' />
349 /// <para>[To be supplied.]</para>
352 public bool IsCompiled {
354 return isCompiled || isCompiledBySet ;
359 internal bool IsCompiledBySet {
360 get { return isCompiledBySet; }
361 set { isCompiledBySet = value; }
365 internal bool IsPreprocessed {
366 get { return isPreprocessed; }
367 set { isPreprocessed = value; }
371 internal bool IsRedefined {
372 get { return isRedefined; }
373 set { isRedefined = value; }
376 /// <include file='doc\XmlSchema.uex' path='docs/doc[@for="XmlSchema.Attributes"]/*' />
378 /// <para>[To be supplied.]</para>
381 public XmlSchemaObjectTable Attributes {
383 if (attributes == null) {
384 attributes = new XmlSchemaObjectTable();
390 /// <include file='doc\XmlSchema.uex' path='docs/doc[@for="XmlSchema.AttributeGroups"]/*' />
392 /// <para>[To be supplied.]</para>
395 public XmlSchemaObjectTable AttributeGroups {
397 if (attributeGroups == null) {
398 attributeGroups = new XmlSchemaObjectTable();
400 return attributeGroups;
404 /// <include file='doc\XmlSchema.uex' path='docs/doc[@for="XmlSchema.SchemaTypes"]/*' />
406 /// <para>[To be supplied.]</para>
409 public XmlSchemaObjectTable SchemaTypes {
412 types = new XmlSchemaObjectTable();
418 /// <include file='doc\XmlSchema.uex' path='docs/doc[@for="XmlSchema.Elements"]/*' />
420 /// <para>[To be supplied.]</para>
423 public XmlSchemaObjectTable Elements {
425 if (elements == null) {
426 elements = new XmlSchemaObjectTable();
432 /// <include file='doc\XmlSchema.uex' path='docs/doc[@for="XmlSchema.Id"]/*' />
434 /// <para>[To be supplied.]</para>
436 [XmlAttribute("id", DataType="ID")]
442 /// <include file='doc\XmlSchema.uex' path='docs/doc[@for="XmlSchema.UnhandledAttributes"]/*' />
444 /// <para>[To be supplied.]</para>
447 public XmlAttribute[] UnhandledAttributes {
448 get { return moreAttributes; }
449 set { moreAttributes = value; }
452 /// <include file='doc\XmlSchema.uex' path='docs/doc[@for="XmlSchema.Groups"]/*' />
454 /// <para>[To be supplied.]</para>
457 public XmlSchemaObjectTable Groups {
458 get { return groups; }
461 /// <include file='doc\XmlSchema.uex' path='docs/doc[@for="XmlSchema.Notations"]/*' />
463 /// <para>[To be supplied.]</para>
466 public XmlSchemaObjectTable Notations {
467 get { return notations; }
471 internal XmlSchemaObjectTable IdentityConstraints {
472 get { return identityConstraints; }
476 internal Uri BaseUri {
477 get { return baseUri; }
484 // Please be careful with this property. Since it lazy initialized and its value depends on a global state
485 // if it gets called on multiple schemas in a different order the schemas will end up with different IDs
486 // Unfortunately the IDs are used to sort the schemas in the schema set and thus changing the IDs might change
487 // the order which would be a breaking change!!
488 // Simply put if you are planning to add or remove a call to this getter you need to be extra carefull
489 // or better don't do it at all.
490 internal int SchemaId {
492 if (schemaId == -1) {
493 schemaId = Interlocked.Increment(ref globalIdCounter);
500 internal bool IsChameleon {
501 get { return isChameleon; }
502 set { isChameleon = value; }
506 internal Hashtable Ids {
511 internal XmlDocument Document {
512 get { if (document == null) document = new XmlDocument(); return document; }
516 internal int ErrorCount {
517 get { return errorCount; }
518 set { errorCount = value; }
521 internal new XmlSchema Clone() {
522 XmlSchema that = new XmlSchema();
523 that.attributeFormDefault = this.attributeFormDefault;
524 that.elementFormDefault = this.elementFormDefault;
525 that.blockDefault = this.blockDefault;
526 that.finalDefault = this.finalDefault;
527 that.targetNs = this.targetNs;
528 that.version = this.version;
529 that.includes = this.includes;
531 that.Namespaces = this.Namespaces;
532 that.items = this.items;
533 that.BaseUri = this.BaseUri;
535 SchemaCollectionCompiler.Cleanup(that);
539 internal XmlSchema DeepClone() {
540 XmlSchema that = new XmlSchema();
541 that.attributeFormDefault = this.attributeFormDefault;
542 that.elementFormDefault = this.elementFormDefault;
543 that.blockDefault = this.blockDefault;
544 that.finalDefault = this.finalDefault;
545 that.targetNs = this.targetNs;
546 that.version = this.version;
547 that.isPreprocessed = this.isPreprocessed;
548 //that.IsProcessing = this.IsProcessing; //Not sure if this is needed
551 for (int i = 0; i < this.items.Count; ++i) {
552 XmlSchemaObject newItem;
554 XmlSchemaComplexType complexType;
555 XmlSchemaElement element;
556 XmlSchemaGroup group;
558 if ((complexType = items[i] as XmlSchemaComplexType) != null) {
559 newItem = complexType.Clone(this);
561 else if ((element = items[i] as XmlSchemaElement) != null) {
562 newItem = element.Clone(this);
564 else if ((group = items[i] as XmlSchemaGroup) != null) {
565 newItem = group.Clone(this);
568 newItem = items[i].Clone();
570 that.Items.Add(newItem);
574 for (int i = 0; i < this.includes.Count; ++i) {
575 XmlSchemaExternal newInclude = (XmlSchemaExternal)this.includes[i].Clone();
576 that.Includes.Add(newInclude);
578 that.Namespaces = this.Namespaces;
579 //that.includes = this.includes; //Need to verify this is OK for redefines
580 that.BaseUri = this.BaseUri;
585 internal override string IdAttribute {
590 internal void SetIsCompiled(bool isCompiled) {
591 this.isCompiled = isCompiled;
594 internal override void SetUnhandledAttributes(XmlAttribute[] moreAttributes) {
595 this.moreAttributes = moreAttributes;
597 internal override void AddAnnotation(XmlSchemaAnnotation annotation) {
598 items.Add(annotation);
601 internal XmlNameTable NameTable {
602 get { if (nameTable == null) nameTable = new System.Xml.NameTable(); return nameTable; }
605 internal ArrayList ImportedSchemas {
607 if (importedSchemas == null) {
608 importedSchemas = new ArrayList();
610 return importedSchemas;
614 internal ArrayList ImportedNamespaces {
616 if (importedNamespaces == null) {
617 importedNamespaces = new ArrayList();
619 return importedNamespaces;
623 internal void GetExternalSchemasList(IList extList, XmlSchema schema) {
624 Debug.Assert(extList != null && schema != null);
625 if (extList.Contains(schema)) {
629 for (int i = 0; i < schema.Includes.Count; ++i) {
630 XmlSchemaExternal ext = (XmlSchemaExternal)schema.Includes[i];
631 if (ext.Schema != null) {
632 GetExternalSchemasList(extList, ext.Schema);
637 #if TRUST_COMPILE_STATE
638 internal void AddCompiledInfo(SchemaInfo schemaInfo) {
639 XmlQualifiedName itemName;
640 foreach (XmlSchemaElement element in elements.Values) {
641 itemName = element.QualifiedName;
642 schemaInfo.TargetNamespaces[itemName.Namespace] = true;
643 if (schemaInfo.ElementDecls[itemName] == null) {
644 schemaInfo.ElementDecls.Add(itemName, element.ElementDecl);
647 foreach (XmlSchemaAttribute attribute in attributes.Values) {
648 itemName = attribute.QualifiedName;
649 schemaInfo.TargetNamespaces[itemName.Namespace] = true;
650 if (schemaInfo.ElementDecls[itemName] == null) {
651 schemaInfo.AttributeDecls.Add(itemName, attribute.AttDef);
654 foreach (XmlSchemaType type in types.Values) {
655 itemName = type.QualifiedName;
656 schemaInfo.TargetNamespaces[itemName.Namespace] = true;
657 XmlSchemaComplexType complexType = type as XmlSchemaComplexType;
658 if ((complexType == null || type != XmlSchemaComplexType.AnyType) && schemaInfo.ElementDeclsByType[itemName] == null) {
659 schemaInfo.ElementDeclsByType.Add(itemName, type.ElementDecl);
662 foreach (XmlSchemaNotation notation in notations.Values) {
663 itemName = notation.QualifiedName;
664 schemaInfo.TargetNamespaces[itemName.Namespace] = true;
665 SchemaNotation no = new SchemaNotation(itemName);
666 no.SystemLiteral = notation.System;
667 no.Pubid = notation.Public;
668 if (schemaInfo.Notations[itemName.Name] == null) {
669 schemaInfo.Notations.Add(itemName.Name, no);
673 #endif//TRUST_COMPILE_STATE