#region Disclaimer / License // Copyright (C) 2009, Kenneth Skovhede // http://www.hexad.dk, opensource@hexad.dk // // 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 using System; using System.Xml; using System.Collections.Generic; namespace OSGeo.MapGuide.MaestroAPI { /// <summary> /// Dummy class that represents an unknown data type /// </summary> public class UnmappedDataType { } /// <summary> /// Class that represents a the layout of a datasource /// </summary> public class FeatureSourceDescription { private FeatureSourceSchema[] m_schemas; public FeatureSourceDescription(System.IO.Stream stream) { XmlDocument doc = new XmlDocument(); doc.Load(stream); if (doc.FirstChild.Name != "xml") throw new Exception("Bad document"); XmlNode root; if (doc.ChildNodes.Count == 2 && doc.ChildNodes[1].Name == "fdo:DataStore") root = doc.ChildNodes[1]; else if (doc.ChildNodes.Count != 2 || doc.ChildNodes[1].Name != "xs:schema") throw new Exception("Bad document"); else root = doc; XmlNamespaceManager mgr = new XmlNamespaceManager(doc.NameTable); mgr.AddNamespace("xs", "http://www.w3.org/2001/XMLSchema"); mgr.AddNamespace("gml", "http://www.opengis.net/gml"); mgr.AddNamespace("fdo", "http://fdo.osgeo.org/schemas"); var keys = new Dictionary<string, string[]>(); var classMap = new Dictionary<string, FeatureSourceSchema>(); XmlNodeList lst = root.SelectNodes("xs:schema/xs:complexType[@abstract='false']", mgr); m_schemas = new FeatureSourceSchema[lst.Count]; for (int i = 0; i < m_schemas.Length; i++) { m_schemas[i] = new FeatureSourceSchema(lst[i], mgr); classMap.Add(m_schemas[i].FullnameDecoded, m_schemas[i]); } XmlNodeList keyNodes = root.SelectNodes("xs:schema/xs:element[@abstract='false']", mgr); foreach (XmlNode keyNode in keyNodes) { var typeAttr = keyNode.Attributes["type"]; if (typeAttr != null) { string clsName = typeAttr.Value.Substring(0, typeAttr.Value.Length - 4); //class name is suffixed with type if (classMap.ContainsKey(clsName)) { List<string> keyFieldNames = new List<string>(); var cls = classMap[clsName]; XmlNodeList keyFields = keyNode.SelectNodes("xs:key/xs:field", mgr); foreach (XmlNode keyField in keyFields) { var xpathAttr = keyField.Attributes["xpath"]; if (xpathAttr != null) { keyFieldNames.Add(xpathAttr.Value); } } cls.MarkIdentityProperties(keyFieldNames); } } } } public FeatureSourceSchema[] Schemas { get { return m_schemas; } } public FeatureSourceSchema this[int index] { get { return m_schemas[index]; } } public FeatureSourceSchema this[string index] { get { for(int i =0 ;i<m_schemas.Length; i++) if (m_schemas[i].Name == index) return m_schemas[i]; throw new OverflowException("No such item found: " + index); } } public class FeatureSourceSchema { private string m_name; private string m_schema; private FeatureSetColumn[] m_columns; public FeatureSourceSchema(XmlNode node, XmlNamespaceManager mgr) { XmlNode root = node.ParentNode; if (root.NodeType == XmlNodeType.XmlDeclaration) root = root.NextSibling; m_schema = root.Attributes["targetNamespace"] == null ? null : root.Attributes["targetNamespace"].Value; if (m_schema != null && m_schema.IndexOf("/") > 0) m_schema = m_schema.Substring(m_schema.LastIndexOf("/") + 1); m_name = node.Attributes["name"].Value; if (m_name.EndsWith("Type")) m_name = m_name.Substring(0, m_name.Length - "Type".Length); XmlNodeList lst; if (node.ChildNodes.Count == 0) { m_columns = new FeatureSetColumn[0]; return; } else if (node.FirstChild.Name == "xs:sequence") lst = node.SelectNodes("xs:sequence/xs:element", mgr); else lst = node.SelectNodes("xs:complexContent/xs:extension/xs:sequence/xs:element", mgr); m_columns = new FeatureSetColumn[lst.Count]; for(int i = 0;i<lst.Count;i++) m_columns[i] = new ClassPropertyColumn(lst[i]); XmlNode extension = node.SelectSingleNode("xs:complexContent/xs:extension", mgr); if (extension != null && extension.Attributes["base"] != null) { string extTypeName = extension.Attributes["base"].Value; extTypeName = extTypeName.Substring(extTypeName.IndexOf(":") + 1); XmlNode baseEl = node.ParentNode.SelectSingleNode("xs:complexType[@name='" + extTypeName + "']", mgr); if (baseEl != null) { FeatureSourceSchema tmpScm = new FeatureSourceSchema(baseEl, mgr); FeatureSetColumn[] tmpCol = new FeatureSetColumn[m_columns.Length + tmpScm.m_columns.Length]; Array.Copy(m_columns, tmpCol, m_columns.Length); Array.Copy(tmpScm.m_columns, 0, tmpCol, m_columns.Length, tmpScm.m_columns.Length); m_columns = tmpCol; } } } public string Name { get { return m_name; } } public string Schema { get { return m_schema; } } public string Fullname { get { return m_schema == null ? m_name : m_schema + ":" + m_name; } } public string FullnameDecoded { get { return Utility.DecodeFDOName(this.Fullname); } } public FeatureSetColumn[] Columns { get { return m_columns; } } internal void MarkIdentityProperties(IEnumerable<string> keyFieldNames) { foreach (var name in keyFieldNames) { foreach (var col in m_columns) { if (col.Name.Equals(name)) { col.IsIdentity = true; } } } } public string[] GetIdentityProperties() { List<string> keys = new List<string>(); foreach (var col in m_columns) { if (col.IsIdentity) keys.Add(col.Name); } return keys.ToArray(); } } } internal class ClassPropertyColumn : XmlFeatureSetColumn { internal ClassPropertyColumn(XmlNode node) : base(node) { } } }