XmlReader.cs 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305
  1. //
  2. // XmlReader.cs
  3. //
  4. // Authors:
  5. // Jason Diamond ([email protected])
  6. // Gonzalo Paniagua Javier ([email protected])
  7. // Atsushi Enomoto ([email protected])
  8. //
  9. // (C) 2001, 2002 Jason Diamond http://injektilo.org/
  10. // (c) 2002 Ximian, Inc. (http://www.ximian.com)
  11. // (C) 2003 Atsushi Enomoto
  12. //
  13. //
  14. // Permission is hereby granted, free of charge, to any person obtaining
  15. // a copy of this software and associated documentation files (the
  16. // "Software"), to deal in the Software without restriction, including
  17. // without limitation the rights to use, copy, modify, merge, publish,
  18. // distribute, sublicense, and/or sell copies of the Software, and to
  19. // permit persons to whom the Software is furnished to do so, subject to
  20. // the following conditions:
  21. //
  22. // The above copyright notice and this permission notice shall be
  23. // included in all copies or substantial portions of the Software.
  24. //
  25. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  26. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  27. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  28. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  29. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  30. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  31. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  32. //
  33. using System.Collections;
  34. using System.Diagnostics;
  35. using System.IO;
  36. using System.Text;
  37. #if !NET_2_1
  38. using System.Xml.Schema; // only required for NET_2_0 (SchemaInfo)
  39. using System.Xml.Serialization; // only required for NET_2_0 (SchemaInfo)
  40. using Mono.Xml.Schema; // only required for NET_2_0
  41. #endif
  42. using Mono.Xml; // only required for NET_2_0
  43. namespace System.Xml
  44. {
  45. #if NET_2_0
  46. public abstract class XmlReader : IDisposable
  47. #else
  48. public abstract class XmlReader
  49. #endif
  50. {
  51. private StringBuilder readStringBuffer;
  52. private XmlReaderBinarySupport binary;
  53. #if NET_2_0
  54. private XmlReaderSettings settings;
  55. #endif
  56. #region Constructor
  57. protected XmlReader ()
  58. {
  59. }
  60. #endregion
  61. #region Properties
  62. public abstract int AttributeCount { get; }
  63. public abstract string BaseURI { get; }
  64. internal XmlReaderBinarySupport Binary {
  65. get { return binary; }
  66. }
  67. internal XmlReaderBinarySupport.CharGetter BinaryCharGetter {
  68. get { return binary != null ? binary.Getter : null; }
  69. set {
  70. if (binary == null)
  71. binary = new XmlReaderBinarySupport (this);
  72. binary.Getter = value;
  73. }
  74. }
  75. #if NET_2_0
  76. // To enable it internally in sys.xml, just insert these
  77. // two lines into Read():
  78. //
  79. // #if NET_2_0
  80. // if (Binary != null)
  81. // Binary.Reset ();
  82. // #endif
  83. //
  84. public virtual bool CanReadBinaryContent {
  85. get { return false; }
  86. }
  87. public virtual bool CanReadValueChunk {
  88. get { return false; }
  89. }
  90. #else
  91. internal virtual bool CanReadBinaryContent {
  92. get { return false; }
  93. }
  94. internal virtual bool CanReadValueChunk {
  95. get { return false; }
  96. }
  97. #endif
  98. public virtual bool CanResolveEntity
  99. {
  100. get { return false; }
  101. }
  102. public abstract int Depth { get; }
  103. public abstract bool EOF { get; }
  104. public virtual bool HasAttributes
  105. {
  106. get { return AttributeCount > 0; }
  107. }
  108. #if !NET_2_1
  109. public abstract bool HasValue { get; }
  110. #endif
  111. public abstract bool IsEmptyElement { get; }
  112. #if NET_2_0
  113. public virtual bool IsDefault {
  114. get { return false; }
  115. }
  116. public virtual string this [int i] {
  117. get { return GetAttribute (i); }
  118. }
  119. public virtual string this [string name] {
  120. get { return GetAttribute (name); }
  121. }
  122. public virtual string this [string name, string namespaceURI] {
  123. get { return GetAttribute (name, namespaceURI); }
  124. }
  125. #else
  126. public abstract bool IsDefault { get; }
  127. public abstract string this [int i] { get; }
  128. public abstract string this [string name] { get; }
  129. public abstract string this [string localName, string namespaceName] { get; }
  130. #endif
  131. public abstract string LocalName { get; }
  132. #if NET_2_0
  133. public virtual string Name {
  134. get {
  135. return Prefix.Length > 0 ?
  136. String.Concat (Prefix, ":", LocalName) :
  137. LocalName;
  138. }
  139. }
  140. #else
  141. public abstract string Name { get; }
  142. #endif
  143. public abstract string NamespaceURI { get; }
  144. public abstract XmlNameTable NameTable { get; }
  145. public abstract XmlNodeType NodeType { get; }
  146. public abstract string Prefix { get; }
  147. #if NET_2_0
  148. public virtual char QuoteChar {
  149. get { return '\"'; }
  150. }
  151. #else
  152. public abstract char QuoteChar { get; }
  153. #endif
  154. public abstract ReadState ReadState { get; }
  155. #if NET_2_0
  156. #if !NET_2_1
  157. public virtual IXmlSchemaInfo SchemaInfo {
  158. get { return null; }
  159. }
  160. #endif
  161. public virtual XmlReaderSettings Settings {
  162. get { return settings; }
  163. }
  164. #endif
  165. public abstract string Value { get; }
  166. #if NET_2_0
  167. public virtual string XmlLang {
  168. get { return String.Empty; }
  169. }
  170. public virtual XmlSpace XmlSpace {
  171. get { return XmlSpace.None; }
  172. }
  173. #else
  174. public abstract string XmlLang { get; }
  175. public abstract XmlSpace XmlSpace { get; }
  176. #endif
  177. #endregion
  178. #region Methods
  179. public abstract void Close ();
  180. #if NET_2_0
  181. private static XmlNameTable PopulateNameTable (
  182. XmlReaderSettings settings)
  183. {
  184. XmlNameTable nameTable = settings.NameTable;
  185. if (nameTable == null)
  186. nameTable = new NameTable ();
  187. return nameTable;
  188. }
  189. private static XmlParserContext PopulateParserContext (
  190. XmlReaderSettings settings, string baseUri)
  191. {
  192. XmlNameTable nt = PopulateNameTable (settings);
  193. return new XmlParserContext (nt,
  194. new XmlNamespaceManager (nt),
  195. baseUri,
  196. XmlSpace.None);
  197. }
  198. private static XmlNodeType GetNodeType (
  199. XmlReaderSettings settings)
  200. {
  201. ConformanceLevel level = settings != null ? settings.ConformanceLevel : ConformanceLevel.Auto;
  202. return
  203. level == ConformanceLevel.Fragment ?
  204. XmlNodeType.Element :
  205. XmlNodeType.Document;
  206. }
  207. public static XmlReader Create (Stream stream)
  208. {
  209. return Create (stream, null);
  210. }
  211. public static XmlReader Create (string url)
  212. {
  213. return Create (url, null);
  214. }
  215. public static XmlReader Create (TextReader reader)
  216. {
  217. return Create (reader, null);
  218. }
  219. public static XmlReader Create (string url, XmlReaderSettings settings)
  220. {
  221. return Create (url, settings, null);
  222. }
  223. public static XmlReader Create (Stream stream, XmlReaderSettings settings)
  224. {
  225. return Create (stream, settings, String.Empty);
  226. }
  227. public static XmlReader Create (TextReader reader, XmlReaderSettings settings)
  228. {
  229. return Create (reader, settings, String.Empty);
  230. }
  231. static XmlReaderSettings PopulateSettings (XmlReaderSettings src)
  232. {
  233. if (src == null)
  234. return new XmlReaderSettings ();
  235. else
  236. return src.Clone ();
  237. }
  238. public static XmlReader Create (Stream stream, XmlReaderSettings settings, string baseUri)
  239. {
  240. settings = PopulateSettings (settings);
  241. return Create (stream, settings,
  242. PopulateParserContext (settings, baseUri));
  243. }
  244. public static XmlReader Create (TextReader reader, XmlReaderSettings settings, string baseUri)
  245. {
  246. settings = PopulateSettings (settings);
  247. return Create (reader, settings,
  248. PopulateParserContext (settings, baseUri));
  249. }
  250. public static XmlReader Create (XmlReader reader, XmlReaderSettings settings)
  251. {
  252. settings = PopulateSettings (settings);
  253. XmlReader r = CreateFilteredXmlReader (reader, settings);
  254. r.settings = settings;
  255. return r;
  256. }
  257. public static XmlReader Create (string url, XmlReaderSettings settings, XmlParserContext context)
  258. {
  259. settings = PopulateSettings (settings);
  260. if (context == null)
  261. context = PopulateParserContext (settings, url);
  262. XmlTextReader xtr = new XmlTextReader (false, settings.XmlResolver, url, GetNodeType (settings), context);
  263. XmlReader ret = CreateCustomizedTextReader (xtr, settings);
  264. xtr.CloseInput = true; // forced. See XmlReaderCommonTests.CreateFromUrlClose().
  265. return ret;
  266. }
  267. public static XmlReader Create (Stream stream, XmlReaderSettings settings, XmlParserContext context)
  268. {
  269. settings = PopulateSettings (settings);
  270. if (context == null)
  271. context = PopulateParserContext (settings, String.Empty);
  272. return CreateCustomizedTextReader (new XmlTextReader (stream, GetNodeType (settings), context), settings);
  273. }
  274. public static XmlReader Create (TextReader reader, XmlReaderSettings settings, XmlParserContext context)
  275. {
  276. settings = PopulateSettings (settings);
  277. if (context == null)
  278. context = PopulateParserContext (settings, String.Empty);
  279. return CreateCustomizedTextReader (new XmlTextReader (context.BaseURI, reader, GetNodeType (settings), context), settings);
  280. }
  281. private static XmlReader CreateCustomizedTextReader (XmlTextReader reader, XmlReaderSettings settings)
  282. {
  283. reader.XmlResolver = settings.XmlResolver;
  284. // Normalization is set true by default.
  285. reader.Normalization = true;
  286. reader.EntityHandling = EntityHandling.ExpandEntities;
  287. if (settings.ProhibitDtd)
  288. reader.ProhibitDtd = true;
  289. if (!settings.CheckCharacters)
  290. reader.CharacterChecking = false;
  291. // I guess it might be changed in 2.0 RTM to set true
  292. // as default, or just disappear. It goes against
  293. // XmlTextReader's default usage and users will have
  294. // to close input manually (that's annoying). Moreover,
  295. // MS XmlTextReader consumes text input more than
  296. // actually read and users can acquire those extra
  297. // consumption by GetRemainder() that returns different
  298. // TextReader.
  299. reader.CloseInput = settings.CloseInput;
  300. // I would like to support it in detail later;
  301. // MSDN description looks source of confusion. We don't
  302. // need examples, but precise list of how it works.
  303. reader.Conformance = settings.ConformanceLevel;
  304. reader.AdjustLineInfoOffset (settings.LineNumberOffset,
  305. settings.LinePositionOffset);
  306. if (settings.NameTable != null)
  307. reader.SetNameTable (settings.NameTable);
  308. XmlReader r = CreateFilteredXmlReader (reader, settings);
  309. r.settings = settings;
  310. return r;
  311. }
  312. private static XmlReader CreateFilteredXmlReader (XmlReader reader, XmlReaderSettings settings)
  313. {
  314. ConformanceLevel conf = ConformanceLevel.Auto;
  315. if (reader is XmlTextReader)
  316. conf = ((XmlTextReader) reader).Conformance;
  317. else if (reader.Settings != null)
  318. conf = reader.Settings.ConformanceLevel;
  319. else
  320. conf = settings.ConformanceLevel;
  321. if (settings.ConformanceLevel != ConformanceLevel.Auto &&
  322. conf != settings.ConformanceLevel)
  323. throw new InvalidOperationException (String.Format ("ConformanceLevel cannot be overwritten by a wrapping XmlReader. The source reader has {0}, while {1} is specified.", conf, settings.ConformanceLevel));
  324. settings.ConformanceLevel = conf;
  325. reader = CreateValidatingXmlReader (reader, settings);
  326. if ( settings.IgnoreComments ||
  327. settings.IgnoreProcessingInstructions ||
  328. settings.IgnoreWhitespace)
  329. return new XmlFilterReader (reader, settings);
  330. else {
  331. reader.settings = settings;
  332. return reader;
  333. }
  334. }
  335. private static XmlReader CreateValidatingXmlReader (XmlReader reader, XmlReaderSettings settings)
  336. {
  337. #if NET_2_1
  338. return reader;
  339. #else
  340. XmlValidatingReader xvr = null;
  341. switch (settings.ValidationType) {
  342. // Auto and XDR are obsoleted in 2.0 and therefore ignored.
  343. default:
  344. return reader;
  345. case ValidationType.DTD:
  346. xvr = new XmlValidatingReader (reader);
  347. xvr.XmlResolver = settings.XmlResolver;
  348. xvr.ValidationType = ValidationType.DTD;
  349. break;
  350. case ValidationType.Schema:
  351. return new XmlSchemaValidatingReader (reader, settings);
  352. }
  353. // Actually I don't think they are treated in DTD validation though...
  354. if ((settings.ValidationFlags & XmlSchemaValidationFlags.ProcessIdentityConstraints) == 0)
  355. throw new NotImplementedException ();
  356. //if ((settings.ValidationFlags & XmlSchemaValidationFlags.ProcessInlineSchema) != 0)
  357. // throw new NotImplementedException ();
  358. //if ((settings.ValidationFlags & XmlSchemaValidationFlags.ProcessSchemaLocation) != 0)
  359. // throw new NotImplementedException ();
  360. //if ((settings.ValidationFlags & XmlSchemaValidationFlags.ReportValidationWarnings) == 0)
  361. // throw new NotImplementedException ();
  362. return xvr != null ? xvr : reader;
  363. #endif
  364. }
  365. void IDisposable.Dispose ()
  366. {
  367. Dispose (false);
  368. }
  369. protected virtual void Dispose (bool disposing)
  370. {
  371. if (ReadState != ReadState.Closed)
  372. Close ();
  373. }
  374. #endif
  375. public abstract string GetAttribute (int i);
  376. public abstract string GetAttribute (string name);
  377. public abstract string GetAttribute (
  378. string localName,
  379. string namespaceName);
  380. public static bool IsName (string s)
  381. {
  382. return s != null && XmlChar.IsName (s);
  383. }
  384. public static bool IsNameToken (string s)
  385. {
  386. return s != null && XmlChar.IsNmToken (s);
  387. }
  388. public virtual bool IsStartElement ()
  389. {
  390. return (MoveToContent () == XmlNodeType.Element);
  391. }
  392. public virtual bool IsStartElement (string name)
  393. {
  394. if (!IsStartElement ())
  395. return false;
  396. return (Name == name);
  397. }
  398. public virtual bool IsStartElement (string localName, string namespaceName)
  399. {
  400. if (!IsStartElement ())
  401. return false;
  402. return (LocalName == localName && NamespaceURI == namespaceName);
  403. }
  404. public abstract string LookupNamespace (string prefix);
  405. #if NET_2_0
  406. public virtual void MoveToAttribute (int i)
  407. {
  408. if (i >= AttributeCount)
  409. throw new ArgumentOutOfRangeException ();
  410. MoveToFirstAttribute ();
  411. for (int a = 0; a < i; a++)
  412. MoveToNextAttribute ();
  413. }
  414. #else
  415. public abstract void MoveToAttribute (int i);
  416. #endif
  417. public abstract bool MoveToAttribute (string name);
  418. public abstract bool MoveToAttribute (
  419. string localName,
  420. string namespaceName);
  421. private bool IsContent (XmlNodeType nodeType)
  422. {
  423. /* MS doc says:
  424. * (non-white space text, CDATA, Element, EndElement, EntityReference, or EndEntity)
  425. */
  426. switch (nodeType) {
  427. case XmlNodeType.Text:
  428. return true;
  429. case XmlNodeType.CDATA:
  430. return true;
  431. case XmlNodeType.Element:
  432. return true;
  433. case XmlNodeType.EndElement:
  434. return true;
  435. case XmlNodeType.EntityReference:
  436. return true;
  437. case XmlNodeType.EndEntity:
  438. return true;
  439. }
  440. return false;
  441. }
  442. public virtual XmlNodeType MoveToContent ()
  443. {
  444. if (NodeType == XmlNodeType.Attribute)
  445. MoveToElement ();
  446. do {
  447. if (IsContent (NodeType))
  448. return NodeType;
  449. Read ();
  450. } while (!EOF);
  451. return XmlNodeType.None;
  452. }
  453. public abstract bool MoveToElement ();
  454. public abstract bool MoveToFirstAttribute ();
  455. public abstract bool MoveToNextAttribute ();
  456. public abstract bool Read ();
  457. #if !NET_2_1
  458. public abstract bool ReadAttributeValue ();
  459. #endif
  460. public virtual string ReadElementString ()
  461. {
  462. if (MoveToContent () != XmlNodeType.Element) {
  463. string error = String.Format ("'{0}' is an invalid node type.",
  464. NodeType.ToString ());
  465. throw XmlError (error);
  466. }
  467. string result = String.Empty;
  468. if (!IsEmptyElement) {
  469. Read ();
  470. result = ReadString ();
  471. if (NodeType != XmlNodeType.EndElement) {
  472. string error = String.Format ("'{0}' is an invalid node type.",
  473. NodeType.ToString ());
  474. throw XmlError (error);
  475. }
  476. }
  477. Read ();
  478. return result;
  479. }
  480. public virtual string ReadElementString (string name)
  481. {
  482. if (MoveToContent () != XmlNodeType.Element) {
  483. string error = String.Format ("'{0}' is an invalid node type.",
  484. NodeType.ToString ());
  485. throw XmlError (error);
  486. }
  487. if (name != Name) {
  488. string error = String.Format ("The {0} tag from namespace {1} is expected.",
  489. Name, NamespaceURI);
  490. throw XmlError (error);
  491. }
  492. string result = String.Empty;
  493. if (!IsEmptyElement) {
  494. Read ();
  495. result = ReadString ();
  496. if (NodeType != XmlNodeType.EndElement) {
  497. string error = String.Format ("'{0}' is an invalid node type.",
  498. NodeType.ToString ());
  499. throw XmlError (error);
  500. }
  501. }
  502. Read ();
  503. return result;
  504. }
  505. public virtual string ReadElementString (string localName, string namespaceName)
  506. {
  507. if (MoveToContent () != XmlNodeType.Element) {
  508. string error = String.Format ("'{0}' is an invalid node type.",
  509. NodeType.ToString ());
  510. throw XmlError (error);
  511. }
  512. if (localName != LocalName || NamespaceURI != namespaceName) {
  513. string error = String.Format ("The {0} tag from namespace {1} is expected.",
  514. LocalName, NamespaceURI);
  515. throw XmlError (error);
  516. }
  517. string result = String.Empty;
  518. if (!IsEmptyElement) {
  519. Read ();
  520. result = ReadString ();
  521. if (NodeType != XmlNodeType.EndElement) {
  522. string error = String.Format ("'{0}' is an invalid node type.",
  523. NodeType.ToString ());
  524. throw XmlError (error);
  525. }
  526. }
  527. Read ();
  528. return result;
  529. }
  530. public virtual void ReadEndElement ()
  531. {
  532. if (MoveToContent () != XmlNodeType.EndElement) {
  533. string error = String.Format ("'{0}' is an invalid node type.",
  534. NodeType.ToString ());
  535. throw XmlError (error);
  536. }
  537. Read ();
  538. }
  539. public virtual string ReadInnerXml ()
  540. {
  541. if (ReadState != ReadState.Interactive || NodeType == XmlNodeType.EndElement)
  542. return String.Empty;
  543. if (IsEmptyElement) {
  544. Read ();
  545. return String.Empty;
  546. }
  547. StringWriter sw = new StringWriter ();
  548. XmlTextWriter xtw = new XmlTextWriter (sw);
  549. if (NodeType == XmlNodeType.Element) {
  550. int startDepth = Depth;
  551. Read ();
  552. while (startDepth < Depth) {
  553. if (ReadState != ReadState.Interactive)
  554. throw XmlError ("Unexpected end of the XML reader.");
  555. xtw.WriteNode (this, false);
  556. }
  557. // reader is now end element, then proceed once more.
  558. Read ();
  559. }
  560. else
  561. xtw.WriteNode (this, false);
  562. return sw.ToString ();
  563. }
  564. public virtual string ReadOuterXml ()
  565. {
  566. if (ReadState != ReadState.Interactive || NodeType == XmlNodeType.EndElement)
  567. return String.Empty;
  568. switch (NodeType) {
  569. case XmlNodeType.Element:
  570. case XmlNodeType.Attribute:
  571. StringWriter sw = new StringWriter ();
  572. XmlTextWriter xtw = new XmlTextWriter (sw);
  573. xtw.WriteNode (this, false);
  574. return sw.ToString ();
  575. default:
  576. Skip ();
  577. return String.Empty;
  578. }
  579. }
  580. public virtual void ReadStartElement ()
  581. {
  582. if (MoveToContent () != XmlNodeType.Element) {
  583. string error = String.Format ("'{0}' is an invalid node type.",
  584. NodeType.ToString ());
  585. throw XmlError (error);
  586. }
  587. Read ();
  588. }
  589. public virtual void ReadStartElement (string name)
  590. {
  591. if (MoveToContent () != XmlNodeType.Element) {
  592. string error = String.Format ("'{0}' is an invalid node type.",
  593. NodeType.ToString ());
  594. throw XmlError (error);
  595. }
  596. if (name != Name) {
  597. string error = String.Format ("The {0} tag from namespace {1} is expected.",
  598. Name, NamespaceURI);
  599. throw XmlError (error);
  600. }
  601. Read ();
  602. }
  603. public virtual void ReadStartElement (string localName, string namespaceName)
  604. {
  605. if (MoveToContent () != XmlNodeType.Element) {
  606. string error = String.Format ("'{0}' is an invalid node type.",
  607. NodeType.ToString ());
  608. throw XmlError (error);
  609. }
  610. if (localName != LocalName || NamespaceURI != namespaceName) {
  611. string error = String.Format ("Expecting {0} tag from namespace {1}, got {2} and {3} instead",
  612. localName, namespaceName,
  613. LocalName, NamespaceURI);
  614. throw XmlError (error);
  615. }
  616. Read ();
  617. }
  618. public virtual string ReadString ()
  619. {
  620. if (readStringBuffer == null)
  621. readStringBuffer = new StringBuilder ();
  622. readStringBuffer.Length = 0;
  623. MoveToElement ();
  624. switch (NodeType) {
  625. default:
  626. return String.Empty;
  627. case XmlNodeType.Element:
  628. if (IsEmptyElement)
  629. return String.Empty;
  630. do {
  631. Read ();
  632. switch (NodeType) {
  633. case XmlNodeType.Text:
  634. case XmlNodeType.CDATA:
  635. case XmlNodeType.Whitespace:
  636. case XmlNodeType.SignificantWhitespace:
  637. readStringBuffer.Append (Value);
  638. continue;
  639. }
  640. break;
  641. } while (true);
  642. break;
  643. case XmlNodeType.Text:
  644. case XmlNodeType.CDATA:
  645. case XmlNodeType.Whitespace:
  646. case XmlNodeType.SignificantWhitespace:
  647. do {
  648. switch (NodeType) {
  649. case XmlNodeType.Text:
  650. case XmlNodeType.CDATA:
  651. case XmlNodeType.Whitespace:
  652. case XmlNodeType.SignificantWhitespace:
  653. readStringBuffer.Append (Value);
  654. Read ();
  655. continue;
  656. }
  657. break;
  658. } while (true);
  659. break;
  660. }
  661. string ret = readStringBuffer.ToString ();
  662. readStringBuffer.Length = 0;
  663. return ret;
  664. }
  665. #if NET_2_0
  666. public virtual Type ValueType {
  667. get { return typeof (string); }
  668. }
  669. public virtual bool ReadToDescendant (string name)
  670. {
  671. if (ReadState == ReadState.Initial) {
  672. MoveToContent ();
  673. if (IsStartElement (name))
  674. return true;
  675. }
  676. if (NodeType != XmlNodeType.Element || IsEmptyElement)
  677. return false;
  678. int depth = Depth;
  679. for (Read (); depth < Depth; Read ())
  680. if (NodeType == XmlNodeType.Element && name == Name)
  681. return true;
  682. return false;
  683. }
  684. public virtual bool ReadToDescendant (string localName, string namespaceURI)
  685. {
  686. if (ReadState == ReadState.Initial) {
  687. MoveToContent ();
  688. if (IsStartElement (localName, namespaceURI))
  689. return true;
  690. }
  691. if (NodeType != XmlNodeType.Element || IsEmptyElement)
  692. return false;
  693. int depth = Depth;
  694. for (Read (); depth < Depth; Read ())
  695. if (NodeType == XmlNodeType.Element && localName == LocalName && namespaceURI == NamespaceURI)
  696. return true;
  697. return false;
  698. }
  699. public virtual bool ReadToFollowing (string name)
  700. {
  701. while (Read ())
  702. if (NodeType == XmlNodeType.Element && name == Name)
  703. return true;
  704. return false;
  705. }
  706. public virtual bool ReadToFollowing (string localName, string namespaceURI)
  707. {
  708. while (Read ())
  709. if (NodeType == XmlNodeType.Element && localName == Name && namespaceURI == NamespaceURI)
  710. return true;
  711. return false;
  712. }
  713. public virtual bool ReadToNextSibling (string name)
  714. {
  715. if (ReadState != ReadState.Interactive)
  716. return false;
  717. int depth = Depth;
  718. for (Skip (); depth <= Depth; Skip ())
  719. if (NodeType == XmlNodeType.Element && name == Name)
  720. return true;
  721. return false;
  722. }
  723. public virtual bool ReadToNextSibling (string localName, string namespaceURI)
  724. {
  725. if (ReadState != ReadState.Interactive)
  726. return false;
  727. int depth = Depth;
  728. for (Skip (); depth <= Depth; Skip ())
  729. if (NodeType == XmlNodeType.Element && localName == LocalName && namespaceURI == NamespaceURI)
  730. return true;
  731. return false;
  732. }
  733. public virtual XmlReader ReadSubtree ()
  734. {
  735. return new SubtreeXmlReader (this);
  736. }
  737. private string ReadContentString ()
  738. {
  739. if (NodeType == XmlNodeType.Attribute)
  740. return Value;
  741. return ReadContentString (true);
  742. }
  743. private string ReadContentString (bool isText)
  744. {
  745. if (isText) {
  746. switch (NodeType) {
  747. case XmlNodeType.Text:
  748. case XmlNodeType.SignificantWhitespace:
  749. case XmlNodeType.Whitespace:
  750. case XmlNodeType.CDATA:
  751. break;
  752. default:
  753. throw new InvalidOperationException (String.Format ("Node type {0} is not supported in this operation.{1}", NodeType, GetLocation ()));
  754. }
  755. }
  756. string value = String.Empty;
  757. do {
  758. switch (NodeType) {
  759. case XmlNodeType.Element:
  760. if (isText)
  761. return value;
  762. throw XmlError ("Child element is not expected in this operation.");
  763. case XmlNodeType.EndElement:
  764. return value;
  765. case XmlNodeType.Text:
  766. case XmlNodeType.CDATA:
  767. case XmlNodeType.SignificantWhitespace:
  768. case XmlNodeType.Whitespace:
  769. value += Value;
  770. break;
  771. }
  772. } while (Read ());
  773. throw XmlError ("Unexpected end of document.");
  774. }
  775. string GetLocation ()
  776. {
  777. IXmlLineInfo li = this as IXmlLineInfo;
  778. return li != null && li.HasLineInfo () ?
  779. String.Format (" {0} (line {1}, column {2})", BaseURI, li.LineNumber, li.LinePosition) : String.Empty;
  780. }
  781. [MonoTODO]
  782. public virtual object ReadElementContentAsObject ()
  783. {
  784. return ReadElementContentAs (ValueType, null);
  785. }
  786. [MonoTODO]
  787. public virtual object ReadElementContentAsObject (string localName, string namespaceURI)
  788. {
  789. return ReadElementContentAs (ValueType, null, localName, namespaceURI);
  790. }
  791. [MonoTODO]
  792. public virtual object ReadContentAsObject ()
  793. {
  794. return ReadContentAs (ValueType, null);
  795. }
  796. public virtual object ReadElementContentAs (Type type, IXmlNamespaceResolver resolver)
  797. {
  798. bool isEmpty = IsEmptyElement;
  799. ReadStartElement ();
  800. object obj = ValueAs (isEmpty ? String.Empty : ReadContentString (false), type, resolver);
  801. if (!isEmpty)
  802. ReadEndElement ();
  803. return obj;
  804. }
  805. public virtual object ReadElementContentAs (Type type, IXmlNamespaceResolver resolver, string localName, string namespaceURI)
  806. {
  807. ReadStartElement (localName, namespaceURI);
  808. object obj = ReadContentAs (type, resolver);
  809. ReadEndElement ();
  810. return obj;
  811. }
  812. public virtual object ReadContentAs (Type type, IXmlNamespaceResolver resolver)
  813. {
  814. return ValueAs (ReadContentString (), type, resolver);
  815. }
  816. private object ValueAs (string text, Type type, IXmlNamespaceResolver resolver)
  817. {
  818. try {
  819. if (type == typeof (object))
  820. return text;
  821. if (type == typeof (XmlQualifiedName)) {
  822. if (resolver != null)
  823. return XmlQualifiedName.Parse (text, resolver);
  824. else
  825. return XmlQualifiedName.Parse (text, this);
  826. }
  827. switch (Type.GetTypeCode (type)) {
  828. case TypeCode.Boolean:
  829. return XQueryConvert.StringToBoolean (text);
  830. case TypeCode.DateTime:
  831. return XQueryConvert.StringToDateTime (text);
  832. case TypeCode.Decimal:
  833. return XQueryConvert.StringToDecimal (text);
  834. case TypeCode.Double:
  835. return XQueryConvert.StringToDouble (text);
  836. case TypeCode.Int32:
  837. return XQueryConvert.StringToInt (text);
  838. case TypeCode.Int64:
  839. return XQueryConvert.StringToInteger (text);
  840. case TypeCode.Single:
  841. return XQueryConvert.StringToFloat (text);
  842. case TypeCode.String:
  843. return text;
  844. }
  845. } catch (Exception ex) {
  846. throw XmlError (String.Format ("Current text value '{0}' is not acceptable for specified type '{1}'. {2}", text, type, ex != null ? ex.Message : String.Empty), ex);
  847. }
  848. throw new ArgumentException (String.Format ("Specified type '{0}' is not supported.", type));
  849. }
  850. public virtual bool ReadElementContentAsBoolean ()
  851. {
  852. try {
  853. return XQueryConvert.StringToBoolean (ReadElementContentAsString ());
  854. } catch (FormatException ex) {
  855. throw XmlError ("Typed value is invalid.", ex);
  856. }
  857. }
  858. public virtual DateTime ReadElementContentAsDateTime ()
  859. {
  860. try {
  861. return XQueryConvert.StringToDateTime (ReadElementContentAsString ());
  862. } catch (FormatException ex) {
  863. throw XmlError ("Typed value is invalid.", ex);
  864. }
  865. }
  866. public virtual decimal ReadElementContentAsDecimal ()
  867. {
  868. try {
  869. return XQueryConvert.StringToDecimal (ReadElementContentAsString ());
  870. } catch (FormatException ex) {
  871. throw XmlError ("Typed value is invalid.", ex);
  872. }
  873. }
  874. public virtual double ReadElementContentAsDouble ()
  875. {
  876. try {
  877. return XQueryConvert.StringToDouble (ReadElementContentAsString ());
  878. } catch (FormatException ex) {
  879. throw XmlError ("Typed value is invalid.", ex);
  880. }
  881. }
  882. public virtual float ReadElementContentAsFloat ()
  883. {
  884. try {
  885. return XQueryConvert.StringToFloat (ReadElementContentAsString ());
  886. } catch (FormatException ex) {
  887. throw XmlError ("Typed value is invalid.", ex);
  888. }
  889. }
  890. public virtual int ReadElementContentAsInt ()
  891. {
  892. try {
  893. return XQueryConvert.StringToInt (ReadElementContentAsString ());
  894. } catch (FormatException ex) {
  895. throw XmlError ("Typed value is invalid.", ex);
  896. }
  897. }
  898. public virtual long ReadElementContentAsLong ()
  899. {
  900. try {
  901. return XQueryConvert.StringToInteger (ReadElementContentAsString ());
  902. } catch (FormatException ex) {
  903. throw XmlError ("Typed value is invalid.", ex);
  904. }
  905. }
  906. public virtual string ReadElementContentAsString ()
  907. {
  908. bool isEmpty = IsEmptyElement;
  909. ReadStartElement ();
  910. if (isEmpty)
  911. return String.Empty;
  912. string s = ReadContentString (false);
  913. ReadEndElement ();
  914. return s;
  915. }
  916. public virtual bool ReadElementContentAsBoolean (string localName, string namespaceURI)
  917. {
  918. try {
  919. return XQueryConvert.StringToBoolean (ReadElementContentAsString (localName, namespaceURI));
  920. } catch (FormatException ex) {
  921. throw XmlError ("Typed value is invalid.", ex);
  922. }
  923. }
  924. public virtual DateTime ReadElementContentAsDateTime (string localName, string namespaceURI)
  925. {
  926. try {
  927. return XQueryConvert.StringToDateTime (ReadElementContentAsString (localName, namespaceURI));
  928. } catch (FormatException ex) {
  929. throw XmlError ("Typed value is invalid.", ex);
  930. }
  931. }
  932. public virtual decimal ReadElementContentAsDecimal (string localName, string namespaceURI)
  933. {
  934. try {
  935. return XQueryConvert.StringToDecimal (ReadElementContentAsString (localName, namespaceURI));
  936. } catch (FormatException ex) {
  937. throw XmlError ("Typed value is invalid.", ex);
  938. }
  939. }
  940. public virtual double ReadElementContentAsDouble (string localName, string namespaceURI)
  941. {
  942. try {
  943. return XQueryConvert.StringToDouble (ReadElementContentAsString (localName, namespaceURI));
  944. } catch (FormatException ex) {
  945. throw XmlError ("Typed value is invalid.", ex);
  946. }
  947. }
  948. public virtual float ReadElementContentAsFloat (string localName, string namespaceURI)
  949. {
  950. try {
  951. return XQueryConvert.StringToFloat (ReadElementContentAsString (localName, namespaceURI));
  952. } catch (FormatException ex) {
  953. throw XmlError ("Typed value is invalid.", ex);
  954. }
  955. }
  956. public virtual int ReadElementContentAsInt (string localName, string namespaceURI)
  957. {
  958. try {
  959. return XQueryConvert.StringToInt (ReadElementContentAsString (localName, namespaceURI));
  960. } catch (FormatException ex) {
  961. throw XmlError ("Typed value is invalid.", ex);
  962. }
  963. }
  964. public virtual long ReadElementContentAsLong (string localName, string namespaceURI)
  965. {
  966. try {
  967. return XQueryConvert.StringToInteger (ReadElementContentAsString (localName, namespaceURI));
  968. } catch (FormatException ex) {
  969. throw XmlError ("Typed value is invalid.", ex);
  970. }
  971. }
  972. public virtual string ReadElementContentAsString (string localName, string namespaceURI)
  973. {
  974. bool isEmpty = IsEmptyElement;
  975. ReadStartElement (localName, namespaceURI);
  976. if (isEmpty)
  977. return String.Empty;
  978. string s = ReadContentString (false);
  979. ReadEndElement ();
  980. return s;
  981. }
  982. public virtual bool ReadContentAsBoolean ()
  983. {
  984. try {
  985. return XQueryConvert.StringToBoolean (ReadContentString ());
  986. } catch (FormatException ex) {
  987. throw XmlError ("Typed value is invalid.", ex);
  988. }
  989. }
  990. public virtual DateTime ReadContentAsDateTime ()
  991. {
  992. try {
  993. return XQueryConvert.StringToDateTime (ReadContentString ());
  994. } catch (FormatException ex) {
  995. throw XmlError ("Typed value is invalid.", ex);
  996. }
  997. }
  998. public virtual decimal ReadContentAsDecimal ()
  999. {
  1000. try {
  1001. return XQueryConvert.StringToDecimal (ReadContentString ());
  1002. } catch (FormatException ex) {
  1003. throw XmlError ("Typed value is invalid.", ex);
  1004. }
  1005. }
  1006. public virtual double ReadContentAsDouble ()
  1007. {
  1008. try {
  1009. return XQueryConvert.StringToDouble (ReadContentString ());
  1010. } catch (FormatException ex) {
  1011. throw XmlError ("Typed value is invalid.", ex);
  1012. }
  1013. }
  1014. public virtual float ReadContentAsFloat ()
  1015. {
  1016. try {
  1017. return XQueryConvert.StringToFloat (ReadContentString ());
  1018. } catch (FormatException ex) {
  1019. throw XmlError ("Typed value is invalid.", ex);
  1020. }
  1021. }
  1022. public virtual int ReadContentAsInt ()
  1023. {
  1024. try {
  1025. return XQueryConvert.StringToInt (ReadContentString ());
  1026. } catch (FormatException ex) {
  1027. throw XmlError ("Typed value is invalid.", ex);
  1028. }
  1029. }
  1030. public virtual long ReadContentAsLong ()
  1031. {
  1032. try {
  1033. return XQueryConvert.StringToInteger (ReadContentString ());
  1034. } catch (FormatException ex) {
  1035. throw XmlError ("Typed value is invalid.", ex);
  1036. }
  1037. }
  1038. public virtual string ReadContentAsString ()
  1039. {
  1040. return ReadContentString ();
  1041. }
  1042. public virtual int ReadContentAsBase64 (
  1043. byte [] buffer, int offset, int length)
  1044. {
  1045. CheckSupport ();
  1046. return binary.ReadContentAsBase64 (
  1047. buffer, offset, length);
  1048. }
  1049. public virtual int ReadContentAsBinHex (
  1050. byte [] buffer, int offset, int length)
  1051. {
  1052. CheckSupport ();
  1053. return binary.ReadContentAsBinHex (
  1054. buffer, offset, length);
  1055. }
  1056. public virtual int ReadElementContentAsBase64 (
  1057. byte [] buffer, int offset, int length)
  1058. {
  1059. CheckSupport ();
  1060. return binary.ReadElementContentAsBase64 (
  1061. buffer, offset, length);
  1062. }
  1063. public virtual int ReadElementContentAsBinHex (
  1064. byte [] buffer, int offset, int length)
  1065. {
  1066. CheckSupport ();
  1067. return binary.ReadElementContentAsBinHex (
  1068. buffer, offset, length);
  1069. }
  1070. #endif
  1071. #if NET_2_0
  1072. public virtual int ReadValueChunk (
  1073. char [] buffer, int offset, int length)
  1074. #else
  1075. internal virtual int ReadValueChunk (
  1076. char [] buffer, int offset, int length)
  1077. #endif
  1078. {
  1079. if (!CanReadValueChunk)
  1080. throw new NotSupportedException ();
  1081. if (binary == null)
  1082. binary = new XmlReaderBinarySupport (this);
  1083. return binary.ReadValueChunk (buffer, offset, length);
  1084. }
  1085. private void CheckSupport ()
  1086. {
  1087. // Default implementation expects both.
  1088. if (!CanReadBinaryContent || !CanReadValueChunk)
  1089. throw new NotSupportedException ();
  1090. if (binary == null)
  1091. binary = new XmlReaderBinarySupport (this);
  1092. }
  1093. #if !NET_2_1
  1094. public abstract void ResolveEntity ();
  1095. #endif
  1096. public virtual void Skip ()
  1097. {
  1098. if (ReadState != ReadState.Interactive)
  1099. return;
  1100. MoveToElement ();
  1101. if (NodeType != XmlNodeType.Element || IsEmptyElement) {
  1102. Read ();
  1103. return;
  1104. }
  1105. int depth = Depth;
  1106. while (Read () && depth < Depth)
  1107. ;
  1108. if (NodeType == XmlNodeType.EndElement)
  1109. Read ();
  1110. }
  1111. private XmlException XmlError (string message)
  1112. {
  1113. return new XmlException (this as IXmlLineInfo, BaseURI, message);
  1114. }
  1115. private XmlException XmlError (string message, Exception innerException)
  1116. {
  1117. return new XmlException (this as IXmlLineInfo, BaseURI, message);
  1118. }
  1119. #endregion
  1120. }
  1121. }