#region Disclaimer / License
// Copyright (C) 2013, Jackie Ng
// http://trac.osgeo.org/mapguide/wiki/maestro, jumpinjackie@gmail.com
//
// Original code from SharpDevelop 3.2.1 licensed under the same terms (LGPL 2.1)
// Copyright 2002-2010 by
//
// AlphaSierraPapa, Christoph Wille
// Vordernberger Strasse 27/8
// A-8700 Leoben
// Austria
//
// email: office@alphasierrapapa.com
// court of jurisdiction: Landesgericht Leoben
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//
#endregion Disclaimer / License
using ICSharpCode.TextEditor.Gui.CompletionWindow;
using System;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Schema;
namespace Maestro.Editors.Generic.XmlEditor.AutoCompletion
{
///
/// 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.
///
internal class XmlSchemaCompletionData
{
private string namespaceUri = String.Empty;
private XmlSchema schema;
private string fileName = String.Empty;
private bool readOnly = false;
///
/// Stores attributes that have been prohibited whilst the code
/// generates the attribute completion data.
///
private XmlSchemaObjectCollection prohibitedAttributes = new XmlSchemaObjectCollection();
public XmlSchemaCompletionData()
{
}
///
/// Creates completion data from the schema passed in
/// via the reader object.
///
public XmlSchemaCompletionData(TextReader reader)
{
ReadSchema(String.Empty, reader);
}
///
/// Creates completion data from the schema passed in
/// via the reader object.
///
public XmlSchemaCompletionData(XmlTextReader reader)
{
reader.XmlResolver = null;
ReadSchema(reader);
}
///
/// Creates the completion data from the specified schema file.
///
public XmlSchemaCompletionData(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 XmlSchemaCompletionData(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 ReadOnly
{
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 namespaceUri;
}
}
///
/// Converts the filename into a valid Uri.
///
public static string GetUri(string fileName)
{
string uri = String.Empty;
if (fileName != null)
{
if (fileName.Length > 0)
{
uri = String.Concat("file:///", fileName.Replace('\\', '/'));
}
}
return uri;
}
///
/// Gets the possible root elements for an xml document using this schema.
///
public ICompletionData[] GetElementCompletionData()
{
return GetElementCompletionData(String.Empty);
}
///
/// Gets the possible root elements for an xml document using this schema.
///
public ICompletionData[] GetElementCompletionData(string namespacePrefix)
{
XmlCompletionDataCollection data = new XmlCompletionDataCollection();
foreach (XmlSchemaElement element in schema.Elements.Values)
{
if (element.Name != null)
{
AddElement(data, element.Name, namespacePrefix, element.Annotation);
}
else
{
// Do not add reference element.
}
}
return data.ToArray();
}
///
/// Gets the attribute completion data for the xml element that exists
/// at the end of the specified path.
///
public ICompletionData[] GetAttributeCompletionData(XmlElementPath path)
{
XmlCompletionDataCollection data = new XmlCompletionDataCollection();
// Locate matching element.
XmlSchemaElement element = FindElement(path);
// Get completion data.
if (element != null)
{
prohibitedAttributes.Clear();
data = GetAttributeCompletionData(element);
}
return data.ToArray();
}
///
/// Gets the child element completion data for the xml element that exists
/// at the end of the specified path.
///
public ICompletionData[] GetChildElementCompletionData(XmlElementPath path)
{
XmlCompletionDataCollection data = new XmlCompletionDataCollection();
// Locate matching element.
XmlSchemaElement element = FindElement(path);
// Get completion data.
if (element != null)
{
data = GetChildElementCompletionData(element, path.Elements.LastPrefix);
}
return data.ToArray();
}
///
/// Gets the autocomplete data for the specified attribute value.
///
public ICompletionData[] GetAttributeValueCompletionData(XmlElementPath path, string name)
{
XmlCompletionDataCollection data = new XmlCompletionDataCollection();
// Locate matching element.
XmlSchemaElement element = FindElement(path);
// Get completion data.
if (element != null)
{
data = GetAttributeValueCompletionData(element, name);
}
return data.ToArray();
}
///
/// 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 = FindElement(name);
if (element == null)
{
break;
}
}
else
{
element = FindChildElement(element, name);
if (element == null)
{
break;
}
}
}
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 FindElement(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)
{
XmlSchemaAttribute attribute = null;
XmlSchemaComplexType complexType = GetElementAsComplexType(element);
if (complexType != null)
{
attribute = FindAttribute(complexType, name);
}
return attribute;
}
///
/// 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, namespaceUri);
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 group = schemaObject as XmlSchemaGroup;
if (group != null)
{
if (group.Name == name)
{
return group;
}
}
}
}
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)
{
int index = name.IndexOf(":");
if (index >= 0)
{
string prefix = name.Substring(0, index);
name = name.Substring(index + 1);
foreach (XmlQualifiedName xmlQualifiedName in schema.Namespaces.ToArray())
{
if (xmlQualifiedName.Name == prefix)
{
return new QualifiedName(name, xmlQualifiedName.Namespace, prefix);
}
}
}
// Default behaviour just return the name with the namespace uri.
return new QualifiedName(name, namespaceUri);
}
///
/// 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.
///
private void SchemaValidation(object source, ValidationEventArgs e)
{
// Do nothing.
}
///
/// Loads the schema.
///
private void ReadSchema(XmlReader reader)
{
try
{
schema = XmlSchema.Read(reader, new ValidationEventHandler(SchemaValidation));
schema.Compile(new ValidationEventHandler(SchemaValidation));
namespaceUri = schema.TargetNamespace;
}
finally
{
reader.Close();
}
}
private 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.
///
private XmlSchemaElement FindElement(XmlQualifiedName name)
{
XmlSchemaElement matchedElement = null;
foreach (XmlSchemaElement element in schema.Elements.Values)
{
if (name.Equals(element.QualifiedName))
{
matchedElement = element;
break;
}
}
return matchedElement;
}
private XmlCompletionDataCollection GetChildElementCompletionData(XmlSchemaElement element, string prefix)
{
XmlCompletionDataCollection data = new XmlCompletionDataCollection();
XmlSchemaComplexType complexType = GetElementAsComplexType(element);
if (complexType != null)
{
data = GetChildElementCompletionData(complexType, prefix);
}
return data;
}
private XmlCompletionDataCollection GetChildElementCompletionData(XmlSchemaComplexType complexType, string prefix)
{
XmlCompletionDataCollection data = new XmlCompletionDataCollection();
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)
{
data = GetChildElementCompletionData(sequence.Items, prefix);
}
else if (choice != null)
{
data = GetChildElementCompletionData(choice.Items, prefix);
}
else if (complexContent != null)
{
data = GetChildElementCompletionData(complexContent, prefix);
}
else if (groupRef != null)
{
data = GetChildElementCompletionData(groupRef, prefix);
}
else if (all != null)
{
data = GetChildElementCompletionData(all.Items, prefix);
}
return data;
}
private XmlCompletionDataCollection GetChildElementCompletionData(XmlSchemaObjectCollection items, string prefix)
{
XmlCompletionDataCollection data = new XmlCompletionDataCollection();
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(data, element.QualifiedName, prefix);
}
else
{
AddElement(data, name, prefix, element.Annotation);
}
}
else
{
AddElement(data, name, prefix, childElement.Annotation);
}
}
else
{
AddElement(data, name, prefix, childElement.Annotation);
}
}
else if (childSequence != null)
{
AddElements(data, GetChildElementCompletionData(childSequence.Items, prefix));
}
else if (childChoice != null)
{
AddElements(data, GetChildElementCompletionData(childChoice.Items, prefix));
}
else if (groupRef != null)
{
AddElements(data, GetChildElementCompletionData(groupRef, prefix));
}
}
return data;
}
private XmlCompletionDataCollection GetChildElementCompletionData(XmlSchemaComplexContent complexContent, string prefix)
{
XmlCompletionDataCollection data = new XmlCompletionDataCollection();
XmlSchemaComplexContentExtension extension = complexContent.Content as XmlSchemaComplexContentExtension;
if (extension != null)
{
data = GetChildElementCompletionData(extension, prefix);
}
else
{
XmlSchemaComplexContentRestriction restriction = complexContent.Content as XmlSchemaComplexContentRestriction;
if (restriction != null)
{
data = GetChildElementCompletionData(restriction, prefix);
}
}
return data;
}
private XmlCompletionDataCollection GetChildElementCompletionData(XmlSchemaComplexContentExtension extension, string prefix)
{
XmlCompletionDataCollection data = new XmlCompletionDataCollection();
XmlSchemaComplexType complexType = FindNamedType(schema, extension.BaseTypeName);
if (complexType != null)
{
data = GetChildElementCompletionData(complexType, prefix);
}
// 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)
{
data.AddRange(GetChildElementCompletionData(sequence.Items, prefix));
}
else if (choice != null)
{
data.AddRange(GetChildElementCompletionData(choice.Items, prefix));
}
else if (groupRef != null)
{
data.AddRange(GetChildElementCompletionData(groupRef, prefix));
}
}
return data;
}
private XmlCompletionDataCollection GetChildElementCompletionData(XmlSchemaGroupRef groupRef, string prefix)
{
XmlCompletionDataCollection data = new XmlCompletionDataCollection();
XmlSchemaGroup group = FindGroup(groupRef.RefName.Name);
if (group != null)
{
XmlSchemaSequence sequence = group.Particle as XmlSchemaSequence;
XmlSchemaChoice choice = group.Particle as XmlSchemaChoice;
if (sequence != null)
{
data = GetChildElementCompletionData(sequence.Items, prefix);
}
else if (choice != null)
{
data = GetChildElementCompletionData(choice.Items, prefix);
}
}
return data;
}
private XmlCompletionDataCollection GetChildElementCompletionData(XmlSchemaComplexContentRestriction restriction, string prefix)
{
XmlCompletionDataCollection data = new XmlCompletionDataCollection();
// 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)
{
data = GetChildElementCompletionData(sequence.Items, prefix);
}
else if (choice != null)
{
data = GetChildElementCompletionData(choice.Items, prefix);
}
else if (groupRef != null)
{
data = GetChildElementCompletionData(groupRef, prefix);
}
}
return data;
}
///
/// Adds an element completion data to the collection if it does not
/// already exist.
///
private void AddElement(XmlCompletionDataCollection data, string name, string prefix, string documentation)
{
if (!data.Contains(name))
{
if (prefix.Length > 0)
{
name = String.Concat(prefix, ":", name);
}
XmlCompletionData completionData = new XmlCompletionData(name, documentation);
data.Add(completionData);
}
}
///
/// Adds an element completion data to the collection if it does not
/// already exist.
///
private void AddElement(XmlCompletionDataCollection data, string name, string prefix, XmlSchemaAnnotation annotation)
{
// Get any annotation documentation.
string documentation = GetDocumentation(annotation);
AddElement(data, name, prefix, documentation);
}
///
/// Adds elements to the collection if it does not already exist.
///
private void AddElements(XmlCompletionDataCollection lhs, XmlCompletionDataCollection rhs)
{
foreach (XmlCompletionData data in rhs)
{
if (!lhs.Contains(data))
{
lhs.Add(data);
}
}
}
///
/// Gets the documentation from the annotation element.
///
///
/// All documentation elements are added. All text nodes inside
/// the documentation element are added.
///
private string GetDocumentation(XmlSchemaAnnotation annotation)
{
string documentation = String.Empty;
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);
}
}
}
}
}
}
documentation = documentationBuilder.ToString();
}
return documentation;
}
private XmlCompletionDataCollection GetAttributeCompletionData(XmlSchemaElement element)
{
XmlCompletionDataCollection data = new XmlCompletionDataCollection();
XmlSchemaComplexType complexType = GetElementAsComplexType(element);
if (complexType != null)
{
data.AddRange(GetAttributeCompletionData(complexType));
}
return data;
}
private XmlCompletionDataCollection GetAttributeCompletionData(XmlSchemaComplexContentRestriction restriction)
{
XmlCompletionDataCollection data = new XmlCompletionDataCollection();
data.AddRange(GetAttributeCompletionData(restriction.Attributes));
XmlSchemaComplexType baseComplexType = FindNamedType(schema, restriction.BaseTypeName);
if (baseComplexType != null)
{
data.AddRange(GetAttributeCompletionData(baseComplexType));
}
return data;
}
private XmlCompletionDataCollection GetAttributeCompletionData(XmlSchemaComplexType complexType)
{
XmlCompletionDataCollection data = new XmlCompletionDataCollection();
data = GetAttributeCompletionData(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)
{
data.AddRange(GetAttributeCompletionData(extension));
}
else if (restriction != null)
{
data.AddRange(GetAttributeCompletionData(restriction));
}
}
else
{
XmlSchemaSimpleContent simpleContent = complexType.ContentModel as XmlSchemaSimpleContent;
if (simpleContent != null)
{
data.AddRange(GetAttributeCompletionData(simpleContent));
}
}
return data;
}
private XmlCompletionDataCollection GetAttributeCompletionData(XmlSchemaComplexContentExtension extension)
{
XmlCompletionDataCollection data = new XmlCompletionDataCollection();
data.AddRange(GetAttributeCompletionData(extension.Attributes));
XmlSchemaComplexType baseComplexType = FindNamedType(schema, extension.BaseTypeName);
if (baseComplexType != null)
{
data.AddRange(GetAttributeCompletionData(baseComplexType));
}
return data;
}
private XmlCompletionDataCollection GetAttributeCompletionData(XmlSchemaSimpleContent simpleContent)
{
XmlCompletionDataCollection data = new XmlCompletionDataCollection();
XmlSchemaSimpleContentExtension extension = simpleContent.Content as XmlSchemaSimpleContentExtension;
if (extension != null)
{
data.AddRange(GetAttributeCompletionData(extension));
}
return data;
}
private XmlCompletionDataCollection GetAttributeCompletionData(XmlSchemaSimpleContentExtension extension)
{
XmlCompletionDataCollection data = new XmlCompletionDataCollection();
data.AddRange(GetAttributeCompletionData(extension.Attributes));
return data;
}
private XmlCompletionDataCollection GetAttributeCompletionData(XmlSchemaObjectCollection attributes)
{
XmlCompletionDataCollection data = new XmlCompletionDataCollection();
foreach (XmlSchemaObject schemaObject in attributes)
{
XmlSchemaAttribute attribute = schemaObject as XmlSchemaAttribute;
XmlSchemaAttributeGroupRef attributeGroupRef = schemaObject as XmlSchemaAttributeGroupRef;
if (attribute != null)
{
if (!IsProhibitedAttribute(attribute))
{
AddAttribute(data, attribute);
}
else
{
prohibitedAttributes.Add(attribute);
}
}
else if (attributeGroupRef != null)
{
data.AddRange(GetAttributeCompletionData(attributeGroupRef));
}
}
return data;
}
///
/// Checks that the attribute is prohibited or has been flagged
/// as prohibited previously.
///
private bool IsProhibitedAttribute(XmlSchemaAttribute attribute)
{
bool prohibited = false;
if (attribute.Use == XmlSchemaUse.Prohibited)
{
prohibited = true;
}
else
{
foreach (XmlSchemaAttribute prohibitedAttribute in prohibitedAttributes)
{
if (prohibitedAttribute.QualifiedName == attribute.QualifiedName)
{
prohibited = true;
break;
}
}
}
return prohibited;
}
///
/// Adds an attribute to the completion data collection.
///
///
/// Note the special handling of xml:lang attributes.
///
private void AddAttribute(XmlCompletionDataCollection data, 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);
XmlCompletionData completionData = new XmlCompletionData(name, documentation, XmlCompletionData.DataType.XmlAttribute);
data.Add(completionData);
}
}
///
/// Gets attribute completion data from a group ref.
///
private XmlCompletionDataCollection GetAttributeCompletionData(XmlSchemaAttributeGroupRef groupRef)
{
XmlCompletionDataCollection data = new XmlCompletionDataCollection();
XmlSchemaAttributeGroup group = FindAttributeGroup(schema, groupRef.RefName.Name);
if (group != null)
{
data = GetAttributeCompletionData(group.Attributes);
}
return data;
}
private static XmlSchemaComplexType FindNamedType(XmlSchema schema, XmlQualifiedName name)
{
XmlSchemaComplexType matchedComplexType = null;
if (name != null)
{
foreach (XmlSchemaObject schemaObject in schema.Items)
{
XmlSchemaComplexType complexType = schemaObject as XmlSchemaComplexType;
if (complexType != null)
{
if (complexType.QualifiedName == name)
{
matchedComplexType = complexType;
break;
}
}
}
// Try included schemas.
if (matchedComplexType == null)
{
foreach (XmlSchemaExternal external in schema.Includes)
{
XmlSchemaInclude include = external as XmlSchemaInclude;
if (include != null)
{
if (include.Schema != null)
{
matchedComplexType = FindNamedType(include.Schema, name);
}
}
}
}
}
return matchedComplexType;
}
///
/// Finds an element that matches the specified
/// from the children of the given .
///
private XmlSchemaElement FindChildElement(XmlSchemaElement element, QualifiedName name)
{
XmlSchemaElement matchedElement = null;
XmlSchemaComplexType complexType = GetElementAsComplexType(element);
if (complexType != null)
{
matchedElement = FindChildElement(complexType, name);
}
return matchedElement;
}
private XmlSchemaElement FindChildElement(XmlSchemaComplexType complexType, QualifiedName name)
{
XmlSchemaElement matchedElement = null;
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)
{
matchedElement = FindElement(sequence.Items, name);
}
else if (choice != null)
{
matchedElement = FindElement(choice.Items, name);
}
else if (complexContent != null)
{
XmlSchemaComplexContentExtension extension = complexContent.Content as XmlSchemaComplexContentExtension;
XmlSchemaComplexContentRestriction restriction = complexContent.Content as XmlSchemaComplexContentRestriction;
if (extension != null)
{
matchedElement = FindChildElement(extension, name);
}
else if (restriction != null)
{
matchedElement = FindChildElement(restriction, name);
}
}
else if (groupRef != null)
{
matchedElement = FindElement(groupRef, name);
}
else if (all != null)
{
matchedElement = FindElement(all.Items, name);
}
return matchedElement;
}
///
/// Finds the named child element contained in the extension element.
///
private XmlSchemaElement FindChildElement(XmlSchemaComplexContentExtension extension, QualifiedName name)
{
XmlSchemaElement matchedElement = null;
XmlSchemaComplexType complexType = FindNamedType(schema, extension.BaseTypeName);
if (complexType != null)
{
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)
{
matchedElement = FindElement(sequence.Items, name);
}
else if (choice != null)
{
matchedElement = FindElement(choice.Items, name);
}
else if (groupRef != null)
{
matchedElement = FindElement(groupRef, name);
}
}
}
return matchedElement;
}
///
/// Finds the named child element contained in the restriction element.
///
private XmlSchemaElement FindChildElement(XmlSchemaComplexContentRestriction restriction, QualifiedName name)
{
XmlSchemaElement matchedElement = null;
XmlSchemaSequence sequence = restriction.Particle as XmlSchemaSequence;
XmlSchemaGroupRef groupRef = restriction.Particle as XmlSchemaGroupRef;
if (sequence != null)
{
matchedElement = FindElement(sequence.Items, name);
}
else if (groupRef != null)
{
matchedElement = FindElement(groupRef, name);
}
return matchedElement;
}
///
/// Finds the element in the collection of schema objects.
///
private XmlSchemaElement FindElement(XmlSchemaObjectCollection items, QualifiedName name)
{
XmlSchemaElement matchedElement = null;
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;
if (element != null)
{
if (element.Name != null)
{
if (name.Name == element.Name)
{
matchedElement = 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)
{
break;
}
}
return matchedElement;
}
private XmlSchemaElement FindElement(XmlSchemaGroupRef groupRef, QualifiedName name)
{
XmlSchemaElement matchedElement = null;
XmlSchemaGroup group = FindGroup(groupRef.RefName.Name);
if (group != null)
{
XmlSchemaSequence sequence = group.Particle as XmlSchemaSequence;
XmlSchemaChoice choice = group.Particle as XmlSchemaChoice;
if (sequence != null)
{
matchedElement = FindElement(sequence.Items, name);
}
else if (choice != null)
{
matchedElement = FindElement(choice.Items, name);
}
}
return matchedElement;
}
private static XmlSchemaAttributeGroup FindAttributeGroup(XmlSchema schema, string name)
{
XmlSchemaAttributeGroup matchedGroup = null;
if (name != null)
{
foreach (XmlSchemaObject schemaObject in schema.Items)
{
XmlSchemaAttributeGroup group = schemaObject as XmlSchemaAttributeGroup;
if (group != null)
{
if (group.Name == name)
{
matchedGroup = group;
break;
}
}
}
// Try included schemas.
if (matchedGroup == null)
{
foreach (XmlSchemaExternal external in schema.Includes)
{
XmlSchemaInclude include = external as XmlSchemaInclude;
if (include != null)
{
if (include.Schema != null)
{
matchedGroup = FindAttributeGroup(include.Schema, name);
}
}
}
}
}
return matchedGroup;
}
private XmlCompletionDataCollection GetAttributeValueCompletionData(XmlSchemaElement element, string name)
{
XmlCompletionDataCollection data = new XmlCompletionDataCollection();
XmlSchemaComplexType complexType = GetElementAsComplexType(element);
if (complexType != null)
{
XmlSchemaAttribute attribute = FindAttribute(complexType, name);
if (attribute != null)
{
data.AddRange(GetAttributeValueCompletionData(attribute));
}
}
return data;
}
private XmlCompletionDataCollection GetAttributeValueCompletionData(XmlSchemaAttribute attribute)
{
XmlCompletionDataCollection data = new XmlCompletionDataCollection();
if (attribute.SchemaType != null)
{
XmlSchemaSimpleTypeRestriction simpleTypeRestriction = attribute.SchemaType.Content as XmlSchemaSimpleTypeRestriction;
if (simpleTypeRestriction != null)
{
data.AddRange(GetAttributeValueCompletionData(simpleTypeRestriction));
}
}
else if (attribute.AttributeSchemaType != null)
{
XmlSchemaSimpleType simpleType = attribute.AttributeSchemaType as XmlSchemaSimpleType;
if (simpleType != null)
{
if (simpleType.Name == "boolean")
{
data.AddRange(GetBooleanAttributeValueCompletionData());
}
else
{
data.AddRange(GetAttributeValueCompletionData(simpleType));
}
}
}
return data;
}
private XmlCompletionDataCollection GetAttributeValueCompletionData(XmlSchemaSimpleTypeRestriction simpleTypeRestriction)
{
XmlCompletionDataCollection data = new XmlCompletionDataCollection();
foreach (XmlSchemaObject schemaObject in simpleTypeRestriction.Facets)
{
XmlSchemaEnumerationFacet enumFacet = schemaObject as XmlSchemaEnumerationFacet;
if (enumFacet != null)
{
AddAttributeValue(data, enumFacet.Value, enumFacet.Annotation);
}
}
return data;
}
private XmlCompletionDataCollection GetAttributeValueCompletionData(XmlSchemaSimpleTypeUnion union)
{
XmlCompletionDataCollection data = new XmlCompletionDataCollection();
foreach (XmlSchemaObject schemaObject in union.BaseTypes)
{
XmlSchemaSimpleType simpleType = schemaObject as XmlSchemaSimpleType;
if (simpleType != null)
{
data.AddRange(GetAttributeValueCompletionData(simpleType));
}
}
return data;
}
private XmlCompletionDataCollection GetAttributeValueCompletionData(XmlSchemaSimpleType simpleType)
{
XmlCompletionDataCollection data = new XmlCompletionDataCollection();
XmlSchemaSimpleTypeRestriction simpleTypeRestriction = simpleType.Content as XmlSchemaSimpleTypeRestriction;
XmlSchemaSimpleTypeUnion union = simpleType.Content as XmlSchemaSimpleTypeUnion;
XmlSchemaSimpleTypeList list = simpleType.Content as XmlSchemaSimpleTypeList;
if (simpleTypeRestriction != null)
{
data.AddRange(GetAttributeValueCompletionData(simpleTypeRestriction));
}
else if (union != null)
{
data.AddRange(GetAttributeValueCompletionData(union));
}
else if (list != null)
{
data.AddRange(GetAttributeValueCompletionData(list));
}
return data;
}
private XmlCompletionDataCollection GetAttributeValueCompletionData(XmlSchemaSimpleTypeList list)
{
XmlCompletionDataCollection data = new XmlCompletionDataCollection();
if (list.ItemType != null)
{
data.AddRange(GetAttributeValueCompletionData(list.ItemType));
}
else if (list.ItemTypeName != null)
{
XmlSchemaSimpleType simpleType = FindSimpleType(list.ItemTypeName);
if (simpleType != null)
{
data.AddRange(GetAttributeValueCompletionData(simpleType));
}
}
return data;
}
///
/// Gets the set of attribute values for an xs:boolean type.
///
private XmlCompletionDataCollection GetBooleanAttributeValueCompletionData()
{
XmlCompletionDataCollection data = new XmlCompletionDataCollection();
AddAttributeValue(data, "0");
AddAttributeValue(data, "1");
AddAttributeValue(data, "true");
AddAttributeValue(data, "false");
return data;
}
private XmlSchemaAttribute FindAttribute(XmlSchemaComplexType complexType, string name)
{
XmlSchemaAttribute matchedAttribute = null;
matchedAttribute = FindAttribute(complexType.Attributes, name);
if (matchedAttribute == null)
{
XmlSchemaComplexContent complexContent = complexType.ContentModel as XmlSchemaComplexContent;
if (complexContent != null)
{
matchedAttribute = FindAttribute(complexContent, name);
}
}
return matchedAttribute;
}
private XmlSchemaAttribute FindAttribute(XmlSchemaObjectCollection schemaObjects, string name)
{
XmlSchemaAttribute matchedAttribute = null;
foreach (XmlSchemaObject schemaObject in schemaObjects)
{
XmlSchemaAttribute attribute = schemaObject as XmlSchemaAttribute;
XmlSchemaAttributeGroupRef groupRef = schemaObject as XmlSchemaAttributeGroupRef;
if (attribute != null)
{
if (attribute.Name == name)
{
matchedAttribute = attribute;
break;
}
}
else if (groupRef != null)
{
matchedAttribute = FindAttribute(groupRef, name);
if (matchedAttribute != null)
{
break;
}
}
}
return matchedAttribute;
}
private XmlSchemaAttribute FindAttribute(XmlSchemaAttributeGroupRef groupRef, string name)
{
XmlSchemaAttribute matchedAttribute = null;
if (groupRef.RefName != null)
{
XmlSchemaAttributeGroup group = FindAttributeGroup(schema, groupRef.RefName.Name);
if (group != null)
{
matchedAttribute = FindAttribute(group.Attributes, name);
}
}
return matchedAttribute;
}
private XmlSchemaAttribute FindAttribute(XmlSchemaComplexContent complexContent, string name)
{
XmlSchemaAttribute matchedAttribute = null;
XmlSchemaComplexContentExtension extension = complexContent.Content as XmlSchemaComplexContentExtension;
XmlSchemaComplexContentRestriction restriction = complexContent.Content as XmlSchemaComplexContentRestriction;
if (extension != null)
{
matchedAttribute = FindAttribute(extension, name);
}
else if (restriction != null)
{
matchedAttribute = FindAttribute(restriction, name);
}
return matchedAttribute;
}
private XmlSchemaAttribute FindAttribute(XmlSchemaComplexContentExtension extension, string name)
{
return FindAttribute(extension.Attributes, name);
}
private XmlSchemaAttribute FindAttribute(XmlSchemaComplexContentRestriction restriction, string name)
{
XmlSchemaAttribute matchedAttribute = FindAttribute(restriction.Attributes, name);
if (matchedAttribute == null)
{
XmlSchemaComplexType complexType = FindNamedType(schema, restriction.BaseTypeName);
if (complexType != null)
{
matchedAttribute = FindAttribute(complexType, name);
}
}
return matchedAttribute;
}
///
/// Adds an attribute value to the completion data collection.
///
private void AddAttributeValue(XmlCompletionDataCollection data, string valueText)
{
XmlCompletionData completionData = new XmlCompletionData(valueText, XmlCompletionData.DataType.XmlAttributeValue);
data.Add(completionData);
}
///
/// Adds an attribute value to the completion data collection.
///
private void AddAttributeValue(XmlCompletionDataCollection data, string valueText, XmlSchemaAnnotation annotation)
{
string documentation = GetDocumentation(annotation);
XmlCompletionData completionData = new XmlCompletionData(valueText, documentation, XmlCompletionData.DataType.XmlAttributeValue);
data.Add(completionData);
}
///
/// Adds an attribute value to the completion data collection.
///
private void AddAttributeValue(XmlCompletionDataCollection data, string valueText, string description)
{
XmlCompletionData completionData = new XmlCompletionData(valueText, description, XmlCompletionData.DataType.XmlAttributeValue);
data.Add(completionData);
}
private XmlSchemaSimpleType FindSimpleType(XmlQualifiedName name)
{
XmlSchemaSimpleType matchedSimpleType = null;
foreach (XmlSchemaObject schemaObject in schema.SchemaTypes.Values)
{
XmlSchemaSimpleType simpleType = schemaObject as XmlSchemaSimpleType;
if (simpleType != null)
{
if (simpleType.QualifiedName == name)
{
matchedSimpleType = simpleType;
break;
}
}
}
return matchedSimpleType;
}
///
/// Adds any elements that have the specified substitution group.
///
private void AddSubstitionGroupElements(XmlCompletionDataCollection data, XmlQualifiedName group, string prefix)
{
foreach (XmlSchemaElement element in schema.Elements.Values)
{
if (element.SubstitutionGroup == group)
{
AddElement(data, element.Name, prefix, element.Annotation);
}
}
}
///
/// Looks for the substitution group element of the specified name.
///
private XmlSchemaElement FindSubstitutionGroupElement(XmlQualifiedName group, QualifiedName name)
{
XmlSchemaElement matchedElement = null;
foreach (XmlSchemaElement element in schema.Elements.Values)
{
if (element.SubstitutionGroup == group)
{
if (element.Name != null)
{
if (element.Name == name.Name)
{
matchedElement = element;
break;
}
}
}
}
return matchedElement;
}
}
}