DTMXPathDocumentWriter2.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770
  1. //
  2. // Mono.Xml.XPath.DTMXPathDocumentWriter2
  3. //
  4. // Author:
  5. // Atsushi Enomoto <[email protected]>
  6. //
  7. // (C) 2004 Novell Inc.
  8. //
  9. //
  10. // Permission is hereby granted, free of charge, to any person obtaining
  11. // a copy of this software and associated documentation files (the
  12. // "Software"), to deal in the Software without restriction, including
  13. // without limitation the rights to use, copy, modify, merge, publish,
  14. // distribute, sublicense, and/or sell copies of the Software, and to
  15. // permit persons to whom the Software is furnished to do so, subject to
  16. // the following conditions:
  17. //
  18. // The above copyright notice and this permission notice shall be
  19. // included in all copies or substantial portions of the Software.
  20. //
  21. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  22. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  23. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  24. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  25. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  26. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  27. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  28. //
  29. using System;
  30. using System.Collections;
  31. using System.IO;
  32. using System.Xml;
  33. using System.Xml.Schema;
  34. using System.Xml.XPath;
  35. namespace Mono.Xml.XPath
  36. {
  37. #if OUTSIDE_SYSTEM_XML
  38. public
  39. #else
  40. internal
  41. #endif
  42. class DTMXPathDocumentWriter2 : XmlWriter
  43. {
  44. public DTMXPathDocumentWriter2 (XmlNameTable nt, int defaultCapacity)
  45. {
  46. nameTable = nt == null ? new NameTable () : nt;
  47. nodeCapacity = defaultCapacity;
  48. attributeCapacity = nodeCapacity;
  49. nsCapacity = 10;
  50. idTable = new Hashtable ();
  51. nodes = new DTMXPathLinkedNode2 [nodeCapacity];
  52. attributes = new DTMXPathAttributeNode2 [attributeCapacity];
  53. namespaces = new DTMXPathNamespaceNode2 [nsCapacity];
  54. atomicStringPool = new string [20];
  55. nonAtomicStringPool = new string [20];
  56. Init ();
  57. }
  58. XmlNameTable nameTable;
  59. int nodeCapacity;
  60. int attributeCapacity;
  61. int nsCapacity;
  62. // Linked Node
  63. DTMXPathLinkedNode2 [] nodes;
  64. // Attribute
  65. DTMXPathAttributeNode2 [] attributes;
  66. // NamespaceNode
  67. DTMXPathNamespaceNode2 [] namespaces;
  68. // String pool
  69. string [] atomicStringPool;
  70. int atomicIndex;
  71. string [] nonAtomicStringPool;
  72. int nonAtomicIndex;
  73. // idTable [string value] -> int nodeId
  74. Hashtable idTable;
  75. int nodeIndex;
  76. int attributeIndex;
  77. int nsIndex;
  78. int [] parentStack = new int [10];
  79. int parentStackIndex = 0;
  80. // for attribute processing; should be reset per each element.
  81. bool hasAttributes;
  82. bool hasLocalNs;
  83. int attrIndexAtStart;
  84. int nsIndexAtStart;
  85. int lastNsInScope;
  86. // They are only used in Writer
  87. int prevSibling;
  88. WriteState state;
  89. bool openNamespace;
  90. bool isClosed;
  91. public DTMXPathDocument2 CreateDocument ()
  92. {
  93. if (!isClosed)
  94. Close ();
  95. return new DTMXPathDocument2 (nameTable,
  96. nodes,
  97. attributes,
  98. namespaces,
  99. atomicStringPool,
  100. nonAtomicStringPool,
  101. idTable
  102. );
  103. }
  104. public void Init ()
  105. {
  106. // string pool index 0 to 3 are fixed.
  107. atomicStringPool [0] = nonAtomicStringPool [0] = "";
  108. atomicStringPool [1] = nonAtomicStringPool [1] = null;
  109. atomicStringPool [2] = nonAtomicStringPool [2] = XmlNamespaces.XML;
  110. atomicStringPool [3] = nonAtomicStringPool [3] = XmlNamespaces.XMLNS;
  111. atomicIndex = nonAtomicIndex = 4;
  112. // index 0 is dummy. No node (including Root) is assigned to this index
  113. // So that we can easily compare index != 0 instead of index < 0.
  114. // (Difference between jnz or jbe in 80x86.)
  115. AddNode (0, 0, 0, XPathNodeType.All, "", false, "", "", "", "", "", 0, 0, 0);
  116. nodeIndex++;
  117. AddAttribute (0, "", "", "", "", 0, 0);
  118. AddNsNode (0, "", "", 0);
  119. nsIndex++;
  120. AddNsNode (1, "xml", XmlNamespaces.XML, 0);
  121. // add root.
  122. AddNode (0, 0, 0, XPathNodeType.Root, "", false, "", "", "", "", "", 1, 0, 0);
  123. this.nodeIndex = 1;
  124. this.lastNsInScope = 1;
  125. parentStack [0] = nodeIndex;
  126. state = WriteState.Content;
  127. }
  128. private int GetParentIndex ()
  129. {
  130. return parentStack [parentStackIndex];
  131. }
  132. private int GetPreviousSiblingIndex ()
  133. {
  134. int parent = parentStack [parentStackIndex];
  135. if (parent == nodeIndex)
  136. return 0;
  137. int prevSibling = nodeIndex;
  138. while (nodes [prevSibling].Parent != parent)
  139. prevSibling = nodes [prevSibling].Parent;
  140. return prevSibling;
  141. }
  142. private void UpdateTreeForAddition ()
  143. {
  144. int parent = GetParentIndex ();
  145. prevSibling = GetPreviousSiblingIndex ();
  146. nodeIndex++;
  147. if (prevSibling != 0)
  148. nodes [prevSibling].NextSibling = nodeIndex;
  149. if (parent == nodeIndex - 1)
  150. nodes [parent].FirstChild = nodeIndex;
  151. }
  152. private void CloseStartElement ()
  153. {
  154. if (attrIndexAtStart != attributeIndex)
  155. nodes [nodeIndex].FirstAttribute = attrIndexAtStart + 1;
  156. if (nsIndexAtStart != nsIndex) {
  157. nodes [nodeIndex].FirstNamespace = nsIndex;
  158. lastNsInScope = nsIndex;
  159. }
  160. parentStackIndex++;
  161. if (parentStack.Length == parentStackIndex) {
  162. int [] tmp = new int [parentStackIndex * 2];
  163. Array.Copy (parentStack, tmp, parentStackIndex);
  164. parentStack = tmp;
  165. }
  166. parentStack [parentStackIndex] = nodeIndex;
  167. state = WriteState.Content;
  168. }
  169. #region Adding Nodes
  170. private int AtomicIndex (string s)
  171. {
  172. if (s == "")
  173. return 0;
  174. if (s == null)
  175. return 1;
  176. int i = 2;
  177. for (; i < atomicIndex; i++)
  178. if (Object.ReferenceEquals (s, atomicStringPool [i]))
  179. return i;
  180. if (atomicIndex == atomicStringPool.Length) {
  181. string [] newArr = new string [atomicIndex * 2];
  182. Array.Copy (atomicStringPool, newArr, atomicIndex);
  183. atomicStringPool = newArr;
  184. }
  185. atomicStringPool [atomicIndex] = s;
  186. return atomicIndex++;
  187. }
  188. private int NonAtomicIndex (string s)
  189. {
  190. if (s == "")
  191. return 0;
  192. if (s == null)
  193. return 1;
  194. int i = 2;
  195. // Here we don't compare all the entries (sometimes it
  196. // goes extremely slow).
  197. int max = nonAtomicIndex < 100 ? nonAtomicIndex : 100;
  198. for (; i < max; i++)
  199. if (s == nonAtomicStringPool [i])
  200. return i;
  201. if (nonAtomicIndex == nonAtomicStringPool.Length) {
  202. string [] newArr = new string [nonAtomicIndex * 2];
  203. Array.Copy (nonAtomicStringPool, newArr, nonAtomicIndex);
  204. nonAtomicStringPool = newArr;
  205. }
  206. nonAtomicStringPool [nonAtomicIndex] = s;
  207. return nonAtomicIndex++;
  208. }
  209. private void SetNodeArrayLength (int size)
  210. {
  211. DTMXPathLinkedNode2 [] newArr = new DTMXPathLinkedNode2 [size];
  212. Array.Copy (nodes, newArr, System.Math.Min (size, nodes.Length));
  213. nodes = newArr;
  214. }
  215. private void SetAttributeArrayLength (int size)
  216. {
  217. DTMXPathAttributeNode2 [] newArr =
  218. new DTMXPathAttributeNode2 [size];
  219. Array.Copy (attributes, newArr, System.Math.Min (size, attributes.Length));
  220. attributes = newArr;
  221. }
  222. private void SetNsArrayLength (int size)
  223. {
  224. DTMXPathNamespaceNode2 [] newArr =
  225. new DTMXPathNamespaceNode2 [size];
  226. Array.Copy (namespaces, newArr, System.Math.Min (size, namespaces.Length));
  227. namespaces = newArr;
  228. }
  229. // Here followings are skipped: firstChild, nextSibling,
  230. public void AddNode (int parent, int firstAttribute, int previousSibling, XPathNodeType nodeType, string baseUri, bool isEmptyElement, string localName, string ns, string prefix, string value, string xmlLang, int namespaceNode, int lineNumber, int linePosition)
  231. {
  232. if (nodes.Length < nodeIndex + 1) {
  233. nodeCapacity *= 4;
  234. SetNodeArrayLength (nodeCapacity);
  235. }
  236. #if DTM_CLASS
  237. nodes [nodeIndex] = new DTMXPathLinkedNode2 ();
  238. #endif
  239. nodes [nodeIndex].FirstChild = 0; // dummy
  240. nodes [nodeIndex].Parent = parent;
  241. nodes [nodeIndex].FirstAttribute = firstAttribute;
  242. nodes [nodeIndex].PreviousSibling = previousSibling;
  243. nodes [nodeIndex].NextSibling = 0; // dummy
  244. nodes [nodeIndex].NodeType = nodeType;
  245. nodes [nodeIndex].BaseURI = AtomicIndex (baseUri);
  246. nodes [nodeIndex].IsEmptyElement = isEmptyElement;
  247. nodes [nodeIndex].LocalName = AtomicIndex (localName);
  248. nodes [nodeIndex].NamespaceURI = AtomicIndex (ns);
  249. nodes [nodeIndex].Prefix = AtomicIndex (prefix);
  250. nodes [nodeIndex].Value = NonAtomicIndex (value);
  251. nodes [nodeIndex].XmlLang = AtomicIndex (xmlLang);
  252. nodes [nodeIndex].FirstNamespace = namespaceNode;
  253. nodes [nodeIndex].LineNumber = lineNumber;
  254. nodes [nodeIndex].LinePosition = linePosition;
  255. }
  256. // Followings are skipped: nextAttribute,
  257. public void AddAttribute (int ownerElement, string localName, string ns, string prefix, string value, int lineNumber, int linePosition)
  258. {
  259. if (attributes.Length < attributeIndex + 1) {
  260. attributeCapacity *= 4;
  261. SetAttributeArrayLength (attributeCapacity);
  262. }
  263. #if DTM_CLASS
  264. attributes [attributeIndex] = new DTMXPathAttributeNode2 ();
  265. #endif
  266. attributes [attributeIndex].OwnerElement = ownerElement;
  267. attributes [attributeIndex].LocalName = AtomicIndex (localName);
  268. attributes [attributeIndex].NamespaceURI = AtomicIndex (ns);
  269. attributes [attributeIndex].Prefix = AtomicIndex (prefix);
  270. attributes [attributeIndex].Value = NonAtomicIndex (value);
  271. attributes [attributeIndex].LineNumber = lineNumber;
  272. attributes [attributeIndex].LinePosition = linePosition;
  273. }
  274. // Followings are skipped: nextNsNode (may be next attribute in the same element, or ancestors' nsNode)
  275. public void AddNsNode (int declaredElement, string name, string ns, int nextNs)
  276. {
  277. if (namespaces.Length < nsIndex + 1) {
  278. nsCapacity *= 4;
  279. SetNsArrayLength (nsCapacity);
  280. }
  281. #if DTM_CLASS
  282. namespaces [nsIndex] = new DTMXPathNamespaceNode2 ();
  283. #endif
  284. namespaces [nsIndex].DeclaredElement = declaredElement;
  285. namespaces [nsIndex].Name = AtomicIndex (name);
  286. namespaces [nsIndex].Namespace = AtomicIndex (ns);
  287. namespaces [nsIndex].NextNamespace = nextNs;
  288. }
  289. #endregion
  290. #region XmlWriter methods
  291. // They are not supported
  292. public override string XmlLang { get { return null; } }
  293. public override XmlSpace XmlSpace { get { return XmlSpace.None; } }
  294. public override WriteState WriteState { get { return state; } }
  295. public override void Close ()
  296. {
  297. // Fixup arrays
  298. SetNodeArrayLength (nodeIndex + 1);
  299. SetAttributeArrayLength (attributeIndex + 1);
  300. SetNsArrayLength (nsIndex + 1);
  301. string [] newArr = new string [atomicIndex];
  302. Array.Copy (atomicStringPool, newArr, atomicIndex);
  303. atomicStringPool = newArr;
  304. newArr = new string [nonAtomicIndex];
  305. Array.Copy (nonAtomicStringPool, newArr, nonAtomicIndex);
  306. nonAtomicStringPool = newArr;
  307. isClosed = true;
  308. }
  309. public override void Flush ()
  310. {
  311. // do nothing
  312. }
  313. public override string LookupPrefix (string ns)
  314. {
  315. int tmp = nsIndex;
  316. while (tmp != 0) {
  317. if (atomicStringPool [namespaces [tmp].Namespace] == ns)
  318. return atomicStringPool [namespaces [tmp].Name];
  319. tmp = namespaces [tmp].NextNamespace;
  320. }
  321. return null;
  322. }
  323. public override void WriteCData (string data)
  324. {
  325. AddTextNode (data);
  326. }
  327. private void AddTextNode (string data)
  328. {
  329. switch (state) {
  330. case WriteState.Element:
  331. CloseStartElement ();
  332. break;
  333. case WriteState.Content:
  334. break;
  335. default:
  336. throw new InvalidOperationException ("Invalid document state for CDATA section: " + state);
  337. }
  338. // When text after text, just add the value, and return.
  339. if (nodes [nodeIndex].Parent == parentStack [parentStackIndex]) {
  340. switch (nodes [nodeIndex].NodeType) {
  341. case XPathNodeType.Text:
  342. case XPathNodeType.SignificantWhitespace:
  343. string value = nonAtomicStringPool [nodes [nodeIndex].Value] + data;
  344. nodes [nodeIndex].Value = NonAtomicIndex (value);
  345. if (IsWhitespace (value))
  346. nodes [nodeIndex].NodeType = XPathNodeType.SignificantWhitespace;
  347. else
  348. nodes [nodeIndex].NodeType = XPathNodeType.Text;
  349. return;
  350. }
  351. }
  352. int parent = GetParentIndex ();
  353. UpdateTreeForAddition ();
  354. AddNode (parent,
  355. 0, // attribute
  356. prevSibling,
  357. XPathNodeType.Text,
  358. null,
  359. false,
  360. String.Empty,
  361. String.Empty,
  362. String.Empty,
  363. data,
  364. null,
  365. 0, // nsIndex
  366. 0, // line info
  367. 0);
  368. }
  369. private void CheckTopLevelNode ()
  370. {
  371. switch (state) {
  372. case WriteState.Element:
  373. CloseStartElement ();
  374. break;
  375. case WriteState.Content:
  376. case WriteState.Prolog:
  377. case WriteState.Start:
  378. break;
  379. default:
  380. throw new InvalidOperationException ("Invalid document state for CDATA section: " + state);
  381. }
  382. }
  383. public override void WriteComment (string data)
  384. {
  385. CheckTopLevelNode ();
  386. int parent = GetParentIndex ();
  387. UpdateTreeForAddition ();
  388. AddNode (parent,
  389. 0, // attribute
  390. prevSibling,
  391. XPathNodeType.Comment,
  392. null,
  393. false,
  394. String.Empty,
  395. String.Empty,
  396. String.Empty,
  397. data,
  398. null,
  399. 0, // nsIndex
  400. 0, // line info
  401. 0);
  402. }
  403. public override void WriteProcessingInstruction (string name, string data)
  404. {
  405. CheckTopLevelNode ();
  406. int parent = GetParentIndex ();
  407. UpdateTreeForAddition ();
  408. AddNode (parent,
  409. 0, // attribute
  410. prevSibling,
  411. XPathNodeType.ProcessingInstruction,
  412. null,
  413. false,
  414. name,
  415. String.Empty,
  416. String.Empty,
  417. data,
  418. null,
  419. 0, // nsIndex
  420. 0, // line info
  421. 0);
  422. }
  423. public override void WriteWhitespace (string data)
  424. {
  425. CheckTopLevelNode ();
  426. int parent = GetParentIndex ();
  427. UpdateTreeForAddition ();
  428. AddNode (parent,
  429. 0, // attribute
  430. prevSibling,
  431. XPathNodeType.Whitespace,
  432. null,
  433. false,
  434. String.Empty,
  435. String.Empty,
  436. String.Empty,
  437. data,
  438. null,
  439. 0, // nsIndex
  440. 0, // line info
  441. 0);
  442. }
  443. public override void WriteStartDocument ()
  444. {
  445. // do nothing
  446. }
  447. public override void WriteStartDocument (bool standalone)
  448. {
  449. // do nothing
  450. }
  451. public override void WriteEndDocument ()
  452. {
  453. // do nothing
  454. }
  455. public override void WriteStartElement (string prefix, string localName, string ns)
  456. {
  457. if (ns == null)
  458. ns = String.Empty;
  459. else if (prefix == null && ns.Length > 0)
  460. prefix = LookupPrefix (ns);
  461. if (prefix == null)
  462. prefix = String.Empty;
  463. switch (state) {
  464. case WriteState.Element:
  465. CloseStartElement ();
  466. break;
  467. case WriteState.Start:
  468. case WriteState.Prolog:
  469. case WriteState.Content:
  470. break;
  471. default:
  472. throw new InvalidOperationException ("Invalid document state for writing element: " + state);
  473. }
  474. int parent = GetParentIndex ();
  475. UpdateTreeForAddition ();
  476. WriteStartElement (parent, prevSibling, prefix, localName, ns);
  477. state = WriteState.Element;
  478. }
  479. private void WriteStartElement (int parent, int previousSibling, string prefix, string localName, string ns)
  480. {
  481. PrepareStartElement (previousSibling);
  482. AddNode (parent,
  483. 0, // dummy:firstAttribute
  484. previousSibling,
  485. XPathNodeType.Element,
  486. null,
  487. false,
  488. localName,
  489. ns,
  490. prefix,
  491. "", // Element has no internal value.
  492. null,
  493. lastNsInScope,
  494. 0,
  495. 0);
  496. }
  497. private void PrepareStartElement (int previousSibling)
  498. {
  499. hasAttributes = false;
  500. hasLocalNs = false;
  501. attrIndexAtStart = attributeIndex;
  502. nsIndexAtStart = nsIndex;
  503. while (namespaces [lastNsInScope].DeclaredElement == previousSibling) {
  504. lastNsInScope = namespaces [lastNsInScope].NextNamespace;
  505. }
  506. }
  507. public override void WriteEndElement ()
  508. {
  509. WriteEndElement (false);
  510. }
  511. public override void WriteFullEndElement ()
  512. {
  513. WriteEndElement (true);
  514. }
  515. private void WriteEndElement (bool full)
  516. {
  517. switch (state) {
  518. case WriteState.Element:
  519. CloseStartElement ();
  520. break;
  521. case WriteState.Content:
  522. break;
  523. default:
  524. throw new InvalidOperationException ("Invalid state for writing EndElement: " + state);
  525. }
  526. parentStackIndex--;
  527. if (nodes [nodeIndex].NodeType == XPathNodeType.Element) {
  528. if (!full)
  529. nodes [nodeIndex].IsEmptyElement = true;
  530. }
  531. }
  532. public override void WriteStartAttribute (string prefix, string localName, string ns)
  533. {
  534. if (ns == null)
  535. ns = String.Empty;
  536. if (state != WriteState.Element)
  537. throw new InvalidOperationException ("Invalid document state for attribute: " + state);
  538. state = WriteState.Attribute;
  539. if (ns == XmlNamespaces.XMLNS)
  540. ProcessNamespace ((prefix == null || prefix == String.Empty) ? "" : localName, String.Empty); // dummy: Value should be completed
  541. else
  542. ProcessAttribute (prefix, localName, ns, String.Empty); // dummy: Value should be completed
  543. }
  544. private void ProcessNamespace (string prefix, string ns)
  545. {
  546. int nextTmp = hasLocalNs ? nsIndex : nodes [nodeIndex].FirstNamespace;
  547. nsIndex++;
  548. this.AddNsNode (nodeIndex,
  549. prefix,
  550. ns,
  551. nextTmp);
  552. hasLocalNs = true;
  553. openNamespace = true;
  554. }
  555. private void ProcessAttribute (string prefix, string localName, string ns, string value)
  556. {
  557. if (prefix == null && ns.Length > 0)
  558. prefix = LookupPrefix (ns);
  559. attributeIndex ++;
  560. this.AddAttribute (nodeIndex,
  561. localName,
  562. ns,
  563. prefix != null ? prefix : String.Empty,
  564. value,
  565. 0,
  566. 0);
  567. if (hasAttributes)
  568. attributes [attributeIndex - 1].NextAttribute = attributeIndex;
  569. else
  570. hasAttributes = true;
  571. }
  572. public override void WriteEndAttribute ()
  573. {
  574. if (state != WriteState.Attribute)
  575. throw new InvalidOperationException ();
  576. openNamespace = false;
  577. state = WriteState.Element;
  578. }
  579. public override void WriteString (string text)
  580. {
  581. if (WriteState == WriteState.Attribute) {
  582. if (openNamespace) {
  583. string value = atomicStringPool [namespaces [nsIndex].Namespace] + text;
  584. namespaces [nsIndex].Namespace = AtomicIndex (value);
  585. } else {
  586. string value = nonAtomicStringPool [attributes [attributeIndex].Value] + text;
  587. attributes [attributeIndex].Value = NonAtomicIndex (value);
  588. }
  589. }
  590. else
  591. AddTextNode (text);
  592. }
  593. // Well, they cannot be supported, but actually used to
  594. // disable-output-escaping = "true"
  595. public override void WriteRaw (string data)
  596. {
  597. WriteString (data);
  598. }
  599. public override void WriteRaw (char [] data, int start, int len)
  600. {
  601. WriteString (new string (data, start, len));
  602. }
  603. public override void WriteName (string name)
  604. {
  605. WriteString (name);
  606. }
  607. public override void WriteNmToken (string name)
  608. {
  609. WriteString (name);
  610. }
  611. public override void WriteBase64 (byte [] buffer, int index, int count)
  612. {
  613. WriteString (Convert.ToBase64String (buffer, index, count));
  614. }
  615. public override void WriteBinHex (byte [] buffer, int index, int count)
  616. {
  617. throw new NotSupportedException ();
  618. }
  619. public override void WriteChars (char [] buffer, int index, int count)
  620. {
  621. WriteString (new string (buffer, index, count));
  622. }
  623. public override void WriteCharEntity (char c)
  624. {
  625. WriteString (c.ToString ());
  626. }
  627. public override void WriteDocType (string name, string pub, string sys, string intSubset)
  628. {
  629. throw new NotSupportedException ();
  630. }
  631. public override void WriteEntityRef (string name)
  632. {
  633. throw new NotSupportedException ();
  634. }
  635. public override void WriteQualifiedName (string localName, string ns)
  636. {
  637. string prefix = (ns == null || ns.Length == 0) ? null : LookupPrefix (ns);
  638. if (prefix != null && prefix.Length > 0)
  639. WriteString (prefix + ":" + localName);
  640. else
  641. WriteString (localName);
  642. }
  643. public override void WriteSurrogateCharEntity (char high, char low)
  644. {
  645. WriteString (high.ToString ());
  646. WriteString (low.ToString ());
  647. }
  648. private bool IsWhitespace (string data)
  649. {
  650. for (int i = 0; i < data.Length; i++) {
  651. switch (data [i]) {
  652. case ' ':
  653. case '\r':
  654. case '\n':
  655. case '\t':
  656. continue;
  657. default:
  658. return false;
  659. }
  660. }
  661. return true;
  662. }
  663. #endregion
  664. }
  665. }