#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 System.Text; namespace Maestro.Editors.Generic.XmlEditor.AutoCompletion { /// /// Represents the path to an xml element starting from the root of the /// document. /// internal class XmlElementPath { private QualifiedNameCollection elements = new QualifiedNameCollection(); public XmlElementPath() { } /// /// Gets the elements specifying the path. /// /// The order of the elements determines the path. public QualifiedNameCollection Elements => elements; /// /// Compacts the path so it only contains the elements that are from /// the namespace of the last element in the path. /// /// This method is used when we need to know the path for a /// particular namespace and do not care about the complete path. /// public void Compact() { if (elements.Count > 0) { QualifiedName lastName = Elements[Elements.Count - 1]; if (lastName != null) { int index = FindNonMatchingParentElement(lastName.Namespace); if (index != -1) { RemoveParentElements(index); } } } } /// /// An xml element path is considered to be equal if /// each path item has the same name and namespace. /// public override bool Equals(object obj) { var rhs = obj as XmlElementPath; if (rhs == null) return false; if (this == obj) return true; if (elements.Count == rhs.elements.Count) { for (int i = 0; i < elements.Count; ++i) { if (!elements[i].Equals(rhs.elements[i])) { return false; } } return true; } return false; } public override int GetHashCode() => elements.GetHashCode(); /// /// Gets a string that represents the XmlElementPath. /// public override string ToString() { if (elements.Count > 0) { StringBuilder toString = new StringBuilder(); int lastIndex = elements.Count - 1; for (int i = 0; i < elements.Count; ++i) { string elementToString = GetElementToString(elements[i]); if (i == lastIndex) { toString.Append(elementToString); } else { toString.Append(elementToString); toString.Append(" > "); } } return toString.ToString(); } return string.Empty; } /// /// Removes elements up to and including the specified index. /// private void RemoveParentElements(int index) { while (index >= 0) { --index; elements.RemoveFirst(); } } /// /// Finds the first parent that does belong in the specified /// namespace. /// private int FindNonMatchingParentElement(string namespaceUri) { int index = -1; if (elements.Count > 1) { // Start the check from the the last but one item. for (int i = elements.Count - 2; i >= 0; --i) { QualifiedName name = elements[i]; if (name.Namespace != namespaceUri) { index = i; break; } } } return index; } /// /// Returns the qualified name as a string. If the name has a /// prefix then it returns "prefix:element" otherwise it returns /// just the element name. /// private static string GetElementToString(QualifiedName name) { if (name.Prefix.Length > 0) { return $"{name.Prefix}:{name.Name}"; } return name.Name; } } }