//\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
using System.IO; // for Driver\r
using System.Text; // for Driver\r
using System.Xml;\r
+using System.Xml.Schema;\r
using System.Xml.Serialization;\r
\r
namespace System.Data\r
\r
internal class TableMapping\r
{\r
+ private bool existsInDataSet;\r
+\r
public DataTable Table;\r
public ArrayList Elements = new ArrayList ();\r
public ArrayList Attributes = new ArrayList ();\r
// decoded LocalName -> TableMapping\r
public TableMappingCollection ChildTables = new TableMappingCollection ();\r
\r
- public TableMapping (string name)\r
+ public TableMapping (string name, string ns)\r
{\r
Table = new DataTable (name);\r
+ Table.Namespace = ns;\r
}\r
\r
public TableMapping (DataTable dt)\r
{\r
+ existsInDataSet = true;\r
Table = dt;\r
foreach (DataColumn col in dt.Columns) {\r
switch (col.ColumnMapping) {\r
break;\r
}\r
}\r
+ PrimaryKey = dt.PrimaryKey.Length > 0 ? dt.PrimaryKey [0] : null;\r
+ }\r
+\r
+ public bool ExistsInDataSet {\r
+ get { return existsInDataSet; }\r
}\r
\r
public bool ContainsColumn (string name)\r
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
// 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
dataset.DataSetName = localName;\r
dataset.Namespace = el.NamespaceURI;\r
dataset.Prefix = el.Prefix;\r
- foreach (XmlNode n in el.ChildNodes)\r
+ foreach (XmlNode n in el.ChildNodes) {\r
+ if (n.NamespaceURI == XmlSchema.Namespace)\r
+ continue;\r
if (n.NodeType == XmlNodeType.Element)\r
InferTopLevelTable (n as XmlElement);\r
+ }\r
}\r
\r
foreach (TableMapping map in tables) {\r
}\r
\r
foreach (TableMapping map in tables) {\r
+ if (map.ExistsInDataSet)\r
+ continue;\r
if (map.PrimaryKey != null)\r
map.Table.Columns.Add (map.PrimaryKey);\r
foreach (DataColumn col in map.Elements)\r
string localName = XmlConvert.DecodeName (el.LocalName);\r
// FIXME: can be checked later\r
CheckExtraneousElementColumn (parentTable, el);\r
- TableMapping table = GetMappedTable (parentTable, localName);\r
+ TableMapping table = GetMappedTable (parentTable, localName, el.NamespaceURI);\r
\r
// If the mapping is actually complex type (not simple\r
// repeatable), then ignore it.\r
CheckExtraneousElementColumn (parentTable, el);\r
\r
string localName = XmlConvert.DecodeName (el.LocalName);\r
- TableMapping table = GetMappedTable (parentTable, localName);\r
+ TableMapping table = GetMappedTable (parentTable, localName, el.NamespaceURI);\r
\r
bool hasChildElements = false;\r
bool hasAttributes = false;\r
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
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
}\r
}\r
\r
- private TableMapping GetMappedTable (TableMapping parent, string tableName)\r
+ private TableMapping GetMappedTable (TableMapping parent, string tableName, string ns)\r
{\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);\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
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
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
}\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
}\r
}\r
\r
-#endregion\r
+#endif\r
\r
//\r
// * Design Notes\r