In System.Data.OleDb:
[mono.git] / mcs / class / System.Data / System.Data / XmlDataInferenceLoader.cs
old mode 100755 (executable)
new mode 100644 (file)
index 5cd191b..b4ee404
@@ -9,6 +9,29 @@
 //\r
 // Design notes are the bottom of the source.\r
 //\r
+
+//
+// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
 using System;\r
 using System.Collections;\r
 using System.Data;\r
@@ -95,36 +118,34 @@ namespace System.Data
                        return GetColumn (name) != null;\r
                }\r
 \r
-               public DataColumn GetColumn (string name)
-               {
-                       foreach (DataColumn col in Elements)
-                               if (col.ColumnName == name)
-                                       return col;
-                       foreach (DataColumn col in Attributes)
-                               if (col.ColumnName == name)
-                                       return col;
-                       if (SimpleContent != null && name == SimpleContent.ColumnName)
-                               return SimpleContent;
-                       if (PrimaryKey != null && name == PrimaryKey.ColumnName)
-                               return PrimaryKey;
-                       return null;
-               }
-
-               public void RemoveElementColumn (string name)
-               {
-                       foreach (DataColumn col in Elements) {
-                               if (col.ColumnName == name) {
-                                       Elements.Remove (col);
-                                       return;
-                               }
-                       }
-               }
+               public DataColumn GetColumn (string name)\r
+               {\r
+                       foreach (DataColumn col in Elements)\r
+                               if (col.ColumnName == name)\r
+                                       return col;\r
+                       foreach (DataColumn col in Attributes)\r
+                               if (col.ColumnName == name)\r
+                                       return col;\r
+                       if (SimpleContent != null && name == SimpleContent.ColumnName)\r
+                               return SimpleContent;\r
+                       if (PrimaryKey != null && name == PrimaryKey.ColumnName)\r
+                               return PrimaryKey;\r
+                       return null;\r
+               }\r
+\r
+               public void RemoveElementColumn (string name)\r
+               {\r
+                       foreach (DataColumn col in Elements) {\r
+                               if (col.ColumnName == name) {\r
+                                       Elements.Remove (col);\r
+                                       return;\r
+                               }\r
+                       }\r
+               }\r
        }\r
 \r
        internal class XmlDataInferenceLoader\r
        {\r
-               const string XmlnsNS = "http://www.w3.org/2000/xmlns/";\r
-\r
                public static void Infer (DataSet dataset, XmlDocument document, XmlReadMode mode, string [] ignoredNamespaces)\r
                {\r
                        new XmlDataInferenceLoader (dataset, document, mode, ignoredNamespaces).ReadXml ();\r
@@ -159,6 +180,9 @@ namespace System.Data
                        // Read one element. It might be DataSet element.\r
                        XmlElement el = document.DocumentElement;\r
 \r
+                       if (el.NamespaceURI == XmlSchema.Namespace)\r
+                               throw new InvalidOperationException ("DataSet is not designed to handle XML Schema as data content. Please use ReadXmlSchema method instead of InferXmlSchema method.");\r
+\r
                        if (IsDocumentElementTable ())\r
                                InferTopLevelTable (el);\r
                        else {\r
@@ -322,9 +346,10 @@ namespace System.Data
                        bool hasText = false;\r
 \r
                        foreach (XmlAttribute attr in el.Attributes) {\r
-                               if (attr.NamespaceURI == XmlnsNS)\r
+                               if (attr.NamespaceURI == XmlConstants.XmlnsNS)\r
                                        continue;\r
-                               if (ignoredNamespaces.Contains (attr.NamespaceURI))\r
+                               if (ignoredNamespaces != null &&\r
+                                       ignoredNamespaces.Contains (attr.NamespaceURI))\r
                                        continue;\r
 \r
                                hasAttributes = true;\r
@@ -348,7 +373,7 @@ namespace System.Data
                                        XmlElement cel = n as XmlElement;\r
                                        string childLocalName = XmlConvert.DecodeName (cel.LocalName);\r
 \r
-                                       switch (GetElementMappingType (cel)) {\r
+                                       switch (GetElementMappingType (cel, ignoredNamespaces, null)) {\r
                                        case ElementMappingType.Simple:\r
                                                InferColumnElement (table, cel);\r
                                                break;\r
@@ -378,13 +403,22 @@ namespace System.Data
                {\r
                        TableMapping map = tables [tableName];\r
                        if (map != null) {\r
-                               if (map.ParentTable != parent)\r
-                                       throw new DataException (String.Format ("The table {0} is already allocated as another table's child table.", tableName));\r
+                               if (parent != null && map.ParentTable != null && map.ParentTable != parent)\r
+                                       throw new DataException (String.Format ("The table '{0}' is already allocated as a child of another table '{1}'. Cannot set table '{2}' as parent table.", tableName, map.ParentTable.Table.TableName, parent.Table.TableName));\r
                        } else {\r
                                map = new TableMapping (tableName, ns);\r
                                map.ParentTable = parent;\r
                                tables.Add (map);\r
-                               if (parent != null)\r
+                       }\r
+                       if (parent != null) {\r
+                               bool shouldAdd = true;\r
+                               foreach (TableMapping child in parent.ChildTables) {\r
+                                       if (child.Table.TableName == tableName) {\r
+                                               shouldAdd = false;\r
+                                               break;\r
+                                       }\r
+                               }\r
+                               if (shouldAdd)\r
                                        parent.ChildTables.Add (map);\r
                        }\r
                        return map;\r
@@ -422,42 +456,87 @@ namespace System.Data
                        return col;\r
                }\r
 \r
-               private ElementMappingType GetElementMappingType (XmlElement el)\r
+               private static void SetAsExistingTable (XmlElement el, Hashtable existingTables)\r
+               {\r
+                       if (existingTables == null)\r
+                               return;\r
+                       ArrayList al = existingTables [el.NamespaceURI] as ArrayList;\r
+                       if (al == null) {\r
+                               al = new ArrayList ();\r
+                               existingTables [el.NamespaceURI] = al;\r
+                       }\r
+                       if (al.Contains (el.LocalName))\r
+                               return;\r
+                       al.Add (el.LocalName);\r
+               }\r
+\r
+               private static ElementMappingType GetElementMappingType (\r
+                       XmlElement el, ArrayList ignoredNamespaces, Hashtable existingTables)\r
                {\r
+                       if (existingTables != null) {\r
+                               ArrayList al = existingTables [el.NamespaceURI] as ArrayList;\r
+                               if (al != null && al.Contains (el.LocalName))\r
+                                       // this is not precise, but it is enough\r
+                                       // for IsDocumentElementTable().\r
+                                       return ElementMappingType.Complex;\r
+                       }\r
+\r
                        foreach (XmlAttribute attr in el.Attributes) {\r
-                               if (attr.NamespaceURI == XmlnsNS)\r
+                               if (attr.NamespaceURI == XmlConstants.XmlnsNS)\r
                                        continue;\r
-                               if (ignoredNamespaces.Contains (attr.NamespaceURI))\r
+                               if (ignoredNamespaces != null && ignoredNamespaces.Contains (attr.NamespaceURI))\r
                                        continue;\r
+                               SetAsExistingTable (el, existingTables);\r
                                return ElementMappingType.Complex;\r
                        }\r
-                       foreach (XmlNode n in el.ChildNodes)\r
-                               if (n.NodeType == XmlNodeType.Element)\r
+                       foreach (XmlNode n in el.ChildNodes) {\r
+                               if (n.NodeType == XmlNodeType.Element) {\r
+                                       SetAsExistingTable (el, existingTables);\r
                                        return ElementMappingType.Complex;\r
+                               }\r
+                       }\r
 \r
-                       for (XmlNode n = el.NextSibling; n != null; n = n.NextSibling)\r
-                               if (n.NodeType == XmlNodeType.Element && n.LocalName == el.LocalName)\r
-                                       return GetElementMappingType (n as XmlElement) == ElementMappingType.Complex ? ElementMappingType.Complex : ElementMappingType.Repeated;\r
+                       for (XmlNode n = el.NextSibling; n != null; n = n.NextSibling) {\r
+                               if (n.NodeType == XmlNodeType.Element && n.LocalName == el.LocalName) {\r
+                                       SetAsExistingTable (el, existingTables);\r
+                                       return GetElementMappingType (n as XmlElement,\r
+                                               ignoredNamespaces, null)\r
+                                               == ElementMappingType.Complex ?\r
+                                               ElementMappingType.Complex :\r
+                                               ElementMappingType.Repeated;\r
+                               }\r
+                       }\r
 \r
                        return ElementMappingType.Simple;\r
                }\r
 \r
                private bool IsDocumentElementTable ()\r
                {\r
-                       XmlElement top = document.DocumentElement;\r
+                       return IsDocumentElementTable (\r
+                               document.DocumentElement,\r
+                               ignoredNamespaces);\r
+               }\r
+\r
+               internal static bool IsDocumentElementTable (XmlElement top,\r
+                       ArrayList ignoredNamespaces)\r
+               {\r
                        foreach (XmlAttribute attr in top.Attributes) {\r
-                               if (attr.NamespaceURI == XmlnsNS)\r
+                               if (attr.NamespaceURI == XmlConstants.XmlnsNS)\r
                                        continue;\r
-                               if (ignoredNamespaces.Contains (attr.NamespaceURI))\r
+                               if (ignoredNamespaces != null &&\r
+                                       ignoredNamespaces.Contains (attr.NamespaceURI))\r
                                        continue;\r
                                // document element has attributes other than xmlns\r
                                return true;\r
                        }\r
+                       Hashtable existingTables = new Hashtable ();\r
                        foreach (XmlNode n in top.ChildNodes) {\r
                                XmlElement el = n as XmlElement;\r
                                if (el == null)\r
                                        continue;\r
-                               if (this.GetElementMappingType (el) == ElementMappingType.Simple)\r
+                               if (GetElementMappingType (el, ignoredNamespaces,\r
+                                       existingTables)\r
+                                       == ElementMappingType.Simple)\r
                                        return true;\r
                        }\r
                        return false;\r
@@ -469,7 +548,7 @@ namespace System.Data
                private bool IsPossibleColumnElement (XmlElement el)\r
                {\r
                        foreach (XmlAttribute attr in el.Attributes) {\r
-                               if (attr.NamespaceURI == "http://www.w3.org/2000/xmlns/")\r
+                               if (attr.NamespaceURI == XmlConstants.XmlnsNS)\r
                                        continue;\r
                                return false;\r
                        }\r
@@ -482,8 +561,8 @@ namespace System.Data
 }\r
 \r
 \r
-#region FOR_TEST\r
-public class Driver\r
+#if TEST_STANDALONE_INFERENCE\r
+internal class Driver\r
 {\r
        private static void DumpDataTable (DataTable dt)\r
        {\r
@@ -631,7 +710,7 @@ sw = Console.Out;
        }\r
 }\r
 \r
-#endregion\r
+#endif\r
 \r
 //\r
 // * Design Notes\r