2006-10-18 Nagappan A <anagappan@novell.com>
[mono.git] / mcs / class / System.Data / System.Data / XmlSchemaWriter.cs
index 6d11f041e7083e881763424c9ee0989c12fd81a3..ee67b434bed544ba6ffec14279ce8f71cdf31782 100644 (file)
@@ -64,22 +64,58 @@ namespace System.Data
                        XmlWriter writer, DataTableCollection tables,
                        DataRelationCollection relations)
                {
-                       ds = dataset;
+                       dataSetName = dataset.DataSetName;
+                       dataSetNamespace = dataset.Namespace;
+                       dataSetLocale = dataset.Locale;
+                       dataSetProperties = dataset.ExtendedProperties;
+                       w = writer;
+                       if (tables != null) {
+                               this.tables = new DataTable[tables.Count];
+                               for(int i=0;i<tables.Count;i++) this.tables[i] = tables[i];
+                       }
+                       if (relations != null) {
+                               this.relations = new DataRelation[relations.Count];
+                               for(int i=0;i<relations.Count;i++) this.relations[i] = relations[i];
+                       }
+               }
+
+               public XmlSchemaWriter (XmlWriter writer,
+                       DataTable[] tables,
+                       DataRelation[] relations,
+                       string mainDataTable,
+                       string dataSetName)
+               {
                        w = writer;
                        this.tables = tables;
                        this.relations = relations;
+                       this.mainDataTable = mainDataTable;
+                       this.dataSetName = dataSetName;
+                       this.dataSetProperties = new PropertyCollection();
+                       if (tables[0].DataSet != null) {
+                               dataSetNamespace = tables[0].DataSet.Namespace;
+                               dataSetLocale = tables[0].DataSet.Locale;
+                       } else {
+                               dataSetNamespace = tables[0].Namespace;
+                               dataSetLocale = tables[0].Locale;
+                       }
                }
 
-               DataSet ds;
                XmlWriter w;
-               DataTableCollection tables;
-               DataRelationCollection relations;
+               DataTable[] tables;
+               DataRelation[] relations;
+               string mainDataTable;
+               string dataSetName;
+               string dataSetNamespace;
+               PropertyCollection dataSetProperties;
+               CultureInfo dataSetLocale;
 
                ArrayList globalTypeTables = new ArrayList ();
                Hashtable additionalNamespaces = new Hashtable ();
 
+               ArrayList annotation = new ArrayList ();
+
                public string ConstraintPrefix {
-                       get { return ds.Namespace != String.Empty ? XmlConstants.TnsPrefix + ':' : String.Empty; }
+                       get { return dataSetNamespace != String.Empty ? XmlConstants.TnsPrefix + ':' : String.Empty; }
                }
 
                // the whole DataSet
@@ -97,18 +133,18 @@ namespace System.Data
                        }
 
                        w.WriteStartElement ("xs", "schema", xmlnsxs);
-                       w.WriteAttributeString ("id", XmlConvert.EncodeLocalName (ds.DataSetName));
+                       w.WriteAttributeString ("id", XmlHelper.Encode (dataSetName));
 
-                       if (ds.Namespace != String.Empty) {
+                       if (dataSetNamespace != String.Empty) {
                                w.WriteAttributeString ("targetNamespace",
-                                       ds.Namespace);
+                                       dataSetNamespace);
                                w.WriteAttributeString (
                                        "xmlns",
                                        XmlConstants.TnsPrefix,
                                        XmlConstants.XmlnsNS,
-                                       ds.Namespace);
+                                       dataSetNamespace);
                        }
-                       w.WriteAttributeString ("xmlns", ds.Namespace);
+                       w.WriteAttributeString ("xmlns", dataSetNamespace);
 
                        w.WriteAttributeString ("xmlns", "xs",
                                XmlConstants.XmlnsNS, xmlnsxs);
@@ -123,7 +159,7 @@ namespace System.Data
                                        XmlConstants.XmlnsNS,
                                        XmlConstants.MspropNamespace);
 
-                       if (ds.Namespace != String.Empty) {
+                       if (dataSetNamespace != String.Empty) {
                                w.WriteAttributeString ("attributeFormDefault", "qualified");
                                w.WriteAttributeString ("elementFormDefault", "qualified");
                        }
@@ -154,12 +190,19 @@ namespace System.Data
                private void WriteDataSetElement ()
                {
                        w.WriteStartElement ("xs", "element", xmlnsxs);
-                       w.WriteAttributeString ("name", XmlConvert.EncodeLocalName (ds.DataSetName));
+                       w.WriteAttributeString ("name", XmlHelper.Encode (dataSetName));
                        w.WriteAttributeString (XmlConstants.MsdataPrefix,
                                "IsDataSet", XmlConstants.MsdataNamespace,
                                "true");
+
+                       if(mainDataTable != null && mainDataTable != "")
+                               w.WriteAttributeString (
+                                       XmlConstants.MsdataPrefix,
+                                       "MainDataTable",
+                                       XmlConstants.MsdataNamespace,
+                                       mainDataTable);
 #if NET_2_0
-                       if (ds.Locale == CultureInfo.CurrentCulture) {
+                       if (dataSetLocale == CultureInfo.CurrentCulture) {
                                w.WriteAttributeString (
                                        XmlConstants.MsdataPrefix,
                                        "UseCurrentCulture",
@@ -173,10 +216,10 @@ namespace System.Data
                                        XmlConstants.MsdataPrefix,
                                        "Locale",
                                        XmlConstants.MsdataNamespace,
-                                       ds.Locale.Name);
+                                       dataSetLocale.Name);
                        }
 
-                       AddExtendedPropertyAttributes (ds.ExtendedProperties);
+                       AddExtendedPropertyAttributes (dataSetProperties);
 
                        w.WriteStartElement ("xs", "complexType", xmlnsxs);
                        w.WriteStartElement ("xs", "choice", xmlnsxs);
@@ -192,13 +235,13 @@ namespace System.Data
                                }
                                
                                if (isTopLevel) {
-                                       if (ds.Namespace != table.Namespace) {
+                                       if (dataSetNamespace != table.Namespace) {
                                                // <xs:element ref="X:y" />
                                                w.WriteStartElement ("xs",
                                                        "element",
                                                        xmlnsxs);
                                                w.WriteStartAttribute ("ref", String.Empty);
-                                               w.WriteQualifiedName (XmlConvert.EncodeLocalName (table.TableName), table.Namespace);
+                                               w.WriteQualifiedName (XmlHelper.Encode (table.TableName), table.Namespace);
                                                w.WriteEndAttribute ();
                                                w.WriteEndElement ();
                                        }
@@ -213,9 +256,61 @@ namespace System.Data
                        WriteConstraints (); // DataSet constraints
 
                        w.WriteEndElement (); // element
+
+                       if (annotation.Count > 0) {
+                               w.WriteStartElement ("xs", "annotation", xmlnsxs);
+                               w.WriteStartElement ("xs", "appinfo", xmlnsxs);
+
+                               foreach (object o in annotation) {
+                                       if (!(o is DataRelation))
+                                               continue;
+                                       WriteDataRelationAnnotation ((DataRelation)o);  
+                               }
+                               w.WriteEndElement ();
+                               w.WriteEndElement ();
+                       }
                }
 
-               // Relation based Constraints
+               private void WriteDataRelationAnnotation (DataRelation rel) 
+               {
+                       String colnames = String.Empty;
+                       w.WriteStartElement (XmlConstants.MsdataPrefix, "Relationship",
+                                XmlConstants.MsdataNamespace);
+
+                       w.WriteAttributeString ("name", XmlHelper.Encode (rel.RelationName));
+
+                       w.WriteAttributeString (
+                                       XmlConstants.MsdataPrefix,
+                                       "parent",
+                                       XmlConstants.MsdataNamespace,
+                                       XmlHelper.Encode (rel.ParentTable.TableName));
+
+                       w.WriteAttributeString (
+                                       XmlConstants.MsdataPrefix,
+                                       "child",
+                                       XmlConstants.MsdataNamespace,
+                                       XmlHelper.Encode (rel.ChildTable.TableName));
+
+                       colnames = String.Empty;
+                       foreach (DataColumn col in rel.ParentColumns)
+                               colnames += XmlHelper.Encode (col.ColumnName) + " ";
+                       w.WriteAttributeString (
+                                       XmlConstants.MsdataPrefix,
+                                       "parentkey",
+                                       XmlConstants.MsdataNamespace,
+                                       colnames.TrimEnd ());
+
+                       colnames = String.Empty;
+                       foreach (DataColumn col in rel.ChildColumns)
+                               colnames += XmlHelper.Encode (col.ColumnName) + " ";
+                       w.WriteAttributeString (
+                                       XmlConstants.MsdataPrefix,
+                                       "childkey",
+                                       XmlConstants.MsdataNamespace,
+                                       colnames.TrimEnd ());
+
+                       w.WriteEndElement ();
+               }
 
                private void WriteConstraints ()
                {
@@ -226,17 +321,35 @@ namespace System.Data
                                foreach (Constraint c in table.Constraints) {
                                        UniqueConstraint u =
                                                c as UniqueConstraint;
-                                       if (u != null)
+                                       if (u != null) {
                                                AddUniqueConstraints (u, names);
+                                               continue;
+                                       }
+
+                                       ForeignKeyConstraint fk = c as ForeignKeyConstraint;
+                                       bool haveConstraint = false;
+                                       if (relations != null)
+                                               foreach (DataRelation r in relations)
+                                                       if(r.RelationName == fk.ConstraintName)
+                                                               haveConstraint = true;
+                                       if (fk != null && !haveConstraint) {
+                                               DataRelation rel = new DataRelation (fk.ConstraintName,
+                                                                               fk.RelatedColumns, fk.Columns);
+                                               AddForeignKeys (rel, names, true);
+                                               continue;
+                                       }
                                }
                        }
 
                        // Add all foriegn key constraints.
                        if (relations != null)
-                               foreach (DataRelation rel in relations)
-                                       if (rel.ParentKeyConstraint != null &&
-                                               rel.ChildKeyConstraint != null)
-                                               AddForeignKeys (rel, names);
+                               foreach (DataRelation rel in relations) {
+                                       if (rel.ParentKeyConstraint == null || rel.ChildKeyConstraint == null) {
+                                               annotation.Add (rel);
+                                               continue;
+                                       }
+                                       AddForeignKeys (rel, names,false);
+                               }
                }
 
                // Add unique constaraints to the schema.
@@ -253,19 +366,19 @@ namespace System.Data
                        // if constaraint name do not exist in the hashtable we can use it.
                        string name;
                        if (!names.Contains (uniq.ConstraintName)) {
-                               name = uniq.ConstraintName;
+                               name = XmlHelper.Encode (uniq.ConstraintName);
                                w.WriteAttributeString ("name", name);
                        }
                        // otherwise generate new constraint name for the
                        // XmlSchemaUnique element.
                        else {
-                               name = XmlConvert.EncodeLocalName (uniq.Table.TableName) + "_" + uniq.ConstraintName;
+                               name = XmlHelper.Encode (uniq.Table.TableName) + "_" + XmlHelper.Encode (uniq.ConstraintName);
                                w.WriteAttributeString ("name", name);
                                w.WriteAttributeString (
                                        XmlConstants.MsdataPrefix,
                                        XmlConstants.ConstraintName,
                                        XmlConstants.MsdataNamespace,
-                                       uniq.ConstraintName);
+                                       XmlHelper.Encode (uniq.ConstraintName));
                        }
                        names.Add (name);
 
@@ -282,7 +395,7 @@ namespace System.Data
                        w.WriteStartElement ("xs", "selector",
                                xmlnsxs);
                        w.WriteAttributeString ("xpath", ".//" +
-                               ConstraintPrefix + XmlConvert.EncodeLocalName (uniq.Table.TableName));
+                               ConstraintPrefix + XmlHelper.Encode (uniq.Table.TableName));
                        w.WriteEndElement (); // selector
                        foreach (DataColumn c in uniq.Columns) {
                                w.WriteStartElement ("xs", "field",
@@ -291,7 +404,7 @@ namespace System.Data
                                if (c.ColumnMapping == MappingType.Attribute)
                                        w.WriteString ("@");
                                w.WriteString (ConstraintPrefix);
-                               w.WriteString (XmlConvert.EncodeLocalName (c.ColumnName));
+                               w.WriteString (XmlHelper.Encode (c.ColumnName));
                                w.WriteEndAttribute (); // xpath
                                w.WriteEndElement (); // field
                        }
@@ -300,7 +413,7 @@ namespace System.Data
                }
 
                // Add the foriegn keys to the schema.
-               private void AddForeignKeys (DataRelation rel, ArrayList names)
+               private void AddForeignKeys (DataRelation rel, ArrayList names, bool isConstraintOnly)
                {
                        // Do nothing if it contains hidden relation
                        foreach (DataColumn col in rel.ParentColumns)
@@ -311,26 +424,42 @@ namespace System.Data
                                        return;
 
                        w.WriteStartElement ("xs", "keyref", xmlnsxs);
-                       w.WriteAttributeString ("name", XmlConvert.EncodeLocalName (rel.RelationName));
+                       w.WriteAttributeString ("name", XmlHelper.Encode (rel.RelationName));
+
+                       //ForeignKeyConstraint fkConst = rel.ChildKeyConstraint;
+                       UniqueConstraint uqConst = null; 
 
-                       ForeignKeyConstraint fkConst = rel.ChildKeyConstraint;
-                       UniqueConstraint uqConst = rel.ParentKeyConstraint;
+                       if (isConstraintOnly) {
+                               foreach (Constraint c in rel.ParentTable.Constraints) {
+                                       uqConst = c as UniqueConstraint;
+                                       if (uqConst == null)
+                                               continue;
+                                       if (uqConst.Columns == rel.ParentColumns)
+                                               break;
+                               }
+                       } 
+                       else
+                               uqConst = rel.ParentKeyConstraint;
 
-                       string concatName = XmlConvert.EncodeLocalName (rel.ParentTable.TableName) + "_" + uqConst.ConstraintName;
+                       string concatName = XmlHelper.Encode (rel.ParentTable.TableName) + "_" + XmlHelper.Encode (uqConst.ConstraintName);
                        // first try to find the concatenated name. If we didn't find it - use constraint name.
                        if (names.Contains (concatName)) {
                                w.WriteStartAttribute ("refer", String.Empty);
-                               w.WriteQualifiedName (concatName, ds.Namespace);
+                               w.WriteQualifiedName (concatName, dataSetNamespace);
                                w.WriteEndAttribute ();
                        }
                        else {
                                w.WriteStartAttribute ("refer", String.Empty);
-                               w.WriteQualifiedName (
-                                       uqConst.ConstraintName, ds.Namespace);
+                               w.WriteQualifiedName (XmlHelper.Encode (uqConst.ConstraintName), dataSetNamespace);
                                w.WriteEndAttribute ();
                        }
 
-                       if (rel.Nested)
+                       if (isConstraintOnly)
+                               w.WriteAttributeString ( XmlConstants.MsdataPrefix,
+                                       XmlConstants.ConstraintOnly,
+                                       XmlConstants.MsdataNamespace,
+                                       "true");
+                       else if (rel.Nested)
                                w.WriteAttributeString (
                                        XmlConstants.MsdataPrefix,
                                        XmlConstants.IsNested,
@@ -341,7 +470,7 @@ namespace System.Data
 
                        w.WriteStartElement ("xs", "selector", xmlnsxs);
                        w.WriteAttributeString ("xpath", ".//" + 
-                               ConstraintPrefix + XmlConvert.EncodeLocalName (rel.ChildTable.TableName));
+                               ConstraintPrefix + XmlHelper.Encode (rel.ChildTable.TableName));
                        w.WriteEndElement ();
 
                        foreach (DataColumn c in rel.ChildColumns) {
@@ -351,7 +480,7 @@ namespace System.Data
                                if (c.ColumnMapping == MappingType.Attribute)
                                        w.WriteString ("@");
                                w.WriteString (ConstraintPrefix);
-                               w.WriteString (XmlConvert.EncodeLocalName (c.ColumnName));
+                               w.WriteString (XmlHelper.Encode (c.ColumnName));
                                w.WriteEndAttribute ();
                                w.WriteEndElement (); // field
                        }
@@ -362,10 +491,10 @@ namespace System.Data
                // ExtendedProperties
 
                private bool CheckExtendedPropertyExists (
-                       DataTableCollection tables,
-                       DataRelationCollection relations)
+                       DataTable[] tables,
+                       DataRelation[] relations)
                {
-                       if (ds.ExtendedProperties.Count > 0)
+                       if (dataSetProperties.Count > 0)
                                return true;
                        foreach (DataTable dt in tables) {
                                if (dt.ExtendedProperties.Count > 0)
@@ -405,7 +534,7 @@ namespace System.Data
                private void WriteTableElement (DataTable table)
                {
                        w.WriteStartElement ("xs", "element", xmlnsxs);
-                       w.WriteAttributeString ("name", XmlConvert.EncodeLocalName (table.TableName));
+                       w.WriteAttributeString ("name", XmlHelper.Encode (table.TableName));
 
                        AddExtendedPropertyAttributes (table.ExtendedProperties);
 
@@ -429,9 +558,9 @@ namespace System.Data
                                // add column name attribute
                                w.WriteAttributeString (
                                        XmlConstants.MsdataPrefix,
-                                       XmlConvert.EncodeLocalName (XmlConstants.ColumnName),
+                                       XmlConstants.ColumnName,
                                        XmlConstants.MsdataNamespace,
-                                       XmlConvert.EncodeLocalName (simple.ColumnName));
+                                       XmlHelper.Encode (simple.ColumnName));
 
                                // add ordinal attribute
                                w.WriteAttributeString (
@@ -456,15 +585,15 @@ namespace System.Data
                                if (elements.Count > 0) {
                                        w.WriteStartElement ("xs", "sequence",
                                                xmlnsxs);
+
                                        foreach (DataColumn col in elements)
-                                               WriteTableTypeParticles (
-                                                       col);
+                                               WriteTableTypeParticles (col);
+
+                                       foreach (DataRelation rel in table.ChildRelations)
+                                               if (rel.Nested)
+                                                       WriteChildRelations (rel);
                                        w.WriteEndElement ();
                                }
-
-                               foreach (DataRelation rel in table.ChildRelations)
-                                       if (rel.Nested)
-                                               WriteChildRelations (rel);
                        }
 
                        w.WriteFullEndElement (); // complexType
@@ -472,10 +601,8 @@ namespace System.Data
 
                private void WriteTableTypeParticles (DataColumn col)
                {
-                       w.WriteStartElement ("xs", "element",
-                               xmlnsxs);
-                       w.WriteAttributeString ("name",
-                               XmlConvert.EncodeLocalName (col.ColumnName));
+                       w.WriteStartElement ("xs", "element", xmlnsxs);
+                       w.WriteAttributeString ("name", XmlHelper.Encode (col.ColumnName));
 
                        if (col.ColumnName != col.Caption && col.Caption != String.Empty)
                                w.WriteAttributeString (
@@ -559,26 +686,27 @@ namespace System.Data
 
                private void WriteChildRelations (DataRelation rel)
                {
-                       if (rel.ChildTable.Namespace != ds.Namespace) {
+                       if (rel.ChildTable.Namespace != dataSetNamespace) {
                                w.WriteStartElement ("xs", "element", xmlnsxs);
                                w.WriteStartAttribute ("ref", String.Empty);
                                w.WriteQualifiedName (
-                                       XmlConvert.EncodeLocalName (rel.ChildTable.TableName),
+                                       XmlHelper.Encode (rel.ChildTable.TableName),
                                        rel.ChildTable.Namespace);
                                w.WriteEndAttribute ();
                        } else {
                                w.WriteStartElement ("xs", "element", xmlnsxs);
-                               w.WriteStartAttribute ("type", String.Empty);
+                               w.WriteStartAttribute ("name", String.Empty);
                                w.WriteQualifiedName (
-                                       XmlConvert.EncodeLocalName (rel.ChildTable.TableName),
+                                       XmlHelper.Encode (rel.ChildTable.TableName),
                                        rel.ChildTable.Namespace);
                                w.WriteEndAttribute ();
-                               w.WriteEndElement ();
-
-                               globalTypeTables.Add (rel.ChildTable);
                                w.WriteAttributeString ("minOccurs", "0");
                                w.WriteAttributeString ("maxOccurs", "unbounded");
+
+                               globalTypeTables.Add (rel.ChildTable);
                        }
+                       WriteTableType (rel.ChildTable);
+                       w.WriteEndElement ();
                }
 
                private void WriteTableAttributes (ArrayList atts)
@@ -587,7 +715,7 @@ namespace System.Data
                        foreach (DataColumn col in atts) {
                                w.WriteStartElement ("xs", "attribute", xmlnsxs);
 
-                               string name = XmlConvert.EncodeLocalName (col.ColumnName);
+                               string name = XmlHelper.Encode (col.ColumnName);
                                if (col.Namespace != String.Empty) {
                                        w.WriteAttributeString ("form", "qualified");
                                        string prefix = col.Prefix == String.Empty ? "app" + additionalNamespaces.Count : col.Prefix;
@@ -652,8 +780,8 @@ namespace System.Data
                {
                        if (ns == String.Empty)
                                return;
-                       if (ds.Namespace != ns) {
-                               if (names [prefix] != ns) {
+                       if (dataSetNamespace != ns) {
+                               if ((string)names [prefix] != ns) {
                                        for (int i = 1; i < int.MaxValue; i++) {
                                                string p = "app" + i;
                                                if (names [p] == null) {