XmlDataLoader.cs :  » 2.6.4-mono-.net-core » System.Data » System » Data » C# / CSharp Open Source

Home
C# / CSharp Open Source
1.2.6.4 mono .net core
2.2.6.4 mono core
3.Aspect Oriented Frameworks
4.Bloggers
5.Build Systems
6.Business Application
7.Charting Reporting Tools
8.Chat Servers
9.Code Coverage Tools
10.Content Management Systems CMS
11.CRM ERP
12.Database
13.Development
14.Email
15.Forum
16.Game
17.GIS
18.GUI
19.IDEs
20.Installers Generators
21.Inversion of Control Dependency Injection
22.Issue Tracking
23.Logging Tools
24.Message
25.Mobile
26.Network Clients
27.Network Servers
28.Office
29.PDF
30.Persistence Frameworks
31.Portals
32.Profilers
33.Project Management
34.RSS RDF
35.Rule Engines
36.Script
37.Search Engines
38.Sound Audio
39.Source Control
40.SQL Clients
41.Template Engines
42.Testing
43.UML
44.Web Frameworks
45.Web Service
46.Web Testing
47.Wiki Engines
48.Windows Presentation Foundation
49.Workflows
50.XML Parsers
C# / C Sharp
C# / C Sharp by API
C# / CSharp Tutorial
C# / CSharp Open Source » 2.6.4 mono .net core » System.Data 
System.Data » System » Data » XmlDataLoader.cs
//
// mcs/class/System.Data/System.Data/XmlDataLoader.cs
//
// Purpose: Loads XmlDocument to DataSet 
//
// class: XmlDataLoader
// assembly: System.Data.dll
// namespace: System.Data
//
// Author:
//     Ville Palo <vi64pa@koti.soon.fi>
//     Atsushi Enomoto <atsushi@ximian.com>
//
// (c)copyright 2002 Ville Palo
// (C)2004 Novell Inc.
//
// XmlDataLoader is included within the Mono Class Library.
//

//
// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//

using System;
using System.Data;
using System.Xml;
using System.Collections;
using System.Globalization;

namespace System.Data{

  internal class XmlDataLoader
  {
  
    private DataSet DSet;

    public XmlDataLoader (DataSet set) 
    {
      DSet = set;
    }

    public XmlReadMode LoadData (XmlReader reader, XmlReadMode mode)
    {
      XmlReadMode Result = mode;

      switch (mode) {
      case XmlReadMode.Auto:
        Result = DSet.Tables.Count == 0 ? XmlReadMode.InferSchema : XmlReadMode.IgnoreSchema;
        ReadModeSchema (reader, DSet.Tables.Count == 0 ? XmlReadMode.Auto : XmlReadMode.IgnoreSchema);
        break;
      case XmlReadMode.InferSchema:
        Result = XmlReadMode.InferSchema;
        ReadModeSchema (reader, mode);
        break;
      case XmlReadMode.IgnoreSchema:
        Result = XmlReadMode.IgnoreSchema;
        ReadModeSchema (reader, mode);
        break;
      default:
        reader.Skip ();
        break;
      }

      return Result;
    }

    #region reading

    // Read information from the reader.
    private void ReadModeSchema (XmlReader reader, XmlReadMode mode)
    {
      bool inferSchema = mode == XmlReadMode.InferSchema || mode == XmlReadMode.Auto;
      bool fillRows = mode != XmlReadMode.InferSchema;
      // This check is required for full DiffGram.
      // It is not described in MSDN and it is impossible
      // with WriteXml(), but when writing XML using
      // XmlSerializer, the output is like this:
      // <dataset>
      //  <schema>...</schema>
      //  <diffgram>...</diffgram>
      // </dataset>
      //
      // FIXME: This, this check should (also) be done
      // after reading the top-level element.

      //check if the current element is schema.
      if (reader.LocalName == "schema") {
        if (mode != XmlReadMode.Auto)
          reader.Skip(); // skip the schema node.
        else
          DSet.ReadXmlSchema(reader);
        
        reader.MoveToContent();
      }

      // load an XmlDocument from the reader.
      XmlDocument doc = new XmlDocument ();
      doc.Load (reader);
      if (doc.DocumentElement == null)
        return;

      // treatment for .net compliancy :
      // if xml representing dataset has exactly depth of 2 elements,
      // than the root element actually represents datatable and not dataset
      // so we add new root element to doc 
      // in order to create an element representing dataset.
      //
      // FIXME: Consider attributes. 
      // <root a='1' b='2' /> is regarded as a valid DataTable.
      int rootNodeDepth = XmlNodeElementsDepth(doc.DocumentElement);
      switch (rootNodeDepth) {
      case 1:
        if (inferSchema) {
          DSet.DataSetName = doc.DocumentElement.LocalName;
          DSet.Prefix = doc.DocumentElement.Prefix;
          DSet.Namespace = doc.DocumentElement.NamespaceURI;
        }
        return;
      case 2:
        // create new document
        XmlDocument newDoc = new XmlDocument();
        // create element for dataset
        XmlElement datasetElement = newDoc.CreateElement("dummy");
        // make the new created element to be the new doc root
        newDoc.AppendChild(datasetElement);
        // import all the elements from doc and insert them into new doc
        XmlNode root = newDoc.ImportNode(doc.DocumentElement,true);
        datasetElement.AppendChild(root);
        doc = newDoc;
        break;
      default:
        if (inferSchema) {
          DSet.DataSetName = doc.DocumentElement.LocalName;
          DSet.Prefix = doc.DocumentElement.Prefix;
          DSet.Namespace = doc.DocumentElement.NamespaceURI;
        }
        break;
      }

      // set EnforceConstraint to false - we do not want any validation during 
      // load time.
      bool origEnforceConstraint = DSet.EnforceConstraints;
      DSet.EnforceConstraints = false;

      // The childs are tables.
      XmlNodeList nList = doc.DocumentElement.ChildNodes;

      // FIXME: When reading DataTable (not DataSet), 
      // the nodes are column items, not rows.
      for (int i = 0; i < nList.Count; i++) {
        XmlNode node = nList[i];
        // node represents a table onky if it is of type XmlNodeType.Element
        if (node.NodeType == XmlNodeType.Element) {
          AddRowToTable(node, null, inferSchema, fillRows);
        }
      }
      // set the EnforceConstraints to original value;
      DSet.EnforceConstraints = origEnforceConstraint;
    }

    #endregion // reading

    #region Private helper methods
/*    
    private void ReadColumns (XmlReader reader, DataRow row, DataTable table, string TableName)
    {
      do {
        if (reader.NodeType == XmlNodeType.Element) {
          DataColumn col = table.Columns [reader.LocalName];
          if (col != null) {
            row [col] = StringToObject (col.DataType, reader.Value);
          }
          reader.Read ();
        }
        else {
          reader.Read ();
        }
        
      } while (table.TableName != reader.LocalName 
        || reader.NodeType != XmlNodeType.EndElement);
    }
*/
    internal static object StringToObject (Type type, string value)
    {
      if (type == null) return value;

      switch (Type.GetTypeCode (type)) {
        case TypeCode.Boolean: return XmlConvert.ToBoolean (value);
        case TypeCode.Byte: return XmlConvert.ToByte (value);
        case TypeCode.Char: return (char)XmlConvert.ToInt32 (value);
#if NET_2_0
        case TypeCode.DateTime: return XmlConvert.ToDateTime (value, XmlDateTimeSerializationMode.Unspecified);
#else
        case TypeCode.DateTime: return XmlConvert.ToDateTime (value);
#endif
        case TypeCode.Decimal: return XmlConvert.ToDecimal (value);
        case TypeCode.Double: return XmlConvert.ToDouble (value);
        case TypeCode.Int16: return XmlConvert.ToInt16 (value);
        case TypeCode.Int32: return XmlConvert.ToInt32 (value);
        case TypeCode.Int64: return XmlConvert.ToInt64 (value);
        case TypeCode.SByte: return XmlConvert.ToSByte (value);
        case TypeCode.Single: return XmlConvert.ToSingle (value);
        case TypeCode.UInt16: return XmlConvert.ToUInt16 (value);
        case TypeCode.UInt32: return XmlConvert.ToUInt32 (value);
        case TypeCode.UInt64: return XmlConvert.ToUInt64 (value);
      }

      if (type == typeof (TimeSpan)) return XmlConvert.ToTimeSpan (value);
      if (type == typeof (Guid)) return XmlConvert.ToGuid (value);
      if (type == typeof (byte[])) return Convert.FromBase64String (value);
      if (type == typeof (System.Type)) return System.Type.GetType (value);

      return Convert.ChangeType (value, type);
    }

    private void AddRowToTable(XmlNode tableNode, DataColumn relationColumn, bool inferSchema, bool fillRows)
    {
      Hashtable rowValue = new Hashtable();
      DataTable table;

      // Check if the table exists in the DataSet. If not create one.
      if (DSet.Tables.Contains(tableNode.LocalName))
        table = DSet.Tables[tableNode.LocalName];
      else if (inferSchema) {
        table = new DataTable(tableNode.LocalName);
        DSet.Tables.Add(table);
      }
      else
        return;

      // For elements that are inferred as tables and that contain text 
      // but have no child elements, a new column named "TableName_Text" 
      // is created for the text of each of the elements. 
      // If an element is inferred as a table and has text, but also has child elements,
      // the text is ignored.
      // Note : if an element is inferred as a table and has text 
      // and has no child elements, 
      // but the repeated ements of this table have child elements, 
      // then the text is ignored.
      if(!HaveChildElements(tableNode) && HaveText(tableNode) &&
        !IsRepeatedHaveChildNodes(tableNode)) {
        string columnName = tableNode.Name + "_Text";
        if (!table.Columns.Contains(columnName)) {
          table.Columns.Add(columnName);
        }
        rowValue.Add(columnName, tableNode.InnerText);
      }
      
      // Get the child nodes of the table. Any child can be one of the following tow:
      // 1. DataTable - if there was a relation with another table..
      // 2. DataColumn - column of the current table.
      XmlNodeList childList = tableNode.ChildNodes;
      for (int i = 0; i < childList.Count; i++) {
        XmlNode childNode = childList[i];

        // we are looping through elements only
        // Note : if an element is inferred as a table and has text, but also has child elements,
        // the text is ignored.
        if (childNode.NodeType != XmlNodeType.Element)
          continue;
        
        // Elements that have attributes are inferred as tables. 
        // Elements that have child elements are inferred as tables. 
        // Elements that repeat are inferred as a single table. 
        if (IsInferredAsTable(childNode)) {
          // child node inferred as table
          if (inferSchema) {
            // We need to create new column for the relation between the current
            // table and the new table we found (the child table).
            string newRelationColumnName = table.TableName + "_Id";
            if (!table.Columns.Contains(newRelationColumnName)) {
              DataColumn newRelationColumn = new DataColumn(newRelationColumnName, typeof(int));
              newRelationColumn.AllowDBNull = false;
              newRelationColumn.AutoIncrement = true;
              // we do not want to serialize this column so MappingType is Hidden.
              newRelationColumn.ColumnMapping = MappingType.Hidden;
              table.Columns.Add(newRelationColumn);
            }
            // Add a row to the new table we found.
            AddRowToTable(childNode, table.Columns[newRelationColumnName], inferSchema, fillRows);
          }
          else
            AddRowToTable(childNode, null, inferSchema, fillRows);
          
        }
        else {
          // Elements that have no attributes or child elements, and do not repeat, 
          // are inferred as columns.
          object val = null;
          if (childNode.FirstChild != null)
            val = childNode.FirstChild.Value;
          else
            val = "";
          if (table.Columns.Contains(childNode.LocalName))
            rowValue.Add(childNode.LocalName, val);
          else if (inferSchema) {
            table.Columns.Add(childNode.LocalName);
            rowValue.Add(childNode.LocalName, val);
          }
        }
            
      }

      // Column can be attribute of the table element.
      XmlAttributeCollection aCollection = tableNode.Attributes;
      for (int i = 0; i < aCollection.Count; i++) {
        XmlAttribute attr = aCollection[i];
        //the atrribute can be the namespace.
        if (attr.Prefix.Equals("xmlns"))
          table.Namespace = attr.Value;
        else { // the attribute is a column.
          if (!table.Columns.Contains(attr.LocalName)) {
            DataColumn col = table.Columns.Add(attr.LocalName);
            col.ColumnMapping = MappingType.Attribute;
          }
          table.Columns[attr.LocalName].Namespace = table.Namespace;

          rowValue.Add(attr.LocalName, attr.Value);
        }
      }

      // If the current table is a child table we need to add a new column for the relation
      // and add a new relation to the DataSet.
      if (relationColumn != null) {
        if (!table.Columns.Contains(relationColumn.ColumnName)) {
          DataColumn dc = new DataColumn(relationColumn.ColumnName, typeof(int));
          // we do not want to serialize this column so MappingType is Hidden.
          dc.ColumnMapping = MappingType.Hidden;
          table.Columns.Add(dc);
          // Convention of relation name is: ParentTableName_ChildTableName
          DataRelation dr = new DataRelation(relationColumn.Table.TableName + "_" + dc.Table.TableName, relationColumn, dc);
          dr.Nested = true;
          DSet.Relations.Add(dr);
          UniqueConstraint.SetAsPrimaryKey (dr.ParentTable.Constraints, dr.ParentKeyConstraint);
        }
        rowValue.Add (relationColumn.ColumnName, relationColumn.GetAutoIncrementValue());
      }

      // Create new row and add all values to the row.
      // then add it to the table.
      DataRow row = table.NewRow ();
          
      IDictionaryEnumerator enumerator = rowValue.GetEnumerator ();
      while (enumerator.MoveNext ()) {
        row [enumerator.Key.ToString ()] = StringToObject (table.Columns[enumerator.Key.ToString ()].DataType, enumerator.Value.ToString ());
      }

      if (fillRows)
        table.Rows.Add (row);
      
    }

    // this method calculates the depth of child nodes tree
    // and it counts nodes of type XmlNodeType.Element only
    private static int XmlNodeElementsDepth(XmlNode node)
    {
      int maxDepth = -1;
            if ((node != null)) {
        if  ((node.HasChildNodes) && (node.FirstChild.NodeType == XmlNodeType.Element)) {
          for (int i=0; i<node.ChildNodes.Count; i++) {
            if (node.ChildNodes[i].NodeType == XmlNodeType.Element) {
              int childDepth = XmlNodeElementsDepth(node.ChildNodes[i]);
              maxDepth = (maxDepth < childDepth) ? childDepth : maxDepth;
            }
          }
        }
        else {
          return 1;
        }
      }
      else {
        return -1;
      }

      return (maxDepth + 1);
    }

    private bool HaveChildElements(XmlNode node)
    {
      bool haveChildElements = true;
      if(node.ChildNodes.Count > 0) {
        foreach(XmlNode childNode in node.ChildNodes) {
          if (childNode.NodeType != XmlNodeType.Element) {
            haveChildElements = false;
            break;
          }
        }
      }
      else {
        haveChildElements = false;
      }
      return haveChildElements;
    }

    private bool HaveText(XmlNode node)
    {
      bool haveText = true;
      if(node.ChildNodes.Count > 0) {
        foreach(XmlNode childNode in node.ChildNodes) {
          if (childNode.NodeType != XmlNodeType.Text) {
            haveText = false;
            break;
          }
        }
      }
      else {
        haveText = false;
      }
      return haveText;
    }

    private bool IsRepeat(XmlNode node)
    {
      bool isRepeat = false;
      if(node.ParentNode != null) {
        foreach(XmlNode childNode in node.ParentNode.ChildNodes) {
          if(childNode != node && childNode.Name == node.Name) {
            isRepeat = true;
            break;
          }
        }
      }
      return isRepeat;
    }

    private bool HaveAttributes(XmlNode node)
    {
      return (node.Attributes != null && node.Attributes.Count > 0);
    }

    private bool IsInferredAsTable(XmlNode node)
    {
      // Elements that have attributes are inferred as tables. 
      // Elements that have child elements are inferred as tables. 
      // Elements that repeat are inferred as a single table. 
      return (HaveChildElements(node) || HaveAttributes(node) ||
          IsRepeat(node));
    }

    /// <summary>
    /// Returns true is any node that is repeated node for the node supplied
    /// (i.e. is child node of node's parent, have the same name and is not the node itself)
    /// have child elements
    /// </summary>
    private bool IsRepeatedHaveChildNodes(XmlNode node)
    {
      bool isRepeatedHaveChildElements = false;
      if(node.ParentNode != null) {
        foreach(XmlNode childNode in node.ParentNode.ChildNodes) {
          if(childNode != node && childNode.Name == node.Name) {
            if (HaveChildElements(childNode)) {
              isRepeatedHaveChildElements = true;
              break;
            }
          }
        }
      }
      return isRepeatedHaveChildElements;
    }

    #endregion // Private helper methods

    
  }

}
www.java2v.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.