// Stuart Caborn <stuart.caborn@virgin.net>
// Tim Coleman (tim@timcoleman.com)
// Ville Palo <vi64pa@koti.soon.fi>
+// Atsushi Enomoto <atsushi@ximian.com>
//
// (C) Ximian, Inc. 2002
-// Copyright (C) Tim Coleman, 2002
+// Copyright (C) Tim Coleman, 2002, 2003
+//
+
+//
+// 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;
using System.Runtime.Serialization;
using System.Xml;
using System.Xml.Schema;
+using System.Xml.Serialization;
+using System.Data.Common;
namespace System.Data {
- /// <summary>
- /// an in-memory cache of data
- /// </summary>
- //[Designer]
+
[ToolboxItem (false)]
[DefaultProperty ("DataSetName")]
+ [DesignerAttribute ("Microsoft.VSDesigner.Data.VS.DataSetDesigner, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.ComponentModel.Design.IDesigner")]
+
[Serializable]
- public class DataSet : MarshalByValueComponent, IListSource,
- ISupportInitialize, ISerializable {
+ public class DataSet : MarshalByValueComponent, IListSource,
+ ISupportInitialize, ISerializable, IXmlSerializable
+ {
private string dataSetName;
private string _namespace = "";
private string prefix;
private DataRelationCollection relationCollection;
private PropertyCollection properties;
private DataViewManager defaultView;
- private CultureInfo locale;
+ private CultureInfo locale = System.Threading.Thread.CurrentThread.CurrentCulture;
+ internal XmlDataDocument _xmlDataDocument = null;
#region Constructors
- public DataSet() : this ("NewDataSet") {
+ public DataSet () : this ("NewDataSet")
+ {
}
-
- public DataSet(string name) {
+
+ public DataSet (string name)
+ {
dataSetName = name;
tableCollection = new DataTableCollection (this);
relationCollection = new DataRelationCollection.DataSetRelationCollection (this);
- properties = new PropertyCollection();
+ properties = new PropertyCollection ();
+ this.prefix = String.Empty;
+
+ this.Locale = CultureInfo.CurrentCulture;
}
- [MonoTODO]
- protected DataSet(SerializationInfo info, StreamingContext context) : this () {
- throw new NotImplementedException ();
+ protected DataSet (SerializationInfo info, StreamingContext context) : this ()
+ {
+ GetSerializationData (info, context);
}
#endregion // Constructors
[DataSysDescription ("Indicates whether comparing strings within the DataSet is case sensitive.")]
[DefaultValue (false)]
public bool CaseSensitive {
- get { return caseSensitive; }
+ get {
+ return caseSensitive;
+ }
set {
- foreach (DataTable T in Tables)
- T.CaseSensitive = value;
-
caseSensitive = value;
+ if (!caseSensitive) {
+ foreach (DataTable table in Tables) {
+ foreach (Constraint c in table.Constraints)
+ c.AssertConstraint ();
+ }
+ }
}
}
[DefaultValue (true)]
public bool EnforceConstraints {
get { return enforceConstraints; }
- set { enforceConstraints = value; }
+ set {
+ if (value != enforceConstraints) {
+ enforceConstraints = value;
+ if (value) {
+ foreach (DataTable table in Tables) {
+ // first assert all unique constraints
+ foreach (UniqueConstraint uc in table.Constraints.UniqueConstraints)
+ uc.AssertConstraint ();
+ // then assert all foreign keys
+ foreach (ForeignKeyConstraint fk in table.Constraints.ForeignKeyConstraints)
+ fk.AssertConstraint ();
+ }
+ }
+ }
+ }
}
[Browsable (false)]
public bool HasErrors {
[MonoTODO]
get {
- throw new NotImplementedException ();
+ for (int i = 0; i < Tables.Count; i++) {
+ if (Tables[i].HasErrors)
+ return true;
+ }
+ return false;
}
}
return locale;
}
set {
- if (locale == null || !locale.Equals(value)) {
+ if (locale == null || !locale.Equals (value)) {
// TODO: check if the new locale is valid
// TODO: update locale of all tables
locale = value;
Merge (table, false, MissingSchemaAction.Add);
}
- [MonoTODO]
public void Merge (DataSet dataSet, bool preserveChanges)
{
Merge (dataSet, preserveChanges, MissingSchemaAction.Add);
[MonoTODO]
public void Merge (DataRow[] rows, bool preserveChanges, MissingSchemaAction missingSchemaAction)
{
- throw new NotImplementedException();
+ if (rows == null)
+ throw new ArgumentNullException ("rows");
+ if (!IsLegalSchemaAction (missingSchemaAction))
+ throw new ArgumentOutOfRangeException ("missingSchemaAction");
+
+ MergeManager.Merge (this, rows, preserveChanges, missingSchemaAction);
}
[MonoTODO]
public void Merge (DataSet dataSet, bool preserveChanges, MissingSchemaAction missingSchemaAction)
{
- throw new NotImplementedException();
+ if (dataSet == null)
+ throw new ArgumentNullException ("dataSet");
+ if (!IsLegalSchemaAction (missingSchemaAction))
+ throw new ArgumentOutOfRangeException ("missingSchemaAction");
+
+ MergeManager.Merge (this, dataSet, preserveChanges, missingSchemaAction);
}
[MonoTODO]
public void Merge (DataTable table, bool preserveChanges, MissingSchemaAction missingSchemaAction)
{
- throw new NotImplementedException();
+ if (table == null)
+ throw new ArgumentNullException ("table");
+ if (!IsLegalSchemaAction (missingSchemaAction))
+ throw new ArgumentOutOfRangeException ("missingSchemaAction");
+
+ MergeManager.Merge (this, table, preserveChanges, missingSchemaAction);
+ }
+
+ private static bool IsLegalSchemaAction (MissingSchemaAction missingSchemaAction)
+ {
+ if (missingSchemaAction == MissingSchemaAction.Add || missingSchemaAction == MissingSchemaAction.AddWithKey
+ || missingSchemaAction == MissingSchemaAction.Error || missingSchemaAction == MissingSchemaAction.Ignore)
+ return true;
+ return false;
}
[DataCategory ("Data")]
[DataSysDescription ("Indicates the XML uri namespace for the root element pointed at by this DataSet.")]
[DefaultValue ("")]
public string Namespace {
- [MonoTODO]
get { return _namespace; }
- [MonoTODO]
set {
//TODO - trigger an event if this happens?
- _namespace = value;
+ if (value == null)
+ value = String.Empty;
+ if (value != this._namespace)
+ RaisePropertyChanging ("Namespace");
+ _namespace = value;
}
}
[DataSysDescription ("Indicates the prefix of the namespace used for this DataSet.")]
[DefaultValue ("")]
public string Prefix {
- [MonoTODO]
get { return prefix; }
- [MonoTODO]
set {
- //TODO - trigger an event if this happens?
+ if (value == null)
+ value = String.Empty;
+ // Prefix cannot contain any special characters other than '_' and ':'
+ for (int i = 0; i < value.Length; i++) {
+ if (!(Char.IsLetterOrDigit (value [i])) && (value [i] != '_') && (value [i] != ':'))
+ throw new DataException ("Prefix '" + value + "' is not valid, because it contains special characters.");
+ }
+
+
+ if (value == null)
+ value = string.Empty;
+
+ if (value != this.prefix)
+ RaisePropertyChanging ("Prefix");
prefix = value;
}
}
#region Public Methods
[MonoTODO]
- public void AcceptChanges()
+ public void AcceptChanges ()
{
foreach (DataTable tempTable in tableCollection)
tempTable.AcceptChanges ();
}
- public void Clear()
+ /// <summary>
+ /// Clears all the tables
+ /// </summary>
+ public void Clear ()
{
- throw new NotImplementedException ();
+ if (_xmlDataDocument != null)
+ throw new NotSupportedException ("Clear function on dataset and datatable is not supported when XmlDataDocument is bound to the DataSet.");
+ bool enforceConstraints = this.EnforceConstraints;
+ this.EnforceConstraints = false;
+ for (int t = 0; t < tableCollection.Count; t++) {
+ tableCollection[t].Clear ();
+ }
+ this.EnforceConstraints = enforceConstraints;
}
- public virtual DataSet Clone()
+ public virtual DataSet Clone ()
{
- DataSet Copy = new DataSet ();
+ // need to return the same type as this...
+ DataSet Copy = (DataSet) Activator.CreateInstance(GetType(), true);
+
CopyProperties (Copy);
foreach (DataTable Table in Tables) {
- Copy.Tables.Add (Table.Clone ());
- }
+ // tables are often added in no-args constructor, don't add them
+ // twice.
+ if (!Copy.Tables.Contains(Table.TableName)) {
+ Copy.Tables.Add (Table.Clone ());
+ }
+ }
+
+ //Copy Relationships between tables after existance of tables
+ //and setting properties correctly
+ CopyRelations (Copy);
return Copy;
}
// Copies both the structure and data for this DataSet.
- public DataSet Copy()
+ public DataSet Copy ()
{
DataSet Copy = new DataSet ();
CopyProperties (Copy);
// Copy DatSet's tables
- foreach (DataTable Table in Tables) {
+ foreach (DataTable Table in Tables)
Copy.Tables.Add (Table.Copy ());
- }
+
+ //Copy Relationships between tables after existance of tables
+ //and setting properties correctly
+ CopyRelations (Copy);
return Copy;
}
- [MonoTODO]
private void CopyProperties (DataSet Copy)
{
Copy.CaseSensitive = CaseSensitive;
//Copy.DefaultViewManager
//Copy.DesignMode
Copy.EnforceConstraints = EnforceConstraints;
- //Copy.ExtendedProperties
- //Copy.HasErrors
- //Copy.Locale = Locale;
+ if(ExtendedProperties.Count > 0) {
+ // Cannot copy extended properties directly as the property does not have a set accessor
+ Array tgtArray = Array.CreateInstance( typeof (object), ExtendedProperties.Count);
+ ExtendedProperties.Keys.CopyTo (tgtArray, 0);
+ for (int i=0; i < ExtendedProperties.Count; i++)
+ Copy.ExtendedProperties.Add (tgtArray.GetValue (i), ExtendedProperties[tgtArray.GetValue (i)]);
+ }
+ Copy.Locale = Locale;
Copy.Namespace = Namespace;
- Copy.Prefix = Prefix;
- //Copy.Relations = Relations;
- //Copy.Site = Site;
+ Copy.Prefix = Prefix;
+ //Copy.Site = Site; // FIXME : Not sure of this.
}
+
+
+ private void CopyRelations (DataSet Copy)
+ {
- public DataSet GetChanges()
+ //Creation of the relation contains some of the properties, and the constructor
+ //demands these values. instead changing the DataRelation constructor and behaviour the
+ //parameters are pre-configured and sent to the most general constructor
+
+ foreach (DataRelation MyRelation in this.Relations) {
+ string pTable = MyRelation.ParentTable.TableName;
+ string cTable = MyRelation.ChildTable.TableName;
+ DataColumn[] P_DC = new DataColumn[MyRelation.ParentColumns.Length];
+ DataColumn[] C_DC = new DataColumn[MyRelation.ChildColumns.Length];
+ int i = 0;
+
+ foreach (DataColumn DC in MyRelation.ParentColumns) {
+ P_DC[i]=Copy.Tables[pTable].Columns[DC.ColumnName];
+ i++;
+ }
+
+ i = 0;
+
+ foreach (DataColumn DC in MyRelation.ChildColumns) {
+ C_DC[i]=Copy.Tables[cTable].Columns[DC.ColumnName];
+ i++;
+ }
+
+ DataRelation cRel = new DataRelation (MyRelation.RelationName, P_DC, C_DC);
+ //cRel.ChildColumns = MyRelation.ChildColumns;
+ //cRel.ChildTable = MyRelation.ChildTable;
+ //cRel.ExtendedProperties = cRel.ExtendedProperties;
+ //cRel.Nested = MyRelation.Nested;
+ //cRel.ParentColumns = MyRelation.ParentColumns;
+ //cRel.ParentTable = MyRelation.ParentTable;
+
+ Copy.Relations.Add (cRel);
+ }
+ }
+
+
+
+
+ public DataSet GetChanges ()
{
- throw new NotImplementedException ();
+ return GetChanges (DataRowState.Added | DataRowState.Deleted | DataRowState.Modified);
}
- public DataSet GetChanges(DataRowState rowStates)
+ public DataSet GetChanges (DataRowState rowStates)
+ {
+ if (!HasChanges (rowStates))
+ return null;
+
+ DataSet copySet = Clone ();
+ Hashtable addedRows = new Hashtable ();
+
+ IEnumerator tableEnumerator = Tables.GetEnumerator ();
+ DataTable origTable;
+ DataTable copyTable;
+ while (tableEnumerator.MoveNext ()) {
+ origTable = (DataTable)tableEnumerator.Current;
+ copyTable = copySet.Tables[origTable.TableName];
+
+ // Look for relations that have this table as child
+ IEnumerator relations = origTable.ParentRelations.GetEnumerator ();
+
+ IEnumerator rowEnumerator = origTable.Rows.GetEnumerator ();
+ while (rowEnumerator.MoveNext ()) {
+ DataRow row = (DataRow)rowEnumerator.Current;
+
+ if (row.IsRowChanged (rowStates))
+ AddChangedRow (addedRows, copySet, copyTable, relations, row);
+ }
+ }
+ return copySet;
+ }
+
+ void AddChangedRow (Hashtable addedRows, DataSet copySet, DataTable copyTable, IEnumerator relations, DataRow row)
+ {
+ if (addedRows.ContainsKey (row)) return;
+
+ relations.Reset ();
+ while (relations.MoveNext ()) {
+ DataRow parentRow = row.GetParentRow ((DataRelation) relations.Current);
+ if (parentRow == null || addedRows.ContainsKey (parentRow)) continue;
+ DataTable parentCopyTable = copySet.Tables [parentRow.Table.TableName];
+ AddChangedRow (addedRows, copySet, parentCopyTable, parentRow.Table.ParentRelations.GetEnumerator (), parentRow);
+ }
+
+ DataRow newRow = copyTable.NewRow ();
+ row.CopyValuesToRow (newRow);
+ copyTable.Rows.Add (newRow);
+ newRow.XmlRowID = row.XmlRowID;
+ addedRows.Add (row,row);
+ }
+
+#if NET_2_0
+ [MonoTODO]
+ public DataTableReader GetDataReader (DataTable[] dataTables)
{
throw new NotImplementedException ();
}
- public string GetXml()
+ [MonoTODO]
+ public DataTableReader GetDataReader ()
+ {
+ throw new NotImplementedException ();
+ }
+#endif
+
+ public string GetXml ()
{
StringWriter Writer = new StringWriter ();
WriteXml (Writer, XmlWriteMode.IgnoreSchema);
return Writer.ToString ();
}
- public string GetXmlSchema()
+ public string GetXmlSchema ()
{
StringWriter Writer = new StringWriter ();
WriteXmlSchema (Writer);
}
[MonoTODO]
- public bool HasChanges()
+ public bool HasChanges ()
{
- throw new NotImplementedException ();
+ return HasChanges (DataRowState.Added | DataRowState.Deleted | DataRowState.Modified);
}
[MonoTODO]
- public bool HasChanges(DataRowState rowState)
+ public bool HasChanges (DataRowState rowState)
+ {
+ if (((int)rowState & 0xffffffe0) != 0)
+ throw new ArgumentOutOfRangeException ("rowState");
+
+ DataTableCollection tableCollection = Tables;
+ DataTable table;
+ DataRowCollection rowCollection;
+ DataRow row;
+
+ for (int i = 0; i < tableCollection.Count; i++) {
+ table = tableCollection[i];
+ rowCollection = table.Rows;
+ for (int j = 0; j < rowCollection.Count; j++) {
+ row = rowCollection[j];
+ if ((row.RowState & rowState) != 0)
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public void InferXmlSchema (XmlReader reader, string[] nsArray)
{
- throw new NotImplementedException ();
+ if (reader == null)
+ return;
+ XmlDocument doc = new XmlDocument ();
+ doc.Load (reader);
+ InferXmlSchema (doc, nsArray);
}
- [MonoTODO]
- public void InferXmlSchema(XmlReader reader, string[] nsArray)
+ private void InferXmlSchema (XmlDocument doc, string [] nsArray)
{
+ XmlDataInferenceLoader.Infer (this, doc, XmlReadMode.InferSchema, nsArray);
}
- public void InferXmlSchema(Stream stream, string[] nsArray)
+ public void InferXmlSchema (Stream stream, string[] nsArray)
{
- InferXmlSchema (new XmlTextReader(stream), nsArray);
+ InferXmlSchema (new XmlTextReader (stream), nsArray);
}
- public void InferXmlSchema(TextReader reader, string[] nsArray)
+ public void InferXmlSchema (TextReader reader, string[] nsArray)
{
- InferXmlSchema (new XmlTextReader(reader), nsArray);
+ InferXmlSchema (new XmlTextReader (reader), nsArray);
}
- public void InferXmlSchema(string fileName, string[] nsArray)
+ public void InferXmlSchema (string fileName, string[] nsArray)
{
- XmlTextReader reader = new XmlTextReader(fileName);
+ XmlTextReader reader = new XmlTextReader (fileName);
try {
InferXmlSchema (reader, nsArray);
} finally {
}
}
- public virtual void RejectChanges()
+#if NET_2_0
+ [MonoTODO]
+ public void Load (IDataReader reader, LoadOption loadOption, DataTable[] tables)
{
throw new NotImplementedException ();
}
- public virtual void Reset()
+ [MonoTODO]
+ public void Load (IDataReader reader, LoadOption loadOption, string[] tables)
{
throw new NotImplementedException ();
}
+#endif
- public void WriteXml(Stream stream)
+ public virtual void RejectChanges ()
{
- XmlWriter writer = new XmlTextWriter(stream, null );
+ int i;
+ bool oldEnforceConstraints = this.EnforceConstraints;
+ this.EnforceConstraints = false;
- WriteXml( writer );
+ for (i = 0; i < this.Tables.Count;i++)
+ this.Tables[i].RejectChanges ();
+
+ this.EnforceConstraints = oldEnforceConstraints;
+ }
+
+ public virtual void Reset ()
+ {
+ IEnumerator constraintEnumerator;
+
+ // first we remove all ForeignKeyConstraints (if we will not do that
+ // we will get an exception when clearing the tables).
+ for (int i = 0; i < Tables.Count; i++) {
+ ConstraintCollection cc = Tables[i].Constraints;
+ for (int j = 0; j < cc.Count; j++) {
+ if (cc[j] is ForeignKeyConstraint)
+ cc.Remove (cc[j]);
+ }
+ }
+
+ Clear ();
+ Relations.Clear ();
+ Tables.Clear ();
+ }
+
+ public void WriteXml (Stream stream)
+ {
+ XmlTextWriter writer = new XmlTextWriter (stream, null);
+ writer.Formatting = Formatting.Indented;
+ WriteXml (writer);
}
///<summary>
/// Writes the current data for the DataSet to the specified file.
/// </summary>
/// <param name="filename">Fully qualified filename to write to</param>
- public void WriteXml(string fileName)
+ public void WriteXml (string fileName)
{
- XmlWriter writer = new XmlTextWriter(fileName, null );
-
- WriteXml( writer );
+ XmlTextWriter writer = new XmlTextWriter (fileName, null);
+ writer.Formatting = Formatting.Indented;
+ writer.WriteStartDocument (true);
+ try {
+ WriteXml (writer);
+ }
+ finally {
+ writer.WriteEndDocument ();
+ writer.Close ();
+ }
}
- public void WriteXml(TextWriter writer)
+ public void WriteXml (TextWriter writer)
{
- XmlWriter xwriter = new XmlTextWriter(writer );
-
- WriteXml( xwriter );
+ XmlTextWriter xwriter = new XmlTextWriter (writer);
+ xwriter.Formatting = Formatting.Indented;
+ WriteXml (xwriter);
}
- public void WriteXml(XmlWriter writer)
+ public void WriteXml (XmlWriter writer)
{
- WriteXml( writer, XmlWriteMode.IgnoreSchema );
+ WriteXml (writer, XmlWriteMode.IgnoreSchema);
}
- public void WriteXml(Stream stream, XmlWriteMode mode)
+ public void WriteXml (string filename, XmlWriteMode mode)
{
- XmlWriter writer = new XmlTextWriter(stream, null );
+ XmlTextWriter writer = new XmlTextWriter (filename, null);
+ writer.Formatting = Formatting.Indented;
+ writer.WriteStartDocument (true);
- WriteXml( writer, mode );
+ try {
+ WriteXml (writer, mode);
+ }
+ finally {
+ writer.WriteEndDocument ();
+ writer.Close ();
+ }
}
- public void WriteXml(string fileName, XmlWriteMode mode)
+ public void WriteXml (Stream stream, XmlWriteMode mode)
{
- XmlWriter writer = new XmlTextWriter(fileName, null );
-
- WriteXml( writer, mode );
+ XmlTextWriter writer = new XmlTextWriter (stream, null);
+ writer.Formatting = Formatting.Indented;
+ WriteXml (writer, mode);
}
- public void WriteXml(TextWriter writer, XmlWriteMode mode)
+ public void WriteXml (TextWriter writer, XmlWriteMode mode)
{
- XmlWriter xwriter = new XmlTextWriter(writer);
-
- WriteXml( xwriter, mode );
+ XmlTextWriter xwriter = new XmlTextWriter (writer);
+ xwriter.Formatting = Formatting.Indented;
+ WriteXml (xwriter, mode);
}
- public void WriteXml(XmlWriter writer, XmlWriteMode mode)
+ public void WriteXml (XmlWriter writer, XmlWriteMode mode)
{
- ((XmlTextWriter)writer).Formatting = Formatting.Indented;
- WriteStartElement( writer, mode, Namespace, Prefix, DataSetName );
-
- if( mode == XmlWriteMode.WriteSchema )
- {
- DoWriteXmlSchema( writer );
+ if (mode == XmlWriteMode.DiffGram) {
+ SetRowsID();
+ WriteDiffGramElement(writer);
}
- //Write out each table in order, providing it is not
- //part of another table structure via a nested parent relationship
- foreach( DataTable table in Tables )
- {
- bool isTopLevel = true;
- foreach( DataRelation rel in table.ParentRelations )
- {
- if( rel.Nested )
- {
- isTopLevel = false;
- break;
- }
- }
+ // It should not write when there is no content to be written
+ bool shouldOutputContent = (mode != XmlWriteMode.DiffGram);
+ for (int n = 0; n < tableCollection.Count && !shouldOutputContent; n++)
+ shouldOutputContent = tableCollection [n].Rows.Count > 0;
+
+ if (shouldOutputContent) {
+ WriteStartElement (writer, mode, Namespace, Prefix, XmlConvert.EncodeName (DataSetName));
+
+ if (mode == XmlWriteMode.WriteSchema)
+ DoWriteXmlSchema (writer);
- if( isTopLevel )
- {
- WriteTable( writer, table, mode );
+ WriteTables (writer, mode, Tables, DataRowVersion.Default);
+ writer.WriteEndElement ();
+ }
+
+ if (mode == XmlWriteMode.DiffGram) {
+ if (HasChanges(DataRowState.Modified | DataRowState.Deleted)) {
+
+ DataSet beforeDS = GetChanges (DataRowState.Modified | DataRowState.Deleted);
+ WriteStartElement (writer, XmlWriteMode.DiffGram, XmlConstants.DiffgrNamespace, XmlConstants.DiffgrPrefix, "before");
+ WriteTables (writer, mode, beforeDS.Tables, DataRowVersion.Original);
+ writer.WriteEndElement ();
}
}
- writer.WriteEndElement();
+ if (mode == XmlWriteMode.DiffGram)
+ writer.WriteEndElement (); // diffgr:diffgram
+
+ writer.Flush ();
}
- public void WriteXmlSchema(Stream stream)
+ public void WriteXmlSchema (Stream stream)
{
- XmlWriter writer = new XmlTextWriter(stream, null );
-
- WriteXmlSchema( writer );
+ XmlTextWriter writer = new XmlTextWriter (stream, null );
+ writer.Formatting = Formatting.Indented;
+ WriteXmlSchema (writer);
}
- public void WriteXmlSchema(string fileName)
+ public void WriteXmlSchema (string fileName)
{
- XmlWriter writer = new XmlTextWriter( fileName, null );
-
- WriteXmlSchema( writer );
+ XmlTextWriter writer = new XmlTextWriter (fileName, null);
+ try {
+ writer.Formatting = Formatting.Indented;
+ writer.WriteStartDocument (true);
+ WriteXmlSchema (writer);
+ } finally {
+ writer.WriteEndDocument ();
+ writer.Close ();
+ }
}
- public void WriteXmlSchema(TextWriter writer)
+ public void WriteXmlSchema (TextWriter writer)
{
- XmlWriter xwriter = new XmlTextWriter( writer );
-
- WriteXmlSchema( xwriter );
+ XmlTextWriter xwriter = new XmlTextWriter (writer);
+ try {
+ xwriter.Formatting = Formatting.Indented;
+// xwriter.WriteStartDocument ();
+ WriteXmlSchema (xwriter);
+ } finally {
+// xwriter.WriteEndDocument ();
+ xwriter.Close ();
+ }
}
- public void WriteXmlSchema(XmlWriter writer)
+ public void WriteXmlSchema (XmlWriter writer)
{
- ((XmlTextWriter)writer).Formatting = Formatting.Indented;
//Create a skeleton doc and then write the schema
//proper which is common to the WriteXml method in schema mode
- writer.WriteStartDocument();
-
- DoWriteXmlSchema( writer );
-
- writer.WriteEndDocument();
+ DoWriteXmlSchema (writer);
}
- public void ReadXmlSchema(Stream stream)
+ public void ReadXmlSchema (Stream stream)
{
- XmlReader reader = new XmlTextReader( stream, null );
- ReadXmlSchema( reader);
+ XmlReader reader = new XmlTextReader (stream, null);
+ ReadXmlSchema (reader);
}
- public void ReadXmlSchema(string str)
+ public void ReadXmlSchema (string str)
{
- XmlReader reader = new XmlTextReader( str );
- ReadXmlSchema( reader );
+ XmlReader reader = new XmlTextReader (str);
+ try {
+ ReadXmlSchema (reader);
+ }
+ finally {
+ reader.Close ();
+ }
}
- public void ReadXmlSchema(TextReader treader)
+ public void ReadXmlSchema (TextReader treader)
{
- XmlReader reader = new XmlTextReader( treader );
- ReadXmlSchema( reader );
+ XmlReader reader = new XmlTextReader (treader);
+ ReadXmlSchema (reader);
}
- public void ReadXmlSchema(XmlReader reader)
+ public void ReadXmlSchema (XmlReader reader)
{
+#if true
+ new XmlSchemaDataImporter (this, reader).Process ();
+#else
XmlSchemaMapper SchemaMapper = new XmlSchemaMapper (this);
SchemaMapper.Read (reader);
+#endif
}
public XmlReadMode ReadXml (Stream stream)
public XmlReadMode ReadXml (string str)
{
- return ReadXml (new XmlTextReader (str));
+ XmlTextReader reader = new XmlTextReader (str);
+ try {
+ return ReadXml (reader);
+ }
+ finally {
+ reader.Close ();
+ }
}
public XmlReadMode ReadXml (TextReader reader)
public XmlReadMode ReadXml (XmlReader r)
{
- XmlDataLoader Loader = new XmlDataLoader (this);
- // FIXME: somekinda exception?
- if (!r.Read ())
- return XmlReadMode.Auto; // FIXME
-
- /*\
- * If document is diffgram we will use diffgram
- \*/
- if (r.LocalName == "diffgram")
- return ReadXml (r, XmlReadMode.DiffGram);
-
- /*\
- * If we already have a schema, or the document
- * contains an in-line schema, sets XmlReadMode to ReadSchema.
- \*/
-
- // FIXME: is this always true: "if we have tables we have to have schema also"
- if (Tables.Count > 0)
- return ReadXml (r, XmlReadMode.ReadSchema);
-
- /*\
- * If we dont have a schema yet and document
- * contains no inline-schema mode is XmlReadMode.InferSchema
- \*/
-
- return ReadXml (r, XmlReadMode.InferSchema);
-
+ return ReadXml (r, XmlReadMode.Auto);
}
public XmlReadMode ReadXml (Stream stream, XmlReadMode mode)
public XmlReadMode ReadXml (string str, XmlReadMode mode)
{
- return ReadXml (new XmlTextReader (str), mode);
+ XmlTextReader reader = new XmlTextReader (str);
+ try {
+ return ReadXml (reader, mode);
+ }
+ finally {
+ reader.Close ();
+ }
}
public XmlReadMode ReadXml (TextReader reader, XmlReadMode mode)
return ReadXml (new XmlTextReader (reader), mode);
}
- [MonoTODO]
- public XmlReadMode ReadXml (XmlReader reader, XmlReadMode mode)
+ // LAMESPEC: XmlReadMode.Fragment is far from presisely
+ // documented. MS.NET infers schema against this mode.
+ public XmlReadMode ReadXml (XmlReader input, XmlReadMode mode)
{
- XmlReadMode Result = XmlReadMode.Auto;
+ switch (input.ReadState) {
+ case ReadState.EndOfFile:
+ case ReadState.Error:
+ case ReadState.Closed:
+ return mode;
+ }
+ // Skip XML declaration and prolog
+ input.MoveToContent ();
+ if (input.EOF)
+ return mode;
+
+ // FIXME: We need more decent code here, but for now
+ // I don't know the precise MS.NET behavior, I just
+ // delegate to specific read process.
+ switch (mode) {
+ case XmlReadMode.IgnoreSchema:
+ return ReadXmlIgnoreSchema (input, mode, true);
+ case XmlReadMode.ReadSchema:
+ return ReadXmlReadSchema (input, mode, true);
+ }
+ // remaining modes are: Auto, InferSchema, Fragment, Diffgram
+
+ XmlReader reader = input;
+
+ int depth = reader.Depth;
+ XmlReadMode result = mode;
+ bool skippedTopLevelElement = false;
+ string potentialDataSetName = null;
+ XmlDocument doc = null;
+ bool shouldReadData = mode != XmlReadMode.DiffGram;
+ bool shouldNotInfer = Tables.Count > 0;
+
+ switch (mode) {
+ case XmlReadMode.Auto:
+ case XmlReadMode.InferSchema:
+ doc = new XmlDocument ();
+ do {
+ doc.AppendChild (doc.ReadNode (reader));
+ } while (!reader.EOF &&
+ doc.DocumentElement == null);
+ reader = new XmlNodeReader (doc);
+ reader.MoveToContent ();
+ break;
+ case XmlReadMode.DiffGram:
+ if (!(reader.LocalName == "diffgram" &&
+ reader.NamespaceURI == XmlConstants.DiffgrNamespace))
+ goto case XmlReadMode.Auto;
+ break;
+ }
- if (mode == XmlReadMode.DiffGram) {
- XmlDiffLoader DiffLoader = new XmlDiffLoader (this);
- DiffLoader.Load (reader);
- Result = XmlReadMode.DiffGram;
+ switch (mode) {
+ case XmlReadMode.Auto:
+ case XmlReadMode.InferSchema:
+ case XmlReadMode.ReadSchema:
+ if (!(reader.LocalName == "diffgram" &&
+ reader.NamespaceURI == XmlConstants.DiffgrNamespace) &&
+ !(reader.LocalName == "schema" &&
+ reader.NamespaceURI == XmlSchema.Namespace))
+ potentialDataSetName = reader.LocalName;
+ goto default;
+ case XmlReadMode.Fragment:
+ break;
+ default:
+ if (!(reader.LocalName == "diffgram" &&
+ reader.NamespaceURI == XmlConstants.DiffgrNamespace) &&
+ !(reader.LocalName == "schema" &&
+ reader.NamespaceURI == XmlSchema.Namespace)) {
+ if (!reader.IsEmptyElement) {
+ reader.Read ();
+ reader.MoveToContent ();
+ skippedTopLevelElement = true;
+ }
+ else {
+ switch (mode) {
+ case XmlReadMode.Auto:
+ case XmlReadMode.InferSchema:
+ DataSetName = reader.LocalName;
+ break;
+ }
+ reader.Read ();
+ }
+ }
+ break;
}
- else {
- XmlDataLoader Loader = new XmlDataLoader (this);
- Result = Loader.LoadData (reader, mode);
+
+ // If schema, then read the first element as schema
+ if (reader.LocalName == "schema" && reader.NamespaceURI == XmlSchema.Namespace) {
+ shouldNotInfer = true;
+ switch (mode) {
+ case XmlReadMode.IgnoreSchema:
+ case XmlReadMode.InferSchema:
+ reader.Skip ();
+ break;
+ case XmlReadMode.Fragment:
+ ReadXmlSchema (reader);
+ break;
+ case XmlReadMode.DiffGram:
+ case XmlReadMode.Auto:
+ if (Tables.Count == 0) {
+ ReadXmlSchema (reader);
+ if (mode == XmlReadMode.Auto)
+ result = XmlReadMode.ReadSchema;
+ } else {
+ // otherwise just ignore and return IgnoreSchema
+ reader.Skip ();
+ result = XmlReadMode.IgnoreSchema;
+ }
+ break;
+ case XmlReadMode.ReadSchema:
+ ReadXmlSchema (reader);
+ break;
+ }
}
- return Result;
- }
+ // If diffgram, then read the first element as diffgram
+ if (reader.LocalName == "diffgram" && reader.NamespaceURI == XmlConstants.DiffgrNamespace) {
+ switch (mode) {
+ case XmlReadMode.Auto:
+ case XmlReadMode.IgnoreSchema:
+ case XmlReadMode.DiffGram:
+ XmlDiffLoader DiffLoader = new XmlDiffLoader (this);
+ DiffLoader.Load (reader);
+ if (mode == XmlReadMode.Auto)
+ result = XmlReadMode.DiffGram;
+ shouldReadData = false;
+ break;
+ case XmlReadMode.Fragment:
+ reader.Skip ();
+ break;
+ default:
+ reader.Skip ();
+ break;
+ }
+ }
+
+ // if schema after diffgram, just skip it.
+ if (!shouldReadData && reader.LocalName == "schema" && reader.NamespaceURI == XmlSchema.Namespace) {
+ shouldNotInfer = true;
+ switch (mode) {
+ default:
+ reader.Skip ();
+ break;
+ case XmlReadMode.ReadSchema:
+ case XmlReadMode.DiffGram:
+ if (Tables.Count == 0)
+ ReadXmlSchema (reader);
+ break;
+ }
+ }
+ if (reader.EOF)
+ return result == XmlReadMode.Auto ?
+ potentialDataSetName != null && !shouldNotInfer ?
+ XmlReadMode.InferSchema :
+ XmlReadMode.IgnoreSchema : result;
+
+ // Otherwise, read as dataset... but only when required.
+ if (shouldReadData && !shouldNotInfer) {
+ switch (mode) {
+ case XmlReadMode.Auto:
+ if (Tables.Count > 0)
+ goto case XmlReadMode.IgnoreSchema;
+ else
+ goto case XmlReadMode.InferSchema;
+ case XmlReadMode.InferSchema:
+ InferXmlSchema (doc, null);
+ if (mode == XmlReadMode.Auto)
+ result = XmlReadMode.InferSchema;
+ break;
+ case XmlReadMode.IgnoreSchema:
+ case XmlReadMode.Fragment:
+ case XmlReadMode.DiffGram:
+ break;
+ default:
+ shouldReadData = false;
+ break;
+ }
+ }
+
+ if (shouldReadData) {
+ XmlReader dataReader = reader;
+ if (doc != null) {
+ dataReader = new XmlNodeReader (doc);
+ dataReader.MoveToContent ();
+ }
+ if (reader.NodeType == XmlNodeType.Element)
+ XmlDataReader.ReadXml (this, dataReader,
+ mode);
+ }
+
+ if (skippedTopLevelElement) {
+ switch (result) {
+ case XmlReadMode.Auto:
+ case XmlReadMode.InferSchema:
+// DataSetName = potentialDataSetName;
+// result = XmlReadMode.InferSchema;
+ break;
+ }
+ if (reader.NodeType == XmlNodeType.EndElement)
+ reader.ReadEndElement ();
+ }
+//*
+ while (input.Depth > depth)
+ input.Read ();
+ if (input.NodeType == XmlNodeType.EndElement)
+ input.Read ();
+//*/
+ input.MoveToContent ();
+
+ return result == XmlReadMode.Auto ?
+ XmlReadMode.IgnoreSchema : result;
+ }
#endregion // Public Methods
#region Public Events
#endregion // Public Events
- #region Destructors
-
- ~DataSet()
- {
- }
-
- #endregion Destructors
-
#region IListSource methods
IList IListSource.GetList ()
{
#region ISupportInitialize methods
public void BeginInit ()
{
- throw new NotImplementedException ();
}
public void EndInit ()
{
- throw new NotImplementedException ();
}
#endregion
#region ISerializable
void ISerializable.GetObjectData (SerializationInfo si, StreamingContext sc)
{
- throw new NotImplementedException ();
+ StringWriter sw = new StringWriter ();
+ XmlTextWriter writer = new XmlTextWriter (sw);
+ DoWriteXmlSchema (writer);
+ writer.Flush ();
+ si.AddValue ("XmlSchema", sw.ToString ());
+
+ sw = new StringWriter ();
+ writer = new XmlTextWriter (sw);
+ WriteXml (writer, XmlWriteMode.DiffGram);
+ writer.Flush ();
+ si.AddValue ("XmlDiffGram", sw.ToString ());
}
#endregion
#region Protected Methods
- protected void GetSerializationData(SerializationInfo info, StreamingContext context)
+ protected void GetSerializationData (SerializationInfo info, StreamingContext context)
{
- string s = info.GetValue ("XmlDiffGram", typeof (String)) as String;
- if (s != null) ReadXmlSerializable (new XmlTextReader(new StringReader(s)));
+ string s = info.GetValue ("XmlSchema", typeof (String)) as String;
+ XmlTextReader reader = new XmlTextReader (new StringReader (s));
+ ReadXmlSchema (reader);
+ reader.Close ();
+
+ s = info.GetValue ("XmlDiffGram", typeof (String)) as String;
+ reader = new XmlTextReader (new StringReader (s));
+ ReadXml (reader, XmlReadMode.DiffGram);
+ reader.Close ();
}
- protected virtual System.Xml.Schema.XmlSchema GetSchemaSerializable()
+ protected virtual System.Xml.Schema.XmlSchema GetSchemaSerializable ()
{
- return null; // FIXME
+ return null;
}
- protected virtual void ReadXmlSerializable(XmlReader reader)
+ protected virtual void ReadXmlSerializable (XmlReader reader)
{
- ReadXml(reader, XmlReadMode.DiffGram); // FIXME
+ ReadXml (reader);
+ }
+
+ void IXmlSerializable.ReadXml (XmlReader reader)
+ {
+ ReadXmlSerializable(reader);
}
+ void IXmlSerializable.WriteXml (XmlWriter writer)
+ {
+ DoWriteXmlSchema (writer);
+ WriteXml (writer, XmlWriteMode.DiffGram);
+ }
+
+ XmlSchema IXmlSerializable.GetSchema ()
+ {
+ return GetSchemaSerializable ();
+ }
+
protected virtual bool ShouldSerializeRelations ()
{
return true;
}
[MonoTODO]
- protected virtual void OnPropertyChanging (PropertyChangedEventArgs pcevent)
+ protected internal virtual void OnPropertyChanging (PropertyChangedEventArgs pcevent)
{
}
{
}
+ internal virtual void OnMergeFailed (MergeFailedEventArgs e)
+ {
+ if (MergeFailed != null)
+ MergeFailed (this, e);
+ }
+
[MonoTODO]
- protected void RaisePropertyChanging (string name)
+ protected internal void RaisePropertyChanging (string name)
{
}
#endregion
- #region Private Xml Serialisation
-
- private void WriteTable( XmlWriter writer, DataTable table, XmlWriteMode mode )
+ #region Private Methods
+
+ private XmlReadMode ReadXmlIgnoreSchema (XmlReader input, XmlReadMode mode, bool checkRecurse)
+ {
+ if (input.LocalName == "schema" &&
+ input.NamespaceURI == XmlSchema.Namespace) {
+ input.Skip ();
+ }
+ else if (input.LocalName == "diffgram" &&
+ input.NamespaceURI == XmlConstants.DiffgrNamespace) {
+ XmlDiffLoader DiffLoader = new XmlDiffLoader (this);
+ DiffLoader.Load (input);
+ }
+ else if (checkRecurse ||
+ input.LocalName == DataSetName &&
+ input.NamespaceURI == Namespace) {
+ XmlDataReader.ReadXml (this, input, mode);
+ }
+ else if (checkRecurse && !input.IsEmptyElement) {
+ int depth = input.Depth;
+ input.Read ();
+ input.MoveToContent ();
+ ReadXmlIgnoreSchema (input, mode, false);
+ while (input.Depth > depth)
+ input.Skip ();
+ if (input.NodeType == XmlNodeType.EndElement)
+ input.ReadEndElement ();
+ }
+ input.MoveToContent ();
+ return XmlReadMode.IgnoreSchema;
+ }
+
+ private XmlReadMode ReadXmlReadSchema (XmlReader input, XmlReadMode mode, bool checkRecurse)
+ {
+ if (input.LocalName == "schema" &&
+ input.NamespaceURI == XmlSchema.Namespace) {
+ ReadXmlSchema (input);
+ }
+ else if (checkRecurse && !input.IsEmptyElement) {
+ int depth = input.Depth;
+ input.Read ();
+ input.MoveToContent ();
+ ReadXmlReadSchema (input, mode, false);
+ while (input.Depth > depth)
+ input.Skip ();
+ if (input.NodeType == XmlNodeType.EndElement)
+ input.ReadEndElement ();
+ }
+ else
+ input.Skip ();
+ input.MoveToContent ();
+ return XmlReadMode.ReadSchema;
+ }
+
+ private string WriteObjectXml (object o)
+ {
+ switch (Type.GetTypeCode (o.GetType ())) {
+ case TypeCode.Boolean:
+ return XmlConvert.ToString ((Boolean) o);
+ case TypeCode.Byte:
+ return XmlConvert.ToString ((Byte) o);
+ case TypeCode.Char:
+ return XmlConvert.ToString ((Char) o);
+ case TypeCode.DateTime:
+ return XmlConvert.ToString ((DateTime) o);
+ case TypeCode.Decimal:
+ return XmlConvert.ToString ((Decimal) o);
+ case TypeCode.Double:
+ return XmlConvert.ToString ((Double) o);
+ case TypeCode.Int16:
+ return XmlConvert.ToString ((Int16) o);
+ case TypeCode.Int32:
+ return XmlConvert.ToString ((Int32) o);
+ case TypeCode.Int64:
+ return XmlConvert.ToString ((Int64) o);
+ case TypeCode.SByte:
+ return XmlConvert.ToString ((SByte) o);
+ case TypeCode.Single:
+ return XmlConvert.ToString ((Single) o);
+ case TypeCode.UInt16:
+ return XmlConvert.ToString ((UInt16) o);
+ case TypeCode.UInt32:
+ return XmlConvert.ToString ((UInt32) o);
+ case TypeCode.UInt64:
+ return XmlConvert.ToString ((UInt64) o);
+ }
+ if (o is TimeSpan) return XmlConvert.ToString ((TimeSpan) o);
+ if (o is Guid) return XmlConvert.ToString ((Guid) o);
+ if (o is byte[]) return Convert.ToBase64String ((byte[])o);
+ return o.ToString ();
+ }
+
+ private void WriteTables (XmlWriter writer, XmlWriteMode mode, DataTableCollection tableCollection, DataRowVersion version)
+ {
+ //Write out each table in order, providing it is not
+ //part of another table structure via a nested parent relationship
+ foreach (DataTable table in tableCollection) {
+ bool isTopLevel = true;
+ /*
+ foreach (DataRelation rel in table.ParentRelations) {
+ if (rel.Nested) {
+ isTopLevel = false;
+ break;
+ }
+ }
+ */
+ if (isTopLevel) {
+ WriteTable ( writer, table, mode, version);
+ }
+ }
+ }
+
+ private void WriteTable (XmlWriter writer, DataTable table, XmlWriteMode mode, DataRowVersion version)
{
DataRow[] rows = new DataRow [table.Rows.Count];
table.Rows.CopyTo (rows, 0);
- WriteTable (writer, rows, mode);
+ WriteTable (writer, rows, mode, version, true);
}
- private void WriteTable( XmlWriter writer, DataRow[] rows, XmlWriteMode mode )
+ private void WriteTable (XmlWriter writer, DataRow[] rows, XmlWriteMode mode, DataRowVersion version, bool skipIfNested)
{
//The columns can be attributes, hidden, elements, or simple content
//There can be 0-1 simple content cols or 0-* elements
if (rows.Length == 0) return;
DataTable table = rows[0].Table;
- SplitColumns( table, out atts, out elements, out simple );
-
- foreach( DataRow row in rows )
- {
- //sort out the namespacing
- string nspc = table.Namespace.Length > 0 ? table.Namespace : Namespace;
+ SplitColumns (table, out atts, out elements, out simple);
+ //sort out the namespacing
+ string nspc = table.Namespace.Length > 0 ? table.Namespace : Namespace;
+ int relationCount = table.ParentRelations.Count;
+ DataRelation oneRel = relationCount == 1 ? table.ParentRelations [0] : null;
+
+ foreach (DataRow row in rows) {
+ if (skipIfNested) {
+ // Skip rows that is a child of any tables.
+ switch (relationCount) {
+ case 0:
+ break;
+ case 1:
+ if (!oneRel.Nested)
+ break;
+ if (row.GetParentRow (oneRel) != null)
+ continue;
+ break;
+ case 2:
+ bool skip = false;
+ for (int i = 0; i < table.ParentRelations.Count; i++) {
+ DataRelation prel = table.ParentRelations [i];
+ if (!prel.Nested)
+ continue;
+ if (row.GetParentRow (prel) != null) {
+ skip = true;
+ continue;
+ }
+ }
+ if (skip)
+ continue;
+ break;
+ }
+ }
+ if (!row.HasVersion(version) ||
+ (mode == XmlWriteMode.DiffGram && row.RowState == DataRowState.Unchanged
+ && version == DataRowVersion.Original))
+ continue;
+
// First check are all the rows null. If they are we just write empty element
bool AllNulls = true;
foreach (DataColumn dc in table.Columns) {
- if (row [dc.ColumnName] != DBNull.Value) {
+ if (row [dc.ColumnName, version] != DBNull.Value) {
AllNulls = false;
break;
}
// If all of the columns were null, we have to write empty element
if (AllNulls) {
- writer.WriteElementString (table.TableName, "");
+ writer.WriteElementString (XmlConvert.EncodeLocalName (table.TableName), "");
continue;
}
-
- WriteStartElement( writer, mode, nspc, table.Prefix, table.TableName );
- foreach( DataColumn col in atts )
- {
- WriteAttributeString( writer, mode, col.Namespace, col.Prefix, col.ColumnName, row[col].ToString() );
- }
+ WriteTableElement (writer, mode, table, row, version);
- if( simple != null )
- {
- writer.WriteString( row[simple].ToString() );
+ foreach (DataColumn col in atts) {
+ WriteColumnAsAttribute (writer, mode, col, row, version);
}
- else
- {
- foreach( DataColumn col in elements )
- {
- string colnspc = nspc;
- object rowObject = row [col];
-
- if (rowObject == null || rowObject == DBNull.Value)
- continue;
-
- if( col.Namespace != null )
- {
- colnspc = col.Namespace;
- }
- //TODO check if I can get away with write element string
- WriteStartElement( writer, mode, colnspc, col.Prefix, col.ColumnName );
- writer.WriteString( rowObject.ToString() );
- writer.WriteEndElement();
+ if (simple != null) {
+ writer.WriteString (WriteObjectXml (row[simple, version]));
+ }
+ else {
+ foreach (DataColumn col in elements) {
+ WriteColumnAsElement (writer, mode, col, row, version);
}
}
foreach (DataRelation relation in table.ChildRelations) {
if (relation.Nested) {
- WriteTable (writer, row.GetChildRows(relation), mode);
+ WriteTable (writer, row.GetChildRows (relation), mode, version, false);
}
}
- writer.WriteEndElement();
+ writer.WriteEndElement ();
}
}
+
+ private void WriteColumnAsElement (XmlWriter writer, XmlWriteMode mode, DataColumn col, DataRow row, DataRowVersion version)
+ {
+ string colnspc = null;
+ object rowObject = row [col, version];
+
+ if (rowObject == null || rowObject == DBNull.Value)
+ return;
+
+ if (col.Namespace != String.Empty)
+ colnspc = col.Namespace;
+
+ //TODO check if I can get away with write element string
+ WriteStartElement (writer, mode, colnspc, col.Prefix, XmlConvert.EncodeLocalName (col.ColumnName));
+ writer.WriteString (WriteObjectXml (rowObject));
+ writer.WriteEndElement ();
+ }
+
+ private void WriteColumnAsAttribute (XmlWriter writer, XmlWriteMode mode, DataColumn col, DataRow row, DataRowVersion version)
+ {
+ if (!row.IsNull (col))
+ WriteAttributeString (writer, mode, col.Namespace, col.Prefix, XmlConvert.EncodeLocalName (col.ColumnName), WriteObjectXml (row[col, version]));
+ }
+
+ private void WriteTableElement (XmlWriter writer, XmlWriteMode mode, DataTable table, DataRow row, DataRowVersion version)
+ {
+ //sort out the namespacing
+ string nspc = table.Namespace.Length > 0 ? table.Namespace : Namespace;
+
+ WriteStartElement (writer, mode, nspc, table.Prefix, XmlConvert.EncodeLocalName (table.TableName));
+
+ if (mode == XmlWriteMode.DiffGram) {
+ WriteAttributeString (writer, mode, XmlConstants.DiffgrNamespace, XmlConstants.DiffgrPrefix, "id", table.TableName + (row.XmlRowID + 1));
+ WriteAttributeString (writer, mode, XmlConstants.MsdataNamespace, XmlConstants.MsdataPrefix, "rowOrder", XmlConvert.ToString (row.XmlRowID));
+ string modeName = null;
+ if (row.RowState == DataRowState.Modified)
+ modeName = "modified";
+ else if (row.RowState == DataRowState.Added)
+ modeName = "inserted";
+
+ if (version != DataRowVersion.Original && modeName != null)
+ WriteAttributeString (writer, mode, XmlConstants.DiffgrNamespace, XmlConstants.DiffgrPrefix, "hasChanges", modeName);
+ }
+ }
- private void WriteStartElement( XmlWriter writer, XmlWriteMode mode, string nspc, string prefix, string name )
- {
- switch( mode )
- {
- case XmlWriteMode.WriteSchema:
- if( nspc == null || nspc == "" )
- {
- writer.WriteStartElement( name );
- }
- else if( prefix != null )
- {
- writer.WriteStartElement(prefix, name, nspc );
- }
- else
- {
- writer.WriteStartElement( writer.LookupPrefix( nspc ), name, nspc );
- }
- break;
- case XmlWriteMode.DiffGram:
- throw new NotImplementedException();
- default:
- writer.WriteStartElement(name );
- break;
- };
+ private void WriteStartElement (XmlWriter writer, XmlWriteMode mode, string nspc, string prefix, string name)
+ {
+ writer.WriteStartElement (prefix, name, nspc);
}
- private void WriteAttributeString( XmlWriter writer, XmlWriteMode mode, string nspc, string prefix, string name, string stringValue )
- {
- switch( mode )
- {
- case XmlWriteMode.WriteSchema:
- writer.WriteAttributeString(prefix, name, nspc );
- break;
- case XmlWriteMode.DiffGram:
- throw new NotImplementedException();
- default:
- writer.WriteAttributeString(name, stringValue );
- break;
- };
+ private void WriteAttributeString (XmlWriter writer, XmlWriteMode mode, string nspc, string prefix, string name, string stringValue)
+ {
+ switch ( mode) {
+ case XmlWriteMode.WriteSchema:
+ writer.WriteAttributeString (prefix, name, nspc);
+ break;
+ case XmlWriteMode.DiffGram:
+ writer.WriteAttributeString (prefix, name, nspc,stringValue);
+ break;
+ default:
+ writer.WriteAttributeString (name, stringValue);
+ break;
+ };
}
- private void DoWriteXmlSchema( XmlWriter writer )
- {
- //Create the root element and declare all the namespaces etc
- writer.WriteStartElement(XmlConstants.SchemaPrefix, XmlConstants.SchemaElement,
- XmlConstants.SchemaNamespace );
- writer.WriteAttributeString( XmlConstants.TargetNamespace, Namespace );
- writer.WriteAttributeString( "xmlns:" + XmlConstants.TnsPrefix, Namespace );
- writer.WriteAttributeString( "xmlns", Namespace );
- writer.WriteAttributeString( "xmlns:" + XmlConstants.MsdataPrefix,
- XmlConstants.MsdataNamespace );
- //Set up the attribute and element forms.
- //TODO - is it possible to change this?
- //I couldn't spot if it was so I assumed
- //that this is set to qualified all round basedon the MS output
- writer.WriteAttributeString( XmlConstants.AttributeFormDefault,
- XmlConstants.Qualified );
- writer.WriteAttributeString( XmlConstants.ElementFormDefault,
- XmlConstants.Qualified );
-
-
- //<xs:element name="DSName msdata:IsDataSet="true" msdata:Locale="machine-locale">
- //Create the data set element
- //All the tables are represented as choice elements in an unlimited series
- writer.WriteStartElement( XmlConstants.SchemaPrefix,
- XmlConstants.Element,
- XmlConstants.SchemaNamespace );
-
- writer.WriteAttributeString( XmlConstants.Name, DataSetName );
- writer.WriteAttributeString( XmlConstants.MsdataPrefix, XmlConstants.IsDataSet, XmlConstants.MsdataNamespace, "true" );
- //FIXME - sort out the locale string!
+ internal void WriteIndividualTableContent (XmlWriter writer, DataTable table, XmlWriteMode mode)
+ {
+ ((XmlTextWriter)writer).Formatting = Formatting.Indented;
- writer.WriteAttributeString( XmlConstants.MsdataPrefix, XmlConstants.Locale, XmlConstants.MsdataNamespace, Thread.CurrentThread.CurrentCulture.Name);
+ if (mode == XmlWriteMode.DiffGram) {
+ SetTableRowsID (table);
+ WriteDiffGramElement (writer);
+ }
- //<xs:complexType>
- writer.WriteStartElement( XmlConstants.SchemaPrefix,
- XmlConstants.ComplexType,
- XmlConstants.SchemaNamespace );
+ WriteStartElement (writer, mode, Namespace, Prefix, XmlConvert.EncodeName (DataSetName));
- //<xs:choice maxOccurs="unbounded">
- writer.WriteStartElement( XmlConstants.SchemaPrefix,
- XmlConstants.Choice,
- XmlConstants.SchemaNamespace );
+ WriteTable (writer, table, mode, DataRowVersion.Default);
- writer.WriteAttributeString( XmlConstants.MaxOccurs, XmlConstants.Unbounded );
+ if (mode == XmlWriteMode.DiffGram) {
+ writer.WriteEndElement (); //DataSet name
+ if (HasChanges (DataRowState.Modified | DataRowState.Deleted)) {
+
+ DataSet beforeDS = GetChanges (DataRowState.Modified | DataRowState.Deleted);
+ WriteStartElement (writer, XmlWriteMode.DiffGram, XmlConstants.DiffgrNamespace, XmlConstants.DiffgrPrefix, "before");
+ WriteTable (writer, beforeDS.Tables [table.TableName], mode, DataRowVersion.Original);
+ writer.WriteEndElement ();
+ }
+ }
+ writer.WriteEndElement (); // DataSet name or diffgr:diffgram
+ }
+
+
+ private void CheckNamespace (string prefix, string ns, XmlNamespaceManager nsmgr, XmlSchema schema)
+ {
+ if (ns == String.Empty)
+ return;
+ if (ns != nsmgr.DefaultNamespace) {
+ if (nsmgr.LookupNamespace (nsmgr.NameTable.Get (prefix)) != ns) {
+ for (int i = 1; i < int.MaxValue; i++) {
+ string p = nsmgr.NameTable.Add ("app" + i);
+ if (!nsmgr.HasNamespace (p)) {
+ nsmgr.AddNamespace (p, ns);
+ HandleExternalNamespace (p, ns, schema);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ XmlSchema BuildSchema ()
+ {
+ return BuildSchema (Tables, Relations);
+ }
+
+ internal XmlSchema BuildSchema (DataTableCollection tables, DataRelationCollection relations)
+ {
+ string constraintPrefix = "";
+ XmlSchema schema = new XmlSchema ();
+ XmlNamespaceManager nsmgr = new XmlNamespaceManager (new NameTable ());
+ if (Namespace != "") {
+ schema.AttributeFormDefault = XmlSchemaForm.Qualified;
+ schema.ElementFormDefault = XmlSchemaForm.Qualified;
+ schema.TargetNamespace = Namespace;
+ constraintPrefix = XmlConstants.TnsPrefix + ":";
+ }
+
+ // set the schema id
+ schema.Id = DataSetName;
+ XmlDocument doc = new XmlDocument ();
+ XmlAttribute attr = null;
+ ArrayList atts = new ArrayList ();
+
+ attr = doc.CreateAttribute ("", "xmlns", XmlConstants.XmlnsNS);
+ atts.Add (attr);
+
+ nsmgr.AddNamespace ("xs", XmlSchema.Namespace);
+ nsmgr.AddNamespace (XmlConstants.MsdataPrefix, XmlConstants.MsdataNamespace);
+ if (Namespace != "") {
+ nsmgr.AddNamespace (XmlConstants.TnsPrefix, Namespace);
+ nsmgr.AddNamespace (String.Empty, Namespace);
+ }
+ if (CheckExtendedPropertyExists (tables, relations))
+ nsmgr.AddNamespace (XmlConstants.MspropPrefix, XmlConstants.MspropNamespace);
+
+ if (atts.Count > 0)
+ schema.UnhandledAttributes = atts.ToArray (typeof (XmlAttribute)) as XmlAttribute [];
+
+ XmlSchemaElement elem = new XmlSchemaElement ();
+ elem.Name = XmlConvert.EncodeName (DataSetName);
+
+ // Add namespaces used in DataSet components (tables, columns, ...)
+ foreach (DataTable dt in tables) {
+ foreach (DataColumn col in dt.Columns)
+ CheckNamespace (col.Prefix, col.Namespace, nsmgr, schema);
+ CheckNamespace (dt.Prefix, dt.Namespace, nsmgr, schema);
+ }
+
+ // Attributes for DataSet element
+ atts.Clear ();
+ attr = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.IsDataSet, XmlConstants.MsdataNamespace);
+ attr.Value = "true";
+ atts.Add (attr);
+
+ attr = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.Locale, XmlConstants.MsdataNamespace);
+ attr.Value = locale.Name;
+ atts.Add (attr);
+
+ elem.UnhandledAttributes = atts.ToArray (typeof (XmlAttribute)) as XmlAttribute [];
+
+ AddExtendedPropertyAttributes (elem, ExtendedProperties, doc);
+
+ XmlSchemaComplexType complex = new XmlSchemaComplexType ();
+ elem.SchemaType = complex;
+
+ XmlSchemaChoice choice = new XmlSchemaChoice ();
+ complex.Particle = choice;
+ choice.MaxOccursString = XmlConstants.Unbounded;
- //Write out schema for each table in order, providing it is not
- //part of another table structure via a nested parent relationship
- foreach( DataTable table in Tables )
- {
+ //Write out schema for each table in order
+ foreach (DataTable table in tables) {
bool isTopLevel = true;
- foreach( DataRelation rel in table.ParentRelations )
- {
- if( rel.Nested )
- {
+ foreach (DataRelation rel in table.ParentRelations) {
+ if (rel.Nested) {
isTopLevel = false;
break;
}
}
- if( isTopLevel )
- {
- WriteTableSchema( writer, table );
+ if (isTopLevel) {
+ if (table.Namespace != SafeNS (schema.TargetNamespace)) {
+ XmlSchemaElement extElem = new XmlSchemaElement ();
+ extElem.RefName = new XmlQualifiedName (table.TableName, table.Namespace);
+ choice.Items.Add (extElem);
+ }
+ else
+ choice.Items.Add (GetTableSchema (doc, table, schema, nsmgr));
}
}
+
+ schema.Items.Add (elem);
- //</xs:choice>
- writer.WriteEndElement();
- //</xs:complexType>
- writer.WriteEndElement();
-
- //TODO - now add in the relationships as key and unique constraints etc
-
- //</xs:element>
- writer.WriteEndElement();
-
-
- //</schema>
- writer.WriteEndElement();
+ AddConstraintsToSchema (elem, constraintPrefix, tables, relations, doc);
+ foreach (string prefix in nsmgr) {
+ string ns = nsmgr.LookupNamespace (nsmgr.NameTable.Get (prefix));
+ if (prefix != "xmlns" && prefix != "xml" && ns != null && ns != String.Empty)
+ schema.Namespaces.Add (prefix, ns);
+ }
+
+ return schema;
+ }
+
+ private bool CheckExtendedPropertyExists (
+ DataTableCollection tables,
+ DataRelationCollection relations)
+ {
+ if (ExtendedProperties.Count > 0)
+ return true;
+ foreach (DataTable dt in tables) {
+ if (dt.ExtendedProperties.Count > 0)
+ return true;
+ foreach (DataColumn col in dt.Columns)
+ if (col.ExtendedProperties.Count > 0)
+ return true;
+ foreach (Constraint c in dt.Constraints)
+ if (c.ExtendedProperties.Count > 0)
+ return true;
+ }
+ if (relations == null)
+ return false;
+ foreach (DataRelation rel in relations)
+ if (rel.ExtendedProperties.Count > 0)
+ return true;
+ return false;
+ }
+
+ // Add all constraints in all tables to the schema.
+ private void AddConstraintsToSchema (XmlSchemaElement elem, string constraintPrefix, DataTableCollection tables, DataRelationCollection relations, XmlDocument doc)
+ {
+ // first add all unique constraints.
+ Hashtable uniqueNames = AddUniqueConstraints (elem, constraintPrefix, tables, doc);
+ // Add all foriegn key constraints.
+ AddForeignKeys (uniqueNames, elem, constraintPrefix, relations, doc);
+ }
+
+ // Add unique constaraints to the schema.
+ // return hashtable with the names of all XmlSchemaUnique elements we created.
+ private Hashtable AddUniqueConstraints (XmlSchemaElement elem, string constraintPrefix, DataTableCollection tables, XmlDocument doc)
+ {
+ Hashtable uniqueNames = new Hashtable();
+ foreach (DataTable table in tables) {
+
+ foreach (Constraint constraint in table.Constraints) {
+
+ if (constraint is UniqueConstraint) {
+ ArrayList attrs = new ArrayList ();
+ XmlAttribute attrib;
+ UniqueConstraint uqConst = (UniqueConstraint) constraint;
+ XmlSchemaUnique uniq = new XmlSchemaUnique ();
+
+ // if column of the constraint is hidden do not write the constraint.
+ bool isHidden = false;
+ foreach (DataColumn column in uqConst.Columns) {
+ if (column.ColumnMapping == MappingType.Hidden) {
+ isHidden = true;
+ break;
+ }
+ }
+
+ if (isHidden)
+ continue;
+
+ // if constaraint name do not exist in the hashtable we can use it.
+ if (!uniqueNames.ContainsKey (uqConst.ConstraintName)) {
+ uniq.Name = uqConst.ConstraintName;
+ }
+ // generate new constraint name for the XmlSchemaUnique element.
+ else {
+ uniq.Name = uqConst.Table.TableName + "_" + uqConst.ConstraintName;
+ attrib = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.ConstraintName, XmlConstants.MsdataNamespace);
+ attrib.Value = uqConst.ConstraintName;
+ attrs.Add (attrib);
+ }
+ if (uqConst.IsPrimaryKey) {
+ attrib = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.PrimaryKey, XmlConstants.MsdataNamespace);
+ attrib.Value = "true";
+ attrs.Add (attrib);
+ }
+
+ uniq.UnhandledAttributes = (XmlAttribute[])attrs.ToArray (typeof (XmlAttribute));
+
+ uniq.Selector = new XmlSchemaXPath();
+ uniq.Selector.XPath = ".//"+constraintPrefix + uqConst.Table.TableName;
+ XmlSchemaXPath field;
+ foreach (DataColumn column in uqConst.Columns) {
+ field = new XmlSchemaXPath();
+ string typePrefix = column.ColumnMapping == MappingType.Attribute ? "@" : "";
+ field.XPath = typePrefix + constraintPrefix+column.ColumnName;
+ uniq.Fields.Add(field);
+ }
+
+ AddExtendedPropertyAttributes (uniq, constraint.ExtendedProperties, doc);
+
+ elem.Constraints.Add (uniq);
+ uniqueNames.Add (uniq.Name, null);
+ }
+ }
+ }
+ return uniqueNames;
}
- private void WriteTableSchema( XmlWriter writer, DataTable table )
+ // Add the foriegn keys to the schema.
+ private void AddForeignKeys (Hashtable uniqueNames, XmlSchemaElement elem, string constraintPrefix, DataRelationCollection relations, XmlDocument doc)
+ {
+ if (relations == null) return;
+
+ foreach (DataRelation rel in relations) {
+
+ if (rel.ParentKeyConstraint == null || rel.ChildKeyConstraint == null)
+ continue;
+
+ bool isHidden = false;
+ foreach (DataColumn col in rel.ParentColumns) {
+ if (col.ColumnMapping == MappingType.Hidden) {
+ isHidden = true;
+ break;
+ }
+ }
+ foreach (DataColumn col in rel.ChildColumns) {
+ if (col.ColumnMapping == MappingType.Hidden) {
+ isHidden = true;
+ break;
+ }
+ }
+ if (isHidden)
+ continue;
+
+ ArrayList attrs = new ArrayList ();
+ XmlAttribute attrib;
+ XmlSchemaKeyref keyRef = new XmlSchemaKeyref();
+ keyRef.Name = rel.RelationName;
+ ForeignKeyConstraint fkConst = rel.ChildKeyConstraint;
+ UniqueConstraint uqConst = rel.ParentKeyConstraint;
+
+ string concatName = rel.ParentTable.TableName + "_" + uqConst.ConstraintName;
+ // first try to find the concatenated name. If we didn't find it - use constraint name.
+ if (uniqueNames.ContainsKey (concatName)) {
+ keyRef.Refer = new XmlQualifiedName(concatName);
+ }
+ else {
+ keyRef.Refer = new XmlQualifiedName(uqConst.ConstraintName);
+ }
+
+ if (rel.Nested) {
+ attrib = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.IsNested, XmlConstants.MsdataNamespace);
+ attrib.Value = "true";
+ attrs.Add (attrib);
+ }
+
+ keyRef.Selector = new XmlSchemaXPath();
+ keyRef.Selector.XPath = ".//" + constraintPrefix + rel.ChildTable.TableName;
+ XmlSchemaXPath field;
+ foreach (DataColumn column in rel.ChildColumns) {
+ field = new XmlSchemaXPath();
+ string typePrefix = column.ColumnMapping == MappingType.Attribute ? "@" : "";
+ field.XPath = typePrefix + constraintPrefix + column.ColumnName;
+ keyRef.Fields.Add(field);
+ }
+
+ keyRef.UnhandledAttributes = (XmlAttribute[])attrs.ToArray (typeof (XmlAttribute));
+ AddExtendedPropertyAttributes (keyRef, rel.ExtendedProperties, doc);
+
+ elem.Constraints.Add (keyRef);
+ }
+ }
+
+ private XmlSchemaElement GetTableSchema (XmlDocument doc, DataTable table, XmlSchema schemaToAdd, XmlNamespaceManager nsmgr)
{
ArrayList elements;
ArrayList atts;
DataColumn simple;
-
- SplitColumns( table,out atts, out elements, out simple );
-
- //<xs:element name="TableName">
- writer.WriteStartElement( XmlConstants.SchemaPrefix,
- XmlConstants.Element,
- XmlConstants.SchemaNamespace );
-
- writer.WriteAttributeString( XmlConstants.Name, table.TableName );
-
- //<xs:complexType>
- writer.WriteStartElement( XmlConstants.SchemaPrefix,
- XmlConstants.ComplexType,
- XmlConstants.SchemaNamespace );
-
- //TODO - what about the simple content?
- if( elements.Count == 0 )
- {
- }
- else
- {
- //A sequence of element types or a simple content node
- //<xs:sequence>
- writer.WriteStartElement( XmlConstants.SchemaPrefix,
- XmlConstants.Sequence,
- XmlConstants.SchemaNamespace );
- foreach( DataColumn col in elements )
- {
- //<xs:element name=ColumnName type=MappedType Ordinal=index>
- writer.WriteStartElement( XmlConstants.SchemaPrefix,
- XmlConstants.Element,
- XmlConstants.SchemaNamespace );
+
+ ArrayList xattrs = new ArrayList();
+ XmlAttribute xattr;
+
+ SplitColumns (table, out atts, out elements, out simple);
+
+ XmlSchemaElement elem = new XmlSchemaElement ();
+ elem.Name = table.TableName;
+
+ XmlSchemaComplexType complex = new XmlSchemaComplexType ();
+ elem.SchemaType = complex;
+
+ XmlSchemaObjectCollection schemaAttributes = null;
+
+ if (simple != null) {
+ // add simpleContent
+ XmlSchemaSimpleContent simpleContent = new XmlSchemaSimpleContent();
+ complex.ContentModel = simpleContent;
+
+ // add column name attribute
+ XmlAttribute[] xlmAttrs = new XmlAttribute [2];
+ xlmAttrs[0] = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.ColumnName, XmlConstants.MsdataNamespace);
+ xlmAttrs[0].Value = simple.ColumnName;
+
+ // add ordinal attribute
+ xlmAttrs[1] = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.Ordinal, XmlConstants.MsdataNamespace);
+ xlmAttrs[1].Value = XmlConvert.ToString (simple.Ordinal);
+ simpleContent.UnhandledAttributes = xlmAttrs;
- writer.WriteAttributeString( XmlConstants.Name, col.ColumnName );
+
+ // add extension
+ XmlSchemaSimpleContentExtension extension = new XmlSchemaSimpleContentExtension();
+ simpleContent.Content = extension;
+ extension.BaseTypeName = MapType (simple.DataType);
+ schemaAttributes = extension.Attributes;
+ } else {
+ schemaAttributes = complex.Attributes;
+ //A sequence of element types or a simple content node
+ //<xs:sequence>
+ XmlSchemaSequence seq = new XmlSchemaSequence ();
+
+ foreach (DataColumn col in elements) {
+
+ // Add element for the column.
+ XmlSchemaElement colElem = new XmlSchemaElement ();
+ colElem.Name = col.ColumnName;
- if (col.ColumnName != col.Caption && col.Caption != string.Empty)
- writer.WriteAttributeString( XmlConstants.MsdataPrefix, XmlConstants.Caption,
- XmlConstants.MsdataNamespace, col.Caption);
+ if (col.ColumnName != col.Caption && col.Caption != String.Empty) {
+ xattr = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.Caption, XmlConstants.MsdataNamespace);
+ xattr.Value = col.Caption;
+ xattrs.Add (xattr);
+ }
+
+ if (col.AutoIncrement == true) {
+ xattr = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.AutoIncrement, XmlConstants.MsdataNamespace);
+ xattr.Value = "true";
+ xattrs.Add (xattr);
+ }
- if (col.DefaultValue.ToString () != string.Empty)
- writer.WriteAttributeString( XmlConstants.Default, col.DefaultValue.ToString ());
+ if (col.AutoIncrementSeed != 0) {
+ xattr = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.AutoIncrementSeed, XmlConstants.MsdataNamespace);
+ xattr.Value = XmlConvert.ToString (col.AutoIncrementSeed);
+ xattrs.Add (xattr);
+ }
- writer.WriteAttributeString( XmlConstants.Type, MapType( col.DataType ) );
+ if (col.DefaultValue.ToString () != String.Empty)
+ colElem.DefaultValue = WriteObjectXml (col.DefaultValue);
- if( col.AllowDBNull )
- {
- writer.WriteAttributeString( XmlConstants.MinOccurs, "0" );
- }
+ if (col.ReadOnly) {
+ xattr = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.ReadOnly, XmlConstants.MsdataNamespace);
+ xattr.Value = "true";
+ xattrs.Add (xattr);
+ }
- //writer.WriteAttributeString( XmlConstants.MsdataPrefix,
- // XmlConstants.Ordinal,
- // XmlConstants.MsdataNamespace,
- // col.Ordinal.ToString() );
+ if (col.MaxLength < 0)
+ colElem.SchemaTypeName = MapType (col.DataType);
+
+ if (colElem.SchemaTypeName == XmlConstants.QnString && col.DataType != typeof (string)
+ && col.DataType != typeof (char)) {
+ xattr = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.DataType, XmlConstants.MsdataNamespace);
+ xattr.Value = col.DataType.AssemblyQualifiedName;
+ xattrs.Add (xattr);
+ }
- // Write SimpleType if column have MaxLength
- if (col.MaxLength > -1) {
+ if (col.AllowDBNull) {
+ colElem.MinOccurs = 0;
+ }
+
+ //writer.WriteAttributeString (XmlConstants.MsdataPrefix,
+ // XmlConstants.Ordinal,
+ // XmlConstants.MsdataNamespace,
+ // col.Ordinal.ToString ());
- WriteTableSimpleType (writer, col);
+ // Write SimpleType if column have MaxLength
+ if (col.MaxLength > -1) {
+ colElem.SchemaType = GetTableSimpleType (doc, col);
+ }
+
+ colElem.UnhandledAttributes = (XmlAttribute[])xattrs.ToArray(typeof (XmlAttribute));
+ xattrs.Clear ();
+ AddExtendedPropertyAttributes (colElem, col.ExtendedProperties, doc);
+ seq.Items.Add (colElem);
}
-
- //</xs:element>
- writer.WriteEndElement();
- }
- //</xs:sequence>
- writer.WriteEndElement();
-
+ foreach (DataRelation rel in table.ChildRelations) {
+ if (rel.Nested) {
+ if (rel.ChildTable.Namespace != SafeNS (schemaToAdd.TargetNamespace)) {
+ XmlSchemaElement el = new XmlSchemaElement ();
+ el.RefName = new XmlQualifiedName (rel.ChildTable.TableName, rel.ChildTable.Namespace);
+ } else {
+ XmlSchemaElement el = GetTableSchema (doc, rel.ChildTable, schemaToAdd, nsmgr);
+ el.MinOccurs = 0;
+ el.MaxOccursString = "unbounded";
+ XmlSchemaComplexType ct = (XmlSchemaComplexType) el.SchemaType;
+ ct.Name = el.Name;
+ el.SchemaType = null;
+ el.SchemaTypeName = new XmlQualifiedName (ct.Name, schemaToAdd.TargetNamespace);
+ schemaToAdd.Items.Add (ct);
+ seq.Items.Add (el);
+ }
+ }
+ }
+
+ if (seq.Items.Count > 0)
+ complex.Particle = seq;
}
+
//Then a list of attributes
- foreach( DataColumn col in atts )
- {
+ foreach (DataColumn col in atts) {
//<xs:attribute name=col.ColumnName form="unqualified" type=MappedType/>
- writer.WriteStartElement( XmlConstants.SchemaPrefix,
- XmlConstants.Attribute,
- XmlConstants.SchemaNamespace );
-
- writer.WriteAttributeString( XmlConstants.Name, col.ColumnName );
- writer.WriteAttributeString( XmlConstants.Form, XmlConstants.Unqualified );
- writer.WriteAttributeString( XmlConstants.Type, MapType( col.DataType ) );
-
- writer.WriteEndElement();
+ XmlSchemaAttribute att = new XmlSchemaAttribute ();
+ att.Name = col.ColumnName;
+ if (col.Namespace != String.Empty) {
+ att.Form = XmlSchemaForm.Qualified;
+ string prefix = col.Prefix == String.Empty ? "app" + schemaToAdd.Namespaces.Count : col.Prefix;
+ att.Name = prefix + ":" + col.ColumnName;
+ // FIXME: Handle prefix mapping correctly.
+ schemaToAdd.Namespaces.Add (prefix, col.Namespace);
+ }
+ if (!col.AllowDBNull)
+ att.Use = XmlSchemaUse.Required;
+ if (col.DefaultValue.ToString () != String.Empty)
+ att.DefaultValue = WriteObjectXml (col.DefaultValue);
+
+ if (col.ReadOnly) {
+ xattr = doc.CreateAttribute (XmlConstants.MsdataPrefix, XmlConstants.ReadOnly, XmlConstants.MsdataNamespace);
+ xattr.Value = "true";
+ xattrs.Add (xattr);
+ }
+
+ att.UnhandledAttributes = xattrs.ToArray (typeof (XmlAttribute)) as XmlAttribute [];
+ xattrs.Clear ();
+
+ if (col.MaxLength > -1)
+ att.SchemaType = GetTableSimpleType (doc, col);
+ else
+ att.SchemaTypeName = MapType (col.DataType);
+ // FIXME: what happens if extended properties are set on attribute columns??
+ schemaAttributes.Add (att);
}
-
- //</xs:complexType>
- writer.WriteEndElement();
-
- //</xs:element>
- writer.WriteEndElement();
+
+ AddExtendedPropertyAttributes (elem, table.ExtendedProperties, doc);
+
+ return elem;
+ }
+
+ private void AddExtendedPropertyAttributes (XmlSchemaAnnotated xsobj, PropertyCollection props, XmlDocument doc)
+ {
+ ArrayList attList = new ArrayList ();
+ XmlAttribute xmlAttr;
+
+ if (xsobj.UnhandledAttributes != null)
+ attList.AddRange (xsobj.UnhandledAttributes);
+
+ // add extended properties to xs:element
+ foreach (DictionaryEntry de in props) {
+ xmlAttr = doc.CreateAttribute (XmlConstants.MspropPrefix, XmlConvert.EncodeName (de.Key.ToString ()), XmlConstants.MspropNamespace);
+ xmlAttr.Value = de.Value != null ? WriteObjectXml (de.Value) : String.Empty;
+ attList.Add (xmlAttr);
+ }
+ if (attList.Count > 0)
+ xsobj.UnhandledAttributes = attList.ToArray (typeof (XmlAttribute)) as XmlAttribute [];
}
- private void WriteTableSimpleType (XmlWriter writer, DataColumn col)
+ private string SafeNS (string ns)
+ {
+ return ns != null ? ns : String.Empty;
+ }
+
+ private void HandleExternalNamespace (string prefix, string ns, XmlSchema schema)
+ {
+ foreach (XmlSchemaExternal ext in schema.Includes) {
+ XmlSchemaImport imp = ext as XmlSchemaImport;
+ if (imp != null && imp.Namespace == ns)
+ return; // nothing to do
+ }
+ XmlSchemaImport i = new XmlSchemaImport ();
+ i.Namespace = ns;
+ i.SchemaLocation = "_" + prefix + ".xsd";
+ schema.Includes.Add (i);
+ }
+
+ private XmlSchemaSimpleType GetTableSimpleType (XmlDocument doc, DataColumn col)
{
// SimpleType
- writer.WriteStartElement( XmlConstants.SchemaPrefix, XmlConstants.SimpleType,
- XmlConstants.SchemaNamespace);
-
+ XmlSchemaSimpleType simple = new XmlSchemaSimpleType ();
+
// Restriction
- writer.WriteStartElement( XmlConstants.SchemaPrefix, XmlConstants.Restriction,
- XmlConstants.SchemaNamespace);
-
- writer.WriteAttributeString( XmlConstants.Base, MapType( col.DataType ) );
+ XmlSchemaSimpleTypeRestriction restriction = new XmlSchemaSimpleTypeRestriction ();
+ restriction.BaseTypeName = MapType (col.DataType);
// MaxValue
- writer.WriteStartElement( XmlConstants.SchemaPrefix, XmlConstants.MaxLength,
- XmlConstants.SchemaNamespace);
- writer.WriteAttributeString( XmlConstants.Value, col.MaxLength.ToString ());
-
+ XmlSchemaMaxLengthFacet max = new XmlSchemaMaxLengthFacet ();
+ max.Value = XmlConvert.ToString (col.MaxLength);
+ restriction.Facets.Add (max);
- writer.WriteEndElement();
-
- writer.WriteEndElement();
-
- writer.WriteEndElement();
+ simple.Content = restriction;
+ return simple;
}
+ private void DoWriteXmlSchema (XmlWriter writer)
+ {
+ BuildSchema ().Write (writer);
+ }
+
///<summary>
/// Helper function to split columns into attributes elements and simple
/// content
/// </summary>
- private void SplitColumns( DataTable table,
- out ArrayList atts,
- out ArrayList elements,
- out DataColumn simple)
+ private void SplitColumns (DataTable table,
+ out ArrayList atts,
+ out ArrayList elements,
+ out DataColumn simple)
{
//The columns can be attributes, hidden, elements, or simple content
//There can be 0-1 simple content cols or 0-* elements
- atts = new System.Collections.ArrayList();
- elements = new System.Collections.ArrayList();
+ atts = new System.Collections.ArrayList ();
+ elements = new System.Collections.ArrayList ();
simple = null;
//Sort out the columns
- foreach( DataColumn col in table.Columns )
- {
- switch( col.ColumnMapping )
- {
+ foreach (DataColumn col in table.Columns) {
+ switch (col.ColumnMapping) {
case MappingType.Attribute:
- atts.Add( col );
+ atts.Add (col);
break;
case MappingType.Element:
- elements.Add( col );
+ elements.Add (col);
break;
case MappingType.SimpleContent:
- if( simple != null )
- {
- throw new System.InvalidOperationException( "There may only be one simple content element" );
+ if (simple != null) {
+ throw new System.InvalidOperationException ("There may only be one simple content element");
}
simple = col;
break;
}
}
}
+
+ private void WriteDiffGramElement(XmlWriter writer)
+ {
+ WriteStartElement (writer, XmlWriteMode.DiffGram, XmlConstants.DiffgrNamespace, XmlConstants.DiffgrPrefix, "diffgram");
+ WriteAttributeString(writer, XmlWriteMode.DiffGram, null, "xmlns", XmlConstants.MsdataPrefix, XmlConstants.MsdataNamespace);
+ }
+
+ private void SetRowsID()
+ {
+ foreach (DataTable Table in Tables)
+ SetTableRowsID (Table);
+ }
- [MonoTODO]
- private string MapType( Type type )
- {
- string Result = "xs:string";
-
- // TODO: More types to map?
-
- if (typeof (string) == type)
- Result = "xs:string";
- else if (typeof (short) == type)
- Result = "xs:short";
- else if (typeof (int) == type)
- Result = "xs:int";
- else if (typeof (long) == type)
- Result = "xs:long";
- else if (typeof (bool) == type)
- Result = "xs:boolean";
- else if (typeof (byte) == type)
- Result = "xs:unsignedByte";
- else if (typeof (char) == type)
- Result = "xs:char";
- else if (typeof (DateTime) == type)
- Result = "xs:dateTime";
- else if (typeof (decimal) == type)
- Result = "xs:decimal";
- else if (typeof (double) == type)
- Result = "xs:double";
- else if (typeof (sbyte) == type)
- Result = "xs:sbyte";
- else if (typeof (Single) == type)
- Result = "xs:float";
- else if (typeof (TimeSpan) == type)
- Result = "xs:duration";
- else if (typeof (ushort) == type)
- Result = "xs:usignedShort";
- else if (typeof (uint) == type)
- Result = "xs:unsignedInt";
- else if (typeof (ulong) == type)
- Result = "xs:unsignedLong";
-
- return Result;
+ private void SetTableRowsID (DataTable Table)
+ {
+ int dataRowID = 0;
+ foreach (DataRow Row in Table.Rows) {
+ Row.XmlRowID = dataRowID;
+ dataRowID++;
+ }
}
+
+ private XmlQualifiedName MapType (Type type)
+ {
+ switch (Type.GetTypeCode (type)) {
+ case TypeCode.String: return XmlConstants.QnString;
+ case TypeCode.Int16: return XmlConstants.QnShort;
+ case TypeCode.Int32: return XmlConstants.QnInt;
+ case TypeCode.Int64: return XmlConstants.QnLong;
+ case TypeCode.Boolean: return XmlConstants.QnBoolean;
+ case TypeCode.Byte: return XmlConstants.QnUnsignedByte;
+ //case TypeCode.Char: return XmlConstants.QnChar;
+ case TypeCode.DateTime: return XmlConstants.QnDateTime;
+ case TypeCode.Decimal: return XmlConstants.QnDecimal;
+ case TypeCode.Double: return XmlConstants.QnDouble;
+ case TypeCode.SByte: return XmlConstants.QnSbyte;
+ case TypeCode.Single: return XmlConstants.QnFloat;
+ case TypeCode.UInt16: return XmlConstants.QnUsignedShort;
+ case TypeCode.UInt32: return XmlConstants.QnUnsignedInt;
+ case TypeCode.UInt64: return XmlConstants.QnUnsignedLong;
+ }
+
+ if (typeof (TimeSpan) == type)
+ return XmlConstants.QnDuration;
+ else if (typeof (System.Uri) == type)
+ return XmlConstants.QnUri;
+ else if (typeof (byte[]) == type)
+ return XmlConstants.QnBase64Binary;
+ else if (typeof (XmlQualifiedName) == type)
+ return XmlConstants.QnXmlQualifiedName;
+ else
+ return XmlConstants.QnString;
+ }
+
#endregion //Private Xml Serialisation
}
}