XmlDocumentNavigator.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576
  1. //
  2. // System.Xml.XmlDocumentNavigator
  3. //
  4. // Authors:
  5. // Jason Diamond <[email protected]>
  6. // Atsushi Enomoto <[email protected]>
  7. //
  8. // (C) 2002 Jason Diamond
  9. // (C) 2003 Atsushi Enomoto
  10. //
  11. using System;
  12. using System.Collections;
  13. using System.Xml;
  14. using System.Xml.XPath;
  15. namespace System.Xml
  16. {
  17. internal class XmlDocumentNavigator : XPathNavigator, IHasXmlNode
  18. {
  19. #region Constructors
  20. internal XmlDocumentNavigator (XmlNode node)
  21. : this (node, null)
  22. {
  23. nsNodeXml = document.CreateAttribute ("xmlns", "xml", Xmlns);
  24. nsNodeXml.Value = XmlnsXML;
  25. }
  26. private XmlDocumentNavigator (XmlNode node, XmlAttribute nsNodeXml)
  27. {
  28. this.node = node;
  29. this.document = node.NodeType == XmlNodeType.Document ?
  30. node as XmlDocument : node.OwnerDocument;
  31. this.nsNodeXml = nsNodeXml;
  32. }
  33. #endregion
  34. #region Fields
  35. private const string Xmlns = "http://www.w3.org/2000/xmlns/";
  36. private const string XmlnsXML = "http://www.w3.org/XML/1998/namespace";
  37. private XmlAttribute nsNodeXml;
  38. private XmlNode node;
  39. private XmlDocument document;
  40. // Current namespace node (ancestor's attribute of current node).
  41. private XmlNode nsNode;
  42. #endregion
  43. #region Properties
  44. public override string BaseURI {
  45. get {
  46. return node.BaseURI;
  47. }
  48. }
  49. public override bool HasAttributes {
  50. get {
  51. if (nsNode != null)
  52. return false;
  53. if (node.Attributes != null)
  54. for (int i = 0; i < node.Attributes.Count; i++)
  55. if (node.Attributes [i].NamespaceURI != Xmlns)
  56. return true;
  57. return false;
  58. }
  59. }
  60. public override bool HasChildren {
  61. get {
  62. if (nsNode != null)
  63. return false;
  64. XPathNodeType nodeType = NodeType;
  65. bool canHaveChildren = nodeType == XPathNodeType.Root || nodeType == XPathNodeType.Element;
  66. return canHaveChildren && node.FirstChild != null;
  67. }
  68. }
  69. public override bool IsEmptyElement {
  70. get {
  71. if (nsNode != null)
  72. return false;
  73. return node.NodeType == XmlNodeType.Element
  74. && ((XmlElement) node).IsEmpty;
  75. }
  76. }
  77. public override string LocalName {
  78. get {
  79. if (nsNode != null) {
  80. if (nsNode == nsNodeXml)
  81. return "xml";
  82. else
  83. return (nsNode.Name == "xmlns") ? String.Empty : nsNode.LocalName;
  84. }
  85. XPathNodeType nodeType = NodeType;
  86. bool canHaveName =
  87. nodeType == XPathNodeType.Element ||
  88. nodeType == XPathNodeType.Attribute ||
  89. nodeType == XPathNodeType.ProcessingInstruction ||
  90. nodeType == XPathNodeType.Namespace;
  91. return canHaveName ? node.LocalName : String.Empty;
  92. }
  93. }
  94. public override string Name {
  95. get {
  96. if (nsNode != null)
  97. return LocalName;
  98. XPathNodeType nodeType = NodeType;
  99. bool canHaveName =
  100. nodeType == XPathNodeType.Element ||
  101. nodeType == XPathNodeType.Attribute ||
  102. nodeType == XPathNodeType.ProcessingInstruction ||
  103. nodeType == XPathNodeType.Namespace;
  104. return canHaveName ? node.Name : String.Empty;
  105. }
  106. }
  107. public override string NamespaceURI {
  108. get { return (nsNode != null) ? String.Empty : node.NamespaceURI; }
  109. }
  110. public override XmlNameTable NameTable {
  111. get {
  112. return document.NameTable;
  113. }
  114. }
  115. public override XPathNodeType NodeType {
  116. get { return (nsNode != null) ? XPathNodeType.Namespace : node.XPathNodeType; }
  117. }
  118. public override string Prefix {
  119. get { return (nsNode != null) ? String.Empty : node.Prefix; }
  120. }
  121. public override string Value {
  122. get {
  123. switch (NodeType) {
  124. case XPathNodeType.Attribute:
  125. case XPathNodeType.Comment:
  126. case XPathNodeType.ProcessingInstruction:
  127. return node.Value;
  128. case XPathNodeType.Text:
  129. case XPathNodeType.Whitespace:
  130. case XPathNodeType.SignificantWhitespace:
  131. string value = node.Value;
  132. for (XmlNode n = node.NextSibling; n != null; n = n.NextSibling) {
  133. switch (n.XPathNodeType) {
  134. case XPathNodeType.Text:
  135. case XPathNodeType.Whitespace:
  136. case XPathNodeType.SignificantWhitespace:
  137. value += n.Value;
  138. continue;
  139. }
  140. break;
  141. }
  142. return value;
  143. case XPathNodeType.Element:
  144. case XPathNodeType.Root:
  145. return node.InnerText;
  146. case XPathNodeType.Namespace:
  147. return nsNode == nsNodeXml ? XmlnsXML : nsNode.Value;
  148. }
  149. return String.Empty;
  150. }
  151. }
  152. public override string XmlLang {
  153. get {
  154. return node.XmlLang;
  155. }
  156. }
  157. #endregion
  158. #region Methods
  159. public override XPathNavigator Clone ()
  160. {
  161. XmlDocumentNavigator clone = new XmlDocumentNavigator (node, nsNodeXml);
  162. clone.nsNode = nsNode;
  163. return clone;
  164. }
  165. public override string GetAttribute (string localName, string namespaceURI)
  166. {
  167. if (HasAttributes) {
  168. XmlElement el = Node as XmlElement;
  169. return el != null ? el.GetAttribute (localName, namespaceURI) : String.Empty;
  170. }
  171. return String.Empty;
  172. }
  173. public override string GetNamespace (string name)
  174. {
  175. // MSDN says "String.Empty if a matching namespace
  176. // node is not found or if the navigator is not
  177. // positioned on an element node", but in fact it
  178. // returns actual namespace for the other nodes.
  179. return Node.GetNamespaceOfPrefix (name);
  180. }
  181. public override bool IsSamePosition (XPathNavigator other)
  182. {
  183. XmlDocumentNavigator otherDocumentNavigator = other as XmlDocumentNavigator;
  184. if (otherDocumentNavigator != null)
  185. return node == otherDocumentNavigator.node
  186. && nsNode == otherDocumentNavigator.nsNode;
  187. return false;
  188. }
  189. public override bool MoveTo (XPathNavigator other)
  190. {
  191. XmlDocumentNavigator otherDocumentNavigator = other as XmlDocumentNavigator;
  192. if (otherDocumentNavigator != null) {
  193. if (document == otherDocumentNavigator.document) {
  194. node = otherDocumentNavigator.node;
  195. nsNode = otherDocumentNavigator.nsNode;
  196. return true;
  197. }
  198. }
  199. return false;
  200. }
  201. public override bool MoveToAttribute (string localName, string namespaceURI)
  202. {
  203. if (node.Attributes != null) {
  204. for (int i = 0; i < node.Attributes.Count; i++) {
  205. XmlAttribute attr = node.Attributes [i];
  206. if (attr.LocalName == localName
  207. && attr.NamespaceURI == namespaceURI) {
  208. node = attr;
  209. nsNode = null;
  210. return true;
  211. }
  212. }
  213. }
  214. return false;
  215. }
  216. public override bool MoveToFirst ()
  217. {
  218. if (nsNode == null && node.NodeType != XmlNodeType.Attribute && node.ParentNode != null) {
  219. if (!MoveToParent ())
  220. return false;
  221. // Follow these 2 steps so that we can skip
  222. // some types of nodes .
  223. MoveToFirstChild ();
  224. return true;
  225. }
  226. return false;
  227. }
  228. public override bool MoveToFirstAttribute ()
  229. {
  230. if (node.Attributes == null)
  231. return false;
  232. if (NodeType == XPathNodeType.Element) {
  233. for (int i = 0; i < node.Attributes.Count; i++) {
  234. XmlAttribute attr = node.Attributes [i];
  235. if (attr.NamespaceURI != Xmlns) {
  236. node = attr;
  237. nsNode = null;
  238. return true;
  239. }
  240. }
  241. }
  242. return false;
  243. }
  244. public override bool MoveToFirstChild ()
  245. {
  246. if (HasChildren) {
  247. if (node == document) {
  248. XmlNode n = node.FirstChild;
  249. if (n == null)
  250. return false;
  251. bool loop = true;
  252. do {
  253. switch (n.NodeType) {
  254. case XmlNodeType.XmlDeclaration:
  255. case XmlNodeType.DocumentType:
  256. n = n.NextSibling;
  257. if (n == null)
  258. return false;
  259. break;
  260. default:
  261. loop = false;
  262. break;
  263. }
  264. } while (loop);
  265. node = n;
  266. } else {
  267. do {
  268. node = node.FirstChild;
  269. if (node.NodeType != XmlNodeType.EntityReference)
  270. break;
  271. node = node.NextSibling;
  272. } while (node != null);
  273. if (node == null)
  274. return false;
  275. }
  276. return true;
  277. }
  278. return false;
  279. }
  280. public override bool MoveToFirstNamespace (XPathNamespaceScope namespaceScope)
  281. {
  282. if (NodeType != XPathNodeType.Element)
  283. return false;
  284. XmlElement el = node as XmlElement;
  285. if (node.Attributes != null) {
  286. do {
  287. for (int i = 0; i < el.Attributes.Count; i++) {
  288. XmlAttribute attr = el.Attributes [i];
  289. if (attr.NamespaceURI == Xmlns) {
  290. nsNode = attr;
  291. return true;
  292. }
  293. }
  294. if (namespaceScope == XPathNamespaceScope.Local)
  295. return false;
  296. el = el.ParentNode as XmlElement;
  297. } while (el != null);
  298. }
  299. if (namespaceScope == XPathNamespaceScope.All) {
  300. nsNode = nsNodeXml;
  301. return true;
  302. }
  303. else
  304. return false;
  305. }
  306. public override bool MoveToId (string id)
  307. {
  308. XmlElement eltNew = document.GetElementById (id);
  309. if (eltNew == null)
  310. return false;
  311. node = eltNew;
  312. return true;
  313. }
  314. public override bool MoveToNamespace (string name)
  315. {
  316. if (name == "xml") {
  317. nsNode = nsNodeXml;
  318. return true;
  319. }
  320. if (NodeType != XPathNodeType.Element)
  321. return false;
  322. XmlElement el = node as XmlElement;
  323. if (node.Attributes != null) {
  324. do {
  325. for (int i = 0; i < el.Attributes.Count; i++) {
  326. XmlAttribute attr = el.Attributes [i];
  327. if (attr.NamespaceURI == Xmlns && attr.Name == name) {
  328. nsNode = attr;
  329. return true;
  330. }
  331. }
  332. el = node.ParentNode as XmlElement;
  333. } while (el != null);
  334. }
  335. return false;
  336. }
  337. public override bool MoveToNext ()
  338. {
  339. if (nsNode != null)
  340. return false;
  341. if (node.NextSibling != null) {
  342. XmlNode n = node.NextSibling;
  343. if (node.ParentNode != null && node.ParentNode.NodeType == XmlNodeType.Document) {
  344. while (n != null) {
  345. switch (n.NodeType) {
  346. case XmlNodeType.DocumentType:
  347. case XmlNodeType.XmlDeclaration:
  348. n = n.NextSibling;
  349. continue;
  350. }
  351. break;
  352. }
  353. if (n != null)
  354. node = n;
  355. else
  356. return false;
  357. } else {
  358. while (n != null) {
  359. if (n.NodeType != XmlNodeType.EntityReference)
  360. break;
  361. n = n.NextSibling;
  362. }
  363. if (n != null)
  364. node = n;
  365. else
  366. return false;
  367. }
  368. return true;
  369. }
  370. else
  371. return false;
  372. }
  373. public override bool MoveToNextAttribute ()
  374. {
  375. if (node == null)
  376. return false;
  377. if (NodeType != XPathNodeType.Attribute)
  378. return false;
  379. // Find current attribute.
  380. int pos = 0;
  381. XmlElement owner = ((XmlAttribute) node).OwnerElement;
  382. if (owner == null)
  383. return false;
  384. int count = owner.Attributes.Count;
  385. for(; pos < count; pos++)
  386. if (owner.Attributes [pos] == node)
  387. break;
  388. if (pos == count)
  389. return false; // Where is current attribute? Maybe removed.
  390. // Find next attribute.
  391. for(pos++; pos < count; pos++) {
  392. if (owner.Attributes [pos].NamespaceURI != Xmlns) {
  393. node = owner.Attributes [pos];
  394. nsNode = null;
  395. return true;
  396. }
  397. }
  398. return false;
  399. }
  400. public override bool MoveToNextNamespace (XPathNamespaceScope namespaceScope)
  401. {
  402. if (nsNode == nsNodeXml)
  403. // Current namespace is "xml", so there should be no more namespace nodes.
  404. return false;
  405. if (nsNode == null)
  406. return false;
  407. // Get current attribute's position.
  408. int pos = 0;
  409. XmlElement owner = ((XmlAttribute) nsNode).OwnerElement;
  410. if (owner == null)
  411. return false;
  412. int count = owner.Attributes.Count;
  413. for(; pos < count; pos++)
  414. if (owner.Attributes [pos] == nsNode)
  415. break;
  416. if (pos == count)
  417. return false; // Where is current attribute? Maybe removed.
  418. // Find next namespace from the same element as current ns node.
  419. for(pos++; pos < count; pos++) {
  420. if (owner.Attributes [pos].NamespaceURI == Xmlns) {
  421. nsNode = owner.Attributes [pos];
  422. return true;
  423. }
  424. }
  425. // If not found more, then find from ancestors.
  426. // But if scope is Local, then it returns false here.
  427. if (namespaceScope == XPathNamespaceScope.Local)
  428. return false;
  429. owner = owner.ParentNode as XmlElement;
  430. while (owner != null) {
  431. for (int i = 0; i < owner.Attributes.Count; i++) {
  432. XmlAttribute attr = owner.Attributes [i];
  433. if (attr.NamespaceURI == Xmlns) {
  434. nsNode = attr;
  435. return true;
  436. }
  437. }
  438. owner = owner.ParentNode as XmlElement;
  439. }
  440. if (namespaceScope == XPathNamespaceScope.All) {
  441. nsNode = nsNodeXml;
  442. return true;
  443. }
  444. else
  445. return false;
  446. }
  447. public override bool MoveToParent ()
  448. {
  449. if (nsNode != null) {
  450. nsNode = null;
  451. return true;
  452. }
  453. else if (node.NodeType == XmlNodeType.Attribute) {
  454. XmlElement ownerElement = ((XmlAttribute)node).OwnerElement;
  455. if (ownerElement != null) {
  456. node = ownerElement;
  457. nsNode = null;
  458. return true;
  459. }
  460. } else if (node.ParentNode != null) {
  461. node = node.ParentNode;
  462. nsNode = null;
  463. return true;
  464. }
  465. return false;
  466. }
  467. public override bool MoveToPrevious ()
  468. {
  469. if (nsNode != null)
  470. return false;
  471. if (node.PreviousSibling != null) {
  472. if (node.ParentNode != null && node.ParentNode.NodeType == XmlNodeType.Document) {
  473. XmlNode n = node.PreviousSibling;
  474. while (n != null) {
  475. switch (n.NodeType) {
  476. case XmlNodeType.DocumentType:
  477. case XmlNodeType.XmlDeclaration:
  478. n = n.PreviousSibling;
  479. continue;
  480. }
  481. break;
  482. }
  483. if (n != null)
  484. node = n;
  485. else
  486. return false;
  487. }
  488. else
  489. node = node.PreviousSibling;
  490. return true;
  491. }
  492. else
  493. return false;
  494. }
  495. public override void MoveToRoot ()
  496. {
  497. XmlAttribute attr = node as XmlAttribute;
  498. XmlNode tmp = attr != null ? attr.OwnerElement : node;
  499. while (tmp.ParentNode != null)
  500. tmp = tmp.ParentNode;
  501. node = tmp;
  502. nsNode = null;
  503. }
  504. internal XmlNode Node { get { return nsNode != null ? nsNode : node; } }
  505. XmlNode IHasXmlNode.GetNode ()
  506. {
  507. return node;
  508. }
  509. #endregion
  510. }
  511. }