|
//------------------------------------------------------------------------------
// <copyright file="xmlsaver.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// <owner current="true" primary="true">Microsoft</owner>
// <owner current="true" primary="false">Microsoft</owner>
//------------------------------------------------------------------------------
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
}
/// <devdoc>
/// </devdoc>
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;
/// <summary>
/// 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.
/// </summary>
Converter<Type, string> 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 <application..> 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 bug to go and write casesensitive attrib as 'true', by default
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<Type, string> 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) );
// Bug 108292: Since we always write complex type as annonymous type, DO NOT WRITE ITS NAME
// DO NOT REVERT THIS CHANGE
}
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;
}
/// <summary>
/// resolve the name from the type for schema output and set the msdata:Data attribute
/// </summary>
/// <param name="root"></param>
/// <param name="type">non-special type to resolve</param>
/// <returns>type.AssemblyQualifiedName or targeted to a different version</returns>
/// <exception cref="DataException">if multipleTargetConverter throws or returns an empty result</exception>
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<rows; j++)
rowsOrder[rc[j]] = j;
}
}
private bool EmptyData() {
for (int i = 0; i < _tables.Count; i++) {
if (((DataTable)_tables[i]).Rows.Count > 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();
}
}
}
|