DataPointer.cs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700
  1. //------------------------------------------------------------------------------
  2. // <copyright file="DataPointer.cs" company="Microsoft">
  3. // Copyright (c) Microsoft Corporation. All rights reserved.
  4. // </copyright>
  5. // <owner current="true" primary="true">Microsoft</owner>
  6. // <owner current="true" primary="false">Microsoft</owner>
  7. //------------------------------------------------------------------------------
  8. #pragma warning disable 618 // ignore obsolete warning about XmlDataDocument
  9. namespace System.Xml {
  10. using System;
  11. using System.Data;
  12. using System.Diagnostics;
  13. internal sealed class DataPointer : IXmlDataVirtualNode {
  14. private XmlDataDocument doc;
  15. private XmlNode node;
  16. private DataColumn column;
  17. private bool fOnValue;
  18. private bool bNeedFoliate = false;
  19. private bool _isInUse;
  20. internal DataPointer( XmlDataDocument doc, XmlNode node ) {
  21. this.doc = doc;
  22. this.node = node;
  23. this.column = null;
  24. this.fOnValue = false;
  25. bNeedFoliate = false;
  26. this._isInUse = true;
  27. AssertValid();
  28. }
  29. internal DataPointer( DataPointer pointer ) {
  30. this.doc = pointer.doc;
  31. this.node = pointer.node;
  32. this.column = pointer.column;
  33. this.fOnValue = pointer.fOnValue;
  34. this.bNeedFoliate = false;
  35. this._isInUse = true;
  36. AssertValid();
  37. }
  38. internal void AddPointer() {
  39. this.doc.AddPointer( (IXmlDataVirtualNode)this );
  40. }
  41. // Returns the row element of the region that the pointer points into
  42. private XmlBoundElement GetRowElement() {
  43. //AssertValid();
  44. XmlBoundElement rowElem;
  45. if ( this.column != null ) {
  46. rowElem = this.node as XmlBoundElement;
  47. Debug.Assert( rowElem != null );
  48. Debug.Assert( rowElem.Row != null );
  49. return rowElem;
  50. }
  51. doc.Mapper.GetRegion( this.node, out rowElem );
  52. return rowElem;
  53. }
  54. private DataRow Row {
  55. get {
  56. //AssertValid();
  57. XmlBoundElement rowElem = GetRowElement();
  58. if ( rowElem == null )
  59. return null;
  60. Debug.Assert( rowElem.Row != null );
  61. return rowElem.Row;
  62. }
  63. }
  64. private static bool IsFoliated( XmlNode node ) {
  65. if (node != null && node is XmlBoundElement)
  66. return((XmlBoundElement)node).IsFoliated;
  67. return true;
  68. }
  69. internal void MoveTo( DataPointer pointer ) {
  70. AssertValid();
  71. // You should not move outside of this document
  72. Debug.Assert( node == this.doc || node.OwnerDocument == this.doc );
  73. this.doc = pointer.doc;
  74. this.node = pointer.node;
  75. this.column = pointer.column;
  76. this.fOnValue = pointer.fOnValue;
  77. AssertValid();
  78. }
  79. private void MoveTo( XmlNode node ) {
  80. //AssertValid();
  81. // You should not move outside of this document
  82. Debug.Assert( node == this.doc || node.OwnerDocument == this.doc );
  83. this.node = node;
  84. this.column = null;
  85. this.fOnValue = false;
  86. AssertValid();
  87. }
  88. private void MoveTo( XmlNode node, DataColumn column, bool fOnValue ) {
  89. //AssertValid();
  90. // You should not move outside of this document
  91. Debug.Assert( node == this.doc || node.OwnerDocument == this.doc );
  92. this.node = node;
  93. this.column = column;
  94. this.fOnValue = fOnValue;
  95. AssertValid();
  96. }
  97. private DataColumn NextColumn( DataRow row, DataColumn col, bool fAttribute, bool fNulls ) {
  98. if (row.RowState == DataRowState.Deleted)
  99. return null;
  100. DataTable table = row.Table;
  101. DataColumnCollection columns = table.Columns;
  102. int iColumn = (col != null) ? col.Ordinal + 1 : 0;
  103. int cColumns = columns.Count;
  104. DataRowVersion rowVersion = ( row.RowState == DataRowState.Detached ) ? DataRowVersion.Proposed : DataRowVersion.Current;
  105. for (; iColumn < cColumns; iColumn++) {
  106. DataColumn c = columns[iColumn];
  107. if (!doc.IsNotMapped( c ) && (c.ColumnMapping == MappingType.Attribute) == fAttribute && (fNulls || ! Convert.IsDBNull( row[c, rowVersion] ) ) )
  108. return c;
  109. }
  110. return null;
  111. }
  112. private DataColumn NthColumn( DataRow row, bool fAttribute, int iColumn, bool fNulls ) {
  113. DataColumn c = null;
  114. while ((c = NextColumn( row, c, fAttribute, fNulls )) != null) {
  115. if (iColumn == 0)
  116. return c;
  117. iColumn = checked((int)iColumn-1);
  118. }
  119. return null;
  120. }
  121. private int ColumnCount( DataRow row, bool fAttribute, bool fNulls ) {
  122. DataColumn c = null;
  123. int count = 0;
  124. while ((c = NextColumn( row, c, fAttribute, fNulls )) != null) {
  125. count++;
  126. }
  127. return count;
  128. }
  129. internal bool MoveToFirstChild() {
  130. RealFoliate();
  131. AssertValid();
  132. if (node == null)
  133. return false;
  134. if (column != null) {
  135. if (fOnValue)
  136. return false;
  137. fOnValue = true;
  138. return true;
  139. }
  140. else if (!IsFoliated( node )) {
  141. // find virtual column elements first
  142. DataColumn c = NextColumn( Row, null, false, false );
  143. if (c != null) {
  144. MoveTo( node, c, doc.IsTextOnly(c) );
  145. return true;
  146. }
  147. }
  148. // look for anything
  149. XmlNode n = doc.SafeFirstChild( node );
  150. if (n != null) {
  151. MoveTo(n);
  152. return true;
  153. }
  154. return false;
  155. }
  156. internal bool MoveToNextSibling() {
  157. RealFoliate();
  158. AssertValid();
  159. if (node != null) {
  160. if (column != null) {
  161. if (fOnValue && !doc.IsTextOnly(column))
  162. return false;
  163. DataColumn c = NextColumn( Row, column, false, false );
  164. if (c != null) {
  165. MoveTo( this.node, c, false );
  166. return true;
  167. }
  168. XmlNode n = doc.SafeFirstChild( node );
  169. if (n != null) {
  170. MoveTo( n );
  171. return true;
  172. }
  173. }
  174. else {
  175. XmlNode n = doc.SafeNextSibling( node );
  176. if (n != null) {
  177. MoveTo(n);
  178. return true;
  179. }
  180. }
  181. }
  182. return false;
  183. }
  184. internal bool MoveToParent() {
  185. RealFoliate();
  186. AssertValid();
  187. if (node != null) {
  188. if (column != null) {
  189. if (fOnValue && !doc.IsTextOnly(column)) {
  190. MoveTo( node, column, false );
  191. return true;
  192. }
  193. if (column.ColumnMapping != MappingType.Attribute) {
  194. MoveTo( node, null, false );
  195. return true;
  196. }
  197. }
  198. else {
  199. XmlNode n = node.ParentNode;
  200. if (n != null) {
  201. MoveTo(n);
  202. return true;
  203. }
  204. }
  205. }
  206. return false;
  207. }
  208. internal bool MoveToOwnerElement() {
  209. RealFoliate();
  210. AssertValid();
  211. if (node != null) {
  212. if (column != null) {
  213. if (fOnValue || doc.IsTextOnly(column) || column.ColumnMapping != MappingType.Attribute)
  214. return false;
  215. MoveTo( node, null, false );
  216. return true;
  217. }
  218. else if (node.NodeType == XmlNodeType.Attribute) {
  219. XmlNode n = ((XmlAttribute)node).OwnerElement;
  220. if (n != null) {
  221. MoveTo( n, null, false );
  222. return true;
  223. }
  224. }
  225. }
  226. return false;
  227. }
  228. internal int AttributeCount {
  229. get {
  230. RealFoliate();
  231. AssertValid();
  232. if (node != null) {
  233. if (column == null && node.NodeType == XmlNodeType.Element) {
  234. if (!IsFoliated( node )) {
  235. return ColumnCount( Row, true, false );
  236. }
  237. else
  238. return node.Attributes.Count;
  239. }
  240. }
  241. return 0;
  242. }
  243. }
  244. internal bool MoveToAttribute( int i ) {
  245. RealFoliate();
  246. AssertValid();
  247. if ( i < 0 )
  248. return false;
  249. if (node != null) {
  250. if ((column == null || column.ColumnMapping == MappingType.Attribute) && node.NodeType == XmlNodeType.Element) {
  251. if (!IsFoliated( node )) {
  252. DataColumn c = NthColumn( Row, true, i, false );
  253. if (c != null) {
  254. MoveTo( node, c, false );
  255. return true;
  256. }
  257. }
  258. else {
  259. XmlNode n = node.Attributes.Item(i);
  260. if (n != null) {
  261. MoveTo( n, null, false );
  262. return true;
  263. }
  264. }
  265. }
  266. }
  267. return false;
  268. }
  269. internal XmlNodeType NodeType {
  270. get {
  271. RealFoliate();
  272. AssertValid();
  273. if (this.node == null) {
  274. return XmlNodeType.None;
  275. }
  276. else if (this.column == null) {
  277. return this.node.NodeType;
  278. }
  279. else if (this.fOnValue) {
  280. return XmlNodeType.Text;
  281. }
  282. else if (this.column.ColumnMapping == MappingType.Attribute) {
  283. return XmlNodeType.Attribute;
  284. }
  285. else {
  286. return XmlNodeType.Element;
  287. }
  288. }
  289. }
  290. internal string LocalName {
  291. get {
  292. RealFoliate();
  293. AssertValid();
  294. if (this.node == null) {
  295. return string.Empty;
  296. }else if (this.column == null) {
  297. String name = node.LocalName;
  298. Debug.Assert( name != null );
  299. if ( IsLocalNameEmpty( this.node.NodeType ) )
  300. return String.Empty;
  301. return name;
  302. }
  303. else if (this.fOnValue) {
  304. return String.Empty;
  305. }
  306. else {
  307. return doc.NameTable.Add(column.EncodedColumnName);
  308. }
  309. }
  310. }
  311. internal string NamespaceURI {
  312. get {
  313. RealFoliate();
  314. AssertValid();
  315. if (this.node == null) {
  316. return string.Empty;
  317. }
  318. else if (this.column == null) {
  319. return node.NamespaceURI;
  320. }
  321. else if (this.fOnValue) {
  322. return string.Empty;
  323. }
  324. else {
  325. return doc.NameTable.Add(column.Namespace);
  326. }
  327. }
  328. }
  329. internal string Name {
  330. get {
  331. RealFoliate();
  332. AssertValid();
  333. if (this.node == null) {
  334. return string.Empty;
  335. }
  336. else if (this.column == null) {
  337. String name = node.Name;
  338. //Again it could be String.Empty at null position
  339. Debug.Assert( name != null );
  340. if ( IsLocalNameEmpty( this.node.NodeType ) )
  341. return String.Empty;
  342. return name;
  343. }
  344. else {
  345. string prefix = Prefix;
  346. string lname = LocalName;
  347. if (prefix != null && prefix.Length > 0) {
  348. if (lname != null && lname.Length > 0) {
  349. return doc.NameTable.Add( prefix + ":" + lname );
  350. }
  351. else {
  352. return prefix;
  353. }
  354. }
  355. else {
  356. return lname;
  357. }
  358. }
  359. }
  360. }
  361. private bool IsLocalNameEmpty ( XmlNodeType nt) {
  362. switch ( nt ) {
  363. case XmlNodeType.None :
  364. case XmlNodeType.Text :
  365. case XmlNodeType.CDATA :
  366. case XmlNodeType.Comment :
  367. case XmlNodeType.Document :
  368. case XmlNodeType.DocumentFragment :
  369. case XmlNodeType.Whitespace :
  370. case XmlNodeType.SignificantWhitespace :
  371. case XmlNodeType.EndElement :
  372. case XmlNodeType.EndEntity :
  373. return true;
  374. case XmlNodeType.Element :
  375. case XmlNodeType.Attribute :
  376. case XmlNodeType.EntityReference :
  377. case XmlNodeType.Entity :
  378. case XmlNodeType.ProcessingInstruction :
  379. case XmlNodeType.DocumentType :
  380. case XmlNodeType.Notation :
  381. case XmlNodeType.XmlDeclaration :
  382. return false;
  383. default :
  384. return true;
  385. }
  386. }
  387. internal string Prefix {
  388. get {
  389. RealFoliate();
  390. AssertValid();
  391. if (this.node == null) {
  392. return string.Empty;
  393. }
  394. else if (this.column == null) {
  395. return node.Prefix;
  396. }
  397. else {
  398. return string.Empty;
  399. }
  400. }
  401. }
  402. internal string Value {
  403. get {
  404. RealFoliate();
  405. AssertValid();
  406. if (this.node == null) {
  407. return null;
  408. }
  409. else if (this.column == null) {
  410. return this.node.Value;
  411. }
  412. else if (this.column.ColumnMapping == MappingType.Attribute || this.fOnValue) {
  413. DataRow row = this.Row;
  414. DataRowVersion rowVersion = ( row.RowState == DataRowState.Detached ) ? DataRowVersion.Proposed : DataRowVersion.Current;
  415. object value = row[ this.column, rowVersion ];
  416. if ( ! Convert.IsDBNull( value ) )
  417. return this.column.ConvertObjectToXml( value );
  418. return null;
  419. }
  420. else {
  421. // column element has no value
  422. return null;
  423. }
  424. }
  425. }
  426. bool IXmlDataVirtualNode.IsOnNode( XmlNode nodeToCheck ) {
  427. RealFoliate();
  428. return nodeToCheck == this.node;
  429. }
  430. bool IXmlDataVirtualNode.IsOnColumn( DataColumn col ) {
  431. RealFoliate();
  432. return col == this.column;
  433. }
  434. internal XmlNode GetNode() {
  435. return this.node;
  436. }
  437. internal bool IsEmptyElement {
  438. get {
  439. RealFoliate();
  440. AssertValid();
  441. if (node != null && column == null) {
  442. //
  443. if (node.NodeType == XmlNodeType.Element) {
  444. return((XmlElement)node).IsEmpty;
  445. }
  446. }
  447. return false;
  448. }
  449. }
  450. internal bool IsDefault {
  451. get {
  452. RealFoliate();
  453. AssertValid();
  454. if (node != null && column == null && node.NodeType == XmlNodeType.Attribute) {
  455. return !((XmlAttribute)node).Specified;
  456. }
  457. return false;
  458. }
  459. }
  460. void IXmlDataVirtualNode.OnFoliated( XmlNode foliatedNode ) {
  461. // update the pointer if the element node has been foliated
  462. if (node == foliatedNode) {
  463. // if already on this node, nothing to do!
  464. if (column == null)
  465. return;
  466. bNeedFoliate = true;
  467. }
  468. }
  469. internal void RealFoliate() {
  470. if ( !bNeedFoliate )
  471. return;
  472. XmlNode n = null;
  473. if (doc.IsTextOnly( column )) {
  474. n = node.FirstChild;
  475. }
  476. else {
  477. if (column.ColumnMapping == MappingType.Attribute) {
  478. n = node.Attributes.GetNamedItem( column.EncodedColumnName, column.Namespace );
  479. }
  480. else {
  481. for (n = node.FirstChild; n != null; n = n.NextSibling) {
  482. if (n.LocalName == column.EncodedColumnName && n.NamespaceURI == column.Namespace)
  483. break;
  484. }
  485. }
  486. if (n != null && fOnValue)
  487. n = n.FirstChild;
  488. }
  489. if (n == null)
  490. throw new InvalidOperationException(Res.GetString(Res.DataDom_Foliation));
  491. // Cannot use MoveTo( n ); b/c the initial state for MoveTo is invalid (region is foliated but this is not)
  492. this.node = n;
  493. this.column = null;
  494. this.fOnValue = false;
  495. AssertValid();
  496. bNeedFoliate = false;
  497. }
  498. //for the 6 properties below, only when the this.column == null that the nodetype could be XmlDeclaration node
  499. internal String PublicId {
  500. get {
  501. XmlNodeType nt = NodeType;
  502. switch ( nt ) {
  503. case XmlNodeType.DocumentType : {
  504. Debug.Assert( this.column == null );
  505. return ( ( XmlDocumentType ) (this.node)).PublicId;
  506. }
  507. case XmlNodeType.Entity : {
  508. Debug.Assert( this.column == null );
  509. return ( ( XmlEntity ) (this.node)).PublicId;
  510. }
  511. case XmlNodeType.Notation : {
  512. Debug.Assert( this.column == null );
  513. return ( ( XmlNotation ) (this.node)).PublicId;
  514. }
  515. }
  516. return null;
  517. }
  518. }
  519. internal String SystemId {
  520. get {
  521. XmlNodeType nt = NodeType;
  522. switch ( nt ) {
  523. case XmlNodeType.DocumentType : {
  524. Debug.Assert( this.column == null );
  525. return ( ( XmlDocumentType ) (this.node)).SystemId;
  526. }
  527. case XmlNodeType.Entity : {
  528. Debug.Assert( this.column == null );
  529. return ( ( XmlEntity ) (this.node)).SystemId;
  530. }
  531. case XmlNodeType.Notation : {
  532. Debug.Assert( this.column == null );
  533. return ( ( XmlNotation ) (this.node)).SystemId;
  534. }
  535. }
  536. return null;
  537. }
  538. }
  539. internal String InternalSubset {
  540. get {
  541. if ( NodeType == XmlNodeType.DocumentType ) {
  542. Debug.Assert( this.column == null );
  543. return ( ( XmlDocumentType ) (this.node)).InternalSubset;
  544. }
  545. return null;
  546. }
  547. }
  548. internal XmlDeclaration Declaration {
  549. get {
  550. XmlNode child = doc.SafeFirstChild(doc);
  551. if ( child != null && child.NodeType == XmlNodeType.XmlDeclaration )
  552. return (XmlDeclaration)child;
  553. return null;
  554. }
  555. }
  556. internal String Encoding {
  557. get {
  558. if ( NodeType == XmlNodeType.XmlDeclaration ) {
  559. Debug.Assert( this.column == null );
  560. return ( ( XmlDeclaration ) (this.node)).Encoding;
  561. } else if ( NodeType == XmlNodeType.Document ) {
  562. XmlDeclaration dec = Declaration;
  563. if ( dec != null )
  564. return dec.Encoding;
  565. }
  566. return null;
  567. }
  568. }
  569. internal String Standalone {
  570. get {
  571. if ( NodeType == XmlNodeType.XmlDeclaration ) {
  572. Debug.Assert( this.column == null );
  573. return ( ( XmlDeclaration ) (this.node)).Standalone;
  574. } else if ( NodeType == XmlNodeType.Document ) {
  575. XmlDeclaration dec = Declaration;
  576. if ( dec != null )
  577. return dec.Standalone;
  578. }
  579. return null;
  580. }
  581. }
  582. internal String Version {
  583. get {
  584. if ( NodeType == XmlNodeType.XmlDeclaration ) {
  585. Debug.Assert( this.column == null );
  586. return ( ( XmlDeclaration ) (this.node)).Version;
  587. } else if ( NodeType == XmlNodeType.Document ) {
  588. XmlDeclaration dec = Declaration;
  589. if ( dec != null )
  590. return dec.Version;
  591. }
  592. return null;
  593. }
  594. }
  595. [System.Diagnostics.Conditional("DEBUG")]
  596. private void AssertValid() {
  597. // This pointer must be int the document list
  598. if ( this.column != null ) {
  599. // We must be on a de-foliated region
  600. XmlBoundElement rowElem = this.node as XmlBoundElement;
  601. Debug.Assert( rowElem != null );
  602. DataRow row = rowElem.Row;
  603. Debug.Assert( row != null );
  604. ElementState state = rowElem.ElementState;
  605. Debug.Assert( state == ElementState.Defoliated, "Region is accessed using column, but it's state is FOLIATED" );
  606. // We cannot be on a column for which the value is DBNull
  607. DataRowVersion rowVersion = ( row.RowState == DataRowState.Detached ) ? DataRowVersion.Proposed : DataRowVersion.Current;
  608. Debug.Assert( ! Convert.IsDBNull( row[ this.column, rowVersion ] ) );
  609. // If we are on the Text column, we should always have fOnValue == true
  610. Debug.Assert( (this.column.ColumnMapping == MappingType.SimpleContent) ? (this.fOnValue == true) : true );
  611. }
  612. }
  613. bool IXmlDataVirtualNode.IsInUse() {
  614. return _isInUse;
  615. }
  616. internal void SetNoLongerUse() {
  617. this.node = null;
  618. this.column = null;
  619. this.fOnValue = false;
  620. this.bNeedFoliate = false;
  621. this._isInUse = false;
  622. }
  623. }
  624. }