//
//
//
//
// $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;
}
}
}