// // // // // $Revision$ // using System; using System.Linq; using System.IO; using System.Text; using System.Xml; using System.Xml.Schema; using ICSharpCode.SharpDevelop.Editor.CodeCompletion; namespace ICSharpCode.XmlEditor { /// /// Holds the completion (intellisense) data for an xml schema. /// /// /// The XmlSchema class throws an exception if we attempt to load /// the xhtml1-strict.xsd schema. It does not like the fact that /// this schema redefines the xml namespace, even though this is /// allowed by the w3.org specification. /// public class XmlSchemaCompletion { XmlSchema schema; string fileName = String.Empty; bool readOnly; XmlNamespace xmlNamespace = new XmlNamespace(); /// /// Stores attributes that have been prohibited whilst the code /// generates the attribute completion data. /// XmlSchemaObjectCollection prohibitedAttributes = new XmlSchemaObjectCollection(); public XmlSchemaCompletion() { } public string DefaultNamespacePrefix { get { return xmlNamespace.Prefix; } set { xmlNamespace.Prefix = value; } } /// /// Creates completion data from the schema passed in /// via the reader object. /// public XmlSchemaCompletion(TextReader reader) { ReadSchema(String.Empty, reader); } /// /// Creates the completion data from the specified schema file. /// public XmlSchemaCompletion(string fileName) : this(String.Empty, fileName) { } /// /// Creates the completion data from the specified schema file and uses /// the specified baseUri to resolve any referenced schemas. /// public XmlSchemaCompletion(string baseUri, string fileName) { StreamReader reader = new StreamReader(fileName, true); ReadSchema(baseUri, reader); this.fileName = fileName; } /// /// Gets the schema. /// public XmlSchema Schema { get { return schema; } } /// /// Read only schemas are those that are installed with /// SharpDevelop. /// public bool IsReadOnly { get { return readOnly; } set { readOnly = value; } } /// /// Gets or sets the schema's file name. /// public string FileName { get { return fileName; } set { fileName = value; } } /// /// Gets the namespace URI for the schema. /// public string NamespaceUri { get { return xmlNamespace.Name; } } public bool HasNamespaceUri { get { return !String.IsNullOrWhiteSpace(NamespaceUri); } } public XmlNamespace Namespace { get { return xmlNamespace; } } /// /// Converts the filename into a valid Uri. /// public static string GetUri(string fileName) { if (fileName != null) { if (fileName.Length > 0) { return String.Concat("file:///", fileName.Replace('\\', '/')); } } return String.Empty; } public XmlCompletionItemCollection GetRootElementCompletion() { return GetRootElementCompletion(DefaultNamespacePrefix); } public XmlCompletionItemCollection GetRootElementCompletion(string namespacePrefix) { XmlCompletionItemCollection items = new XmlCompletionItemCollection(); foreach (XmlSchemaElement element in schema.Elements.Values) { if (element.Name != null) { AddElement(items, element.Name, namespacePrefix, element.Annotation); } else { // Do not add reference element. } } return items; } /// /// Gets the attribute completion data for the xml element that exists /// at the end of the specified path. /// public XmlCompletionItemCollection GetAttributeCompletion(XmlElementPath path) { // Locate matching element. XmlSchemaElement element = FindElement(path); // Get completion data. if (element != null) { prohibitedAttributes.Clear(); return GetAttributeCompletion(element); } return new XmlCompletionItemCollection(); } /// /// Gets the child element completion data for the xml element that exists /// at the end of the specified path. /// public XmlCompletionItemCollection GetChildElementCompletion(XmlElementPath path) { XmlSchemaElement element = FindElement(path); if (element != null) { return GetChildElementCompletion(element, path.Elements.GetLastPrefix()); } return new XmlCompletionItemCollection(); } public XmlCompletionItemCollection GetAttributeValueCompletion(XmlElementPath path, string attributeName) { XmlSchemaElement element = FindElement(path); if (element != null) { return GetAttributeValueCompletion(element, attributeName); } return new XmlCompletionItemCollection(); } /// /// Finds the element that exists at the specified path. /// /// This method is not used when generating completion data, /// but is a useful method when locating an element so we can jump /// to its schema definition. /// if no element can be found. public XmlSchemaElement FindElement(XmlElementPath path) { XmlSchemaElement element = null; for (int i = 0; i < path.Elements.Count; ++i) { QualifiedName name = path.Elements[i]; if (i == 0) { // Look for root element. element = FindRootElement(name); if (element == null) { return null; } } else { element = FindChildElement(element, name); if (element == null) { return null; } } } return element; } /// /// Finds an element in the schema. /// /// /// Only looks at the elements that are defined in the /// root of the schema so it will not find any elements /// that are defined inside any complex types. /// public XmlSchemaElement FindRootElement(QualifiedName name) { foreach (XmlSchemaElement element in schema.Elements.Values) { if (name.Equals(element.QualifiedName)) { return element; } } return null; } /// /// Finds the complex type with the specified name. /// public XmlSchemaComplexType FindComplexType(QualifiedName name) { XmlQualifiedName qualifiedName = new XmlQualifiedName(name.Name, name.Namespace); return FindNamedType(schema, qualifiedName); } /// /// Finds the specified attribute name given the element. /// /// This method is not used when generating completion data, /// but is a useful method when locating an attribute so we can jump /// to its schema definition. /// if no attribute can be found. public XmlSchemaAttribute FindAttribute(XmlSchemaElement element, string name) { XmlSchemaComplexType complexType = GetElementAsComplexType(element); if (complexType != null) { return FindAttribute(complexType, name); } return null; } /// /// Finds the attribute group with the specified name. /// public XmlSchemaAttributeGroup FindAttributeGroup(string name) { return FindAttributeGroup(schema, name); } /// /// Finds the simple type with the specified name. /// public XmlSchemaSimpleType FindSimpleType(string name) { XmlQualifiedName qualifiedName = new XmlQualifiedName(name, xmlNamespace.Name); return FindSimpleType(qualifiedName); } /// /// Finds the specified attribute in the schema. This method only checks /// the attributes defined in the root of the schema. /// public XmlSchemaAttribute FindAttribute(string name) { foreach (XmlSchemaAttribute attribute in schema.Attributes.Values) { if (attribute.Name == name) { return attribute; } } return null; } /// /// Finds the schema group with the specified name. /// public XmlSchemaGroup FindGroup(string name) { if (name != null) { foreach (XmlSchemaObject schemaObject in schema.Groups.Values) { XmlSchemaGroup schemaGroup = schemaObject as XmlSchemaGroup; if (schemaGroup != null) { if (schemaGroup.Name == name) { return schemaGroup; } } } } return null; } /// /// Takes the name and creates a qualified name using the namespace of this /// schema. /// /// If the name is of the form myprefix:mytype then the correct /// namespace is determined from the prefix. If the name is not of this /// form then no prefix is added. public QualifiedName CreateQualifiedName(string name) { QualifiedName qualifiedName = QualifiedName.FromString(name); if (qualifiedName.HasPrefix) { foreach (XmlQualifiedName xmlQualifiedName in schema.Namespaces.ToArray()) { if (xmlQualifiedName.Name == qualifiedName.Prefix) { qualifiedName.Namespace = xmlQualifiedName.Namespace; return qualifiedName; } } } // Default behaviour just return the name with the namespace uri. qualifiedName.Namespace = xmlNamespace.Name; return qualifiedName; } /// /// Converts the element to a complex type if possible. /// public XmlSchemaComplexType GetElementAsComplexType(XmlSchemaElement element) { XmlSchemaComplexType complexType = element.SchemaType as XmlSchemaComplexType; if (complexType == null) { complexType = FindNamedType(schema, element.SchemaTypeName); } return complexType; } /// /// Handler for schema validation errors. /// void SchemaValidation(object source, ValidationEventArgs e) { // Do nothing. } /// /// Loads the schema. /// void ReadSchema(XmlReader reader) { try { schema = XmlSchema.Read(reader, SchemaValidation); if (schema != null) { XmlSchemaSet schemaSet = new XmlSchemaSet(); schemaSet.ValidationEventHandler += SchemaValidation; schemaSet.Add(schema); schemaSet.Compile(); xmlNamespace.Name = schema.TargetNamespace; } } finally { reader.Close(); } } void ReadSchema(string baseUri, TextReader reader) { XmlTextReader xmlReader = new XmlTextReader(baseUri, reader); // Setting the resolver to null allows us to // load the xhtml1-strict.xsd without any exceptions if // the referenced dtds exist in the same folder as the .xsd // file. If this is not set to null the dtd files are looked // for in the assembly's folder. xmlReader.XmlResolver = null; ReadSchema(xmlReader); } /// /// Finds an element in the schema. /// /// /// Only looks at the elements that are defined in the /// root of the schema so it will not find any elements /// that are defined inside any complex types. /// XmlSchemaElement FindElement(XmlQualifiedName name) { foreach (XmlSchemaElement element in schema.Elements.Values) { if (name.Equals(element.QualifiedName)) { return element; } } return null; } XmlCompletionItemCollection GetChildElementCompletion(XmlSchemaElement element, string prefix) { XmlSchemaComplexType complexType = GetElementAsComplexType(element); if (complexType != null) { return GetChildElementCompletion(complexType, prefix); } return new XmlCompletionItemCollection(); } XmlCompletionItemCollection GetChildElementCompletion(XmlSchemaComplexType complexType, string prefix) { XmlSchemaSequence sequence = complexType.Particle as XmlSchemaSequence; XmlSchemaChoice choice = complexType.Particle as XmlSchemaChoice; XmlSchemaGroupRef groupRef = complexType.Particle as XmlSchemaGroupRef; XmlSchemaComplexContent complexContent = complexType.ContentModel as XmlSchemaComplexContent; XmlSchemaAll all = complexType.Particle as XmlSchemaAll; if (sequence != null) { return GetChildElementCompletion(sequence.Items, prefix); } else if (choice != null) { return GetChildElementCompletion(choice.Items, prefix); } else if (complexContent != null) { return GetChildElementCompletion(complexContent, prefix); } else if (groupRef != null) { return GetChildElementCompletion(groupRef, prefix); } else if (all != null) { return GetChildElementCompletion(all.Items, prefix); } return new XmlCompletionItemCollection(); } XmlCompletionItemCollection GetChildElementCompletion(XmlSchemaObjectCollection items, string prefix) { XmlCompletionItemCollection completionItems = new XmlCompletionItemCollection(); foreach (XmlSchemaObject schemaObject in items) { XmlSchemaElement childElement = schemaObject as XmlSchemaElement; XmlSchemaSequence childSequence = schemaObject as XmlSchemaSequence; XmlSchemaChoice childChoice = schemaObject as XmlSchemaChoice; XmlSchemaGroupRef groupRef = schemaObject as XmlSchemaGroupRef; if (childElement != null) { string name = childElement.Name; if (name == null) { name = childElement.RefName.Name; XmlSchemaElement element = FindElement(childElement.RefName); if (element != null) { if (element.IsAbstract) { AddSubstitionGroupElements(completionItems, element.QualifiedName, prefix); } else { AddElement(completionItems, name, prefix, element.Annotation); } } else { AddElement(completionItems, name, prefix, childElement.Annotation); } } else { AddElement(completionItems, name, prefix, childElement.Annotation); } } else if (childSequence != null) { AddElements(completionItems, GetChildElementCompletion(childSequence.Items, prefix)); } else if (childChoice != null) { AddElements(completionItems, GetChildElementCompletion(childChoice.Items, prefix)); } else if (groupRef != null) { AddElements(completionItems, GetChildElementCompletion(groupRef, prefix)); } } return completionItems; } XmlCompletionItemCollection GetChildElementCompletion(XmlSchemaComplexContent complexContent, string prefix) { XmlSchemaComplexContentExtension extension = complexContent.Content as XmlSchemaComplexContentExtension; if (extension != null) { return GetChildElementCompletion(extension, prefix); } else { XmlSchemaComplexContentRestriction restriction = complexContent.Content as XmlSchemaComplexContentRestriction; if (restriction != null) { return GetChildElementCompletion(restriction, prefix); } } return new XmlCompletionItemCollection(); } XmlCompletionItemCollection GetChildElementCompletion(XmlSchemaComplexContentExtension extension, string prefix) { XmlCompletionItemCollection completionItems; XmlSchemaComplexType complexType = FindNamedType(schema, extension.BaseTypeName); if (complexType != null) { completionItems = GetChildElementCompletion(complexType, prefix); } else { completionItems = new XmlCompletionItemCollection(); } // Add any elements. if (extension.Particle != null) { XmlSchemaSequence sequence = extension.Particle as XmlSchemaSequence; XmlSchemaChoice choice = extension.Particle as XmlSchemaChoice; XmlSchemaGroupRef groupRef = extension.Particle as XmlSchemaGroupRef; if(sequence != null) { completionItems.AddRange(GetChildElementCompletion(sequence.Items, prefix)); } else if (choice != null) { completionItems.AddRange(GetChildElementCompletion(choice.Items, prefix)); } else if (groupRef != null) { completionItems.AddRange(GetChildElementCompletion(groupRef, prefix)); } } return completionItems; } XmlCompletionItemCollection GetChildElementCompletion(XmlSchemaGroupRef groupRef, string prefix) { XmlSchemaGroup schemaGroup = FindGroup(groupRef.RefName.Name); if (schemaGroup != null) { XmlSchemaSequence sequence = schemaGroup.Particle as XmlSchemaSequence; XmlSchemaChoice choice = schemaGroup.Particle as XmlSchemaChoice; if(sequence != null) { return GetChildElementCompletion(sequence.Items, prefix); } else if (choice != null) { return GetChildElementCompletion(choice.Items, prefix); } } return new XmlCompletionItemCollection(); } XmlCompletionItemCollection GetChildElementCompletion(XmlSchemaComplexContentRestriction restriction, string prefix) { // Add any elements. if (restriction.Particle != null) { XmlSchemaSequence sequence = restriction.Particle as XmlSchemaSequence; XmlSchemaChoice choice = restriction.Particle as XmlSchemaChoice; XmlSchemaGroupRef groupRef = restriction.Particle as XmlSchemaGroupRef; if(sequence != null) { return GetChildElementCompletion(sequence.Items, prefix); } else if (choice != null) { return GetChildElementCompletion(choice.Items, prefix); } else if (groupRef != null) { return GetChildElementCompletion(groupRef, prefix); } } return new XmlCompletionItemCollection(); } /// /// Adds an element completion data to the collection if it does not /// already exist. /// static void AddElement(XmlCompletionItemCollection completionItems, string name, string prefix, string documentation) { if (!completionItems.Contains(name)) { if (prefix.Length > 0) { name = String.Concat(prefix, ":", name); } XmlCompletionItem item = new XmlCompletionItem(name, documentation); completionItems.Add(item); } } /// /// Adds an element completion data to the collection if it does not /// already exist. /// static void AddElement(XmlCompletionItemCollection completionItems, string name, string prefix, XmlSchemaAnnotation annotation) { string documentation = GetDocumentation(annotation); AddElement(completionItems, name, prefix, documentation); } /// /// Adds elements to the collection if it does not already exist. /// static void AddElements(XmlCompletionItemCollection lhs, XmlCompletionItemCollection rhs) { foreach (XmlCompletionItem item in rhs) { if (!lhs.Contains(item.Text)) { lhs.Add(item); } } } /// /// Gets the documentation from the annotation element. /// /// /// All documentation elements are added. All text nodes inside /// the documentation element are added. /// static string GetDocumentation(XmlSchemaAnnotation annotation) { if (annotation != null) { StringBuilder documentationBuilder = new StringBuilder(); foreach (XmlSchemaObject schemaObject in annotation.Items) { XmlSchemaDocumentation schemaDocumentation = schemaObject as XmlSchemaDocumentation; if (schemaDocumentation != null) { foreach (XmlNode node in schemaDocumentation.Markup) { XmlText textNode = node as XmlText; if (textNode != null) { if (textNode.Data != null) { if (textNode.Data.Length > 0) { documentationBuilder.Append(textNode.Data); } } } } } } return documentationBuilder.ToString(); } return String.Empty; } XmlCompletionItemCollection GetAttributeCompletion(XmlSchemaElement element) { XmlCompletionItemCollection completionItems = new XmlCompletionItemCollection(); XmlSchemaComplexType complexType = GetElementAsComplexType(element); if (complexType != null) { completionItems.AddRange(GetAttributeCompletion(complexType)); } return completionItems; } XmlCompletionItemCollection GetAttributeCompletion(XmlSchemaComplexContentRestriction restriction) { XmlCompletionItemCollection completionItems = new XmlCompletionItemCollection(); completionItems.AddRange(GetAttributeCompletion(restriction.Attributes)); XmlSchemaComplexType baseComplexType = FindNamedType(schema, restriction.BaseTypeName); if (baseComplexType != null) { completionItems.AddRange(GetAttributeCompletion(baseComplexType)); } return completionItems; } XmlCompletionItemCollection GetAttributeCompletion(XmlSchemaComplexType complexType) { XmlCompletionItemCollection completionItems = GetAttributeCompletion(complexType.Attributes); // Add any complex content attributes. XmlSchemaComplexContent complexContent = complexType.ContentModel as XmlSchemaComplexContent; if (complexContent != null) { XmlSchemaComplexContentExtension extension = complexContent.Content as XmlSchemaComplexContentExtension; XmlSchemaComplexContentRestriction restriction = complexContent.Content as XmlSchemaComplexContentRestriction; if (extension != null) { completionItems.AddRange(GetAttributeCompletion(extension)); } else if (restriction != null) { completionItems.AddRange(GetAttributeCompletion(restriction)); } } else { XmlSchemaSimpleContent simpleContent = complexType.ContentModel as XmlSchemaSimpleContent; if (simpleContent != null) { completionItems.AddRange(GetAttributeCompletion(simpleContent)); } } return completionItems; } XmlCompletionItemCollection GetAttributeCompletion(XmlSchemaComplexContentExtension extension) { XmlCompletionItemCollection completionItems = new XmlCompletionItemCollection(); completionItems.AddRange(GetAttributeCompletion(extension.Attributes)); XmlSchemaComplexType baseComplexType = FindNamedType(schema, extension.BaseTypeName); if (baseComplexType != null) { completionItems.AddRange(GetAttributeCompletion(baseComplexType)); } return completionItems; } XmlCompletionItemCollection GetAttributeCompletion(XmlSchemaSimpleContent simpleContent) { XmlCompletionItemCollection completionItems = new XmlCompletionItemCollection(); XmlSchemaSimpleContentExtension extension = simpleContent.Content as XmlSchemaSimpleContentExtension; if (extension != null) { completionItems.AddRange(GetAttributeCompletion(extension)); } return completionItems; } XmlCompletionItemCollection GetAttributeCompletion(XmlSchemaSimpleContentExtension extension) { XmlCompletionItemCollection completionItems = new XmlCompletionItemCollection(); completionItems.AddRange(GetAttributeCompletion(extension.Attributes)); return completionItems; } XmlCompletionItemCollection GetAttributeCompletion(XmlSchemaObjectCollection attributes) { XmlCompletionItemCollection completionItems = new XmlCompletionItemCollection(); foreach (XmlSchemaObject schemaObject in attributes) { XmlSchemaAttribute attribute = schemaObject as XmlSchemaAttribute; XmlSchemaAttributeGroupRef attributeGroupRef = schemaObject as XmlSchemaAttributeGroupRef; if (attribute != null) { if (!IsProhibitedAttribute(attribute)) { AddAttribute(completionItems, attribute); } else { prohibitedAttributes.Add(attribute); } } else if (attributeGroupRef != null) { completionItems.AddRange(GetAttributeCompletion(attributeGroupRef)); } } return completionItems; } /// /// Checks that the attribute is prohibited or has been flagged /// as prohibited previously. /// bool IsProhibitedAttribute(XmlSchemaAttribute attribute) { if (attribute.Use == XmlSchemaUse.Prohibited) { return true; } else { foreach (XmlSchemaAttribute prohibitedAttribute in prohibitedAttributes) { if (prohibitedAttribute.QualifiedName == attribute.QualifiedName) { return true; } } } return false; } /// /// Adds an attribute to the completion data collection. /// /// /// Note the special handling of xml:lang attributes. /// static void AddAttribute(XmlCompletionItemCollection completionItems, XmlSchemaAttribute attribute) { string name = attribute.Name; if (name == null) { if (attribute.RefName.Namespace == "http://www.w3.org/XML/1998/namespace") { name = String.Concat("xml:", attribute.RefName.Name); } } if (name != null) { string documentation = GetDocumentation(attribute.Annotation); XmlCompletionItem item = new XmlCompletionItem(name, documentation, XmlCompletionItemType.XmlAttribute); completionItems.Add(item); } } /// /// Gets attribute completion data from a group ref. /// XmlCompletionItemCollection GetAttributeCompletion(XmlSchemaAttributeGroupRef groupRef) { XmlSchemaAttributeGroup attributeGroup = FindAttributeGroup(schema, groupRef.RefName.Name); if (attributeGroup != null) { return GetAttributeCompletion(attributeGroup.Attributes); } return new XmlCompletionItemCollection(); } static XmlSchemaComplexType FindNamedType(XmlSchema schema, XmlQualifiedName name) { if (name != null) { foreach (XmlSchemaObject schemaObject in schema.Items) { XmlSchemaComplexType complexType = schemaObject as XmlSchemaComplexType; if (complexType != null) { if (complexType.QualifiedName == name) { return complexType; } } } // Try included schemas. foreach (XmlSchemaExternal external in schema.Includes) { XmlSchemaInclude include = external as XmlSchemaInclude; if (include != null) { if (include.Schema != null) { XmlSchemaComplexType matchedComplexType = FindNamedType(include.Schema, name); if (matchedComplexType != null) { return matchedComplexType; } } } } } return null; } /// /// Finds an element that matches the specified /// from the children of the given . /// XmlSchemaElement FindChildElement(XmlSchemaElement element, QualifiedName name) { XmlSchemaComplexType complexType = GetElementAsComplexType(element); if (complexType != null) { return FindChildElement(complexType, name); } return null; } XmlSchemaElement FindChildElement(XmlSchemaComplexType complexType, QualifiedName name) { XmlSchemaSequence sequence = complexType.Particle as XmlSchemaSequence; XmlSchemaChoice choice = complexType.Particle as XmlSchemaChoice; XmlSchemaGroupRef groupRef = complexType.Particle as XmlSchemaGroupRef; XmlSchemaAll all = complexType.Particle as XmlSchemaAll; XmlSchemaComplexContent complexContent = complexType.ContentModel as XmlSchemaComplexContent; if (sequence != null) { return FindElement(sequence.Items, name); } else if (choice != null) { return FindElement(choice.Items, name); } else if (complexContent != null) { XmlSchemaComplexContentExtension extension = complexContent.Content as XmlSchemaComplexContentExtension; XmlSchemaComplexContentRestriction restriction = complexContent.Content as XmlSchemaComplexContentRestriction; if (extension != null) { return FindChildElement(extension, name); } else if (restriction != null) { return FindChildElement(restriction, name); } } else if (groupRef != null) { return FindElement(groupRef, name); } else if (all != null) { return FindElement(all.Items, name); } return null; } /// /// Finds the named child element contained in the extension element. /// XmlSchemaElement FindChildElement(XmlSchemaComplexContentExtension extension, QualifiedName name) { XmlSchemaComplexType complexType = FindNamedType(schema, extension.BaseTypeName); if (complexType != null) { XmlSchemaElement matchedElement = FindChildElement(complexType, name); if (matchedElement == null) { XmlSchemaSequence sequence = extension.Particle as XmlSchemaSequence; XmlSchemaChoice choice = extension.Particle as XmlSchemaChoice; XmlSchemaGroupRef groupRef = extension.Particle as XmlSchemaGroupRef; if (sequence != null) { return FindElement(sequence.Items, name); } else if (choice != null) { return FindElement(choice.Items, name); } else if (groupRef != null) { return FindElement(groupRef, name); } } else { return matchedElement; } } return null; } /// /// Finds the named child element contained in the restriction element. /// XmlSchemaElement FindChildElement(XmlSchemaComplexContentRestriction restriction, QualifiedName name) { XmlSchemaSequence sequence = restriction.Particle as XmlSchemaSequence; XmlSchemaGroupRef groupRef = restriction.Particle as XmlSchemaGroupRef; if (sequence != null) { return FindElement(sequence.Items, name); } else if (groupRef != null) { return FindElement(groupRef, name); } return null; } /// /// Finds the element in the collection of schema objects. /// XmlSchemaElement FindElement(XmlSchemaObjectCollection items, QualifiedName name) { foreach (XmlSchemaObject schemaObject in items) { XmlSchemaElement element = schemaObject as XmlSchemaElement; XmlSchemaSequence sequence = schemaObject as XmlSchemaSequence; XmlSchemaChoice choice = schemaObject as XmlSchemaChoice; XmlSchemaGroupRef groupRef = schemaObject as XmlSchemaGroupRef; XmlSchemaElement matchedElement = null; if (element != null) { if (element.Name != null) { if (name.Name == element.Name) { return element; } } else if (element.RefName != null) { if (name.Name == element.RefName.Name) { matchedElement = FindElement(element.RefName); } else { // Abstract element? XmlSchemaElement abstractElement = FindElement(element.RefName); if (abstractElement != null && abstractElement.IsAbstract) { matchedElement = FindSubstitutionGroupElement(abstractElement.QualifiedName, name); } } } } else if (sequence != null) { matchedElement = FindElement(sequence.Items, name); } else if (choice != null) { matchedElement = FindElement(choice.Items, name); } else if (groupRef != null) { matchedElement = FindElement(groupRef, name); } // Did we find a match? if (matchedElement != null) { return matchedElement; } } return null; } XmlSchemaElement FindElement(XmlSchemaGroupRef groupRef, QualifiedName name) { XmlSchemaGroup schemaGroup = FindGroup(groupRef.RefName.Name); if (schemaGroup != null) { XmlSchemaSequence sequence = schemaGroup.Particle as XmlSchemaSequence; XmlSchemaChoice choice = schemaGroup.Particle as XmlSchemaChoice; if(sequence != null) { return FindElement(sequence.Items, name); } else if (choice != null) { return FindElement(choice.Items, name); } } return null; } static XmlSchemaAttributeGroup FindAttributeGroup(XmlSchema schema, string name) { if (name != null) { foreach (XmlSchemaObject schemaObject in schema.Items) { XmlSchemaAttributeGroup attributeGroup = schemaObject as XmlSchemaAttributeGroup; if (attributeGroup != null) { if (attributeGroup.Name == name) { return attributeGroup; } } } // Try included schemas. foreach (XmlSchemaExternal external in schema.Includes) { XmlSchemaInclude include = external as XmlSchemaInclude; if (include != null) { if (include.Schema != null) { return FindAttributeGroup(include.Schema, name); } } } } return null; } XmlCompletionItemCollection GetAttributeValueCompletion(XmlSchemaElement element, string name) { XmlCompletionItemCollection completionItems = new XmlCompletionItemCollection(); XmlSchemaComplexType complexType = GetElementAsComplexType(element); if (complexType != null) { XmlSchemaAttribute attribute = FindAttribute(complexType, name); if (attribute != null) { completionItems.AddRange(GetAttributeValueCompletion(attribute)); } } return completionItems; } XmlCompletionItemCollection GetAttributeValueCompletion(XmlSchemaAttribute attribute) { XmlCompletionItemCollection completionItems = new XmlCompletionItemCollection(); if (attribute.SchemaType != null) { XmlSchemaSimpleTypeRestriction simpleTypeRestriction = attribute.SchemaType.Content as XmlSchemaSimpleTypeRestriction; if (simpleTypeRestriction != null) { completionItems.AddRange(GetAttributeValueCompletion(simpleTypeRestriction)); } } else if (attribute.AttributeSchemaType != null) { XmlSchemaSimpleType simpleType = attribute.AttributeSchemaType as XmlSchemaSimpleType; if (simpleType != null) { if (simpleType.Datatype.TypeCode == XmlTypeCode.Boolean) { completionItems.AddRange(GetBooleanAttributeValueCompletion()); } else { completionItems.AddRange(GetAttributeValueCompletion(simpleType)); } } } return completionItems; } static XmlCompletionItemCollection GetAttributeValueCompletion(XmlSchemaSimpleTypeRestriction simpleTypeRestriction) { XmlCompletionItemCollection completionItems = new XmlCompletionItemCollection(); foreach (XmlSchemaObject schemaObject in simpleTypeRestriction.Facets) { XmlSchemaEnumerationFacet enumFacet = schemaObject as XmlSchemaEnumerationFacet; if (enumFacet != null) { AddAttributeValue(completionItems, enumFacet.Value, enumFacet.Annotation); } } return completionItems; } XmlCompletionItemCollection GetAttributeValueCompletion(XmlSchemaSimpleTypeUnion union) { XmlCompletionItemCollection completionItems = new XmlCompletionItemCollection(); foreach (XmlSchemaObject schemaObject in union.BaseTypes) { XmlSchemaSimpleType simpleType = schemaObject as XmlSchemaSimpleType; if (simpleType != null) { completionItems.AddRange(GetAttributeValueCompletion(simpleType)); } } return completionItems; } XmlCompletionItemCollection GetAttributeValueCompletion(XmlSchemaSimpleType simpleType) { XmlCompletionItemCollection completionItems = new XmlCompletionItemCollection(); XmlSchemaSimpleTypeRestriction simpleTypeRestriction = simpleType.Content as XmlSchemaSimpleTypeRestriction; XmlSchemaSimpleTypeUnion union = simpleType.Content as XmlSchemaSimpleTypeUnion; XmlSchemaSimpleTypeList list = simpleType.Content as XmlSchemaSimpleTypeList; if (simpleTypeRestriction != null) { completionItems.AddRange(GetAttributeValueCompletion(simpleTypeRestriction)); } else if (union != null) { completionItems.AddRange(GetAttributeValueCompletion(union)); } else if (list != null) { completionItems.AddRange(GetAttributeValueCompletion(list)); } return completionItems; } XmlCompletionItemCollection GetAttributeValueCompletion(XmlSchemaSimpleTypeList list) { XmlCompletionItemCollection completionItems = new XmlCompletionItemCollection(); if (list.ItemType != null) { completionItems.AddRange(GetAttributeValueCompletion(list.ItemType)); } else if (list.ItemTypeName != null) { XmlSchemaSimpleType simpleType = FindSimpleType(list.ItemTypeName); if (simpleType != null) { completionItems.AddRange(GetAttributeValueCompletion(simpleType)); } } return completionItems; } /// /// Gets the set of attribute values for an xs:boolean type. /// static XmlCompletionItemCollection GetBooleanAttributeValueCompletion() { XmlCompletionItemCollection completionItems = new XmlCompletionItemCollection(); AddAttributeValue(completionItems, "0"); AddAttributeValue(completionItems, "1"); AddAttributeValue(completionItems, "true"); AddAttributeValue(completionItems, "false"); return completionItems; } XmlSchemaAttribute FindAttribute(XmlSchemaComplexType complexType, string name) { XmlSchemaAttribute matchedAttribute = FindAttribute(complexType.Attributes, name); if (matchedAttribute == null) { XmlSchemaComplexContent complexContent = complexType.ContentModel as XmlSchemaComplexContent; if (complexContent != null) { return FindAttribute(complexContent, name); } } return matchedAttribute; } XmlSchemaAttribute FindAttribute(XmlSchemaObjectCollection schemaObjects, string name) { foreach (XmlSchemaObject schemaObject in schemaObjects) { XmlSchemaAttribute attribute = schemaObject as XmlSchemaAttribute; XmlSchemaAttributeGroupRef groupRef = schemaObject as XmlSchemaAttributeGroupRef; if (attribute != null) { if (attribute.Name == name) { return attribute; } } else if (groupRef != null) { XmlSchemaAttribute matchedAttribute = FindAttribute(groupRef, name); if (matchedAttribute != null) { return matchedAttribute; } } } return null; } XmlSchemaAttribute FindAttribute(XmlSchemaAttributeGroupRef groupRef, string name) { if (groupRef.RefName != null) { XmlSchemaAttributeGroup attributeGroup = FindAttributeGroup(schema, groupRef.RefName.Name); if (attributeGroup != null) { return FindAttribute(attributeGroup.Attributes, name); } } return null; } XmlSchemaAttribute FindAttribute(XmlSchemaComplexContent complexContent, string name) { XmlSchemaComplexContentExtension extension = complexContent.Content as XmlSchemaComplexContentExtension; XmlSchemaComplexContentRestriction restriction = complexContent.Content as XmlSchemaComplexContentRestriction; if (extension != null) { return FindAttribute(extension, name); } else if (restriction != null) { return FindAttribute(restriction, name); } return null; } XmlSchemaAttribute FindAttribute(XmlSchemaComplexContentExtension extension, string name) { return FindAttribute(extension.Attributes, name); } XmlSchemaAttribute FindAttribute(XmlSchemaComplexContentRestriction restriction, string name) { XmlSchemaAttribute matchedAttribute = FindAttribute(restriction.Attributes, name); if (matchedAttribute == null) { XmlSchemaComplexType complexType = FindNamedType(schema, restriction.BaseTypeName); if (complexType != null) { return FindAttribute(complexType, name); } } return matchedAttribute; } /// /// Adds an attribute value to the completion data collection. /// static void AddAttributeValue(XmlCompletionItemCollection completionItems, string valueText) { XmlCompletionItem item = new XmlCompletionItem(valueText, XmlCompletionItemType.XmlAttributeValue); completionItems.Add(item); } /// /// Adds an attribute value to the completion data collection. /// static void AddAttributeValue(XmlCompletionItemCollection completionItems, string valueText, XmlSchemaAnnotation annotation) { string documentation = GetDocumentation(annotation); XmlCompletionItem item = new XmlCompletionItem(valueText, documentation, XmlCompletionItemType.XmlAttributeValue); completionItems.Add(item); } /// /// Adds an attribute value to the completion data collection. /// static void AddAttributeValue(XmlCompletionItemCollection completionItems, string valueText, string description) { XmlCompletionItem item = new XmlCompletionItem(valueText, description, XmlCompletionItemType.XmlAttributeValue); completionItems.Add(item); } XmlSchemaSimpleType FindSimpleType(XmlQualifiedName name) { foreach (XmlSchemaObject schemaObject in schema.SchemaTypes.Values) { XmlSchemaSimpleType simpleType = schemaObject as XmlSchemaSimpleType; if (simpleType != null) { if (simpleType.QualifiedName == name) { return simpleType; } } } return null; } /// /// Adds any elements that have the specified substitution group. /// void AddSubstitionGroupElements(XmlCompletionItemCollection completionItems, XmlQualifiedName groupName, string prefix) { foreach (XmlSchemaElement element in schema.Elements.Values) { if (element.SubstitutionGroup == groupName) { AddElement(completionItems, element.Name, prefix, element.Annotation); } } } /// /// Looks for the substitution group element of the specified name. /// XmlSchemaElement FindSubstitutionGroupElement(XmlQualifiedName groupName, QualifiedName name) { foreach (XmlSchemaElement element in schema.Elements.Values) { if (element.SubstitutionGroup == groupName) { if (element.Name != null) { if (element.Name == name.Name) { return element; } } } } return null; } } }