XmlDataLoader.cs 66 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300
  1. //------------------------------------------------------------------------------
  2. // <copyright file="XmlDataLoader.cs" company="Microsoft">
  3. // Copyright (c) Microsoft Corporation. All rights reserved.
  4. // </copyright>
  5. // <owner current="true" primary="true">[....]</owner>
  6. // <owner current="true" primary="false">[....]</owner>
  7. //------------------------------------------------------------------------------
  8. namespace System.Data {
  9. using System;
  10. using System.Collections;
  11. using System.Data.Common;
  12. using System.Diagnostics;
  13. using System.Globalization;
  14. using System.Text;
  15. using System.Xml;
  16. using System.Xml.Serialization;
  17. internal sealed class XmlDataLoader {
  18. DataSet dataSet;
  19. XmlToDatasetMap nodeToSchemaMap = null;
  20. Hashtable nodeToRowMap;
  21. Stack childRowsStack = null;
  22. Hashtable htableExcludedNS = null;
  23. bool fIsXdr = false;
  24. internal bool isDiffgram = false;
  25. DataRow topMostRow = null;
  26. XmlElement topMostNode = null;
  27. bool ignoreSchema = false;
  28. DataTable dataTable;
  29. bool isTableLevel = false;
  30. private bool fromInference = false;
  31. internal XmlDataLoader( DataSet dataset, bool IsXdr, bool ignoreSchema) {
  32. // Initialization
  33. this.dataSet = dataset;
  34. this.nodeToRowMap = new Hashtable();
  35. this.fIsXdr = IsXdr;
  36. this.ignoreSchema = ignoreSchema;
  37. }
  38. internal XmlDataLoader( DataSet dataset, bool IsXdr, XmlElement topNode, bool ignoreSchema) {
  39. // Initialization
  40. this.dataSet = dataset;
  41. this.nodeToRowMap = new Hashtable();
  42. this.fIsXdr = IsXdr;
  43. // Allocate the stack and create the mappings
  44. childRowsStack = new Stack(50);
  45. topMostNode = topNode;
  46. this.ignoreSchema = ignoreSchema;
  47. }
  48. internal XmlDataLoader( DataTable datatable, bool IsXdr, bool ignoreSchema) {
  49. // Initialization
  50. this.dataSet = null;
  51. dataTable = datatable;
  52. isTableLevel = true;
  53. this.nodeToRowMap = new Hashtable();
  54. this.fIsXdr = IsXdr;
  55. this.ignoreSchema = ignoreSchema;
  56. }
  57. internal XmlDataLoader( DataTable datatable, bool IsXdr, XmlElement topNode, bool ignoreSchema) {
  58. // Initialization
  59. this.dataSet = null;
  60. dataTable = datatable;
  61. isTableLevel = true;
  62. this.nodeToRowMap = new Hashtable();
  63. this.fIsXdr = IsXdr;
  64. // Allocate the stack and create the mappings
  65. childRowsStack = new Stack(50);
  66. topMostNode = topNode;
  67. this.ignoreSchema = ignoreSchema;
  68. }
  69. internal bool FromInference {
  70. get {
  71. return fromInference;
  72. }
  73. set {
  74. fromInference = value;
  75. }
  76. }
  77. // after loading, all detached DataRows are attached to their tables
  78. private void AttachRows( DataRow parentRow, XmlNode parentElement ) {
  79. if (parentElement == null)
  80. return;
  81. for (XmlNode n = parentElement.FirstChild; n != null; n = n.NextSibling) {
  82. if (n.NodeType == XmlNodeType.Element) {
  83. XmlElement e = (XmlElement) n;
  84. DataRow r = GetRowFromElement( e );
  85. if (r != null && r.RowState == DataRowState.Detached) {
  86. if (parentRow != null)
  87. r.SetNestedParentRow( parentRow, /*setNonNested*/ false );
  88. r.Table.Rows.Add( r );
  89. }
  90. else if (r == null) {
  91. // n is a 'sugar element'
  92. AttachRows( parentRow, n );
  93. }
  94. // attach all detached rows
  95. AttachRows( r, n );
  96. }
  97. }
  98. }
  99. private int CountNonNSAttributes (XmlNode node) {
  100. int count = 0;
  101. for (int i = 0; i < node.Attributes.Count; i++) {
  102. XmlAttribute attr = node.Attributes[i];
  103. if (!FExcludedNamespace(node.Attributes[i].NamespaceURI))
  104. count++;
  105. }
  106. return count;
  107. }
  108. private string GetValueForTextOnlyColums( XmlNode n ) {
  109. string value = null;
  110. // don't consider whitespace
  111. while (n != null && (n.NodeType == XmlNodeType.Whitespace || !IsTextLikeNode(n.NodeType))) {
  112. n = n.NextSibling;
  113. }
  114. if (n != null) {
  115. if (IsTextLikeNode( n.NodeType ) && (n.NextSibling == null || !IsTextLikeNode( n.NodeType ))) {
  116. // don't use string builder if only one text node exists
  117. value = n.Value;
  118. n = n.NextSibling;
  119. }
  120. else {
  121. StringBuilder sb = new StringBuilder();
  122. while (n != null && IsTextLikeNode( n.NodeType )) {
  123. sb.Append( n.Value );
  124. n = n.NextSibling;
  125. }
  126. value = sb.ToString();
  127. }
  128. }
  129. if (value == null)
  130. value = String.Empty;
  131. return value;
  132. }
  133. private string GetInitialTextFromNodes( ref XmlNode n ) {
  134. string value = null;
  135. if (n != null) {
  136. // don't consider whitespace
  137. while (n.NodeType == XmlNodeType.Whitespace)
  138. n = n.NextSibling;
  139. if (IsTextLikeNode( n.NodeType ) && (n.NextSibling == null || !IsTextLikeNode( n.NodeType ))) {
  140. // don't use string builder if only one text node exists
  141. value = n.Value;
  142. n = n.NextSibling;
  143. }
  144. else {
  145. StringBuilder sb = new StringBuilder();
  146. while (n != null && IsTextLikeNode( n.NodeType )) {
  147. sb.Append( n.Value );
  148. n = n.NextSibling;
  149. }
  150. value = sb.ToString();
  151. }
  152. }
  153. if (value == null)
  154. value = String.Empty;
  155. return value;
  156. }
  157. private DataColumn GetTextOnlyColumn( DataRow row ) {
  158. DataColumnCollection columns = row.Table.Columns;
  159. int cCols = columns.Count;
  160. for (int iCol = 0; iCol < cCols; iCol++) {
  161. DataColumn c = columns[iCol];
  162. if (IsTextOnly( c ))
  163. return c;
  164. }
  165. return null;
  166. }
  167. internal DataRow GetRowFromElement( XmlElement e ) {
  168. return(DataRow) nodeToRowMap[e];
  169. }
  170. internal bool FColumnElement(XmlElement e) {
  171. if (nodeToSchemaMap.GetColumnSchema(e, FIgnoreNamespace(e)) == null)
  172. return false;
  173. if (CountNonNSAttributes(e) > 0)
  174. return false;
  175. for (XmlNode tabNode = e.FirstChild; tabNode != null; tabNode = tabNode.NextSibling)
  176. if (tabNode is XmlElement)
  177. return false;
  178. return true;
  179. }
  180. private bool FExcludedNamespace(string ns) {
  181. if (ns.Equals(Keywords.XSD_XMLNS_NS))
  182. return true;
  183. if (htableExcludedNS == null)
  184. return false;
  185. return htableExcludedNS.Contains(ns);
  186. }
  187. private bool FIgnoreNamespace(XmlNode node) {
  188. XmlNode ownerNode;
  189. if (!fIsXdr)
  190. return false;
  191. if (node is XmlAttribute)
  192. ownerNode = ((XmlAttribute)node).OwnerElement;
  193. else
  194. ownerNode = node;
  195. if (ownerNode.NamespaceURI.StartsWith("x-schema:#", StringComparison.Ordinal))
  196. return true;
  197. else
  198. return false;
  199. }
  200. private bool FIgnoreNamespace(XmlReader node) {
  201. if (fIsXdr && node.NamespaceURI.StartsWith("x-schema:#", StringComparison.Ordinal))
  202. return true;
  203. else
  204. return false;
  205. }
  206. internal bool IsTextLikeNode( XmlNodeType n ) {
  207. switch (n) {
  208. case XmlNodeType.EntityReference:
  209. throw ExceptionBuilder.FoundEntity();
  210. case XmlNodeType.Text:
  211. case XmlNodeType.Whitespace:
  212. case XmlNodeType.SignificantWhitespace:
  213. case XmlNodeType.CDATA:
  214. return true;
  215. default:
  216. return false;
  217. }
  218. }
  219. internal bool IsTextOnly( DataColumn c ) {
  220. if (c.ColumnMapping != MappingType.SimpleContent)
  221. return false;
  222. else
  223. return true;
  224. }
  225. internal void LoadData( XmlDocument xdoc ) {
  226. if (xdoc.DocumentElement == null)
  227. return;
  228. bool saveEnforce;
  229. if (isTableLevel) {
  230. saveEnforce = dataTable.EnforceConstraints;
  231. dataTable.EnforceConstraints = false;
  232. }
  233. else {
  234. saveEnforce = dataSet.EnforceConstraints;
  235. dataSet.EnforceConstraints = false;
  236. dataSet.fInReadXml = true;
  237. }
  238. if (isTableLevel) {
  239. nodeToSchemaMap = new XmlToDatasetMap(dataTable, xdoc.NameTable);
  240. }
  241. else {
  242. nodeToSchemaMap = new XmlToDatasetMap(dataSet, xdoc.NameTable);
  243. }
  244. /*
  245. // Top level table or dataset ?
  246. XmlElement rootElement = xdoc.DocumentElement;
  247. Hashtable tableAtoms = new Hashtable();
  248. XmlNode tabNode;
  249. if (CountNonNSAttributes (rootElement) > 0)
  250. dataSet.fTopLevelTable = true;
  251. else {
  252. for (tabNode = rootElement.FirstChild; tabNode != null; tabNode = tabNode.NextSibling) {
  253. if (tabNode is XmlElement && tabNode.LocalName != Keywords.XSD_SCHEMA) {
  254. object value = tableAtoms[QualifiedName (tabNode.LocalName, tabNode.NamespaceURI)];
  255. if (value == null || (bool)value == false) {
  256. dataSet.fTopLevelTable = true;
  257. break;
  258. }
  259. }
  260. }
  261. }
  262. */
  263. DataRow topRow = null;
  264. if (isTableLevel ||(dataSet!= null && dataSet.fTopLevelTable) ){
  265. XmlElement e = xdoc.DocumentElement;
  266. DataTable topTable = (DataTable) nodeToSchemaMap.GetSchemaForNode(e, FIgnoreNamespace(e));
  267. if (topTable != null) {
  268. topRow = topTable.CreateEmptyRow(); //enzol perf
  269. nodeToRowMap[ e ] = topRow;
  270. // get all field values.
  271. LoadRowData( topRow, e );
  272. topTable.Rows.Add(topRow);
  273. }
  274. }
  275. LoadRows( topRow, xdoc.DocumentElement );
  276. AttachRows( topRow, xdoc.DocumentElement );
  277. if (isTableLevel) {
  278. dataTable.EnforceConstraints = saveEnforce;
  279. }
  280. else {
  281. dataSet.fInReadXml = false;
  282. dataSet.EnforceConstraints = saveEnforce;
  283. }
  284. }
  285. private void LoadRowData(DataRow row, XmlElement rowElement) {
  286. XmlNode n;
  287. DataTable table = row.Table;
  288. if (FromInference)
  289. table.Prefix = rowElement.Prefix;
  290. // keep a list of all columns that get updated
  291. Hashtable foundColumns = new Hashtable();
  292. row.BeginEdit();
  293. // examine all children first
  294. n = rowElement.FirstChild;
  295. // Look for data to fill the TextOnly column
  296. DataColumn column = GetTextOnlyColumn( row );
  297. if (column != null) {
  298. foundColumns[column] = column;
  299. string text = GetValueForTextOnlyColums( n ) ;
  300. if (XMLSchema.GetBooleanAttribute(rowElement, Keywords.XSI_NIL, Keywords.XSINS, false) && Common.ADP.IsEmpty(text) )
  301. row[column] = DBNull.Value;
  302. else
  303. SetRowValueFromXmlText( row, column, text );
  304. }
  305. // Walk the region to find elements that map to columns
  306. while (n != null && n != rowElement) {
  307. if (n.NodeType == XmlNodeType.Element) {
  308. XmlElement e = (XmlElement) n;
  309. object schema = nodeToSchemaMap.GetSchemaForNode( e, FIgnoreNamespace(e) );
  310. if (schema is DataTable) {
  311. if (FColumnElement(e))
  312. schema = nodeToSchemaMap.GetColumnSchema( e, FIgnoreNamespace(e) );
  313. }
  314. // if element has its own table mapping, it is a separate region
  315. if (schema == null || schema is DataColumn) {
  316. // descend to examine child elements
  317. n = e.FirstChild;
  318. if (schema != null && schema is DataColumn) {
  319. DataColumn c = (DataColumn) schema;
  320. if (c.Table == row.Table && c.ColumnMapping != MappingType.Attribute && foundColumns[c] == null) {
  321. foundColumns[c] = c;
  322. string text = GetValueForTextOnlyColums( n ) ;
  323. if (XMLSchema.GetBooleanAttribute(e, Keywords.XSI_NIL, Keywords.XSINS, false) && Common.ADP.IsEmpty(text) )
  324. row[c] = DBNull.Value;
  325. else
  326. SetRowValueFromXmlText( row, c, text );
  327. }
  328. }
  329. else if ((schema == null) && (n!=null)) {
  330. continue;
  331. }
  332. // nothing left down here, continue from element
  333. if (n == null)
  334. n = e;
  335. }
  336. }
  337. // if no more siblings, ascend back toward original element (rowElement)
  338. while (n != rowElement && n.NextSibling == null) {
  339. n = n.ParentNode;
  340. }
  341. if (n != rowElement)
  342. n = n.NextSibling;
  343. }
  344. //
  345. // Walk the attributes to find attributes that map to columns.
  346. //
  347. foreach( XmlAttribute attr in rowElement.Attributes ) {
  348. object schema = nodeToSchemaMap.GetColumnSchema( attr, FIgnoreNamespace(attr) );
  349. if (schema != null && schema is DataColumn) {
  350. DataColumn c = (DataColumn) schema;
  351. if (c.ColumnMapping == MappingType.Attribute && foundColumns[c] == null) {
  352. foundColumns[c] = c;
  353. n = attr.FirstChild;
  354. SetRowValueFromXmlText( row, c, GetInitialTextFromNodes( ref n ) );
  355. }
  356. }
  357. }
  358. // Null all columns values that aren't represented in the tree
  359. foreach( DataColumn c in row.Table.Columns ) {
  360. if (foundColumns[c] == null && XmlToDatasetMap.IsMappedColumn(c)) {
  361. if (!c.AutoIncrement) {
  362. if (c.AllowDBNull) {
  363. row[c] = DBNull.Value;
  364. }
  365. else {
  366. row[c] = c.DefaultValue;
  367. }
  368. }
  369. else {
  370. c.Init(row.tempRecord);
  371. }
  372. }
  373. }
  374. row.EndEdit();
  375. }
  376. // load all data from tree structre into datarows
  377. private void LoadRows( DataRow parentRow, XmlNode parentElement ) {
  378. if (parentElement == null)
  379. return;
  380. // Skip schema node as well
  381. if (parentElement.LocalName == Keywords.XSD_SCHEMA && parentElement.NamespaceURI == Keywords.XSDNS ||
  382. parentElement.LocalName == Keywords.SQL_SYNC && parentElement.NamespaceURI == Keywords.UPDGNS ||
  383. parentElement.LocalName == Keywords.XDR_SCHEMA && parentElement.NamespaceURI == Keywords.XDRNS)
  384. return;
  385. for (XmlNode n = parentElement.FirstChild; n != null; n = n.NextSibling) {
  386. if (n is XmlElement) {
  387. XmlElement e = (XmlElement) n;
  388. object schema = nodeToSchemaMap.GetSchemaForNode( e, FIgnoreNamespace(e) );
  389. if (schema != null && schema is DataTable) {
  390. DataRow r = GetRowFromElement( e );
  391. if (r == null) {
  392. // skip columns which has the same name as another table
  393. if (parentRow != null && FColumnElement(e))
  394. continue;
  395. r = ((DataTable)schema).CreateEmptyRow();
  396. nodeToRowMap[ e ] = r;
  397. // get all field values.
  398. LoadRowData( r, e );
  399. }
  400. // recurse down to inner elements
  401. LoadRows( r, n );
  402. }
  403. else {
  404. // recurse down to inner elements
  405. LoadRows( null, n );
  406. }
  407. }
  408. }
  409. }
  410. private void SetRowValueFromXmlText( DataRow row, DataColumn col, string xmlText ) {
  411. row[col] = col.ConvertXmlToObject(xmlText);
  412. }
  413. internal void LoadTopMostRow(ref bool[] foundColumns) {
  414. // Attempt to load row from top node we backed up in DataSet.ReadXml()
  415. // In most cases it contains the DataSet name and no information
  416. // Check if DataSet object matches the top node (it won't in most cases)
  417. Object obj = nodeToSchemaMap.GetSchemaForNode(topMostNode,FIgnoreNamespace(topMostNode));
  418. if (obj is DataTable) { // It's a table? Load it.
  419. DataTable table = (DataTable) obj;
  420. topMostRow = table.CreateEmptyRow();
  421. foundColumns = new bool[topMostRow.Table.Columns.Count];
  422. //
  423. // Walk the attributes to find attributes that map to columns.
  424. //
  425. foreach( XmlAttribute attr in topMostNode.Attributes ) {
  426. object schema = nodeToSchemaMap.GetColumnSchema( attr, FIgnoreNamespace(attr) );
  427. if (schema != null && schema is DataColumn) {
  428. DataColumn c = (DataColumn) schema;
  429. if (c.ColumnMapping == MappingType.Attribute) {
  430. XmlNode n = attr.FirstChild;
  431. SetRowValueFromXmlText( topMostRow, c, GetInitialTextFromNodes( ref n ) );
  432. foundColumns[c.Ordinal] = true;
  433. }
  434. }
  435. }
  436. }
  437. topMostNode = null;
  438. }
  439. private XmlReader dataReader = null;
  440. private object XSD_XMLNS_NS;
  441. private object XDR_SCHEMA;
  442. private object XDRNS;
  443. private object SQL_SYNC;
  444. private object UPDGNS;
  445. private object XSD_SCHEMA;
  446. private object XSDNS;
  447. private object DFFNS;
  448. private object MSDNS;
  449. private object DIFFID;
  450. private object HASCHANGES;
  451. private object ROWORDER;
  452. private void InitNameTable() {
  453. XmlNameTable nameTable = dataReader.NameTable;
  454. XSD_XMLNS_NS = nameTable.Add(Keywords.XSD_XMLNS_NS);
  455. XDR_SCHEMA = nameTable.Add(Keywords.XDR_SCHEMA);
  456. XDRNS = nameTable.Add(Keywords.XDRNS);
  457. SQL_SYNC = nameTable.Add(Keywords.SQL_SYNC);
  458. UPDGNS = nameTable.Add(Keywords.UPDGNS);
  459. XSD_SCHEMA = nameTable.Add(Keywords.XSD_SCHEMA);
  460. XSDNS = nameTable.Add(Keywords.XSDNS);
  461. DFFNS = nameTable.Add(Keywords.DFFNS);
  462. MSDNS = nameTable.Add(Keywords.MSDNS);
  463. DIFFID = nameTable.Add(Keywords.DIFFID);
  464. HASCHANGES = nameTable.Add(Keywords.HASCHANGES);
  465. ROWORDER = nameTable.Add(Keywords.ROWORDER);
  466. }
  467. internal void LoadData(XmlReader reader) {
  468. dataReader = DataTextReader.CreateReader(reader);
  469. int entryDepth = dataReader.Depth; // Store current XML element depth so we'll read
  470. // correct portion of the XML and no more
  471. bool fEnforce = isTableLevel ? dataTable.EnforceConstraints : dataSet.EnforceConstraints;
  472. // Keep constraints status for datataset/table
  473. InitNameTable(); // Adds DataSet namespaces to reader's nametable
  474. if (nodeToSchemaMap == null) { // Create XML to dataset map
  475. nodeToSchemaMap = isTableLevel ? new XmlToDatasetMap(dataReader.NameTable, dataTable) :
  476. new XmlToDatasetMap(dataReader.NameTable, dataSet);
  477. }
  478. if (isTableLevel) {
  479. dataTable.EnforceConstraints = false; // Disable constraints
  480. }
  481. else {
  482. dataSet.EnforceConstraints = false; // Disable constraints
  483. dataSet.fInReadXml = true; // We're in ReadXml now
  484. }
  485. if (topMostNode != null) { // Do we have top node?
  486. if (!isDiffgram && !isTableLevel) { // Not a diffgram and not DataSet?
  487. DataTable table = nodeToSchemaMap.GetSchemaForNode(topMostNode, FIgnoreNamespace(topMostNode)) as DataTable;
  488. // Try to match table in the dataset to this node
  489. if (table != null) { // Got the table ?
  490. LoadTopMostTable(table); // Load top most node
  491. }
  492. }
  493. topMostNode = null; // topMostNode is no more. Good riddance.
  494. }
  495. while( !dataReader.EOF ) { // Main XML parsing loop. Check for EOF just in case.
  496. if (dataReader.Depth < entryDepth) // Stop if we have consumed all elements allowed
  497. break;
  498. if ( reader.NodeType != XmlNodeType.Element ) { // Read till Element is found
  499. dataReader.Read();
  500. continue;
  501. }
  502. DataTable table = nodeToSchemaMap.GetTableForNode(dataReader, FIgnoreNamespace(dataReader));
  503. // Try to get table for node
  504. if (table == null) { // Read till table is found
  505. if (!ProcessXsdSchema()) // Check for schemas...
  506. dataReader.Read(); // Not found? Read next element.
  507. continue;
  508. }
  509. LoadTable(table, false /* isNested */); // Here goes -- load data for this table
  510. // This is a root table, so it's not nested
  511. }
  512. if (isTableLevel) {
  513. dataTable.EnforceConstraints = fEnforce; // Restore constraints and return
  514. }
  515. else {
  516. dataSet.fInReadXml = false; // We're done.
  517. dataSet.EnforceConstraints = fEnforce; // Restore constraints and return
  518. }
  519. }
  520. // Loads a top most table.
  521. // This is neded because desktop is capable of loading almost anything into the dataset.
  522. // The top node could be a DataSet element or a Table element. To make things worse,
  523. // you could have a table with the same name as dataset.
  524. // Here's how we're going to dig into this mess:
  525. //
  526. // TopNode is null ?
  527. // / No \ Yes
  528. // Table matches TopNode ? Current node is the table start
  529. // / No \ Yes (LoadTopMostTable called in this case only)
  530. // Current node is the table start DataSet name matches one of the tables ?
  531. // TopNode is dataset node / Yes \ No
  532. // / TopNode is the table
  533. // Current node matches column or nested table in the table ? and current node
  534. // / No \ Yes is a column or a
  535. // TopNode is DataSet TopNode is table nested table
  536. //
  537. // Yes, it is terrible and I don't like it also..
  538. private void LoadTopMostTable(DataTable table) {
  539. // /------------------------------- This one is in topMostNode (backed up to XML DOM)
  540. // <Table> /----------------------------- We are here on entrance
  541. // <Column>Value</Column>
  542. // <AnotherColumn>Value</AnotherColumn>
  543. // </Table> ...
  544. // \------------------------------ We are here on exit
  545. Debug.Assert (table != null, "Table to be loaded is null on LoadTopMostTable() entry");
  546. Debug.Assert (topMostNode != null, "topMostNode is null on LoadTopMostTable() entry");
  547. Debug.Assert (!isDiffgram, "Diffgram mode is on while we have topMostNode table. This is bad." );
  548. bool topNodeIsTable = isTableLevel || (dataSet.DataSetName != table.TableName);
  549. // If table name we have matches dataset
  550. // name top node could be a DataSet OR a table.
  551. // It's a table overwise.
  552. DataRow row = null; // Data row we're going to add to this table
  553. bool matchFound = false; // Assume we found no matching elements
  554. int entryDepth = dataReader.Depth - 1; // Store current reader depth so we know when to stop reading
  555. // Adjust depth by one as we've read top most element
  556. // outside this method.
  557. string textNodeValue; // Value of a text node we might have
  558. Debug.Assert (entryDepth >= 0, "Wrong entry Depth for top most element." );
  559. int entryChild = childRowsStack.Count; // Memorize child stack level on entry
  560. DataColumn c; // Hold column here
  561. DataColumnCollection collection = table.Columns; // Hold column collectio here
  562. object[] foundColumns = new object[collection.Count];
  563. // This is the columns data we might find
  564. XmlNode n; // Need this to pass by reference
  565. foreach( XmlAttribute attr in topMostNode.Attributes ) {
  566. // Check all attributes in this node
  567. c = nodeToSchemaMap.GetColumnSchema( attr, FIgnoreNamespace(attr)) as DataColumn;
  568. // Try to mach attribute to column
  569. if ((c != null) && (c.ColumnMapping == MappingType.Attribute)) {
  570. // If it's a column with attribute mapping
  571. n = attr.FirstChild;
  572. foundColumns[c.Ordinal] = c.ConvertXmlToObject(GetInitialTextFromNodes(ref n));
  573. // Get value
  574. matchFound = true; // and note we found a matching element
  575. }
  576. }
  577. // Now handle elements. This could be columns or nested tables
  578. // We'll skip the rest as we have no idea what to do with it.
  579. // Note: we do not need to read first as we're already as it has been done by caller.
  580. while (entryDepth < dataReader.Depth ) {
  581. switch (dataReader.NodeType) { // Process nodes based on type
  582. case XmlNodeType.Element: // It's an element
  583. object o = nodeToSchemaMap.GetColumnSchema(table, dataReader, FIgnoreNamespace(dataReader));
  584. // Get dataset element for this XML element
  585. c = o as DataColumn; // Perhaps, it's a column?
  586. if ( c != null ) { // Do we have matched column in this table?
  587. // Let's load column data
  588. if (foundColumns[c.Ordinal] == null) {
  589. // If this column was not found before
  590. LoadColumn (c, foundColumns); // Get column value.
  591. matchFound = true; // Got matched row.
  592. }
  593. else {
  594. dataReader.Read(); // Advance to next element.
  595. }
  596. }
  597. else {
  598. DataTable nestedTable = o as DataTable;
  599. // Perhaps, it's a nested table ?
  600. if ( nestedTable != null ) { // Do we have matched table in DataSet ?
  601. LoadTable (nestedTable, true /* isNested */);
  602. // Yes. Load nested table (recursive)
  603. matchFound = true; // Got matched nested table
  604. }
  605. else if (ProcessXsdSchema()) { // Check for schema. Skip or load if found.
  606. continue; // Schema has been found. Process the next element
  607. // we're already at (done by schema processing).
  608. }
  609. else { // Not a table or column in this table ?
  610. if (!(matchFound || topNodeIsTable)) {
  611. // Could top node be a DataSet?
  612. return; // Assume top node is DataSet
  613. // and stop top node processing
  614. }
  615. dataReader.Read(); // Continue to the next element.
  616. }
  617. }
  618. break;
  619. // Oops. Not supported
  620. case XmlNodeType.EntityReference: // Oops. No support for Entity Reference
  621. throw ExceptionBuilder.FoundEntity();
  622. case XmlNodeType.Text: // It looks like a text.
  623. case XmlNodeType.Whitespace: // This actually could be
  624. case XmlNodeType.CDATA: // if we have XmlText in our table
  625. case XmlNodeType.SignificantWhitespace:
  626. textNodeValue = dataReader.ReadString();
  627. // Get text node value.
  628. c = table.xmlText; // Get XML Text column from our table
  629. if (c != null && foundColumns[c.Ordinal] == null) {
  630. // If XmlText Column is set
  631. // and we do not have data already
  632. foundColumns[c.Ordinal] = c.ConvertXmlToObject(textNodeValue);
  633. // Read and store the data
  634. }
  635. break;
  636. default:
  637. dataReader.Read(); // We don't process that, skip to the next element.
  638. break;
  639. }
  640. }
  641. dataReader.Read(); // Proceed to the next element.
  642. // It's the time to populate row with loaded data and add it to the table we'we just read to the table
  643. for ( int i = foundColumns.Length -1; i >= 0; --i) {
  644. // Check all columns
  645. if (null == foundColumns[i]) { // Got data for this column ?
  646. c = collection[i]; // No. Get column for this index
  647. if (c.AllowDBNull && c.ColumnMapping != MappingType.Hidden && !c.AutoIncrement) {
  648. foundColumns[i] = DBNull.Value; // Assign DBNull if possible
  649. // table.Rows.Add() below will deal
  650. // with default values and autoincrement
  651. }
  652. }
  653. }
  654. row = table.Rows.AddWithColumnEvents(foundColumns); // Create, populate and add row
  655. while (entryChild < childRowsStack.Count) { // Process child rows we might have
  656. DataRow childRow = (DataRow) childRowsStack.Pop();
  657. // Get row from the stack
  658. bool unchanged = (childRow.RowState == DataRowState.Unchanged);
  659. // Is data the same as before?
  660. childRow.SetNestedParentRow(row, /*setNonNested*/ false);
  661. // Set parent row
  662. if (unchanged) // Restore record if child row's unchanged
  663. childRow.oldRecord = childRow.newRecord;
  664. }
  665. }
  666. // Loads a table.
  667. // Yes, I know it's a big method. This is done to avoid performance penalty of calling methods
  668. // with many arguments and to keep recursion within one method only. To make code readable,
  669. // this method divided into 3 parts: attribute processing (including diffgram),
  670. // nested elements processing and loading data. Please keep it this way.
  671. private void LoadTable(DataTable table, bool isNested ) {
  672. // <DataSet> /--------------------------- We are here on entrance
  673. // <Table>
  674. // <Column>Value</Column>
  675. // <AnotherColumn>Value</AnotherColumn>
  676. // </Table> /-------------------------- We are here on exit
  677. // <AnotherTable>
  678. // ...
  679. // </AnotherTable>
  680. // ...
  681. // </DataSet>
  682. Debug.Assert (table != null, "Table to be loaded is null on LoadTable() entry");
  683. DataRow row = null; // Data row we're going to add to this table
  684. int entryDepth = dataReader.Depth; // Store current reader depth so we know when to stop reading
  685. int entryChild = childRowsStack.Count; // Memorize child stack level on entry
  686. DataColumn c; // Hold column here
  687. DataColumnCollection collection = table.Columns; // Hold column collectio here
  688. object[] foundColumns = new object[collection.Count];
  689. // This is the columns data we found
  690. // This is used to process diffgramms
  691. int rowOrder = -1; // Row to insert data to
  692. string diffId = String.Empty; // Diffgram ID string
  693. string hasChanges = null; // Changes string
  694. bool hasErrors = false; // Set this in case of problem
  695. string textNodeValue; // Value of a text node we might have
  696. // Process attributes first
  697. for ( int i = dataReader.AttributeCount -1; i >= 0; --i) {
  698. // Check all attributes one by one
  699. dataReader.MoveToAttribute(i); // Get this attribute
  700. c = nodeToSchemaMap.GetColumnSchema(table, dataReader, FIgnoreNamespace(dataReader)) as DataColumn;
  701. // Try to get column for this attribute
  702. if ((c != null) && (c.ColumnMapping == MappingType.Attribute)) {
  703. // Yep, it is a column mapped as attribute
  704. // Get value from XML and store it in the object array
  705. foundColumns[c.Ordinal] = c.ConvertXmlToObject(dataReader.Value);
  706. } // Oops. No column for this element
  707. //
  708. // else if (table.XmlText != null &&
  709. // dataReader.NamespaceURI == Keywords.XSINS &&
  710. // dataReader.LocalName == Keywords.XSI_NIL ) {
  711. // // Got XMLText column and it's a NIL attribute?
  712. // if (XmlConvert.ToBoolean(dataReader.Value)) {
  713. // // If NIL attribute set to true...
  714. // // Assign DBNull to XmlText column
  715. // foundColumns[table.XmlText.Ordinal] = DBNull.Value;
  716. // }
  717. // }
  718. if ( isDiffgram ) { // Now handle some diffgram attributes
  719. if ( dataReader.NamespaceURI == Keywords.DFFNS ) {
  720. switch (dataReader.LocalName) {
  721. case Keywords.DIFFID: // Is it a diffgeam ID ?
  722. diffId = dataReader.Value; // Store ID
  723. break;
  724. case Keywords.HASCHANGES: // Has chages attribute ?
  725. hasChanges = dataReader.Value; // Store value
  726. break;
  727. case Keywords.HASERRORS: // Has errors attribute ?
  728. hasErrors = (bool)Convert.ChangeType(dataReader.Value, typeof(bool), CultureInfo.InvariantCulture);
  729. // Store value
  730. break;
  731. }
  732. }
  733. else if ( dataReader.NamespaceURI == Keywords.MSDNS ) {
  734. if ( dataReader.LocalName == Keywords.ROWORDER ) {
  735. // Is it a row order attribute ?
  736. rowOrder = (Int32)Convert.ChangeType(dataReader.Value, typeof(Int32), CultureInfo.InvariantCulture);
  737. // Store it
  738. } else if (dataReader.LocalName.StartsWith("hidden", StringComparison.Ordinal)) {
  739. // Hidden column ?
  740. c = collection[XmlConvert.DecodeName(dataReader.LocalName.Substring(6))];
  741. // Let's see if we have one.
  742. // We have to decode name before we look it up
  743. // We could not use XmlToDataSet map as it contains
  744. // no hidden columns
  745. if (( c != null) && (c.ColumnMapping == MappingType.Hidden)) {
  746. // Got column and it is hidden ?
  747. foundColumns[c.Ordinal] = c.ConvertXmlToObject(dataReader.Value);
  748. }
  749. }
  750. }
  751. }
  752. } // Done with attributes
  753. // Now handle elements. This could be columns or nested tables.
  754. // <DataSet> /------------------- We are here after dealing with attributes
  755. // <Table foo="FooValue" bar="BarValue">
  756. // <Column>Value</Column>
  757. // <AnotherColumn>Value</AnotherColumn>
  758. // </Table>
  759. // </DataSet>
  760. if ( dataReader.Read() && entryDepth < dataReader.Depth) {
  761. // Read to the next element and see if we're inside
  762. while ( entryDepth < dataReader.Depth ) { // Get out as soon as we've processed all nested nodes.
  763. switch (dataReader.NodeType) { // Process nodes based on type
  764. case XmlNodeType.Element: // It's an element
  765. object o = nodeToSchemaMap.GetColumnSchema(table, dataReader, FIgnoreNamespace(dataReader));
  766. // Get dataset element for this XML element
  767. c = o as DataColumn; // Perhaps, it's a column?
  768. if ( c != null ) { // Do we have matched column in this table?
  769. // Let's load column data
  770. if (foundColumns[c.Ordinal] == null) {
  771. // If this column was not found before
  772. LoadColumn (c, foundColumns);
  773. // Get column value
  774. }
  775. else {
  776. dataReader.Read(); // Advance to next element.
  777. }
  778. }
  779. else {
  780. DataTable nestedTable = o as DataTable;
  781. // Perhaps, it's a nested table ?
  782. if ( nestedTable != null ) { // Do we have matched nested table in DataSet ?
  783. LoadTable (nestedTable, true /* isNested */);
  784. // Yes. Load nested table (recursive)
  785. } // Not a table nor column? Check if it's schema.
  786. else if (ProcessXsdSchema()) { // Check for schema. Skip or load if found.
  787. continue; // Schema has been found. Process the next element
  788. // we're already at (done by schema processing).
  789. }
  790. else {
  791. // We've got element which is not supposed to he here according to the schema.
  792. // That might be a table which was misplaced. We should've thrown on that,
  793. // but we'll try to load it so we could keep compatibility.
  794. // We won't try to match to columns as we have no idea
  795. // which table this potential column might belong to.
  796. DataTable misplacedTable = nodeToSchemaMap.GetTableForNode(dataReader, FIgnoreNamespace(dataReader));
  797. // Try to get table for node
  798. if (misplacedTable != null) { // Got some matching table?
  799. LoadTable (misplacedTable, false /* isNested */);
  800. // While table's XML element is nested,
  801. // the table itself is not. Load it this way.
  802. }
  803. else {
  804. dataReader.Read(); // Not a table? Try next element.
  805. }
  806. }
  807. }
  808. break;
  809. case XmlNodeType.EntityReference: // Oops. No support for Entity Reference
  810. throw ExceptionBuilder.FoundEntity();
  811. case XmlNodeType.Text: // It looks like a text.
  812. case XmlNodeType.Whitespace: // This actually could be
  813. case XmlNodeType.CDATA: // if we have XmlText in our table
  814. case XmlNodeType.SignificantWhitespace:
  815. textNodeValue = dataReader.ReadString();
  816. // Get text node value.
  817. c = table.xmlText; // Get XML Text column from our table
  818. if (c != null && foundColumns[c.Ordinal] == null) {
  819. // If XmlText Column is set
  820. // and we do not have data already
  821. foundColumns[c.Ordinal] = c.ConvertXmlToObject(textNodeValue);
  822. // Read and store the data
  823. }
  824. break;
  825. default:
  826. dataReader.Read(); // We don't process that, skip to the next element.
  827. break;
  828. }
  829. }
  830. dataReader.Read(); // We're done here, proceed to the next element.
  831. }
  832. // It's the time to populate row with loaded data and add it to the table we'we just read to the table
  833. if (isDiffgram) { // In case of diffgram
  834. row = table.NewRow(table.NewUninitializedRecord());
  835. // just create an empty row
  836. row.BeginEdit(); // and allow it's population with data
  837. for ( int i = foundColumns.Length - 1; i >= 0 ; --i) {
  838. // Check all columns
  839. c = collection[i]; // Get column for this index
  840. c[row.tempRecord] = null != foundColumns[i] ? foundColumns[i] : DBNull.Value;
  841. // Set column to loaded value of to
  842. // DBNull if value is missing.
  843. }
  844. row.EndEdit(); // Done with this row
  845. table.Rows.DiffInsertAt(row, rowOrder); // insert data to specific location
  846. // And do some diff processing
  847. if (hasChanges == null) { // No changes ?
  848. row.oldRecord = row.newRecord; // Restore old record
  849. }
  850. if ((hasChanges == Keywords.MODIFIED) || hasErrors) {
  851. table.RowDiffId[diffId] = row;
  852. }
  853. }
  854. else {
  855. for ( int i = foundColumns.Length -1; i >= 0 ; --i) {
  856. // Check all columns
  857. if (null == foundColumns[i]) { // Got data for this column ?
  858. c = collection[i]; // No. Get column for this index
  859. if (c.AllowDBNull && c.ColumnMapping != MappingType.Hidden && !c.AutoIncrement) {
  860. foundColumns[i] = DBNull.Value; // Assign DBNull if possible
  861. // table.Rows.Add() below will deal
  862. // with default values and autoincrement
  863. }
  864. }
  865. }
  866. row = table.Rows.AddWithColumnEvents(foundColumns); // Create, populate and add row
  867. }
  868. // Data is loaded into the row and row is added to the table at this point
  869. while (entryChild < childRowsStack.Count) { // Process child rows we might have
  870. DataRow childRow = (DataRow) childRowsStack.Pop();
  871. // Get row from the stack
  872. bool unchanged = (childRow.RowState == DataRowState.Unchanged);
  873. // Is data the same as before?
  874. childRow.SetNestedParentRow(row, /*setNonNested*/ false);
  875. // Set parent row
  876. if (unchanged) // Restore record if child row's unchanged
  877. childRow.oldRecord = childRow.newRecord;
  878. }
  879. if (isNested) // Got parent ?
  880. childRowsStack.Push(row); // Push row to the stack
  881. }
  882. // Returns column value
  883. private void LoadColumn (DataColumn column, object[] foundColumns) {
  884. // <DataSet> /--------------------------------- We are here on entrance
  885. // <Table> /
  886. // <Column>Value</Column>
  887. // <AnotherColumn>Value</AnotherColumn>
  888. // </Table> \------------------------------ We are here on exit
  889. // </DataSet>
  890. // <Column> If we have something like this
  891. // <Foo>FooVal</Foo> We would grab first text-like node
  892. // Value In this case it would be "FooVal"
  893. // <Bar>BarVal</Bar> And not "Value" as you might think
  894. // </Column> This is how desktop works
  895. string text = String.Empty; // Column text. Assume empty string
  896. string xsiNilString = null; // Possible NIL attribute string
  897. int entryDepth = dataReader.Depth; // Store depth so we won't read too much
  898. if (dataReader.AttributeCount > 0) // If have attributes
  899. xsiNilString = dataReader.GetAttribute(Keywords.XSI_NIL, Keywords.XSINS);
  900. // Try to get NIL attribute
  901. // We have to do it before we move to the next element
  902. if (column.IsCustomType) { // Custom type column
  903. object columnValue = null; // Column value we're after. Assume no value.
  904. string xsiTypeString = null; // XSI type name from TYPE attribute
  905. string typeName = null; // Type name from MSD_INSTANCETYPE attribute
  906. XmlRootAttribute xmlAttrib = null; // Might need this attribute for XmlSerializer
  907. if (dataReader.AttributeCount > 0) { // If have attributes, get attributes we'll need
  908. xsiTypeString = dataReader.GetAttribute(Keywords.TYPE, Keywords.XSINS);
  909. typeName = dataReader.GetAttribute(Keywords.MSD_INSTANCETYPE, Keywords.MSDNS);
  910. }
  911. // Check if need to use XmlSerializer. We need to do that if type does not implement IXmlSerializable.
  912. // We also need to do that if no polymorphism for this type allowed.
  913. bool useXmlSerializer = !column.ImplementsIXMLSerializable &&
  914. !( (column.DataType == typeof(Object)) || (typeName != null) || (xsiTypeString != null) );
  915. // Check if we have an attribute telling us value is null.
  916. if ((xsiNilString != null) && XmlConvert.ToBoolean(xsiNilString)) {
  917. if (!useXmlSerializer) { // See if need to set typed null.
  918. if (typeName != null && typeName.Length > 0) {
  919. // Got type name
  920. columnValue = SqlUdtStorage.GetStaticNullForUdtType(DataStorage.GetType(typeName));
  921. }
  922. }
  923. if (null == columnValue) { // If no value,
  924. columnValue = DBNull.Value; // change to DBNull;
  925. }
  926. if ( !dataReader.IsEmptyElement ) // In case element is not empty
  927. while (dataReader.Read() && (entryDepth < dataReader.Depth));
  928. // Read current elements
  929. dataReader.Read(); // And start reading next element.
  930. }
  931. else { // No NIL attribute. Get value
  932. bool skipped = false;
  933. if (column.Table.DataSet != null && column.Table.DataSet.UdtIsWrapped) {
  934. dataReader.Read(); // if UDT is wrapped, skip the wrapper
  935. skipped = true;
  936. }
  937. if (useXmlSerializer) { // Create an attribute for XmlSerializer
  938. if (skipped) {
  939. xmlAttrib = new XmlRootAttribute(dataReader.LocalName);
  940. xmlAttrib.Namespace = dataReader.NamespaceURI ;
  941. }
  942. else {
  943. xmlAttrib = new XmlRootAttribute(column.EncodedColumnName);
  944. xmlAttrib.Namespace = column.Namespace;
  945. }
  946. }
  947. columnValue = column.ConvertXmlToObject(dataReader, xmlAttrib);
  948. // Go get the value
  949. if (skipped) {
  950. dataReader.Read(); // if Wrapper is skipped, skip its end tag
  951. }
  952. }
  953. foundColumns[column.Ordinal] = columnValue; // Store value
  954. }
  955. else { // Not a custom type.
  956. if ( dataReader.Read() && entryDepth < dataReader.Depth) {
  957. // Read to the next element and see if we're inside.
  958. while (entryDepth < dataReader.Depth) {
  959. switch (dataReader.NodeType) { // Process nodes based on type
  960. case XmlNodeType.Text: // It looks like a text. And we need it.
  961. case XmlNodeType.Whitespace:
  962. case XmlNodeType.CDATA:
  963. case XmlNodeType.SignificantWhitespace:
  964. if (0 == text.Length) { // In case we do not have value already
  965. text = dataReader.Value; // Get value.
  966. // See if we have other text nodes near. In most cases this loop will not be executed.
  967. StringBuilder builder = null;
  968. while ( dataReader.Read() && entryDepth < dataReader.Depth && IsTextLikeNode(dataReader.NodeType)) {
  969. if (builder == null) {
  970. builder = new StringBuilder(text);
  971. }
  972. builder.Append(dataReader.Value); // Concatenate other sequential text like
  973. // nodes we might have. This is rare.
  974. // We're using this instead of dataReader.ReadString()
  975. // which would do the same thing but slower.
  976. }
  977. if (builder != null) {
  978. text = builder.ToString();
  979. }
  980. }
  981. else {
  982. dataReader.ReadString(); // We've got column value already. Read this one and ignore it.
  983. }
  984. break;
  985. case XmlNodeType.Element:
  986. if (ProcessXsdSchema()) { // Check for schema. Skip or load if found.
  987. continue; // Schema has been found. Process the next element
  988. // we're already at (done by schema processing).
  989. }
  990. else {
  991. // We've got element which is not supposed to he here.
  992. // That might be table which was misplaced.
  993. // Or it might be a column inside column (also misplaced).
  994. object o = nodeToSchemaMap.GetColumnSchema(column.Table, dataReader, FIgnoreNamespace(dataReader));
  995. // Get dataset element for this XML element
  996. DataColumn c = o as DataColumn; // Perhaps, it's a column?
  997. if ( c != null ) { // Do we have matched column in this table?
  998. // Let's load column data
  999. if (foundColumns[c.Ordinal] == null) {
  1000. // If this column was not found before
  1001. LoadColumn (c, foundColumns);
  1002. // Get column value
  1003. }
  1004. else {
  1005. dataReader.Read(); // Already loaded, proceed to the next element
  1006. }
  1007. }
  1008. else {
  1009. DataTable nestedTable = o as DataTable;
  1010. // Perhaps, it's a nested table ?
  1011. if ( nestedTable != null ) {
  1012. // Do we have matched table in DataSet ?
  1013. LoadTable (nestedTable, true /* isNested */);
  1014. // Yes. Load nested table (recursive)
  1015. }
  1016. else { // Not a nested column nor nested table.
  1017. // Let's try other tables in the DataSet
  1018. DataTable misplacedTable = nodeToSchemaMap.GetTableForNode(dataReader, FIgnoreNamespace(dataReader));
  1019. // Try to get table for node
  1020. if (misplacedTable != null) {
  1021. // Got some table to match?
  1022. LoadTable (misplacedTable, false /* isNested */);
  1023. // While table's XML element is nested,
  1024. // the table itself is not. Load it this way.
  1025. }
  1026. else {
  1027. dataReader.Read(); // No match? Try next element
  1028. }
  1029. }
  1030. }
  1031. }
  1032. break;
  1033. case XmlNodeType.EntityReference: // Oops. No support for Entity Reference
  1034. throw ExceptionBuilder.FoundEntity();
  1035. default:
  1036. dataReader.Read(); // We don't process that, skip to the next element.
  1037. break;
  1038. }
  1039. }
  1040. dataReader.Read(); // We're done here. To the next element.
  1041. }
  1042. if (0 == text.Length && xsiNilString != null && XmlConvert.ToBoolean(xsiNilString)) {
  1043. foundColumns[column.Ordinal] = DBNull.Value;
  1044. // If no data and NIL attribute is true set value to null
  1045. }
  1046. else {
  1047. foundColumns[column.Ordinal] = column.ConvertXmlToObject(text);
  1048. }
  1049. }
  1050. }
  1051. // Check for schema and skips or loads XSD schema if found. Returns true if schema found.
  1052. // DataReader would be set on the first XML element after the schema of schema was found.
  1053. // If no schema detected, reader's position will not change.
  1054. private bool ProcessXsdSchema () {
  1055. if (((object)dataReader.LocalName == XSD_SCHEMA && (object)dataReader.NamespaceURI == XSDNS )) {
  1056. // Found XSD schema
  1057. if ( ignoreSchema ) { // Should ignore it?
  1058. dataReader.Skip(); // Yes, skip it
  1059. }
  1060. else { // Have to load schema.
  1061. if ( isTableLevel ) { // Loading into the DataTable ?
  1062. dataTable.ReadXSDSchema(dataReader, false); // Invoke ReadXSDSchema on a table
  1063. nodeToSchemaMap = new XmlToDatasetMap(dataReader.NameTable, dataTable);
  1064. } // Rebuild XML to DataSet map with new schema.
  1065. else { // Loading into the DataSet ?
  1066. dataSet.ReadXSDSchema(dataReader, false); // Invoke ReadXSDSchema on a DataSet
  1067. nodeToSchemaMap = new XmlToDatasetMap(dataReader.NameTable, dataSet);
  1068. } // Rebuild XML to DataSet map with new schema.
  1069. }
  1070. }
  1071. else if (((object)dataReader.LocalName == XDR_SCHEMA && (object)dataReader.NamespaceURI == XDRNS ) ||
  1072. ((object)dataReader.LocalName == SQL_SYNC && (object)dataReader.NamespaceURI == UPDGNS))
  1073. {
  1074. dataReader.Skip(); // Skip XDR or SQL sync
  1075. }
  1076. else {
  1077. return false; // No schema found. That means reader's position
  1078. // is unchganged. Report that to the caller.
  1079. }
  1080. return true; // Schema found, reader's position changed.
  1081. }
  1082. }
  1083. }