//------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // // Microsoft // Microsoft //------------------------------------------------------------------------------ namespace System.Data { using System; using System.Collections; using System.ComponentModel; using System.Data.SqlTypes; using System.Data.Common; using System.Diagnostics; using System.Globalization; using System.IO; using System.Text; using System.Xml; using System.Xml.Serialization; using System.Runtime.Versioning; internal enum SchemaFormat { Public = 1, Remoting = 2, WebService = 3, RemotingSkipSchema = 4, WebServiceSkipSchema = 5 } /// /// internal sealed class XmlTreeGen { ArrayList ConstraintNames; Hashtable namespaces; Hashtable autogenerated; Hashtable prefixes; DataSet _ds; ArrayList _tables = new ArrayList(); ArrayList _relations = new ArrayList(); XmlDocument _dc; XmlElement _sRoot; int prefixCount = 0; private SchemaFormat schFormat = SchemaFormat.Public; private string filePath = null; private string fileName = null; private string fileExt = null; XmlElement dsElement = null; XmlElement constraintSeparator = null; /// /// This converter allows new versions of the framework to write /// the assembly version of older versions of the framework. /// For example, having Dev10 using V4.0 target V2.0 of the framework. /// Converter targetConverter; internal XmlTreeGen(SchemaFormat format) { this.schFormat = format; } internal static void AddExtendedProperties(PropertyCollection props, XmlElement node) { AddExtendedProperties(props, node, null); } internal static void AddExtendedProperties(PropertyCollection props, XmlElement node, Type type) { if(props != null) { foreach(DictionaryEntry entry in props) { String s, v; if (entry.Key is INullable) { s = (String) SqlConvert.ChangeTypeForXML(entry.Key, typeof(string)); } else { s = (String) Convert.ToString(entry.Key, CultureInfo.InvariantCulture); } if (entry.Value is INullable) { v = (String) SqlConvert.ChangeTypeForXML(entry.Value, typeof(string)); } else if (entry.Value is System.Numerics.BigInteger) { v = (string)BigIntegerStorage.ConvertFromBigInteger((System.Numerics.BigInteger)entry.Value, typeof(string), CultureInfo.InvariantCulture); } else { v = (String) Convert.ToString(entry.Value, CultureInfo.InvariantCulture); } if (type == typeof(DataRelation)) { s = Keywords.MSD_REL_PREFIX + s; } else if (type == typeof(ForeignKeyConstraint)) { s = Keywords.MSD_FK_PREFIX + s; } node.SetAttribute(XmlConvert.EncodeLocalName(s), Keywords.MSPROPNS, v); } } } internal void AddXdoProperties(Object instance, XmlElement root, XmlDocument xd) { if (instance == null) { return; } PropertyDescriptorCollection pds = TypeDescriptor.GetProperties(instance) ; if (!((instance is DataSet) || (instance is DataTable) || (instance is DataColumn) || (instance is DataRelation))) { return; } for (int i = 0 ; i < pds.Count ; i++) { AddXdoProperty(pds[i], instance, root, xd); } return; } internal void AddXdoProperty(PropertyDescriptor pd, Object instance, XmlElement root, XmlDocument xd) { Type type = pd.PropertyType; bool bisDataColumn = false; DataColumn col = null; // it may cause problem to assign null here, I will need to change this. bool bIsSqlType = false; bool bImplementsInullable = false; if (instance is DataColumn) { col = (DataColumn)instance; bisDataColumn = true; bIsSqlType = col.IsSqlType; bImplementsInullable = col.ImplementsINullable; } if (bImplementsInullable == false && type != typeof(string) && // DO NOT REMOVE THIS type != typeof(bool) && type != typeof(Type) && type != typeof(object) && type != typeof(CultureInfo) && type != typeof(Int64) && type != typeof(Int32) ) { return; } if ((!pd.ShouldSerializeValue(instance) || !pd.Attributes.Contains(DesignerSerializationVisibilityAttribute.Visible))&&( bIsSqlType == false)) { return; } Object propInst = pd.GetValue(instance) ; if (propInst is InternalDataCollectionBase) return; if (propInst is PropertyCollection) { return; } // Microsoft: perf: Why not have this as a table? // there are several xdo properties that equal to some xml attributes, we should not explicitly ouput them. if ( 0 == String.Compare(pd.Name, "Namespace" , StringComparison.Ordinal) || 0 == String.Compare(pd.Name, "PrimaryKey" , StringComparison.Ordinal) || 0 == String.Compare(pd.Name, "ColumnName" , StringComparison.Ordinal) || 0 == String.Compare(pd.Name, "DefaultValue" , StringComparison.Ordinal) || 0 == String.Compare(pd.Name, "TableName" , StringComparison.Ordinal) || 0 == String.Compare(pd.Name, "DataSetName" , StringComparison.Ordinal) || 0 == String.Compare(pd.Name, "AllowDBNull" , StringComparison.Ordinal) || 0 == String.Compare(pd.Name, "Unique" , StringComparison.Ordinal) || 0 == String.Compare(pd.Name, "NestedInDataSet" , StringComparison.Ordinal) || 0 == String.Compare(pd.Name, "Locale" , StringComparison.Ordinal) || 0 == String.Compare(pd.Name, "CaseSensitive", StringComparison.Ordinal) || 0 == String.Compare(pd.Name, "RemotingFormat" , StringComparison.Ordinal) ) { return; } if (bisDataColumn){ //(instance is DataColumn) { if (0 == String.Compare(pd.Name, "DataType", StringComparison.Ordinal)) { string dt = XmlDataTypeName(col.DataType); if(bIsSqlType || (col.DataType == typeof(System.Numerics.BigInteger))) { root.SetAttribute(Keywords.MSD_DATATYPE, Keywords.MSDNS, col.DataType.FullName); } else if ((dt.Length == 0) || bImplementsInullable || ((dt == Keywords.XSD_ANYTYPE) && (col.XmlDataType != Keywords.XSD_ANYTYPE))|| (col.DataType == typeof(DateTimeOffset))) { // in Whidbey, XmlDataTypeName function changed to return "anyType" for typeof(Object) // should still always hit this code path for all non-built in types // to handle version qualified typeof(Object) and other CDT objects correctly // we must write the output exactly the same way as we read it this.SetMSDataAttribute(root, col.DataType); } return; } if (0 == String.Compare(pd.Name, "Attribute", StringComparison.Ordinal)) { return; } } string textValue = pd.Converter.ConvertToString(propInst) ; root.SetAttribute(pd.Name, Keywords.MSDNS, textValue); return; } // internal static string XmlDataTypeName(Type type) { if (type == typeof(Char)) return "_"; // has to have SimpleType in this column. if (type == typeof(Byte[]) || type == typeof(SqlBytes)) return "base64Binary"; // has to have SimpleType in this column. if (type == typeof(DateTime) || type == typeof(SqlDateTime) ) return "dateTime"; if (type == typeof(TimeSpan)) return "duration"; if (type == typeof(Decimal)|| type == typeof(SqlDecimal) || type == typeof(SqlMoney)) return "decimal"; if (type == typeof(int)) return "int"; if (type == typeof(Boolean)|| type == typeof(SqlBoolean)) return "boolean"; if (type == typeof(Single)|| type == typeof(SqlSingle)) return "float"; if (type == typeof(double) || type == typeof(SqlDouble)) return "double"; if (type == typeof(SByte)|| type == typeof(SqlByte)) return "byte"; if (type == typeof(Byte)) return "unsignedByte"; if (type == typeof(Int16) || type == typeof(SqlInt16)) return "short"; if (type == typeof(Int32) || type == typeof(SqlInt32)) return "int"; if (type == typeof(Int64) || type == typeof(SqlInt64)) return "long"; if (type == typeof(UInt16)) return "unsignedShort"; if (type == typeof(UInt32)) return "unsignedInt"; if (type == typeof(UInt64)) return "unsignedLong"; if (type == typeof(System.Numerics.BigInteger)) return Keywords.XSD_ANYTYPE; //"integer"; if (type == typeof(Uri)) return "anyURI"; if (type == typeof(SqlBinary)) return "hexBinary"; if (type == typeof(string) ||type == typeof(SqlGuid) ||type == typeof(SqlString) || type == typeof(SqlChars)) return "string"; if (type == typeof(object) || type == typeof(SqlXml) || type == typeof(DateTimeOffset)) return Keywords.XSD_ANYTYPE; return String.Empty; // by default, if we dont map anything, we will map to String // but I can not make Sql Types that will map to string be unmapped, because in schema , I will miss the second part and wont // be able to differenciate between string snd SqlString and others that map to String } private void GenerateConstraintNames(DataTable table, bool fromTable) { // if constraint created obased on relation and it is self related rel. then add constraint StringBuilder builder = null; foreach(Constraint constr in table.Constraints) { if (fromTable) { if (constr is ForeignKeyConstraint) { // if parent table does not exist , no need to create FKConst if (!_tables.Contains((DataTable)(((ForeignKeyConstraint)constr).RelatedTable))) { continue; } } } int nameInt = 0; string name = constr.ConstraintName; while (ConstraintNames.Contains(name)) { if (null == builder) { builder = new StringBuilder(); } builder.Append(table.TableName).Append('_').Append(constr.ConstraintName); if (0 < nameInt) { builder.Append('_').Append(nameInt); } nameInt++; name = builder.ToString(); builder.Length = 0; } ConstraintNames.Add(name); constr.SchemaName = name; } } private void GenerateConstraintNames(ArrayList tables) { for (int i = 0; i < tables.Count; i++) { GenerateConstraintNames((DataTable)tables[i], true); } } private void GenerateConstraintNames(DataSet ds) { foreach(DataTable dt in ds.Tables) { GenerateConstraintNames(dt, false); } } //Does the DS or ANY object in it have ExtendedProperties? private static bool _PropsNotEmpty(PropertyCollection props) { return props != null && props.Count != 0; } private bool HaveExtendedProperties(DataSet ds) { if(_PropsNotEmpty(ds.extendedProperties)) { return true; } for(int t = 0; t < ds.Tables.Count; t ++) { DataTable table = ds.Tables[t]; if(_PropsNotEmpty(table.extendedProperties)) { return true; } for(int c = 0; c < table.Columns.Count; c ++) { if(_PropsNotEmpty(table.Columns[c].extendedProperties)) { return true; } } } // What is the best way to enumerate relations? from DataSet of from DataTable? for(int r = 0; r < ds.Relations.Count; r ++) { if(_PropsNotEmpty(ds.Relations[r].extendedProperties)) { return true; } } // What about constraints? return false; }// HaveExtendedProperties internal void WriteSchemaRoot(XmlDocument xd, XmlElement rootSchema, string targetNamespace) { /* if (_ds != null) rootSchema.SetAttribute(Keywords.XSDID, XmlConvert.EncodeLocalName(_ds.DataSetName)); else rootSchema.SetAttribute(Keywords.XSDID, XmlConvert.EncodeLocalName("NewDataSet")); */ if (!Common.ADP.IsEmpty(targetNamespace)) { rootSchema.SetAttribute(Keywords.TARGETNAMESPACE, targetNamespace ); rootSchema.SetAttribute(Keywords.XMLNS_MSTNS, targetNamespace ); } // Add the namespaces // rootSchema.SetAttribute(Keywords.XMLNS, Keywords.XSD_ATOM.String)); rootSchema.SetAttribute(Keywords.XMLNS, targetNamespace); rootSchema.SetAttribute(Keywords.XMLNS_XSD, Keywords.XSDNS); rootSchema.SetAttribute(Keywords.XMLNS_MSDATA, Keywords.MSDNS); if((_ds != null) && (HaveExtendedProperties(_ds))) { rootSchema.SetAttribute(Keywords.XMLNS_MSPROP, Keywords.MSPROPNS); } if (!Common.ADP.IsEmpty(targetNamespace)) { rootSchema.SetAttribute(Keywords.XSD_ATTRIBUTEFORMDEFAULT, Keywords.QUALIFIED); rootSchema.SetAttribute(Keywords.XSD_ELEMENTFORMDEFAULT, Keywords.QUALIFIED); } } internal static void ValidateColumnMapping(Type columnType) { if (DataStorage.IsTypeCustomType(columnType)) { throw ExceptionBuilder.InvalidDataColumnMapping(columnType); } } internal void SetupAutoGenerated(DataSet ds){ foreach (DataTable dt in ds.Tables) SetupAutoGenerated(dt); } internal void SetupAutoGenerated(ArrayList dt){ for(int i = 0; i < dt.Count; i++) { SetupAutoGenerated((DataTable)dt[i]); } } internal void SetupAutoGenerated(DataTable dt){ foreach (DataColumn col in dt.Columns) { if (AutoGenerated(col)) autogenerated[col] = col; } foreach (Constraint cs in dt.Constraints) { ForeignKeyConstraint fk = (cs as ForeignKeyConstraint); if (null != fk) { if (AutoGenerated(fk)) autogenerated[fk] = fk; else { if (autogenerated[fk.Columns[0]] != null) autogenerated[fk.Columns[0]] = null; if (autogenerated[fk.RelatedColumnsReference[0]] != null) autogenerated[fk.RelatedColumnsReference[0]] = null; // special case of the ghosted constraints: UniqueConstraint _constraint = (UniqueConstraint) fk.RelatedTable.Constraints.FindConstraint( new UniqueConstraint( "TEMP", fk.RelatedColumnsReference)); if (_constraint == null) continue; if(autogenerated[_constraint] != null) autogenerated[_constraint] = null; if(autogenerated[_constraint.Key.ColumnsReference[0]] != null) autogenerated[_constraint.Key.ColumnsReference[0]] = null; } } else { UniqueConstraint unique = (UniqueConstraint) cs; if (AutoGenerated(unique)) autogenerated[unique] = unique; else { if (autogenerated[unique.Key.ColumnsReference[0]] != null) autogenerated[unique.Key.ColumnsReference[0]] = null; } } } } private void CreateTablesHierarchy(DataTable dt) { // if (!dt.SerializeHierarchy) // return; foreach( DataRelation r in dt.ChildRelations ) { if (! _tables.Contains((DataTable)r.ChildTable)) { _tables.Add((DataTable)r.ChildTable); CreateTablesHierarchy(r.ChildTable); } } } private void CreateRelations(DataTable dt) { foreach( DataRelation r in dt.ChildRelations ) { if (! _relations.Contains((DataRelation)r)) { _relations.Add((DataRelation)r); // if (dt.SerializeHierarchy) CreateRelations(r.ChildTable); } } } private DataTable[] CreateToplevelTables() { ArrayList topTables = new ArrayList(); for (int i = 0; i < _tables.Count; i++) { DataTable table =(DataTable) _tables[i]; if (table.ParentRelations.Count == 0) topTables.Add(table); else { bool fNestedButNotSelfNested = false; for (int j = 0; j < table.ParentRelations.Count; j++) { if (table.ParentRelations[j].Nested) { if (table.ParentRelations[j].ParentTable == table) { fNestedButNotSelfNested = false; break; } fNestedButNotSelfNested = true; } } if (!fNestedButNotSelfNested) topTables.Add(table); } } if (topTables.Count == 0) return (new DataTable[0]); DataTable[] temp = new DataTable[topTables.Count]; topTables.CopyTo(temp, 0); return temp; } // SxS: this method can generate XSD files if the input xmlWriter is XmlTextWriter or DataTextWriter and its underlying stream is FileStream // These XSDs are located in the same folder as the underlying stream's file path (see SetPath method). // These XSDs are not exposed out of this method, so ResourceExposure annotation is None. [ResourceExposure(ResourceScope.None)] [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] internal void SchemaTree(XmlDocument xd, XmlWriter xmlWriter, DataSet ds, DataTable dt, bool writeHierarchy) { ConstraintNames = new ArrayList(); autogenerated = new Hashtable(); bool genSecondary = filePath != null; //null non-file based streams. dsElement = xd.CreateElement(Keywords.XSD_PREFIX, Keywords.XSD_ELEMENT, Keywords.XSDNS); DataTable [] top; bool fFlat = false; DataTable _dt = dt; if (ds != null) { _ds = ds; foreach(DataTable table in ds.Tables) { _tables.Add(table); } } else { if (dt.DataSet != null) { // preserve datatable's dataset to use for xml // if null it would write out document element instead of dt.DataSet.DataSetName _ds = dt.DataSet; } _tables.Add(dt); if (writeHierarchy) { CreateTablesHierarchy(dt); } } _dc = xd; namespaces = new Hashtable(); prefixes = new Hashtable(); XmlElement rootSchema = xd.CreateElement(Keywords.XSD_PREFIX, Keywords.XSD_SCHEMA, Keywords.XSDNS); _sRoot = rootSchema; // Need to writeid attribute on schema, as webservice relys on it for typeddataset deserialization // to get class name if (_ds != null) { rootSchema.SetAttribute(Keywords.XSDID, XmlConvert.EncodeLocalName(_ds.DataSetName)); } else { rootSchema.SetAttribute(Keywords.XSDID, XmlConvert.EncodeLocalName("NewDataSet")); } if (_ds != null) { WriteSchemaRoot(xd, rootSchema, _ds.Namespace); } else { WriteSchemaRoot(xd, rootSchema, _dt.Namespace); } // register the root element and associated NS if (schFormat == SchemaFormat.Remoting) { if (_ds != null) { namespaces[_ds.Namespace] = rootSchema; } else { namespaces[_dt.Namespace] = rootSchema; } } if (schFormat != SchemaFormat.Remoting) { if (_ds != null) { namespaces[_ds.Namespace] = rootSchema; if (_ds.Namespace.Length == 0) prefixes[_ds.Namespace] = null; else { // generate a prefix for the dataset schema itself. rootSchema.SetAttribute(Keywords.XMLNS_MSTNS, _ds.Namespace ); prefixes[_ds.Namespace] = "mstns"; } } } // Generate all the constraint names if (ds != null) GenerateConstraintNames(ds); else GenerateConstraintNames(_tables); // Setup AutoGenerated table if (schFormat != SchemaFormat.Remoting) { if (ds != null) { SetupAutoGenerated(ds); } else { SetupAutoGenerated(_tables); } } // // Output all top level elements, which will recursively invoke to other tables. // top = ((ds != null) ? ds.TopLevelTables(true) : CreateToplevelTables()); if (top.Length == 0 || schFormat == SchemaFormat.WebServiceSkipSchema || schFormat == SchemaFormat.RemotingSkipSchema) { // return an empty schema for now. // probably we need to throw an exception FillDataSetElement(xd, ds, dt); rootSchema.AppendChild(dsElement); AddXdoProperties(_ds, dsElement, xd ); AddExtendedProperties(ds.extendedProperties, dsElement); xd.AppendChild(rootSchema); xd.Save(xmlWriter); xmlWriter.Flush(); return ; // rootSchema content has already been pushed to xmlWriter } // if (schFormat != SchemaFormat.WebService && namespaces.Count > 1 && !genSecondary) { // rootSchema.SetAttribute(Keywords.MSD_FRAGMENTCOUNT, Keywords.MSDNS, namespaces.Count.ToString()); // } // Fill out dataset element XmlElement dsCompositor = FillDataSetElement(xd, ds, dt); constraintSeparator = xd.CreateElement(Keywords.XSD_PREFIX, "SHOULDNOTBEHERE", Keywords.XSDNS); dsElement.AppendChild(constraintSeparator); // DataSet properties if (_ds != null) { AddXdoProperties(_ds, dsElement, xd ); AddExtendedProperties(_ds.extendedProperties, dsElement); } for (int i = 0; i < top.Length; i++) { XmlElement el = HandleTable(top[i], xd, rootSchema); if (((_ds != null )&& (_ds.Namespace == top[i].Namespace)) || Common.ADP.IsEmpty(top[i].Namespace) || (schFormat == SchemaFormat.Remoting)) { bool fNestedInDataset = top[i].fNestedInDataset; if (((_ds != null )&& (_ds.Namespace.Length != 0)) && Common.ADP.IsEmpty(top[i].Namespace)) { fNestedInDataset = true; } // what if dt has two nested relation , one self nested , the other with dtParent if (top[i].SelfNested) { // regarding above check : is it selfnested! fNestedInDataset = false; } if (top[i].NestedParentsCount > 1) { // if it has multiple parents, it should be global fNestedInDataset = false; } if(fNestedInDataset) { //deal with maxOccurs properly if (top[i].MinOccurs != 1) { el.SetAttribute(Keywords.MINOCCURS, top[i].MinOccurs.ToString(CultureInfo.InvariantCulture)); } if (top[i].MaxOccurs == -1){ el.SetAttribute(Keywords.MAXOCCURS, Keywords.ZERO_OR_MORE); } else if (top[i].MaxOccurs != 1){ el.SetAttribute(Keywords.MAXOCCURS, top[i].MaxOccurs.ToString(CultureInfo.InvariantCulture)); } } if (!fNestedInDataset) { rootSchema.AppendChild(el); XmlElement node = xd.CreateElement(Keywords.XSD_PREFIX, Keywords.XSD_ELEMENT, Keywords.XSDNS); if ((_ds != null && _ds.Namespace == top[i].Namespace) || Common.ADP.IsEmpty(top[i].Namespace) || (schFormat == SchemaFormat.Remoting)) node.SetAttribute(Keywords.REF, top[i].EncodedTableName); else node.SetAttribute(Keywords.REF, ((string)prefixes[top[i].Namespace])+':'+top[i].EncodedTableName); dsCompositor.AppendChild(node); } else dsCompositor.AppendChild(el); } else { AppendChildWithoutRef(rootSchema, top[i].Namespace, el, Keywords.XSD_ELEMENT); XmlElement node = xd.CreateElement(Keywords.XSD_PREFIX, Keywords.XSD_ELEMENT, Keywords.XSDNS); node.SetAttribute(Keywords.REF, ((string)prefixes[top[i].Namespace])+':'+top[i].EncodedTableName); dsCompositor.AppendChild(node); } } dsElement.RemoveChild(constraintSeparator); rootSchema.AppendChild(dsElement); // Output all non-heirarchical relations without constraints DataRelation [] rels = new DataRelation[0]; if (ds != null && _tables.Count> 0) { // we need to make sure we want to write relation just for tables in list rels = new DataRelation[ds.Relations.Count]; for (int i = 0 ; i < ds.Relations.Count ; i++) { rels[i] = ds.Relations[i]; } } else if (writeHierarchy && _tables.Count > 0 ) { CreateRelations((DataTable)_tables[0]); rels = new DataRelation[_relations.Count]; _relations.CopyTo(rels, 0); } XmlElement nodeAnn = null; XmlElement nodeApp = null; for (int i = 0; i < rels.Length; ++i) { DataRelation rel = rels[i]; if (!rel.Nested || fFlat) { if (rel.ChildKeyConstraint == null) { if (nodeAnn == null) { nodeAnn = xd.CreateElement(Keywords.XSD_PREFIX, Keywords.XSD_ANNOTATION, Keywords.XSDNS); rootSchema.AppendChild(nodeAnn); nodeApp = xd.CreateElement(Keywords.XSD_PREFIX, Keywords.XSD_APPINFO, Keywords.XSDNS); nodeAnn.AppendChild(nodeApp); } Debug.Assert(nodeApp != null, "Need to create node first."); nodeApp.AppendChild(HandleRelation(rel, xd)); } } } XmlComment comment = null; bool isMultipleNamespaceAndStreamingWriter = (namespaces.Count > 1 && !genSecondary); if (schFormat != SchemaFormat.Remoting && schFormat != SchemaFormat.RemotingSkipSchema) { // complete processing of rootSchema foreach (string ns in namespaces.Keys) { if (ns == ((_ds != null) ? _ds.Namespace : _dt.Namespace) || Common.ADP.IsEmpty(ns)) { continue; } XmlElement _import = xd.CreateElement(Keywords.XSD_PREFIX, Keywords.XSD_IMPORT, Keywords.XSDNS); _import.SetAttribute(Keywords.XSD_NAMESPACE, ns); if ( schFormat != SchemaFormat.WebService && !isMultipleNamespaceAndStreamingWriter) { _import.SetAttribute(Keywords.XSD_SCHEMALOCATION, fileName + "_" + prefixes[ns] + ".xsd"); } ((XmlNode)rootSchema).PrependChild((XmlNode)_import); } if (schFormat != SchemaFormat.WebService && isMultipleNamespaceAndStreamingWriter) { rootSchema.SetAttribute(Keywords.MSD_FRAGMENTCOUNT, Keywords.MSDNS, namespaces.Count.ToString(CultureInfo.InvariantCulture)); } // Post rootSchema content to xmlWriter. xd.AppendChild(rootSchema); // KB if (schFormat != SchemaFormat.WebService && isMultipleNamespaceAndStreamingWriter) { xd.WriteTo(xmlWriter); } else { xd.Save(xmlWriter); } xd.RemoveChild(rootSchema); //KB foreach(string ns in namespaces.Keys) { if (ns == ((_ds != null)?_ds.Namespace:_dt.Namespace) || Common.ADP.IsEmpty(ns)) { continue; } XmlWriter xw = null; if (!genSecondary) { xw = xmlWriter; } else { xw = new XmlTextWriter(filePath + fileName + "_" + prefixes[ns] + ".xsd", null); } try { if (genSecondary) { if (xw is XmlTextWriter) { ((XmlTextWriter)xw).Formatting = Formatting.Indented; } xw.WriteStartDocument(true); } XmlElement tNode = (XmlElement) namespaces[ns] ; _dc.AppendChild( tNode ); foreach(string imp_ns in namespaces.Keys) { if (ns == imp_ns) { continue; // don't write out yourself } string prefix = (string) prefixes[imp_ns]; if (prefix == null) { // only for dataset.Namespace == empty continue; // do nothing } tNode.SetAttribute("xmlns:"+prefix, imp_ns); XmlElement _import2 = _dc.CreateElement(Keywords.XSD_PREFIX, Keywords.XSD_IMPORT, Keywords.XSDNS); _import2.SetAttribute(Keywords.XSD_NAMESPACE, imp_ns); if ( schFormat != SchemaFormat.WebService && !isMultipleNamespaceAndStreamingWriter) { if (imp_ns == ((_ds != null)?_ds.Namespace:_dt.Namespace)) _import2.SetAttribute(Keywords.XSD_SCHEMALOCATION, fileName + fileExt); // for the dataset namespace don't append anything else _import2.SetAttribute(Keywords.XSD_SCHEMALOCATION, fileName + "_" + prefix +".xsd"); } ((XmlNode)tNode).PrependChild((XmlNode)_import2); } if (schFormat != SchemaFormat.WebService && isMultipleNamespaceAndStreamingWriter) { _dc.WriteTo(xw); } else { _dc.Save(xw); } _dc.RemoveChild( tNode ); if (genSecondary) { xw.WriteEndDocument(); } } finally { if (genSecondary) { xw.Close(); } } } } else { xd.AppendChild(rootSchema); xd.Save(xmlWriter); } if (comment != null) { ((XmlNode)rootSchema).PrependChild((XmlNode)comment); } if (!genSecondary) { xmlWriter.Flush(); } return;// rootSchema; } internal XmlElement SchemaTree(XmlDocument xd, DataTable dt) { dsElement = xd.CreateElement(Keywords.XSD_PREFIX, Keywords.XSD_ELEMENT, Keywords.XSDNS); ConstraintNames = new ArrayList(); _ds = dt.DataSet; _dc = xd; namespaces = new Hashtable(); prefixes = new Hashtable(); if (schFormat != SchemaFormat.Remoting) { autogenerated = new Hashtable(); } XmlElement rootSchema = xd.CreateElement(Keywords.XSD_PREFIX, Keywords.XSD_SCHEMA, Keywords.XSDNS); _sRoot = rootSchema; WriteSchemaRoot(xd, rootSchema, dt.Namespace); XmlElement dsCompositor = FillDataSetElement(xd, null, dt); constraintSeparator = xd.CreateElement(Keywords.XSD_PREFIX, "SHOULDNOTBEHERE", Keywords.XSDNS); dsElement.AppendChild(constraintSeparator); if (schFormat != SchemaFormat.Remoting) { if (_ds != null) { namespaces[_ds.Namespace] = rootSchema; if (_ds.Namespace.Length == 0) { prefixes[_ds.Namespace] = null; } else { // generate a prefix for the dataset schema itself. rootSchema.SetAttribute(Keywords.XMLNS_MSTNS, _ds.Namespace ); prefixes[_ds.Namespace] = "mstns"; } } else { namespaces[dt.Namespace] = rootSchema; if (dt.Namespace.Length == 0) { prefixes[dt.Namespace] = null; } else { // generate a prefix for the dataset schema itself. rootSchema.SetAttribute(Keywords.XMLNS_MSTNS, dt.Namespace ); prefixes[dt.Namespace] = "mstns"; } } } // Generate all the constraint names GenerateConstraintNames(dt, true); // // Output all top level elements, which will recursively invoke to other tables. // XmlElement el = HandleTable(dt, xd, rootSchema, false); rootSchema.AppendChild(el); dsElement.RemoveChild(constraintSeparator); rootSchema.AppendChild(dsElement); return rootSchema; } internal XmlElement FillDataSetElement(XmlDocument xd, DataSet ds, DataTable dt) { DataSet dataSet = (ds != null) ? ds : dt.DataSet; if (dataSet != null) { dsElement.SetAttribute(Keywords.NAME, XmlConvert.EncodeLocalName(dataSet.DataSetName)); dsElement.SetAttribute(Keywords.MSD_ISDATASET, Keywords.MSDNS, Keywords.TRUE); if (ds == null) dsElement.SetAttribute(Keywords.MSD_MAINDATATABLE, Keywords.MSDNS, XmlConvert.EncodeLocalName(((dt.Namespace.Length == 0)?dt.TableName : (dt.Namespace + ":" + dt.TableName)))); // Add CaseSensitive and locale properties if (dataSet.CaseSensitive) { dsElement.SetAttribute(Keywords.MSD_CASESENSITIVE, Keywords.MSDNS, Keywords.TRUE); } if (dataSet.ShouldSerializeLocale() || !dataSet.Locale.Equals(CultureInfo.CurrentCulture)) { dsElement.SetAttribute(Keywords.MSD_LOCALE, Keywords.MSDNS, dataSet.Locale.ToString()); } else { dsElement.SetAttribute(Keywords.MSD_USECURRENTLOCALE, Keywords.MSDNS, Keywords.TRUE); } } else { // No DataSet if (dt != null) { dsElement.SetAttribute(Keywords.NAME, XmlConvert.EncodeLocalName("NewDataSet")); dsElement.SetAttribute(Keywords.MSD_ISDATASET, Keywords.MSDNS, Keywords.TRUE); dsElement.SetAttribute(Keywords.MSD_MAINDATATABLE, Keywords.MSDNS, XmlConvert.EncodeLocalName(((dt.Namespace.Length == 0)?dt.TableName : (dt.Namespace + ":" + dt.TableName)))); if (dt.CaseSensitive) { // WebData 111631 :it is a dsElement.SetAttribute(Keywords.MSD_CASESENSITIVE, Keywords.MSDNS, Keywords.TRUE); } if (dt.ShouldSerializeLocale() || !dt.Locale.Equals(CultureInfo.CurrentCulture)) { dsElement.SetAttribute(Keywords.MSD_LOCALE, Keywords.MSDNS, dt.Locale.ToString()); } else { dsElement.SetAttribute(Keywords.MSD_USECURRENTLOCALE, Keywords.MSDNS, Keywords.TRUE); } } } XmlElement type = xd.CreateElement(Keywords.XSD_PREFIX, Keywords.XSD_COMPLEXTYPE, Keywords.XSDNS); dsElement.AppendChild(type); XmlElement compositor = xd.CreateElement(Keywords.XSD_PREFIX, Keywords.XSD_CHOICE, Keywords.XSDNS); compositor.SetAttribute(Keywords.MINOCCURS, Keywords.ZERO_DIGIT); compositor.SetAttribute(Keywords.MAXOCCURS, Keywords.ZERO_OR_MORE); type.AppendChild(compositor); return compositor; } internal void SetPath(XmlWriter xw){ FileStream fs = null; DataTextWriter sw = xw as DataTextWriter; fs = (sw != null) ? sw.BaseStream as FileStream : null ; if (fs == null) { XmlTextWriter textw = xw as XmlTextWriter; if (textw == null) return; fs = textw.BaseStream as FileStream; if (fs == null) return; } this.filePath = Path.GetDirectoryName(fs.Name); this.fileName = Path.GetFileNameWithoutExtension(fs.Name); this.fileExt = Path.GetExtension(fs.Name); if (!Common.ADP.IsEmpty(this.filePath)) this.filePath = filePath + "\\"; } internal void Save(DataSet ds, XmlWriter xw) { Save(ds, (DataTable)null, xw); } internal void Save(DataTable dt, XmlWriter xw) { XmlDocument doc = new XmlDocument(); if (schFormat == SchemaFormat.Public) { SetPath(xw); } XmlElement rootSchema = SchemaTree(doc, dt); doc.AppendChild( rootSchema ); doc.Save(xw); } internal void Save(DataSet ds, DataTable dt, XmlWriter xw) { Save(ds, dt, xw, false); } internal void Save(DataSet ds, DataTable dt, XmlWriter xw, bool writeHierarchy) { this.Save(ds, dt, xw, writeHierarchy, null); } internal void Save(DataSet ds, DataTable dt, XmlWriter xw, bool writeHierarchy, Converter multipleTargetConverter) { this.targetConverter = multipleTargetConverter; XmlDocument doc = new XmlDocument(); if (schFormat == SchemaFormat.Public) { SetPath(xw); } if (schFormat == SchemaFormat.WebServiceSkipSchema && xw.WriteState==WriteState.Element) { xw.WriteAttributeString(Keywords.MSD, Keywords.MSD_SCHEMASERIALIZATIONMODE, Keywords.MSDNS, Keywords.MSD_EXCLUDESCHEMA); } SchemaTree(doc, xw, ds, dt, writeHierarchy); } internal XmlElement HandleRelation(DataRelation rel, XmlDocument dc) { XmlElement root = dc.CreateElement(Keywords.MSD, Keywords.MSD_RELATION, Keywords.MSDNS); // convert relation name to valid xml name root.SetAttribute( Keywords.NAME, XmlConvert.EncodeLocalName( rel.RelationName )); root.SetAttribute(Keywords.MSD_PARENT, Keywords.MSDNS, rel.ParentKey.Table.EncodedTableName); root.SetAttribute(Keywords.MSD_CHILD, Keywords.MSDNS, rel.ChildKey.Table.EncodedTableName); if ((_ds == null) || (_ds.Tables.InternalIndexOf(rel.ParentKey.Table.TableName) ==-3)) root.SetAttribute( Keywords.MSD_PARENTTABLENS, Keywords.MSDNS, rel.ParentKey.Table.Namespace); if ((_ds == null) || (_ds.Tables.InternalIndexOf(rel.ChildKey.Table.TableName) ==-3)) root.SetAttribute( Keywords.MSD_CHILDTABLENS, Keywords.MSDNS, rel.ChildKey.Table.Namespace); DataColumn[] key = rel.ParentKey.ColumnsReference; string text = key[0].EncodedColumnName; StringBuilder builder = null; if (1 < key.Length) { builder = new StringBuilder(); builder.Append(text); for (int i = 1; i < key.Length; i++) { builder.Append(Keywords.MSD_KEYFIELDSEP).Append(key[i].EncodedColumnName); } text = builder.ToString(); } root.SetAttribute( Keywords.MSD_PARENTKEY, Keywords.MSDNS, text); key = rel.ChildKey.ColumnsReference; text = key[0].EncodedColumnName; if (1 < key.Length) { if (null != builder) { builder.Length = 0; } else { builder = new StringBuilder(); } builder.Append(text); for (int i = 1; i < key.Length; i++) { builder.Append(Keywords.MSD_KEYFIELDSEP).Append(key[i].EncodedColumnName); } text = builder.ToString(); } root.SetAttribute( Keywords.MSD_CHILDKEY, Keywords.MSDNS, text); AddExtendedProperties(rel.extendedProperties, root); return root; } private static XmlElement FindSimpleType(XmlElement schema, string name) { for (XmlNode n = schema.FirstChild; n != null; n = n.NextSibling) { if (n is XmlElement) { XmlElement e = (XmlElement) n; if(e.GetAttribute(Keywords.NAME) == name) { return e; } } } return null; }// FindSimpleType internal XmlElement GetSchema(string NamespaceURI) { XmlElement schemaEl = (XmlElement) namespaces[NamespaceURI]; if (schemaEl == null) { schemaEl = _dc.CreateElement(Keywords.XSD_PREFIX, Keywords.XSD_SCHEMA, Keywords.XSDNS); WriteSchemaRoot(_dc, schemaEl, NamespaceURI); if (!Common.ADP.IsEmpty(NamespaceURI)) { string prefix = Keywords.APP+Convert.ToString(++prefixCount, CultureInfo.InvariantCulture); _sRoot.SetAttribute("xmlns:"+prefix, NamespaceURI); schemaEl.SetAttribute("xmlns:"+prefix, NamespaceURI); prefixes[NamespaceURI] = prefix; } namespaces[NamespaceURI] = schemaEl; } return schemaEl; } internal void HandleColumnType(DataColumn col, XmlDocument dc, XmlElement root, XmlElement schema) { string keyword = Keywords.TYPE; if (col.ColumnMapping == MappingType.SimpleContent) keyword = Keywords.BASE; if (col.SimpleType != null) { // generate simpleType node SimpleType stNode = col.SimpleType; while (stNode != null) { // for remoting, set the msdata:targetNamespace for the simpleType. XmlNode type; string name = stNode.Name; if (name != null && name.Length != 0) { // For remoting, always need to work with root schema's namespace string nSpace = (schFormat != SchemaFormat.Remoting) ? stNode.Namespace : (col.Table.DataSet != null ? col.Table.DataSet.Namespace : col.Table.Namespace); // for remoting we need to use columns NS, for other cases it is wrong to get Columns NS, we need to take type's namespace XmlElement schNode= GetSchema(nSpace); //SchNode To Ensure BaseSimpleType Prefix is Generated if (stNode.BaseSimpleType != null && stNode.BaseSimpleType.Namespace != null && stNode.BaseSimpleType.Namespace.Length>0) GetSchema(stNode.BaseSimpleType.Namespace); //it will ensure a prefix has been created for this namespace type = stNode.ToNode(dc, prefixes, (schFormat == SchemaFormat.Remoting)); if (stNode == col.SimpleType) { string prefix = (string) prefixes[nSpace]; // set the columns's type if (prefix != null && prefix.Length > 0) { if (schFormat != SchemaFormat.Remoting) root.SetAttribute(keyword,(prefix + ":" + name)); // look at below,this loop assumes we would be here just oen time: Its Wrong else // As all types (in remoting) belong to the same namespace, just write type name root.SetAttribute(keyword, name); } else root.SetAttribute(keyword, name); // set the root to the actual type, do not overwrite it in the iteration. } XmlElement elmSimpeType = FindSimpleType(schNode, name); if(elmSimpeType == null) { // if we don't have the defenition for this simpleType yet. Add it schNode.AppendChild(type); }else { #if DEBUG // Microsoft: TO DO: replace the constructor with IsEqual(XmlElement) // Debug.Assert(col.SimpleType.IsEqual(new SimpleType(elmSimpeType)), "simpleTypes with the same name have to be the same: "+name); #endif } } else { //SchNode To Ensure BaseSimpleType Prefix is Generated if (stNode.BaseSimpleType != null && stNode.BaseSimpleType.Namespace != null && stNode.BaseSimpleType.Namespace.Length>0) GetSchema(stNode.BaseSimpleType.Namespace); //it will ensure a prefix has been created for this namespace type = stNode.ToNode(dc, prefixes, schFormat == SchemaFormat.Remoting); root.AppendChild(type); } stNode = stNode.BaseSimpleType; } } else if (col.XmlDataType != null && col.XmlDataType.Length != 0 && XSDSchema.IsXsdType(col.XmlDataType)) { root.SetAttribute(keyword, XSDSchema.QualifiedName(col.XmlDataType)); } else { string typeName = XmlDataTypeName(col.DataType); // do not update the hashtable, as it will not write msdata:DataType if (typeName == null || typeName.Length == 0) { if (col.DataType == typeof(Guid) || col.DataType == typeof(Type) ) { typeName = "string"; } else { if (col.ColumnMapping == MappingType.Attribute) { XmlTreeGen.ValidateColumnMapping(col.DataType); } typeName = Keywords.XSD_ANYTYPE; } } root.SetAttribute(keyword, XSDSchema.QualifiedName(typeName)); } } internal void AddColumnProperties(DataColumn col, XmlElement root){ if (col.DataType != typeof(String)) { string dt = XmlDataTypeName(col.DataType); if ((col.IsSqlType && ((dt.Length == 0) || col.ImplementsINullable)) || (typeof(SqlXml) == col.DataType) || col.DataType == typeof(DateTimeOffset) || col.DataType == typeof(System.Numerics.BigInteger)) { // no need to check if it is Sql typee if it already implements INullable, root.SetAttribute(Keywords.MSD_DATATYPE, Keywords.MSDNS, col.DataType.FullName); } else if ((dt.Length == 0) || col.ImplementsINullable || ((dt == Keywords.XSD_ANYTYPE) && (col.XmlDataType != Keywords.XSD_ANYTYPE))) { // in Whidbey, XmlDataTypeName function changed to return "anyType" for typeof(Object) // should still always hit this code path for all non-built in types // to handle version qualified typeof(Object) and other CDT objects correctly // we must write the output exactly the same way as we read it this.SetMSDataAttribute(root, col.DataType); } } if (col.ReadOnly) root.SetAttribute("ReadOnly", Keywords.MSDNS, Keywords.TRUE); if (col.Expression.Length != 0) root.SetAttribute("Expression", Keywords.MSDNS, col.Expression); if (col.AutoIncrement) { root.SetAttribute("AutoIncrement", Keywords.MSDNS, Keywords.TRUE); } if (col.AutoIncrementSeed !=0 ) root.SetAttribute("AutoIncrementSeed", Keywords.MSDNS, col.AutoIncrementSeed.ToString(CultureInfo.InvariantCulture)); if (col.AutoIncrementStep !=1 ) root.SetAttribute("AutoIncrementStep", Keywords.MSDNS, col.AutoIncrementStep.ToString(CultureInfo.InvariantCulture)); if (col.Caption != col.ColumnName) root.SetAttribute("Caption", Keywords.MSDNS, col.Caption); if (col.Prefix.Length != 0) root.SetAttribute("Prefix", Keywords.MSDNS, col.Prefix); if (col.DataType == typeof(DateTime) && col.DateTimeMode != DataSetDateTime.UnspecifiedLocal) { root.SetAttribute("DateTimeMode", Keywords.MSDNS, col.DateTimeMode.ToString()); } } private string FindTargetNamespace(DataTable table) { string tgNamespace = table.TypeName.IsEmpty ? table.Namespace : table.TypeName.Namespace; if (Common.ADP.IsEmpty(tgNamespace)) { DataRelation [] nestedParentRelations = table.NestedParentRelations; if (nestedParentRelations.Length != 0) { for(int i = 0; i < nestedParentRelations.Length; i++) { DataTable parentTable = nestedParentRelations[i].ParentTable; if (table != parentTable) {// table can be self nested so it may go to infinite loop! tgNamespace = FindTargetNamespace(parentTable); if (!Common.ADP.IsEmpty(tgNamespace)) { break; } } } } else { // if it does not have any parent table , then it should inherit NS from DataSet tgNamespace = _ds.Namespace; } } return tgNamespace; } internal XmlElement HandleColumn(DataColumn col, XmlDocument dc, XmlElement schema, bool fWriteOrdinal) { XmlElement root; int minOccurs; Debug.Assert(col.ColumnMapping != MappingType.SimpleContent , "Illegal state"); String refString = (col.ColumnMapping != MappingType.Element) ? Keywords.XSD_ATTRIBUTE : Keywords.XSD_ELEMENT; root = dc.CreateElement(Keywords.XSD_PREFIX, refString, Keywords.XSDNS); // First add any attributes. root.SetAttribute( Keywords.NAME, col.EncodedColumnName); if (col.Namespace.Length == 0) { DataTable _table = col.Table; // We need to travese the hirerarchy to find the targetnamepace string tgNamespace = FindTargetNamespace(_table); if (col.Namespace != tgNamespace) { root.SetAttribute( Keywords.FORM, Keywords.UNQUALIFIED); } } if (col.GetType() != typeof(DataColumn)) AddXdoProperties(col, root, dc); else AddColumnProperties(col, root); AddExtendedProperties(col.extendedProperties, root); HandleColumnType(col, dc, root, schema); if (col.ColumnMapping == MappingType.Hidden) { // CDT / UDT can not be mapped to Hidden column if (!col.AllowDBNull) root.SetAttribute(Keywords.MSD_ALLOWDBNULL, Keywords.MSDNS, Keywords.FALSE); if (!col.DefaultValueIsNull) if (col.DataType == typeof(bool)) root.SetAttribute(Keywords.MSD_DEFAULTVALUE, Keywords.MSDNS, (bool)(col.DefaultValue)? Keywords.TRUE : Keywords.FALSE); else { XmlTreeGen.ValidateColumnMapping(col.DataType); root.SetAttribute(Keywords.MSD_DEFAULTVALUE, Keywords.MSDNS, col.ConvertObjectToXml(col.DefaultValue)); } } if ((!col.DefaultValueIsNull)&& (col.ColumnMapping != MappingType.Hidden)){ XmlTreeGen.ValidateColumnMapping(col.DataType); if (col.ColumnMapping == MappingType.Attribute && !col.AllowDBNull ) { if (col.DataType == typeof(bool)) { root.SetAttribute(Keywords.MSD_DEFAULTVALUE, Keywords.MSDNS, (bool)(col.DefaultValue)? Keywords.TRUE : Keywords.FALSE); } else { // CDT / UDT columns cn not be mapped to Attribute also root.SetAttribute(Keywords.MSD_DEFAULTVALUE, Keywords.MSDNS, col.ConvertObjectToXml(col.DefaultValue)); } } else { // Element Column : need to handle CDT if (col.DataType == typeof(bool)) { root.SetAttribute(Keywords.DEFAULT, (bool)(col.DefaultValue)? Keywords.TRUE : Keywords.FALSE); } else { if (!col.IsCustomType) { // built in type root.SetAttribute(Keywords.DEFAULT, col.ConvertObjectToXml(col.DefaultValue)); } else { // UDT column } } } } if (schFormat == SchemaFormat.Remoting) root.SetAttribute( Keywords.TARGETNAMESPACE, Keywords.MSDNS, col.Namespace); else { if ((col.Namespace != (col.Table.TypeName.IsEmpty ? col.Table.Namespace : col.Table.TypeName.Namespace)) && (col.Namespace.Length != 0)) { XmlElement schNode = GetSchema(col.Namespace); if (FindTypeNode(schNode, col.EncodedColumnName) == null) schNode.AppendChild(root); root = _dc.CreateElement(Keywords.XSD_PREFIX, refString, Keywords.XSDNS); root.SetAttribute( Keywords.REF, prefixes[ col.Namespace]+":"+ col.EncodedColumnName); if (col.Table.Namespace!=_ds.Namespace) { string prefix = (string)prefixes[col.Namespace]; XmlElement tNode = GetSchema(col.Table.Namespace); } } } minOccurs = (col.AllowDBNull) ? 0 : 1; // Microsoft 2001 change if (col.ColumnMapping == MappingType.Attribute && minOccurs != 0) root.SetAttribute(Keywords.USE, Keywords.REQUIRED); if (col.ColumnMapping == MappingType.Hidden) { root.SetAttribute(Keywords.USE, Keywords.PROHIBITED); } else if (col.ColumnMapping != MappingType.Attribute && minOccurs != 1) root.SetAttribute(Keywords.MINOCCURS, minOccurs.ToString(CultureInfo.InvariantCulture)); if ((col.ColumnMapping == MappingType.Element) && fWriteOrdinal) root.SetAttribute(Keywords.MSD_ORDINAL,Keywords.MSDNS, col.Ordinal.ToString(CultureInfo.InvariantCulture)); return root; } internal static string TranslateAcceptRejectRule( AcceptRejectRule rule ) { switch (rule) { case AcceptRejectRule.Cascade: return "Cascade"; case AcceptRejectRule.None: return "None"; default: return null; } } internal static string TranslateRule( Rule rule ) { switch (rule) { case Rule.Cascade: return "Cascade"; case Rule.None: return "None"; case Rule.SetNull: return "SetNull"; case Rule.SetDefault: return "SetDefault"; default: return null; } } internal void AppendChildWithoutRef(XmlElement node, string Namespace, XmlElement el, string refString) { XmlElement schNode = GetSchema(Namespace); if (FindTypeNode(schNode, el.GetAttribute(Keywords.NAME)) == null) schNode.AppendChild(el); } internal XmlElement FindTypeNode(XmlElement node, string strType) { if (node == null) return null; for (XmlNode n = node.FirstChild; n != null; n = n.NextSibling) { if (!(n is XmlElement)) continue; XmlElement child = (XmlElement) n; if (XSDSchema.FEqualIdentity(child, Keywords.XSD_ELEMENT, Keywords.XSDNS) || XSDSchema.FEqualIdentity(child, Keywords.XSD_ATTRIBUTE, Keywords.XSDNS) || XSDSchema.FEqualIdentity(child, Keywords.XSD_COMPLEXTYPE, Keywords.XSDNS) || XSDSchema.FEqualIdentity(child, Keywords.XSD_SIMPLETYPE, Keywords.XSDNS)) { if (child.GetAttribute(Keywords.NAME) == strType) return child; } } return null; } internal XmlElement HandleTable(DataTable table, XmlDocument dc, XmlElement schema) { return HandleTable(table, dc, schema, true); } // we write out column Ordinals only if the table contains columns // that map both to Attributes and Elements private bool HasMixedColumns(DataTable table) { bool hasAttributes = false; bool hasElements = false; foreach(DataColumn col in table.Columns) { if (!hasElements && col.ColumnMapping == MappingType.Element) hasElements = true; if (!hasAttributes && (col.ColumnMapping == MappingType.Attribute || col.ColumnMapping == MappingType.Hidden)) hasAttributes = !AutoGenerated(col); if (hasAttributes && hasElements) return true; } return false; } internal static bool AutoGenerated(DataColumn col) { // for now we use just this simple logic for the columns. if (col.ColumnMapping != MappingType.Hidden) return false; if (col.DataType != typeof(int)) return false; string generatedname = col.Table.TableName+"_Id"; if ((col.ColumnName == generatedname) || (col.ColumnName == generatedname+"_0")) return true; generatedname = ""; foreach (DataRelation rel in col.Table.ParentRelations) { if (!rel.Nested) continue; if (rel.ChildColumnsReference.Length != 1) continue; if (rel.ChildColumnsReference[0] != col) continue; if (rel.ParentColumnsReference.Length != 1) continue; //ok if we are here it means that we have a 1column-1column relation generatedname = rel.ParentColumnsReference[0].Table.TableName+"_Id"; } if ((col.ColumnName == generatedname) || (col.ColumnName == generatedname+"_0")) return true; return false; } internal static bool AutoGenerated(DataRelation rel) { string rName = rel.ParentTable.TableName + "_" + rel.ChildTable.TableName; if (!rel.RelationName.StartsWith(rName, StringComparison.Ordinal)) return false; if (rel.ExtendedProperties.Count > 0) return false; return true; } internal static bool AutoGenerated(UniqueConstraint unique) { // for now we use just this simple logic for the columns. if (!unique.ConstraintName.StartsWith("Constraint", StringComparison.Ordinal)) return false; if (unique.Key.ColumnsReference.Length !=1) return false; if (unique.ExtendedProperties.Count > 0) return false; return AutoGenerated(unique.Key.ColumnsReference[0]); } private bool AutoGenerated(ForeignKeyConstraint fk) { return AutoGenerated(fk, true); } internal static bool AutoGenerated(ForeignKeyConstraint fk, bool checkRelation) { // for now we use just this simple logic for the columns. DataRelation rel = fk.FindParentRelation(); if (checkRelation) { if (rel == null) return false; // otherwise roundtrip will create column if (!AutoGenerated(rel)) return false; if (rel.RelationName != fk.ConstraintName) return false; } if (fk.ExtendedProperties.Count > 0) return false; if (fk.AcceptRejectRule != AcceptRejectRule.None) return false; if (fk.DeleteRule != Rule.Cascade) return false; if (fk.DeleteRule != Rule.Cascade) return false; if (fk.RelatedColumnsReference.Length !=1) return false; return AutoGenerated(fk.RelatedColumnsReference[0]); } private bool IsAutoGenerated(object o) { if (schFormat != SchemaFormat.Remoting) return autogenerated[o]!=null; return false; } internal XmlElement HandleTable(DataTable table, XmlDocument dc, XmlElement schema, bool genNested) { XmlElement root = dc.CreateElement(Keywords.XSD_PREFIX, Keywords.XSD_ELEMENT, Keywords.XSDNS); bool fWriteOrdinals = false; bool fUnqualified = false; if (((table.DataSet == null) || (_ds!= null && table.Namespace != _ds.Namespace)) && (schFormat == SchemaFormat.Remoting)) root.SetAttribute( Keywords.TARGETNAMESPACE, Keywords.MSDNS, table.Namespace); // First add any attributes. root.SetAttribute( Keywords.NAME, table.EncodedTableName ); if (table.Namespace.Length == 0) { DataTable _table = table; string tgNamespace = _table.Namespace; while (Common.ADP.IsEmpty(tgNamespace)) { DataRelation [] nestedParentRelations = _table.NestedParentRelations; if (nestedParentRelations.Length == 0){ tgNamespace = (_ds != null) ?_ds.Namespace : ""; break; } int nestedparentPosition = -1; // it is find non-self-nested-parent for(int i = 0; i < nestedParentRelations.Length; i++) { if (nestedParentRelations[i].ParentTable != _table) { nestedparentPosition = i; break; } } if (nestedparentPosition == -1) { break; } else { _table = nestedParentRelations[nestedparentPosition].ParentTable; } tgNamespace = _table.Namespace; } if (table.Namespace != tgNamespace) { root.SetAttribute( Keywords.FORM, Keywords.UNQUALIFIED); fUnqualified = true; } } if (table.ShouldSerializeCaseSensitive()) { root.SetAttribute(Keywords.MSD_CASESENSITIVE, Keywords.MSDNS, table.CaseSensitive.ToString(CultureInfo.InvariantCulture)); } if (table.ShouldSerializeLocale()) { root.SetAttribute(Keywords.MSD_LOCALE, Keywords.MSDNS, table.Locale.ToString()); } AddXdoProperties(table, root, dc); DataColumnCollection columns = table.Columns; int cCount = columns.Count; int realCount = 0; if (cCount ==1 || cCount ==2) for (int i = 0; i < cCount; i++) { DataColumn col = columns[i]; if (col.ColumnMapping == MappingType.Hidden) { DataRelationCollection childRelations = table.ChildRelations; for (int j = 0; j < childRelations.Count; j++) { if (childRelations[j].Nested && childRelations[j].ParentKey.ColumnsReference.Length == 1 && childRelations[j].ParentKey.ColumnsReference[0] == col) realCount++; } } if (col.ColumnMapping == MappingType.Element) realCount++; } if ((table.repeatableElement) && (realCount ==1)) { // I only have 1 column and that gives me // the type for this element DataColumn col = table.Columns[0]; string _typeName = XmlDataTypeName(col.DataType); if (_typeName == null || _typeName.Length == 0) { _typeName = Keywords.XSD_ANYTYPE; } root.SetAttribute(Keywords.TYPE, XSDSchema.QualifiedName(_typeName)); return root; } // Now add the type information nested inside the element or global. XmlElement type = dc.CreateElement(Keywords.XSD_PREFIX, Keywords.XSD_COMPLEXTYPE, Keywords.XSDNS); if (!table.TypeName.IsEmpty && schFormat != SchemaFormat.Remoting) { XmlElement typeSchema = GetSchema(table.TypeName.Namespace); if (Common.ADP.IsEmpty(table.TypeName.Namespace)) { if (_ds == null) typeSchema = GetSchema(table.Namespace); else typeSchema = fUnqualified ? GetSchema(_ds.Namespace): GetSchema(table.Namespace); } if (FindTypeNode(typeSchema, table.TypeName.Name) == null) typeSchema.AppendChild(type); type.SetAttribute(Keywords.NAME, table.TypeName.Name); } else { root.AppendChild(type); } if (!table.TypeName.IsEmpty) { if (schFormat != SchemaFormat.Remoting) root.SetAttribute( Keywords.TYPE, NewDiffgramGen.QualifiedName((string)prefixes[table.TypeName.Namespace], table.TypeName.Name) ); // } XmlElement compositor = null; DataColumn colTxt = table.XmlText; if (colTxt != null) { XmlElement sc = dc.CreateElement(Keywords.XSD_PREFIX, Keywords.XSD_SIMPLECONTENT , Keywords.XSDNS); if (colTxt.GetType() != typeof(DataColumn)) AddXdoProperties(colTxt, sc, dc); else AddColumnProperties(colTxt, sc); AddExtendedProperties(colTxt.extendedProperties, sc); if (colTxt.AllowDBNull) root.SetAttribute(Keywords.XSD_NILLABLE, String.Empty, Keywords.TRUE); if (!colTxt.DefaultValueIsNull) { XmlTreeGen.ValidateColumnMapping(colTxt.DataType); sc.SetAttribute(Keywords.MSD_DEFAULTVALUE, Keywords.MSDNS, colTxt.ConvertObjectToXml(colTxt.DefaultValue)); } sc.SetAttribute(Keywords.MSD_COLUMNNAME, Keywords.MSDNS, colTxt.ColumnName); sc.SetAttribute(Keywords.MSD_ORDINAL, Keywords.MSDNS, colTxt.Ordinal.ToString(CultureInfo.InvariantCulture)); type.AppendChild (sc); XmlElement ext = dc.CreateElement(Keywords.XSD_PREFIX, Keywords.XSD_EXTENSION, Keywords.XSDNS); sc.AppendChild(ext); HandleColumnType(colTxt, dc, ext, schema); type = ext; } compositor = dc.CreateElement(Keywords.XSD_PREFIX, Keywords.XSD_SEQUENCE, Keywords.XSDNS); type.AppendChild(compositor); fWriteOrdinals = HasMixedColumns(table); for (int i = 0; i < cCount; i++) { DataColumn col = columns[i]; if (col.ColumnMapping == MappingType.SimpleContent) continue; if (col.ColumnMapping == MappingType.Attribute || col.ColumnMapping == MappingType.Element || col.ColumnMapping == MappingType.Hidden ) { if (IsAutoGenerated(col)) // skip automanifactured columns continue; bool isAttribute = col.ColumnMapping != MappingType.Element; XmlElement el = HandleColumn(col, dc, schema, fWriteOrdinals); XmlElement node = isAttribute ? type : compositor; //bool flag = isAttribute ? col.Namespace == "" : col.Namespace == table.Namespace; node.AppendChild(el); } } if ((table.XmlText == null) && (genNested)) { DataRelationCollection childRelations = table.ChildRelations; for (int j = 0; j < childRelations.Count; j++) { XmlElement NestedTable; if (!childRelations[j].Nested) continue; DataTable childTable = childRelations[j].ChildTable; if (childTable == table) { // self join NestedTable = dc.CreateElement(Keywords.XSD_PREFIX, Keywords.XSD_ELEMENT, Keywords.XSDNS); NestedTable.SetAttribute( Keywords.REF, table.EncodedTableName ); } else if (childTable.NestedParentsCount >1 ) { // skip relations with multiple parents NestedTable = dc.CreateElement(Keywords.XSD_PREFIX, Keywords.XSD_ELEMENT, Keywords.XSDNS); NestedTable.SetAttribute( Keywords.REF, childTable.EncodedTableName); } else NestedTable = HandleTable(childTable, dc, schema); if (childTable.Namespace == table.Namespace) { NestedTable.SetAttribute(Keywords.MINOCCURS , "0"); NestedTable.SetAttribute(Keywords.MAXOCCURS , Keywords.ZERO_OR_MORE); } if ((childTable.Namespace == table.Namespace) || (childTable.Namespace.Length == 0) || schFormat == SchemaFormat.Remoting) { compositor.AppendChild(NestedTable); } else { if (childTable.NestedParentsCount <= 1 ) GetSchema(childTable.Namespace).AppendChild(NestedTable); NestedTable = dc.CreateElement(Keywords.XSD_PREFIX, Keywords.XSD_ELEMENT, Keywords.XSDNS); NestedTable.SetAttribute( Keywords.REF, ((string)prefixes[childTable.Namespace])+':'+childTable.EncodedTableName); compositor.AppendChild(NestedTable); } if (childRelations[j].ChildKeyConstraint != null) continue; // we write the relation using the constraint XmlElement nodeAnn = _dc.CreateElement(Keywords.XSD_PREFIX, Keywords.XSD_ANNOTATION, Keywords.XSDNS); NestedTable.PrependChild(nodeAnn); XmlElement nodeApp = _dc.CreateElement(Keywords.XSD_PREFIX, Keywords.XSD_APPINFO, Keywords.XSDNS); nodeAnn.AppendChild(nodeApp); nodeApp.AppendChild(HandleRelation(childRelations[j], dc)); } } if (compositor != null) if (!compositor.HasChildNodes) type.RemoveChild(compositor); // Output all constraints. ConstraintCollection constraints = table.Constraints; XmlElement selector, field; String xpathprefix = (_ds != null)? (_ds.Namespace.Length != 0 ? Keywords.MSTNS_PREFIX : String.Empty) : String.Empty; if (schFormat != SchemaFormat.Remoting) { GetSchema(table.Namespace); // to ensure prefix handling xpathprefix = table.Namespace.Length != 0 ? (string) prefixes[table.Namespace] +':' : String.Empty; } for (int i = 0; i < constraints.Count; i++) { XmlElement constraint = null; DataColumn[] fields; if (constraints[i] is UniqueConstraint) { UniqueConstraint unique = (UniqueConstraint)constraints[i]; if (IsAutoGenerated(unique)) continue; // special case of the ghosted constraints: fields = unique.Key.ColumnsReference; constraint = dc.CreateElement(Keywords.XSD_PREFIX, Keywords.XSD_UNIQUE, Keywords.XSDNS); if ((_ds == null) || (_ds.Tables.InternalIndexOf(table.TableName) ==-3)) constraint.SetAttribute( Keywords.MSD_TABLENS, Keywords.MSDNS, table.Namespace); // convert constraint name to valid xml name constraint.SetAttribute( Keywords.NAME, XmlConvert.EncodeLocalName( unique.SchemaName )); if (unique.ConstraintName != unique.SchemaName) constraint.SetAttribute(Keywords.MSD_CONSTRAINTNAME, Keywords.MSDNS, unique.ConstraintName); AddExtendedProperties(unique.extendedProperties, constraint); selector = dc.CreateElement(Keywords.XSD_PREFIX, Keywords.XSD_SELECTOR, Keywords.XSDNS); selector.SetAttribute(Keywords.XSD_XPATH, ".//"+xpathprefix+table.EncodedTableName); constraint.AppendChild(selector); if (unique.IsPrimaryKey) { constraint.SetAttribute(Keywords.MSD_PRIMARYKEY, Keywords.MSDNS, Keywords.TRUE); } if (0 < fields.Length) { StringBuilder encodedName = new StringBuilder(); for (int k = 0; k < fields.Length; k++) { encodedName.Length = 0; if (schFormat != SchemaFormat.Remoting) { GetSchema(fields[k].Namespace); if (!Common.ADP.IsEmpty(fields[k].Namespace)) { encodedName.Append(prefixes[fields[k].Namespace]).Append(':'); } encodedName.Append(fields[k].EncodedColumnName); } else { encodedName.Append(xpathprefix).Append(fields[k].EncodedColumnName); } if ((fields[k].ColumnMapping == MappingType.Attribute) || (fields[k].ColumnMapping == MappingType.Hidden)) { encodedName.Insert(0, '@'); } field = dc.CreateElement(Keywords.XSD_PREFIX, Keywords.XSD_FIELD, Keywords.XSDNS); field.SetAttribute(Keywords.XSD_XPATH, encodedName.ToString()); constraint.AppendChild(field); } } dsElement.InsertBefore(constraint, constraintSeparator); } else if (constraints[i] is ForeignKeyConstraint && genNested) { ForeignKeyConstraint foreign = (ForeignKeyConstraint)constraints[i]; if (_tables.Count > 0) { if (!_tables.Contains(foreign.RelatedTable) || !_tables.Contains(foreign.Table)) continue; } if (IsAutoGenerated(foreign)) continue; DataRelation rel = foreign.FindParentRelation(); // special case of the ghosted constraints: fields = foreign.RelatedColumnsReference; UniqueConstraint _constraint = (UniqueConstraint) foreign.RelatedTable.Constraints.FindConstraint( new UniqueConstraint( "TEMP", fields)); if (_constraint == null) { constraint = dc.CreateElement(Keywords.XSD_PREFIX, Keywords.XSD_KEY, Keywords.XSDNS); constraint.SetAttribute( Keywords.NAME, XmlConvert.EncodeLocalName( foreign.SchemaName )); if ((_ds == null) || (_ds.Tables.InternalIndexOf(table.TableName) ==-3)) constraint.SetAttribute( Keywords.MSD_TABLENS, Keywords.MSDNS, table.Namespace); selector = dc.CreateElement(Keywords.XSD_PREFIX, Keywords.XSD_SELECTOR, Keywords.XSDNS); selector.SetAttribute(Keywords.XSD_XPATH, ".//"+xpathprefix+ foreign.RelatedTable.EncodedTableName); constraint.AppendChild(selector); if (0 < fields.Length) { StringBuilder encodedName = new StringBuilder(); for (int k = 0; k < fields.Length; k++) { encodedName.Length = 0; if (schFormat != SchemaFormat.Remoting) { GetSchema(fields[k].Namespace); if (!Common.ADP.IsEmpty(fields[k].Namespace)) { encodedName.Append(prefixes[fields[k].Namespace]).Append(':'); } encodedName.Append(fields[k].EncodedColumnName); } else { encodedName.Append(xpathprefix).Append(fields[k].EncodedColumnName); } if ((fields[k].ColumnMapping == MappingType.Attribute) || (fields[k].ColumnMapping == MappingType.Hidden)) { encodedName.Insert(0, '@'); } field = dc.CreateElement(Keywords.XSD_PREFIX, Keywords.XSD_FIELD, Keywords.XSDNS); field.SetAttribute(Keywords.XSD_XPATH, encodedName.ToString()); constraint.AppendChild(field); } } dsElement.InsertBefore(constraint, constraintSeparator); } constraint = dc.CreateElement(Keywords.XSD_PREFIX, Keywords.XSD_KEYREF, Keywords.XSDNS); // convert constraint name to valid xml name constraint.SetAttribute( Keywords.NAME,XmlConvert.EncodeLocalName( foreign.SchemaName )); if ((_ds == null) || (_ds.Tables.InternalIndexOf(foreign.RelatedTable.TableName) == -3)) // if there is a conflicting name/namespace only constraint.SetAttribute (Keywords.MSD_TABLENS, Keywords.MSDNS, foreign.Table.Namespace); if (_constraint == null) constraint.SetAttribute( Keywords.REFER, XmlConvert.EncodeLocalName( foreign.SchemaName )); else constraint.SetAttribute( Keywords.REFER, XmlConvert.EncodeLocalName( _constraint.SchemaName )); AddExtendedProperties(foreign.extendedProperties, constraint, typeof(ForeignKeyConstraint)); if (foreign.ConstraintName != foreign.SchemaName) constraint.SetAttribute(Keywords.MSD_CONSTRAINTNAME, Keywords.MSDNS, foreign.ConstraintName); if (null == rel) { constraint.SetAttribute(Keywords.MSD_CONSTRAINTONLY , Keywords.MSDNS, Keywords.TRUE ); }else { if (rel.Nested) constraint.SetAttribute(Keywords.MSD_ISNESTED, Keywords.MSDNS, Keywords.TRUE); AddExtendedProperties(rel.extendedProperties, constraint, typeof(DataRelation)); if (foreign.ConstraintName != rel.RelationName) { constraint.SetAttribute( Keywords.MSD_RELATIONNAME , Keywords.MSDNS, XmlConvert.EncodeLocalName( rel.RelationName )); } } selector = dc.CreateElement(Keywords.XSD_PREFIX, Keywords.XSD_SELECTOR, Keywords.XSDNS); selector.SetAttribute(Keywords.XSD_XPATH, ".//"+xpathprefix+table.EncodedTableName); constraint.AppendChild(selector); if (foreign.AcceptRejectRule != ForeignKeyConstraint.AcceptRejectRule_Default) constraint.SetAttribute(Keywords.MSD_ACCEPTREJECTRULE, Keywords.MSDNS, TranslateAcceptRejectRule(foreign.AcceptRejectRule) ); if (foreign.UpdateRule != ForeignKeyConstraint.Rule_Default) constraint.SetAttribute( Keywords.MSD_UPDATERULE, Keywords.MSDNS, TranslateRule(foreign.UpdateRule) ); if (foreign.DeleteRule != ForeignKeyConstraint.Rule_Default) constraint.SetAttribute( Keywords.MSD_DELETERULE, Keywords.MSDNS, TranslateRule(foreign.DeleteRule) ); fields = foreign.Columns; if (0 < fields.Length) { StringBuilder encodedName = new StringBuilder(); for (int k = 0; k < fields.Length; k++) { encodedName.Length = 0; if (schFormat != SchemaFormat.Remoting) { GetSchema(fields[k].Namespace); if (!Common.ADP.IsEmpty(fields[k].Namespace)) { encodedName.Append(prefixes[fields[k].Namespace]).Append(':'); } encodedName.Append(fields[k].EncodedColumnName); } else { encodedName.Append(xpathprefix).Append(fields[k].EncodedColumnName); } if ((fields[k].ColumnMapping == MappingType.Attribute) || (fields[k].ColumnMapping == MappingType.Hidden)) { encodedName.Insert(0, '@'); } field = dc.CreateElement(Keywords.XSD_PREFIX, Keywords.XSD_FIELD, Keywords.XSDNS); field.SetAttribute(Keywords.XSD_XPATH, encodedName.ToString()); constraint.AppendChild(field); } } dsElement.InsertAfter(constraint, constraintSeparator); } } AddExtendedProperties(table.extendedProperties, root); return root; } /// /// resolve the name from the type for schema output and set the msdata:Data attribute /// /// /// non-special type to resolve /// type.AssemblyQualifiedName or targeted to a different version /// if multipleTargetConverter throws or returns an empty result private void SetMSDataAttribute(XmlElement root, Type type) { string result = DataStorage.GetQualifiedName(type); try { if (null != this.targetConverter) { result = this.targetConverter(type); } if (!String.IsNullOrEmpty(result)) { // SetAttribute doesn't fail with invalid data, but the final XmlDocument.Save will fail later // with the ArugmentException when calling the actual XmlWriter.SetAttribute root.SetAttribute(Keywords.MSD_DATATYPE, Keywords.MSDNS, result); } } catch (Exception ex) { if (Common.ADP.IsCatchableExceptionType(ex)) { ExceptionBuilder.ThrowMultipleTargetConverter(ex); } throw; } if (String.IsNullOrEmpty(result)) { ExceptionBuilder.ThrowMultipleTargetConverter(null); } } } internal sealed class NewDiffgramGen { internal XmlDocument _doc; internal DataSet _ds; internal DataTable _dt; internal XmlWriter _xmlw; private bool fBefore = false; private bool fErrors = false; internal Hashtable rowsOrder = null; ArrayList _tables = new ArrayList(); bool _writeHierarchy = false; internal NewDiffgramGen(DataSet ds) { _ds = ds; _dt = null; _doc = new XmlDocument(); for (int i = 0; i < ds.Tables.Count; i++) { _tables.Add(ds.Tables[i]); } DoAssignments(_tables); } internal NewDiffgramGen(DataTable dt, bool writeHierarchy) { _ds = null; _dt = dt; _doc = new XmlDocument(); _tables.Add(dt); if (writeHierarchy) { this._writeHierarchy = true; CreateTableHierarchy(dt); } DoAssignments(_tables); } private void CreateTableHierarchy(DataTable dt) { // if (!dt.SerializeHierarchy) // return; foreach( DataRelation r in dt.ChildRelations ) { if (! _tables.Contains((DataTable)r.ChildTable)) { _tables.Add((DataTable)r.ChildTable); CreateTableHierarchy(r.ChildTable); } } } private void DoAssignments(ArrayList tables) { int rows = 0; for (int i = 0; i < tables.Count; i++) { rows += ((DataTable)tables[i]).Rows.Count ; } rowsOrder = new Hashtable(rows); for (int i = 0; i < tables.Count; i++) { DataTable dt = (DataTable)tables[i]; DataRowCollection rc = dt.Rows; rows = rc.Count ; for (int j=0; j 0) return false; } return true; } internal void Save(XmlWriter xmlw) { Save (xmlw, null); } internal void Save(XmlWriter xmlw, DataTable table) { _xmlw = DataTextWriter.CreateWriter(xmlw); _xmlw.WriteStartElement(Keywords.DFF, Keywords.DIFFGRAM, Keywords.DFFNS); _xmlw.WriteAttributeString(Keywords.XMLNS, Keywords.MSD, null, Keywords.MSDNS); // _xmlw.WriteAttributeString(Keywords.XMLNS, Keywords.UPDG, null, Keywords.UPDGNS); if (! EmptyData()) { // write the datapart if (table != null) new XmlDataTreeWriter(table, this._writeHierarchy).SaveDiffgramData(_xmlw, rowsOrder); else new XmlDataTreeWriter(_ds).SaveDiffgramData(_xmlw, rowsOrder); // Walk the xd using relational apis and create nodes in nodeRoot appropriately. if (table==null) { for (int i = 0; i < _ds.Tables.Count; ++i) { GenerateTable(_ds.Tables[i]); } } else { for(int i = 0; i < _tables.Count; i++) { GenerateTable((DataTable)_tables[i]); } } if (fBefore) _xmlw.WriteEndElement(); //SQL_BEFORE if (table==null) { for (int i = 0; i < _ds.Tables.Count; ++i) { GenerateTableErrors(_ds.Tables[i]); } } else { for(int i = 0; i < _tables.Count; i++) { GenerateTableErrors((DataTable)_tables[i]); } } if (fErrors) _xmlw.WriteEndElement(); //ERRORS } _xmlw.WriteEndElement(); _xmlw.Flush(); } private void GenerateTable(DataTable table) { int rowCount = table.Rows.Count; if (rowCount <= 0) return; for (int rowNum = 0; rowNum < rowCount; ++rowNum) GenerateRow(table.Rows[rowNum]); } private void GenerateTableErrors(DataTable table) { int rowCount = table.Rows.Count; int colCount = table.Columns.Count; if (rowCount <= 0) return; for (int rowNum = 0; rowNum < rowCount; ++rowNum) { bool tableName = false; DataRow row = table.Rows[rowNum]; string prefix = (table.Namespace.Length != 0) ? table.Prefix : String.Empty; if ((row.HasErrors) && (row.RowError.Length > 0)) { if (!fErrors) { _xmlw.WriteStartElement( Keywords.DFF, Keywords.MSD_ERRORS, Keywords.DFFNS ); fErrors = true; } _xmlw.WriteStartElement( prefix, row.Table.EncodedTableName, row.Table.Namespace); _xmlw.WriteAttributeString( Keywords.DFF, Keywords.DIFFID, Keywords.DFFNS, row.Table.TableName+row.rowID.ToString(CultureInfo.InvariantCulture)); _xmlw.WriteAttributeString( Keywords.DFF, Keywords.MSD_ERROR, Keywords.DFFNS, row.RowError); tableName = true; } if (colCount <=0) continue; for (int colNum = 0; colNum < colCount; ++colNum) { DataColumn column = table.Columns[colNum]; string error = row.GetColumnError(column); string columnPrefix = (column.Namespace.Length != 0) ? column.Prefix : String.Empty; if (error == null || error.Length == 0) { continue; } if (!tableName) { if (!fErrors) { _xmlw.WriteStartElement( Keywords.DFF, Keywords.MSD_ERRORS, Keywords.DFFNS ); fErrors = true; } _xmlw.WriteStartElement( prefix, row.Table.EncodedTableName, row.Table.Namespace); _xmlw.WriteAttributeString( Keywords.DFF, Keywords.DIFFID, Keywords.DFFNS, row.Table.TableName+row.rowID.ToString(CultureInfo.InvariantCulture)); tableName = true; } _xmlw.WriteStartElement( columnPrefix, column.EncodedColumnName, column.Namespace); _xmlw.WriteAttributeString( Keywords.DFF, Keywords.MSD_ERROR, Keywords.DFFNS, error); _xmlw.WriteEndElement(); } if(tableName) _xmlw.WriteEndElement(); } } private void GenerateRow(DataRow row) { DataRowState state = row.RowState; if ((state == DataRowState.Unchanged ) || (state == DataRowState.Added)) { return; } if (!fBefore) { _xmlw.WriteStartElement( Keywords.DFF, Keywords.SQL_BEFORE, Keywords.DFFNS); fBefore = true; } DataTable table = row.Table; int colCount = table.Columns.Count; string rowIDString = table.TableName+row.rowID.ToString(CultureInfo.InvariantCulture); string parentId = null; if ( (state == DataRowState.Deleted ) && (row.Table.NestedParentRelations.Length != 0)){ DataRow parentRow = row.GetNestedParentRow(DataRowVersion.Original); if (parentRow != null) { parentId = parentRow.Table.TableName+parentRow.rowID.ToString(CultureInfo.InvariantCulture); } } string tablePrefix = (table.Namespace.Length != 0) ? table.Prefix : String.Empty; // read value if the TextOnly column (if any) object val = (table.XmlText == null ? DBNull.Value : row[table.XmlText, DataRowVersion.Original]); //old row _xmlw.WriteStartElement( tablePrefix, row.Table.EncodedTableName, row.Table.Namespace); _xmlw.WriteAttributeString( Keywords.DFF, Keywords.DIFFID, Keywords.DFFNS, rowIDString); if ( (state == DataRowState.Deleted ) && XmlDataTreeWriter.RowHasErrors(row)) _xmlw.WriteAttributeString( Keywords.DFF, Keywords.HASERRORS, Keywords.DFFNS, Keywords.TRUE); if (parentId != null) _xmlw.WriteAttributeString( Keywords.DFF, Keywords.DIFFPID, Keywords.DFFNS, parentId); _xmlw.WriteAttributeString( Keywords.MSD, Keywords.ROWORDER, Keywords.MSDNS, rowsOrder[row].ToString()); for (int colNum = 0; colNum < colCount; ++colNum) { if ((row.Table.Columns[colNum].ColumnMapping == MappingType.Attribute) || (row.Table.Columns[colNum].ColumnMapping == MappingType.Hidden)) GenerateColumn(row, row.Table.Columns[colNum], DataRowVersion.Original); } for (int colNum = 0; colNum < colCount; ++colNum) { if ((row.Table.Columns[colNum].ColumnMapping == MappingType.Element) || (row.Table.Columns[colNum].ColumnMapping == MappingType.SimpleContent)) GenerateColumn(row, row.Table.Columns[colNum], DataRowVersion.Original); } _xmlw.WriteEndElement(); //old row } private void GenerateColumn(DataRow row, DataColumn col, DataRowVersion version) { string value = null; value = col.GetColumnValueAsString(row, version); // this is useless for CTD if (value == null) { if (col.ColumnMapping == MappingType.SimpleContent) _xmlw.WriteAttributeString(Keywords.XSI, Keywords.XSI_NIL, Keywords.XSINS, Keywords.TRUE); return; } string colPrefix = (col.Namespace.Length != 0) ? col.Prefix : String.Empty; switch (col.ColumnMapping) { case MappingType.Attribute: _xmlw.WriteAttributeString(colPrefix, col.EncodedColumnName, col.Namespace, value); break; case MappingType.Hidden: _xmlw.WriteAttributeString(Keywords.MSD, "hidden"+col.EncodedColumnName, Keywords.MSDNS, value); break; case MappingType.SimpleContent: _xmlw.WriteString(value); break; case MappingType.Element: bool startElementSkipped = true; object columnValue = row[col, version]; // if the object is built in type or if it implements IXMLSerializable, write the start Element, otherwise //(if CDT and does not implement IXmlSerializable) skip it if (!col.IsCustomType || !col.IsValueCustomTypeInstance(columnValue) ||(typeof(IXmlSerializable).IsAssignableFrom(columnValue.GetType()))) { _xmlw.WriteStartElement( colPrefix, col.EncodedColumnName, col.Namespace); startElementSkipped = false; } Type valuesType = columnValue.GetType(); if (!col.IsCustomType ) { // if column's type is built in type CLR or SQLType if(valuesType == typeof(char) || valuesType == typeof(string)) { if (XmlDataTreeWriter.PreserveSpace(value)) { _xmlw.WriteAttributeString(Keywords.XML, Keywords.SPACE, Keywords.XML_XMLNS, Keywords.PRESERVE); } } _xmlw.WriteString(value); } else { // Columns type is CDT if ((columnValue != DBNull.Value) && (!col.ImplementsINullable || !DataStorage.IsObjectSqlNull(columnValue))){ if (col.IsValueCustomTypeInstance(columnValue)/* && valuesType != typeof(Type)*/) {// value is also CDT // if SkippedElement, ie does not implement IXMLSerializable: so No Polymorphysm Support. if (!startElementSkipped && columnValue.GetType() != col.DataType) { _xmlw.WriteAttributeString(Keywords.MSD, Keywords.MSD_INSTANCETYPE, Keywords.MSDNS, DataStorage.GetQualifiedName(valuesType)); } if (!startElementSkipped) { col.ConvertObjectToXml(columnValue, _xmlw, null); // XmlRootAttribute MUST be passed null } else{ // this guy does not implement IXmlSerializable, so we need to handle serialization via XmlSerializer if (columnValue.GetType() != col.DataType) { // throw if polymorphism; not supported throw ExceptionBuilder.PolymorphismNotSupported(valuesType.AssemblyQualifiedName); } // therefore we are skipping the start element, but by passing XmlRootAttribute with the same name as // we open the start element (column's name), XmlSerializer will open and close it for us XmlRootAttribute xmlAttrib = new XmlRootAttribute(col.EncodedColumnName); xmlAttrib.Namespace = col.Namespace; col.ConvertObjectToXml(columnValue, _xmlw, xmlAttrib); } } else { // value is built in CLR type (eg: string, int etc.) // these basic clr types do not have direct xsd type mappings if (valuesType == typeof(Type) || valuesType == typeof(Guid)|| valuesType == typeof(Char) || DataStorage.IsSqlType(valuesType) ) { // if unmapped type or SQL type write msdata:Datatype=typeofinstance _xmlw.WriteAttributeString(Keywords.MSD, Keywords.MSD_INSTANCETYPE, Keywords.MSDNS, valuesType.FullName); } else if (columnValue is Type) { _xmlw.WriteAttributeString(Keywords.MSD, Keywords.MSD_INSTANCETYPE, Keywords.MSDNS, Keywords.TYPEINSTANCE); } else { string xsdTypeName = Keywords.XSD_PREFIXCOLON+ XmlTreeGen.XmlDataTypeName(valuesType); _xmlw.WriteAttributeString(Keywords.XSI, Keywords.TYPE, Keywords.XSINS, xsdTypeName); _xmlw.WriteAttributeString (Keywords.XMLNS_XSD, Keywords.XSDNS); } if (!DataStorage.IsSqlType(valuesType)) { _xmlw.WriteString(col.ConvertObjectToXml(columnValue)); } else { col.ConvertObjectToXml(columnValue, _xmlw, null); } } } } if (!startElementSkipped) { _xmlw.WriteEndElement(); } break; } } internal static string QualifiedName(string prefix, string name) { if (prefix != null) return prefix + ":" + name; return name; } } // DataTreeWriter internal sealed class XmlDataTreeWriter { XmlWriter _xmlw; DataSet _ds = null; DataTable _dt=null; ArrayList _dTables = new ArrayList(); DataTable [] topLevelTables; bool fFromTable = false; // also means no hierarchy bool isDiffgram = false; Hashtable rowsOrder = null; bool _writeHierarchy = false; internal XmlDataTreeWriter(DataSet ds) { _ds = ds; topLevelTables = ds.TopLevelTables(); foreach(DataTable table in ds.Tables) { _dTables.Add(table); } } internal XmlDataTreeWriter(DataSet ds, DataTable dt) { // need to modify this also _ds = ds; _dt = dt; _dTables.Add(dt); topLevelTables = ds.TopLevelTables(); } internal XmlDataTreeWriter(DataTable dt, bool writeHierarchy) { _dt = dt; fFromTable = true; if (dt.DataSet == null) { _dTables.Add(dt); topLevelTables = new DataTable[] {dt}; } else { _ds = dt.DataSet; _dTables.Add(dt); if (writeHierarchy) { this._writeHierarchy = true; CreateTablesHierarchy(dt); topLevelTables = CreateToplevelTables(); } else // if no hierarchy , top level table should be dt topLevelTables = new DataTable[] {dt}; } } private DataTable[] CreateToplevelTables() { ArrayList topTables = new ArrayList(); for (int i = 0; i < _dTables.Count; i++) { DataTable table =(DataTable) _dTables[i]; if (table.ParentRelations.Count == 0) topTables.Add(table); else { bool fNestedButNotSelfNested = false; for (int j = 0; j < table.ParentRelations.Count; j++) { if (table.ParentRelations[j].Nested) { if (table.ParentRelations[j].ParentTable == table) { fNestedButNotSelfNested = false; break; } fNestedButNotSelfNested = true; } } if (!fNestedButNotSelfNested) topTables.Add(table); } } if (topTables.Count == 0) return (new DataTable[0]); DataTable[] temp = new DataTable[topTables.Count]; topTables.CopyTo(temp, 0); return temp; } private void CreateTablesHierarchy(DataTable dt) { // if (!dt.SerializeHierarchy) // return; foreach( DataRelation r in dt.ChildRelations ) { if (! _dTables.Contains((DataTable)r.ChildTable)) { _dTables.Add((DataTable)r.ChildTable); CreateTablesHierarchy(r.ChildTable) ; } } } internal static bool RowHasErrors(DataRow row) { int colCount = row.Table.Columns.Count; if ((row.HasErrors) && (row.RowError.Length > 0)) return true; for (int colNum = 0; colNum < colCount; ++colNum) { DataColumn column = row.Table.Columns[colNum]; string error = row.GetColumnError(column); if (error == null || error.Length == 0) { continue; } return true; } return false; } // the following line writes the data part // for the new diffgram format internal void SaveDiffgramData(XmlWriter xw, Hashtable rowsOrder) { _xmlw = DataTextWriter.CreateWriter(xw); isDiffgram = true; this.rowsOrder = rowsOrder; int countTopTable = topLevelTables.Length; string prefix = (_ds!= null)?(( _ds.Namespace.Length == 0 )? "" : _ds.Prefix):(( _dt.Namespace.Length == 0 )? "" : _dt.Prefix); if (_ds == null || _ds.DataSetName == null || _ds.DataSetName.Length == 0) _xmlw.WriteStartElement(prefix, Keywords.DOCUMENTELEMENT, ( _dt.Namespace == null) ? "":_dt.Namespace); else _xmlw.WriteStartElement(prefix, XmlConvert.EncodeLocalName(_ds.DataSetName), _ds.Namespace); // new XmlTreeGen(true).Save(_ds,_xmlw, false /* we don't care since we specified it's serialized */); for(int i = 0; i < _dTables.Count ; i++) { DataTable tempTable = ((DataTable)_dTables[i]); foreach (DataRow row in tempTable.Rows) { if (row.RowState == DataRowState.Deleted) continue; int nestedParentRowCount = row.GetNestedParentCount(); if (nestedParentRowCount == 0) { DataTable tempDT = ((DataTable)_dTables[i]); XmlDataRowWriter(row,tempDT.EncodedTableName); } else if (nestedParentRowCount > 1){ throw ExceptionBuilder.MultipleParentRows(tempTable.Namespace.Length == 0 ? tempTable.TableName:tempTable.Namespace + tempTable.TableName); // At all times a nested row can only have 0 or 1 parents, never more than 1 } } } _xmlw.WriteEndElement(); _xmlw.Flush(); } internal void Save(XmlWriter xw, bool writeSchema) { _xmlw = DataTextWriter.CreateWriter(xw); int countTopTable = topLevelTables.Length; bool fWriteDSElement = true; string prefix = (_ds!= null)?(( _ds.Namespace.Length == 0 )? "" : _ds.Prefix):(( _dt.Namespace.Length == 0 )? "" : _dt.Prefix); if (!writeSchema && _ds != null && _ds.fTopLevelTable && countTopTable == 1) { if (_ds.TopLevelTables()[0].Rows.Count == 1) fWriteDSElement = false; } if (fWriteDSElement) { if (_ds == null) { _xmlw.WriteStartElement(prefix, Keywords.DOCUMENTELEMENT, _dt.Namespace); } else { if (_ds.DataSetName == null || _ds.DataSetName.Length == 0) _xmlw.WriteStartElement(prefix, Keywords.DOCUMENTELEMENT, _ds.Namespace); else _xmlw.WriteStartElement(prefix, XmlConvert.EncodeLocalName(_ds.DataSetName), _ds.Namespace); } for(int i = 0; i < _dTables.Count ; i++) { if (((DataTable)_dTables[i]).xmlText != null) { _xmlw.WriteAttributeString(Keywords.XMLNS, Keywords.XSI, Keywords.XSD_XMLNS_NS, Keywords.XSINS); break; } } if (writeSchema) { if (!fFromTable) { new XmlTreeGen(SchemaFormat.Public).Save(_ds,_xmlw); } else { new XmlTreeGen(SchemaFormat.Public).Save( null, _dt, _xmlw, this._writeHierarchy); } } } for(int i = 0; i < _dTables.Count ; i++) { foreach (DataRow row in ((DataTable)_dTables[i]).Rows) { if (row.RowState == DataRowState.Deleted) continue; int parentRowCount = row.GetNestedParentCount(); if (parentRowCount == 0) { XmlDataRowWriter(row, ((DataTable)_dTables[i]).EncodedTableName); } else if (parentRowCount > 1) { DataTable dt = (DataTable)_dTables[i]; throw ExceptionBuilder.MultipleParentRows(dt.Namespace.Length == 0 ? dt.TableName : (dt.Namespace + dt.TableName)); // At all times a nested row can only have 0 or 1 parents, never more than 1 } } } if (fWriteDSElement) _xmlw.WriteEndElement(); _xmlw.Flush(); } private ArrayList GetNestedChildRelations(DataRow row) { ArrayList list = new ArrayList(); foreach( DataRelation r in row.Table.ChildRelations ) { if (r.Nested) list.Add(r); } return list; } internal void XmlDataRowWriter(DataRow row, String encodedTableName) { object value; string prefix = (row.Table.Namespace.Length == 0) ? "" : row.Table.Prefix; _xmlw.WriteStartElement(prefix, encodedTableName, row.Table.Namespace); if (isDiffgram) { _xmlw.WriteAttributeString( Keywords.DFF, Keywords.DIFFID, Keywords.DFFNS, row.Table.TableName+row.rowID.ToString(CultureInfo.InvariantCulture)); _xmlw.WriteAttributeString( Keywords.MSD, Keywords.ROWORDER, Keywords.MSDNS, rowsOrder[row].ToString()); if (row.RowState == DataRowState.Added) { _xmlw.WriteAttributeString( Keywords.DFF, Keywords.HASCHANGES, Keywords.DFFNS, Keywords.INSERTED); } if (row.RowState == DataRowState.Modified) { _xmlw.WriteAttributeString( Keywords.DFF, Keywords.HASCHANGES, Keywords.DFFNS, Keywords.MODIFIED); } if (RowHasErrors(row)) { _xmlw.WriteAttributeString( Keywords.DFF, Keywords.HASERRORS, Keywords.DFFNS, Keywords.TRUE); } } //write the attribute columns first, if any foreach( DataColumn col in row.Table.Columns ) { if (col.columnMapping == MappingType.Attribute) { value = row[col]; string colPrefix = (col.Namespace.Length == 0) ? "" : col.Prefix; if ((value != DBNull.Value) && (!col.ImplementsINullable || !DataStorage.IsObjectSqlNull(value))){ XmlTreeGen.ValidateColumnMapping(col.DataType); _xmlw.WriteAttributeString(colPrefix, col.EncodedColumnName, col.Namespace, col.ConvertObjectToXml(value)); } } if (!isDiffgram) continue; if (col.columnMapping == MappingType.Hidden) { value = row[col]; if ((value != DBNull.Value) && (!col.ImplementsINullable || !DataStorage.IsObjectSqlNull(value))){ XmlTreeGen.ValidateColumnMapping(col.DataType); _xmlw.WriteAttributeString(Keywords.MSD, "hidden"+col.EncodedColumnName, Keywords.MSDNS, col.ConvertObjectToXml(value)); } } } //end foreach foreach( DataColumn col in row.Table.Columns ) { if (col.columnMapping != MappingType.Hidden) { value = row[col]; string colPrefix = (col.Namespace.Length == 0) ? "" : col.Prefix; bool startElementSkipped = true; if (((value == DBNull.Value) || (col.ImplementsINullable && DataStorage.IsObjectSqlNull(value))) && (col.ColumnMapping == MappingType.SimpleContent)) _xmlw.WriteAttributeString(Keywords.XSI, Keywords.XSI_NIL, Keywords.XSINS, Keywords.TRUE); // basically this is a continue; if it is null we write xsi:nil='true' // below, the check is if it is not null if (((value != DBNull.Value) && (!col.ImplementsINullable || !DataStorage.IsObjectSqlNull(value)))&&(col.columnMapping != MappingType.Attribute)){ if (col.columnMapping != MappingType.SimpleContent) { // again, if we need to use XmlSerializer, do not write start Element (see above for more info) if (!col.IsCustomType || !col.IsValueCustomTypeInstance(value) ||(typeof(IXmlSerializable).IsAssignableFrom(value.GetType()))) { _xmlw.WriteStartElement(colPrefix, col.EncodedColumnName, col.Namespace); startElementSkipped = false; } } Type valuesType = value.GetType(); if (!col.IsCustomType) { // if column's type is built in type: CLR and SQLTypes : ie storage supported types if(valuesType == typeof(char) || valuesType == typeof(string)) { if (PreserveSpace(value)) { _xmlw.WriteAttributeString(Keywords.XML, Keywords.SPACE, Keywords.XML_XMLNS, Keywords.PRESERVE); } } _xmlw.WriteString(col.ConvertObjectToXml(value)); } else { // Columns type is CDT if (col.IsValueCustomTypeInstance(value) /*&& !(value is Type) && valuesType != typeof(Type)*/) {// value is also CDT // if SkippedElement, ie does not implement IXMLSerializable: so No Polymorphism Support. if (!startElementSkipped && valuesType != col.DataType) { // for polymorphism. _xmlw.WriteAttributeString(Keywords.MSD, Keywords.MSD_INSTANCETYPE, Keywords.MSDNS, DataStorage.GetQualifiedName(valuesType)); } if (!startElementSkipped) { // make sure XmlRootAttribute is passed null as this type implement IXmlSerializable col.ConvertObjectToXml(value, _xmlw, null); // pass XmlRootAttribute as null, it also means: No XmlSerializer } else{ // startElement is skipped: this guy does not implement IXmlSerializable, need to go via XmlSerializer if (value.GetType() != col.DataType) { // throw if polymorphism; not supported throw ExceptionBuilder.PolymorphismNotSupported(valuesType.AssemblyQualifiedName); } // therefore we are skipping the start element, but by passing XmlRootAttribute with the same name as // we open the start element (column's name), XmlSerializer will open and close it for us XmlRootAttribute xmlAttrib = new XmlRootAttribute(col.EncodedColumnName); xmlAttrib.Namespace = col.Namespace; col.ConvertObjectToXml(value, _xmlw, xmlAttrib); } } else { // this is case that column type is object and value is CLR or SQLTypes if (valuesType == typeof(Type) || valuesType == typeof(Guid)|| valuesType == typeof(Char) || DataStorage.IsSqlType(valuesType)) { // if unmapped type or SQL type write msdata:Datatype=typeofinstance _xmlw.WriteAttributeString(Keywords.MSD, Keywords.MSD_INSTANCETYPE, Keywords.MSDNS, valuesType.FullName); } else if (value is Type) { _xmlw.WriteAttributeString(Keywords.MSD, Keywords.MSD_INSTANCETYPE, Keywords.MSDNS, Keywords.TYPEINSTANCE); } else { string xsdTypeName = Keywords.XSD_PREFIXCOLON+ XmlTreeGen.XmlDataTypeName(valuesType); _xmlw.WriteAttributeString(Keywords.XSI, Keywords.TYPE, Keywords.XSINS, xsdTypeName); _xmlw.WriteAttributeString (Keywords.XMLNS_XSD, Keywords.XSDNS); } if (!DataStorage.IsSqlType(valuesType)) { _xmlw.WriteString(col.ConvertObjectToXml(value)); } else { col.ConvertObjectToXml(value, _xmlw, null); } } } if (col.columnMapping != MappingType.SimpleContent && !startElementSkipped) _xmlw.WriteEndElement(); } } } //end foreach if (_ds != null) foreach( DataRelation dr in GetNestedChildRelations(row) ) { foreach( DataRow r in row.GetChildRows(dr) ) { XmlDataRowWriter(r,dr.ChildTable.EncodedTableName); } } _xmlw.WriteEndElement(); } internal static bool PreserveSpace(object value) { Debug.Assert(value != null, "Value can not be null"); string tempValue = value.ToString(); if (tempValue.Length == 0) { return false; } for(int i =0; i < tempValue.Length; i++) { if (!Char.IsWhiteSpace(tempValue, i)) { return false; } } return true; } } internal sealed class DataTextWriter : XmlWriter { private XmlWriter _xmltextWriter; internal static XmlWriter CreateWriter(XmlWriter xw) { return new DataTextWriter(xw); } private DataTextWriter(XmlWriter w) { _xmltextWriter = w; } internal Stream BaseStream { get { XmlTextWriter textWriter = _xmltextWriter as XmlTextWriter; if (null != textWriter) { return textWriter.BaseStream; } return null; } } public override void WriteStartDocument() { _xmltextWriter.WriteStartDocument(); } public override void WriteStartDocument(bool standalone) { _xmltextWriter.WriteStartDocument(standalone); } public override void WriteEndDocument() { _xmltextWriter.WriteEndDocument(); } public override void WriteDocType(string name, string pubid, string sysid, string subset) { _xmltextWriter.WriteDocType(name, pubid, sysid, subset); } public override void WriteStartElement(string prefix, string localName, string ns) { _xmltextWriter.WriteStartElement(prefix, localName, ns); } public override void WriteEndElement() { _xmltextWriter.WriteEndElement(); } public override void WriteFullEndElement() { _xmltextWriter.WriteFullEndElement(); } public override void WriteStartAttribute(string prefix, string localName, string ns) { _xmltextWriter.WriteStartAttribute(prefix, localName, ns); } public override void WriteEndAttribute() { _xmltextWriter.WriteEndAttribute(); } public override void WriteCData(string text) { _xmltextWriter.WriteCData(text); } public override void WriteComment(string text) { _xmltextWriter.WriteComment(text); } public override void WriteProcessingInstruction(string name, string text) { _xmltextWriter.WriteProcessingInstruction(name, text); } public override void WriteEntityRef(string name) { _xmltextWriter.WriteEntityRef(name); } public override void WriteCharEntity(char ch) { _xmltextWriter.WriteCharEntity(ch); } public override void WriteWhitespace(string ws) { _xmltextWriter.WriteWhitespace(ws); } public override void WriteString(string text) { _xmltextWriter.WriteString(text); } public override void WriteSurrogateCharEntity(char lowChar, char highChar){ _xmltextWriter.WriteSurrogateCharEntity(lowChar, highChar); } public override void WriteChars(Char[] buffer, int index, int count) { _xmltextWriter.WriteChars(buffer, index, count); } public override void WriteRaw(Char[] buffer, int index, int count) { _xmltextWriter.WriteRaw(buffer, index, count); } public override void WriteRaw(String data) { _xmltextWriter.WriteRaw(data); } public override void WriteBase64(byte[] buffer, int index, int count) { _xmltextWriter.WriteBase64(buffer, index, count); } public override void WriteBinHex( byte[] buffer, int index, int count ) { _xmltextWriter.WriteBinHex(buffer, index, count); } public override WriteState WriteState { get { return _xmltextWriter.WriteState; } } public override void Close() { _xmltextWriter.Close(); } public override void Flush() { _xmltextWriter.Flush(); } public override void WriteName(string name) { _xmltextWriter.WriteName(name); } public override void WriteQualifiedName(string localName, string ns) { _xmltextWriter.WriteQualifiedName(localName, ns); } public override string LookupPrefix(string ns) { return _xmltextWriter.LookupPrefix(ns); } public override XmlSpace XmlSpace { get { return _xmltextWriter.XmlSpace; } } public override string XmlLang { get { return _xmltextWriter.XmlLang; } } public override void WriteNmToken(string name) { _xmltextWriter.WriteNmToken(name); } } internal sealed class DataTextReader : XmlReader { private XmlReader _xmlreader; internal static XmlReader CreateReader(XmlReader xr) { Debug.Assert(!(xr is DataTextReader), "XmlReader is DataTextReader"); return new DataTextReader(xr); } private DataTextReader( XmlReader input ) { _xmlreader = input; } public override XmlReaderSettings Settings { get { return _xmlreader.Settings; } } public override XmlNodeType NodeType { get { return _xmlreader.NodeType; } } public override string Name { get { return _xmlreader.Name; } } public override string LocalName { get { return _xmlreader.LocalName; } } public override string NamespaceURI { get { return _xmlreader.NamespaceURI; } } public override string Prefix { get { return _xmlreader.Prefix; } } public override bool HasValue { get { return _xmlreader.HasValue; } } public override string Value { get { return _xmlreader.Value; } } public override int Depth { get { return _xmlreader.Depth; } } public override string BaseURI { get { return _xmlreader.BaseURI; } } public override bool IsEmptyElement { get { return _xmlreader.IsEmptyElement; } } public override bool IsDefault { get { return _xmlreader.IsDefault; } } public override char QuoteChar { get { return _xmlreader.QuoteChar; } } public override XmlSpace XmlSpace { get { return _xmlreader.XmlSpace; } } public override string XmlLang { get { return _xmlreader.XmlLang; } } public override int AttributeCount { get { return _xmlreader.AttributeCount; } } public override string GetAttribute( string name ) { return _xmlreader.GetAttribute( name ); } public override string GetAttribute( string localName, string namespaceURI ) { return _xmlreader.GetAttribute( localName, namespaceURI ); } public override string GetAttribute( int i ) { return _xmlreader.GetAttribute( i ); } public override bool MoveToAttribute( string name ) { return _xmlreader.MoveToAttribute( name ); } public override bool MoveToAttribute( string localName, string namespaceURI ) { return _xmlreader.MoveToAttribute( localName, namespaceURI ); } public override void MoveToAttribute( int i ) { _xmlreader.MoveToAttribute( i ); } public override bool MoveToFirstAttribute() { return _xmlreader.MoveToFirstAttribute(); } public override bool MoveToNextAttribute() { return _xmlreader.MoveToNextAttribute(); } public override bool MoveToElement() { return _xmlreader.MoveToElement(); } public override bool ReadAttributeValue() { return _xmlreader.ReadAttributeValue(); } public override bool Read() { return _xmlreader.Read(); } public override bool EOF { get { return _xmlreader.EOF; } } public override void Close() { _xmlreader.Close(); } public override ReadState ReadState { get { return _xmlreader.ReadState; } } public override void Skip() { _xmlreader.Skip(); } public override XmlNameTable NameTable { get { return _xmlreader.NameTable; } } public override String LookupNamespace( String prefix ) { return _xmlreader.LookupNamespace(prefix); } public override bool CanResolveEntity { get { return _xmlreader.CanResolveEntity;} } public override void ResolveEntity() { _xmlreader.ResolveEntity(); } public override bool CanReadBinaryContent { get { return _xmlreader.CanReadBinaryContent ; } } public override int ReadContentAsBase64( byte[] buffer, int index, int count ) { return _xmlreader.ReadContentAsBase64( buffer, index, count ); } public override int ReadElementContentAsBase64( byte[] buffer, int index, int count ) { return _xmlreader.ReadElementContentAsBase64( buffer, index, count ); } public override int ReadContentAsBinHex( byte[] buffer, int index, int count ) { return _xmlreader.ReadContentAsBinHex( buffer, index, count ); } public override int ReadElementContentAsBinHex( byte[] buffer, int index, int count ) { return _xmlreader.ReadElementContentAsBinHex( buffer, index, count ); } public override bool CanReadValueChunk { get { return _xmlreader.CanReadValueChunk ; } } public override string ReadString() { return _xmlreader.ReadString(); } } }