XmlNodeReader.cs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972
  1. //
  2. // System.Xml.XmlNodeReader.cs
  3. //
  4. // Author:
  5. // Duncan Mak ([email protected])
  6. // Atsushi Enomoto ([email protected])
  7. //
  8. // (C) Ximian, Inc.
  9. // (C) Atsushi Enomoto
  10. //
  11. //
  12. // Permission is hereby granted, free of charge, to any person obtaining
  13. // a copy of this software and associated documentation files (the
  14. // "Software"), to deal in the Software without restriction, including
  15. // without limitation the rights to use, copy, modify, merge, publish,
  16. // distribute, sublicense, and/or sell copies of the Software, and to
  17. // permit persons to whom the Software is furnished to do so, subject to
  18. // the following conditions:
  19. //
  20. // The above copyright notice and this permission notice shall be
  21. // included in all copies or substantial portions of the Software.
  22. //
  23. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  24. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  25. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  26. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  27. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  28. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  29. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  30. //
  31. using System;
  32. using System.Collections;
  33. using System.Xml;
  34. using System.Text;
  35. namespace System.Xml
  36. {
  37. public class XmlNodeReader : XmlReader
  38. {
  39. XmlDocument document;
  40. XmlNode startNode;
  41. XmlNode current;
  42. ReadState state = ReadState.Initial;
  43. int depth;
  44. bool isEndElement;
  45. bool nextIsEndElement; // used for ReadString()
  46. bool alreadyRead;
  47. StringBuilder valueBuilder = new StringBuilder ();
  48. XmlNamespaceManager defaultNsmgr;
  49. Stack entityReaderStack = new Stack ();
  50. XmlTextReader entityReader;
  51. private XmlNode ownerLinkedNode {
  52. get {
  53. if (current.ParentNode != null && current.ParentNode.NodeType == XmlNodeType.Attribute)
  54. return ((XmlAttribute) current.ParentNode).OwnerElement;
  55. else if (current.NodeType == XmlNodeType.Attribute)
  56. return ((XmlAttribute) current).OwnerElement;
  57. else
  58. return current;
  59. }
  60. }
  61. #region Constructor
  62. public XmlNodeReader (XmlNode node)
  63. {
  64. startNode = node;
  65. document = startNode.NodeType == XmlNodeType.Document ?
  66. startNode as XmlDocument : startNode.OwnerDocument;
  67. if (node.NodeType != XmlNodeType.Document
  68. && node.NodeType != XmlNodeType.DocumentFragment)
  69. alreadyRead = true;
  70. defaultNsmgr = new XmlNamespaceManager (this.NameTable);
  71. }
  72. #endregion
  73. #region Properties
  74. public override int AttributeCount {
  75. get {
  76. if (entityReader != null)
  77. return entityReader.ReadState == ReadState.Interactive ?
  78. entityReader.AttributeCount : 0;
  79. if (isEndElement || current == null)
  80. return 0;
  81. XmlNode n = ownerLinkedNode;
  82. return n.Attributes != null ? n.Attributes.Count : 0;
  83. }
  84. }
  85. public override string BaseURI {
  86. get {
  87. if (entityReader != null && entityReader.ReadState != ReadState.Initial)
  88. return entityReader.BaseURI;
  89. if (current == null)
  90. return String.Empty;
  91. return current.BaseURI;
  92. }
  93. }
  94. public override bool CanResolveEntity {
  95. get {
  96. return true;
  97. }
  98. }
  99. public override int Depth {
  100. get {
  101. if (entityReader != null && entityReader.ReadState == ReadState.Interactive)
  102. return entityReader.Depth + depth + entityReaderStack.Count + 1;
  103. if (current == null)
  104. return 0;
  105. if (current.NodeType == XmlNodeType.Attribute)
  106. return depth + 1;
  107. if (current.ParentNode != null && current.ParentNode.NodeType == XmlNodeType.Attribute)
  108. return depth + 2;
  109. return depth;
  110. }
  111. }
  112. public override bool EOF {
  113. get {
  114. return this.ReadState == ReadState.EndOfFile
  115. || this.ReadState == ReadState.Error;
  116. }
  117. }
  118. public override bool HasAttributes {
  119. get {
  120. if (entityReader != null)
  121. return entityReader.ReadState == ReadState.Interactive ?
  122. entityReader.HasAttributes : false;
  123. if (isEndElement || current == null)
  124. return false;
  125. // MS BUG: inconsistent return value between XmlTextReader and XmlNodeReader.
  126. // As for attribute and its descendants, XmlReader returns element's HasAttributes.
  127. XmlNode n = ownerLinkedNode;
  128. if (n.Attributes == null ||
  129. n.Attributes.Count == 0)
  130. return false;
  131. else
  132. return true;
  133. }
  134. }
  135. public override bool HasValue {
  136. get {
  137. if (entityReader != null)
  138. return entityReader.ReadState == ReadState.Interactive ?
  139. entityReader.IsDefault : false;
  140. if (current == null)
  141. return false;
  142. switch (current.NodeType) {
  143. case XmlNodeType.Element:
  144. case XmlNodeType.EntityReference:
  145. case XmlNodeType.Document:
  146. case XmlNodeType.DocumentFragment:
  147. case XmlNodeType.Notation:
  148. case XmlNodeType.EndElement:
  149. case XmlNodeType.EndEntity:
  150. return false;
  151. default:
  152. return true;
  153. }
  154. }
  155. }
  156. public override bool IsDefault {
  157. get {
  158. if (entityReader != null)
  159. return entityReader.ReadState == ReadState.Interactive ?
  160. entityReader.IsDefault : false;
  161. if (current == null)
  162. return false;
  163. if (current.NodeType != XmlNodeType.Attribute)
  164. return false;
  165. else
  166. {
  167. return ((XmlAttribute) current).isDefault;
  168. }
  169. }
  170. }
  171. public override bool IsEmptyElement {
  172. get {
  173. if (entityReader != null)
  174. return entityReader.ReadState == ReadState.Interactive ?
  175. entityReader.IsDefault : false;
  176. if (current == null)
  177. return false;
  178. if(current.NodeType == XmlNodeType.Element)
  179. return ((XmlElement) current).IsEmpty;
  180. else
  181. return false;
  182. }
  183. }
  184. public override string this [int i] {
  185. get { return GetAttribute (i); }
  186. }
  187. public override string this [string name] {
  188. get { return GetAttribute (name); }
  189. }
  190. public override string this [string name, string namespaceURI] {
  191. get { return GetAttribute (name, namespaceURI); }
  192. }
  193. public override string LocalName {
  194. get {
  195. if (entityReader != null && entityReader.ReadState != ReadState.Initial)
  196. return entityReader.LocalName;
  197. if (current == null)
  198. return String.Empty;
  199. switch (current.NodeType) {
  200. case XmlNodeType.Attribute:
  201. case XmlNodeType.DocumentType:
  202. case XmlNodeType.Element:
  203. case XmlNodeType.EntityReference:
  204. case XmlNodeType.ProcessingInstruction:
  205. case XmlNodeType.XmlDeclaration:
  206. return current.LocalName;
  207. }
  208. return String.Empty;
  209. }
  210. }
  211. public override string Name {
  212. get {
  213. if (entityReader != null && entityReader.ReadState != ReadState.Initial)
  214. return entityReader.Name;
  215. if (current == null)
  216. return String.Empty;
  217. switch (current.NodeType) {
  218. case XmlNodeType.Attribute:
  219. case XmlNodeType.DocumentType:
  220. case XmlNodeType.Element:
  221. case XmlNodeType.EntityReference:
  222. case XmlNodeType.ProcessingInstruction:
  223. case XmlNodeType.XmlDeclaration:
  224. return current.Name;
  225. }
  226. return String.Empty;
  227. }
  228. }
  229. public override string NamespaceURI {
  230. get {
  231. if (entityReader != null && entityReader.ReadState != ReadState.Initial)
  232. return entityReader.NamespaceURI;
  233. if (current == null)
  234. return String.Empty;
  235. return current.NamespaceURI;
  236. }
  237. }
  238. public override XmlNameTable NameTable {
  239. get { return document.NameTable; }
  240. }
  241. public override XmlNodeType NodeType {
  242. get {
  243. if (entityReader != null)
  244. switch (entityReader.ReadState) {
  245. case ReadState.Interactive:
  246. return entityReader.NodeType;
  247. case ReadState.Initial:
  248. return XmlNodeType.EntityReference;
  249. case ReadState.EndOfFile:
  250. return XmlNodeType.EndEntity;
  251. }
  252. if (current == null)
  253. return XmlNodeType.None;
  254. return isEndElement ? XmlNodeType.EndElement : current.NodeType;
  255. }
  256. }
  257. public override string Prefix {
  258. get {
  259. if (entityReader != null && entityReader.ReadState != ReadState.Initial)
  260. return entityReader.Prefix;
  261. if (current == null)
  262. return String.Empty;
  263. // if (current.NodeType == XmlNodeType.Attribute)
  264. // return current.Prefix != String.Empty ? current.Prefix : null;
  265. // else
  266. return current.Prefix;
  267. }
  268. }
  269. public override char QuoteChar {
  270. get {
  271. if (entityReader != null && entityReader.ReadState != ReadState.Initial)
  272. return entityReader.QuoteChar;
  273. return '"';
  274. }
  275. }
  276. public override ReadState ReadState {
  277. get { return state; }
  278. }
  279. public override string Value {
  280. get {
  281. if (entityReader != null && entityReader.ReadState != ReadState.Initial)
  282. return entityReader.Value;
  283. if (NodeType == XmlNodeType.DocumentType)
  284. return ((XmlDocumentType) current).InternalSubset;
  285. else
  286. return HasValue ? current.Value : String.Empty;
  287. }
  288. }
  289. public override string XmlLang {
  290. get {
  291. if (entityReader != null && entityReader.ReadState != ReadState.Initial)
  292. return entityReader.XmlLang;
  293. if (current == null)
  294. return String.Empty;
  295. return current.XmlLang;
  296. }
  297. }
  298. public override XmlSpace XmlSpace {
  299. get {
  300. if (entityReader != null && entityReader.ReadState != ReadState.Initial)
  301. return entityReader.XmlSpace;
  302. if (current == null)
  303. return XmlSpace.None;
  304. return current.XmlSpace;
  305. }
  306. }
  307. #endregion
  308. #region Methods
  309. // If current entityReference is a child of an attribute,
  310. // then MoveToAttribute simply means that we no more need this entity reader.
  311. // Otherwise, this invokation means that
  312. // it is expected to move to resolved (maybe) element's attribute.
  313. //
  314. // This rule applies to many methods like MoveTo*Attribute().
  315. private bool CheckAndResetEntityReaderOnMoveToAttribute ()
  316. {
  317. if (entityReader == null)
  318. return false;
  319. if (current != null && current.ParentNode != null &&
  320. current.ParentNode.NodeType == XmlNodeType.Attribute) {
  321. entityReader.Close ();
  322. entityReader = entityReaderStack.Count > 0 ?
  323. entityReaderStack.Pop () as XmlTextReader : null;
  324. return true;
  325. }
  326. else
  327. return false;
  328. }
  329. public override void Close ()
  330. {
  331. if (entityReader != null)
  332. entityReader.Close ();
  333. while (entityReaderStack.Count > 0)
  334. ((XmlTextReader) entityReaderStack.Pop ()).Close ();
  335. current = null;
  336. state = ReadState.Closed;
  337. }
  338. public override string GetAttribute (int attributeIndex)
  339. {
  340. if (entityReader != null && entityReader.ReadState != ReadState.Initial)
  341. return entityReader.GetAttribute (attributeIndex);
  342. if (NodeType == XmlNodeType.XmlDeclaration) {
  343. XmlDeclaration decl = current as XmlDeclaration;
  344. if (attributeIndex == 0)
  345. return decl.Version;
  346. else if (attributeIndex == 1) {
  347. if (decl.Encoding != String.Empty)
  348. return decl.Encoding;
  349. else if (decl.Standalone != String.Empty)
  350. return decl.Standalone;
  351. }
  352. else if (attributeIndex == 2 &&
  353. decl.Encoding != String.Empty && decl.Standalone != null)
  354. return decl.Standalone;
  355. throw new ArgumentOutOfRangeException ("Index out of range.");
  356. } else if (NodeType == XmlNodeType.DocumentType) {
  357. XmlDocumentType doctype = current as XmlDocumentType;
  358. if (attributeIndex == 0) {
  359. if (doctype.PublicId != "")
  360. return doctype.PublicId;
  361. else if (doctype.SystemId != "")
  362. return doctype.SystemId;
  363. } else if (attributeIndex == 1)
  364. if (doctype.PublicId == "" && doctype.SystemId != "")
  365. return doctype.SystemId;
  366. throw new ArgumentOutOfRangeException ("Index out of range.");
  367. }
  368. // This is MS.NET bug which returns attributes in spite of EndElement.
  369. if (isEndElement || current == null)
  370. return null;
  371. if (attributeIndex < 0 || attributeIndex > AttributeCount)
  372. throw new ArgumentOutOfRangeException ("Index out of range.");
  373. return ownerLinkedNode.Attributes [attributeIndex].Value;
  374. }
  375. public override string GetAttribute (string name)
  376. {
  377. if (entityReader != null && entityReader.ReadState != ReadState.Initial)
  378. return entityReader.GetAttribute (name);
  379. // This is MS.NET bug which returns attributes in spite of EndElement.
  380. if (isEndElement || current == null)
  381. return null;
  382. if (NodeType == XmlNodeType.XmlDeclaration)
  383. return GetXmlDeclarationAttribute (name);
  384. else if (NodeType == XmlNodeType.DocumentType)
  385. return GetDocumentTypeAttribute (name);
  386. if (ownerLinkedNode.Attributes == null)
  387. return null;
  388. XmlAttribute attr = ownerLinkedNode.Attributes [name];
  389. if (attr == null)
  390. return null;
  391. else
  392. return attr.Value;
  393. }
  394. public override string GetAttribute (string name, string namespaceURI)
  395. {
  396. if (entityReader != null && entityReader.ReadState != ReadState.Initial)
  397. return entityReader.GetAttribute (name, namespaceURI);
  398. // This is MS.NET bug which returns attributes in spite of EndElement.
  399. if (isEndElement || current == null)
  400. return null;
  401. if (NodeType == XmlNodeType.XmlDeclaration)
  402. return GetXmlDeclarationAttribute (name);
  403. else if (NodeType == XmlNodeType.DocumentType)
  404. return GetDocumentTypeAttribute (name);
  405. if (ownerLinkedNode.Attributes == null)
  406. return null;
  407. XmlAttribute attr = ownerLinkedNode.Attributes [name, namespaceURI];
  408. if (attr == null)
  409. return null; // In fact MS.NET returns null instead of String.Empty.
  410. else
  411. return attr.Value;
  412. }
  413. private string GetXmlDeclarationAttribute (string name)
  414. {
  415. XmlDeclaration decl = current as XmlDeclaration;
  416. switch (name) {
  417. case "version":
  418. return decl.Version;
  419. case "encoding":
  420. // This is MS.NET bug that XmlNodeReturns in case of string.empty.
  421. return decl.Encoding != String.Empty ? decl.Encoding : null;
  422. case "standalone":
  423. return decl.Standalone;
  424. }
  425. return null;
  426. }
  427. private string GetDocumentTypeAttribute (string name)
  428. {
  429. XmlDocumentType doctype = current as XmlDocumentType;
  430. switch (name) {
  431. case "PUBLIC":
  432. return doctype.PublicId;
  433. case "SYSTEM":
  434. return doctype.SystemId;
  435. }
  436. return null;
  437. }
  438. internal XmlParserContext GetInternalParserContext ()
  439. {
  440. if (entityReader != null)
  441. return entityReader.GetInternalParserContext ();
  442. else
  443. return new XmlParserContext (document.NameTable,
  444. current.ConstructNamespaceManager (),
  445. document.DocumentType != null ? document.DocumentType.DTD : null,
  446. current.BaseURI, XmlLang, XmlSpace, Encoding.Unicode);
  447. }
  448. public override string LookupNamespace (string prefix)
  449. {
  450. if (entityReader != null && entityReader.ReadState != ReadState.Initial)
  451. return entityReader.LookupNamespace (prefix);
  452. if (current == null)
  453. return null;
  454. XmlAttribute curAttr = current as XmlAttribute;
  455. XmlNode target = curAttr != null ? curAttr.OwnerElement : current;
  456. if (prefix == "") {
  457. do {
  458. XmlAttribute attr = target.Attributes ["xmlns"];
  459. if (attr != null)
  460. return attr.Value;
  461. target = target.ParentNode;
  462. } while (target.NodeType != XmlNodeType.Document);
  463. } else {
  464. string name = "xmlns:" + prefix;
  465. do {
  466. XmlAttribute attr = target.Attributes [name];
  467. if (attr != null)
  468. return attr.Value;
  469. target = target.ParentNode;
  470. } while (target.NodeType != XmlNodeType.Document);
  471. }
  472. return defaultNsmgr.LookupNamespace (prefix, false);
  473. }
  474. public override void MoveToAttribute (int attributeIndex)
  475. {
  476. if (entityReader != null) {
  477. if (!this.CheckAndResetEntityReaderOnMoveToAttribute ()) {
  478. entityReader.MoveToAttribute (attributeIndex);
  479. return;
  480. }
  481. // And in case of abondoning entityReader, go on...
  482. }
  483. if (isEndElement || attributeIndex < 0 || attributeIndex > AttributeCount)
  484. throw new ArgumentOutOfRangeException ();
  485. state = ReadState.Interactive;
  486. current = ownerLinkedNode.Attributes [attributeIndex];
  487. }
  488. public override bool MoveToAttribute (string name)
  489. {
  490. if (entityReader != null) {
  491. if (!this.CheckAndResetEntityReaderOnMoveToAttribute ())
  492. return entityReader.MoveToAttribute (name);
  493. // And in case of abondoning entityReader, go on...
  494. }
  495. if (isEndElement || current == null)
  496. return false;
  497. XmlNode tmpCurrent = current;
  498. if (current.ParentNode.NodeType == XmlNodeType.Attribute)
  499. current = current.ParentNode;
  500. if (ownerLinkedNode.Attributes == null)
  501. return false;
  502. XmlAttribute attr = ownerLinkedNode.Attributes [name];
  503. if (attr == null) {
  504. current = tmpCurrent;
  505. return false;
  506. }
  507. else {
  508. current = attr;
  509. return true;
  510. }
  511. }
  512. public override bool MoveToAttribute (string name, string namespaceURI)
  513. {
  514. if (entityReader != null) {
  515. if (!this.CheckAndResetEntityReaderOnMoveToAttribute ())
  516. return entityReader.MoveToAttribute (name, namespaceURI);
  517. // And in case of abondoning entityReader, go on...
  518. }
  519. if (isEndElement || current == null)
  520. return false;
  521. if (ownerLinkedNode.Attributes == null)
  522. return false;
  523. XmlAttribute attr = ownerLinkedNode.Attributes [name, namespaceURI];
  524. if (attr == null)
  525. return false;
  526. else {
  527. current = attr;
  528. return true;
  529. }
  530. }
  531. private void MoveToParentElement ()
  532. {
  533. // This is buggy. It is not only the case when EndElement = true.
  534. isEndElement = true;
  535. depth--;
  536. current = current.ParentNode;
  537. }
  538. public override bool MoveToElement ()
  539. {
  540. if (entityReader != null) {
  541. if (!this.CheckAndResetEntityReaderOnMoveToAttribute ())
  542. return entityReader.MoveToElement ();
  543. // And in case of abondoning entityReader, go on...
  544. }
  545. if (current == null)
  546. return false;
  547. XmlNode n = ownerLinkedNode;
  548. if (current != n) {
  549. current = n;
  550. return true;
  551. } else
  552. return false;
  553. }
  554. public override bool MoveToFirstAttribute ()
  555. {
  556. if (entityReader != null) {
  557. if (!this.CheckAndResetEntityReaderOnMoveToAttribute ())
  558. return entityReader.MoveToFirstAttribute ();
  559. // And in case of abondoning entityReader, go on...
  560. }
  561. if (current == null)
  562. return false;
  563. if (ownerLinkedNode.Attributes == null)
  564. return false;
  565. if(ownerLinkedNode.Attributes.Count > 0)
  566. {
  567. current = ownerLinkedNode.Attributes [0];
  568. return true;
  569. }
  570. else
  571. return false;
  572. }
  573. public override bool MoveToNextAttribute ()
  574. {
  575. if (entityReader != null) {
  576. if (!this.CheckAndResetEntityReaderOnMoveToAttribute ())
  577. return entityReader.MoveToNextAttribute ();
  578. // And in case of abondoning entityReader, go on...
  579. }
  580. if (current == null)
  581. return false;
  582. if (current.NodeType != XmlNodeType.Attribute)
  583. return MoveToFirstAttribute ();
  584. else
  585. {
  586. XmlAttributeCollection ac = ((XmlAttribute) current).OwnerElement.Attributes;
  587. for (int i=0; i<ac.Count-1; i++)
  588. {
  589. XmlAttribute attr = ac [i];
  590. if (attr == current)
  591. {
  592. i++;
  593. if (i == ac.Count)
  594. return false;
  595. current = ac [i];
  596. return true;
  597. }
  598. }
  599. return false;
  600. }
  601. }
  602. private bool MoveToNextSibling ()
  603. {
  604. if (nextIsEndElement) {
  605. // nextIsEndElement is set only by ReadString.
  606. nextIsEndElement = false;
  607. MoveToParentElement ();
  608. } else if (alreadyRead) {
  609. alreadyRead = false;
  610. return current != null;
  611. }
  612. if (current.NextSibling != null) {
  613. isEndElement = false;
  614. current = current.NextSibling;
  615. } else {
  616. MoveToParentElement ();
  617. }
  618. if (current == null) {
  619. state = ReadState.EndOfFile;
  620. return false;
  621. }
  622. else
  623. return true;
  624. }
  625. public override bool Read ()
  626. {
  627. if (EOF)
  628. return false;
  629. this.CheckAndResetEntityReaderOnMoveToAttribute ();
  630. if (entityReader != null) {
  631. // Read finalizes entity reader.
  632. switch (entityReader.ReadState) {
  633. case ReadState.Interactive:
  634. case ReadState.Initial:
  635. // If it is ended, then other properties/methods will take care.
  636. entityReader.Read ();
  637. return true;
  638. default:
  639. entityReader = entityReaderStack.Count > 0 ?
  640. entityReaderStack.Pop () as XmlTextReader : null;
  641. return Read ();
  642. }
  643. // and go on ...
  644. }
  645. if (ReadState == ReadState.Initial) {
  646. current = startNode;
  647. state = ReadState.Interactive;
  648. // when startNode is document or fragment
  649. if (!alreadyRead)
  650. current = startNode.FirstChild;
  651. else
  652. alreadyRead = false;
  653. if (current == null) {
  654. state = ReadState.Error;
  655. return false;
  656. } else
  657. return true;
  658. }
  659. MoveToElement ();
  660. if (IsEmptyElement || isEndElement) {
  661. // Then go up and move to next.
  662. // If no more nodes, then set EOF.
  663. isEndElement = false;
  664. if (current.ParentNode == null
  665. || current.ParentNode.NodeType == XmlNodeType.Document
  666. || current.ParentNode.NodeType == XmlNodeType.DocumentFragment) {
  667. current = null;
  668. state = ReadState.EndOfFile;
  669. return false;
  670. } else if (current.NextSibling == null) {
  671. depth--;
  672. current = current.ParentNode;
  673. isEndElement = true;
  674. return true;
  675. } else {
  676. current = current.NextSibling;
  677. return true;
  678. }
  679. } else if (nextIsEndElement) {
  680. // nextIsEndElement is set only by ReadString.
  681. nextIsEndElement = false;
  682. isEndElement = true;
  683. return current != null;
  684. } else if (alreadyRead) {
  685. alreadyRead = false;
  686. return current != null;
  687. }
  688. if (!isEndElement && current.FirstChild != null && current.NodeType != XmlNodeType.EntityReference) {
  689. isEndElement = false;
  690. current = current.FirstChild;
  691. depth++;
  692. } else if (current.NodeType == XmlNodeType.Element) {
  693. isEndElement = true;
  694. if (current.FirstChild != null)
  695. depth--;
  696. } else
  697. MoveToNextSibling ();
  698. return current != null;
  699. }
  700. public override bool ReadAttributeValue ()
  701. {
  702. if (entityReader != null) {
  703. switch (entityReader.ReadState) {
  704. case ReadState.Interactive:
  705. case ReadState.Initial:
  706. // If it is ended, then other properties/methods will take care.
  707. return entityReader.ReadAttributeValue ();
  708. default:
  709. entityReader = entityReaderStack.Count > 0 ?
  710. entityReaderStack.Pop () as XmlTextReader : null;
  711. // and go on ...
  712. return ReadAttributeValue ();
  713. }
  714. }
  715. if (current.NodeType == XmlNodeType.Attribute) {
  716. if (current.FirstChild == null)
  717. return false;
  718. current = current.FirstChild;
  719. return true;
  720. } else if (current.ParentNode.NodeType == XmlNodeType.Attribute) {
  721. if (current.NextSibling == null)
  722. return false;
  723. current = current.NextSibling;
  724. return true;
  725. } else
  726. return false;
  727. }
  728. #if NET_1_0
  729. // Its traversal behavior is almost same as Read().
  730. public override string ReadInnerXml ()
  731. {
  732. if (entityReader != null) {
  733. if (entityReader.EOF) {
  734. entityReader = entityReaderStack.Count > 0 ?
  735. entityReaderStack.Pop () as XmlTextReader : null;
  736. return ReadInnerXml ();
  737. } else
  738. return entityReader.ReadInnerXml ();
  739. }
  740. if (this.state != ReadState.Interactive)
  741. return String.Empty;
  742. XmlNode initial = current;
  743. // Almost copied from XmlTextReader.
  744. switch (NodeType) {
  745. case XmlNodeType.Attribute:
  746. return Value;
  747. case XmlNodeType.Element:
  748. if (IsEmptyElement)
  749. return String.Empty;
  750. int startDepth = depth;
  751. bool loop = true;
  752. do {
  753. Read ();
  754. if (NodeType ==XmlNodeType.None)
  755. throw new XmlException ("unexpected end of xml.");
  756. else if (NodeType == XmlNodeType.EndElement && depth == startDepth) {
  757. loop = false;
  758. Read ();
  759. }
  760. } while (loop);
  761. return initial.InnerXml;
  762. case XmlNodeType.None:
  763. return String.Empty;
  764. default:
  765. Read ();
  766. return String.Empty;
  767. }
  768. }
  769. // Its traversal behavior is almost same as Read().
  770. public override string ReadOuterXml ()
  771. {
  772. if (entityReader != null) {
  773. if (entityReader.EOF) {
  774. entityReader = entityReaderStack.Count > 0 ?
  775. entityReaderStack.Pop () as XmlTextReader : null;
  776. return ReadOuterXml ();
  777. } else
  778. return entityReader.ReadOuterXml ();
  779. }
  780. if (NodeType == XmlNodeType.EndElement)
  781. return String.Empty;
  782. XmlNode initial = current;
  783. switch (NodeType) {
  784. case XmlNodeType.Attribute:
  785. return current.OuterXml;
  786. case XmlNodeType.Element:
  787. if (NodeType == XmlNodeType.Element && !IsEmptyElement)
  788. ReadInnerXml ();
  789. else
  790. Read ();
  791. return initial.OuterXml;
  792. case XmlNodeType.None:
  793. return String.Empty;
  794. default:
  795. Read ();
  796. return String.Empty;
  797. }
  798. }
  799. #endif
  800. public override string ReadString ()
  801. {
  802. return ReadStringInternal ();
  803. }
  804. public override void ResolveEntity ()
  805. {
  806. if (NodeType != XmlNodeType.EntityReference)
  807. throw new InvalidOperationException ("The current node is not an Entity Reference");
  808. // FIXME: Now that XmlEntityReference holds the target
  809. // entity's child nodes, we don't have to use
  810. // XmlTextReader and simply use those nodes directly.
  811. string replacementText = current.InnerXml;
  812. XmlNodeType xmlReaderNodeType =
  813. (current.ParentNode != null && current.ParentNode.NodeType == XmlNodeType.Attribute) ?
  814. XmlNodeType.Attribute : XmlNodeType.Element;
  815. XmlParserContext ctx = null;
  816. if (entityReader != null) {
  817. entityReaderStack.Push (entityReader);
  818. ctx = entityReader.GetInternalParserContext ();
  819. }
  820. if (ctx == null) {
  821. ctx = new XmlParserContext (document.NameTable,
  822. current.ConstructNamespaceManager (),
  823. document.DocumentType != null ? document.DocumentType.DTD : null,
  824. BaseURI, XmlLang, XmlSpace, Encoding.Unicode);
  825. }
  826. entityReader = new XmlTextReader (replacementText, xmlReaderNodeType, ctx);
  827. entityReader.XmlResolver = document.Resolver;
  828. entityReader.SkipTextDeclaration ();
  829. }
  830. public override void Skip ()
  831. {
  832. // Why is this overriden? Such skipping might raise
  833. // (or ignore) unexpected validation error.
  834. base.Skip ();
  835. }
  836. #endregion
  837. }
  838. }