1 //------------------------------------------------------------------------------
2 // <copyright file="ReaderOutput.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 // <owner current="true" primary="true">Microsoft</owner>
6 //------------------------------------------------------------------------------
8 namespace System.Xml.Xsl.XsltOld {
9 using Res = System.Xml.Utils.Res;
11 using System.Globalization;
12 using System.Diagnostics;
16 using System.Xml.XPath;
17 using System.Collections;
19 internal class ReaderOutput : XmlReader, RecordOutput {
20 private Processor processor;
21 private XmlNameTable nameTable;
23 // Main node + Fields Collection
24 private RecordBuilder builder;
25 private BuilderInfo mainNode;
26 private ArrayList attributeList;
27 private int attributeCount;
28 private BuilderInfo attributeValue;
31 private OutputScopeManager manager;
33 // Current position in the list
34 private int currentIndex;
35 private BuilderInfo currentInfo;
38 private ReadState state = ReadState.Initial;
39 private bool haveRecord;
41 // Static default record
42 static BuilderInfo s_DefaultInfo = new BuilderInfo();
44 XmlEncoder encoder = new XmlEncoder();
45 XmlCharType xmlCharType = XmlCharType.Instance;
47 internal ReaderOutput(Processor processor) {
48 Debug.Assert(processor != null);
49 Debug.Assert(processor.NameTable != null);
51 this.processor = processor;
52 this.nameTable = processor.NameTable;
57 // XmlReader abstract methods implementation
58 public override XmlNodeType NodeType {
61 return this.currentInfo.NodeType;
65 public override string Name {
68 string prefix = Prefix;
69 string localName = LocalName;
71 if (prefix != null && prefix.Length > 0) {
72 if (localName.Length > 0) {
73 return nameTable.Add(prefix + ":" + localName);
85 public override string LocalName {
88 return this.currentInfo.LocalName;
92 public override string NamespaceURI {
95 return this.currentInfo.NamespaceURI;
99 public override string Prefix {
102 return this.currentInfo.Prefix;
106 public override bool HasValue {
108 return XmlReader.HasValueInternal(NodeType);
112 public override string Value {
115 return this.currentInfo.Value;
119 public override int Depth {
122 return this.currentInfo.Depth;
126 public override string BaseURI {
132 public override bool IsEmptyElement {
135 return this.currentInfo.IsEmptyTag;
139 public override char QuoteChar {
140 get { return encoder.QuoteChar; }
143 public override bool IsDefault {
144 get { return false; }
147 public override XmlSpace XmlSpace {
148 get { return this.manager != null ? this.manager.XmlSpace : XmlSpace.None; }
151 public override string XmlLang {
152 get { return this.manager != null ? this.manager.XmlLang : string.Empty; }
155 // Attribute Accessors
157 public override int AttributeCount {
158 get { return this.attributeCount; }
161 public override string GetAttribute(string name) {
163 if (FindAttribute(name, out ordinal)) {
164 Debug.Assert(ordinal >= 0);
165 return((BuilderInfo)this.attributeList[ordinal]).Value;
168 Debug.Assert(ordinal == -1);
173 public override string GetAttribute(string localName, string namespaceURI) {
175 if (FindAttribute(localName, namespaceURI, out ordinal)) {
176 Debug.Assert(ordinal >= 0);
177 return((BuilderInfo)this.attributeList[ordinal]).Value;
180 Debug.Assert(ordinal == -1);
185 public override string GetAttribute(int i) {
186 BuilderInfo attribute = GetBuilderInfo(i);
187 return attribute.Value;
190 public override string this [int i] {
191 get { return GetAttribute(i); }
194 public override string this [string name] {
195 get { return GetAttribute(name); }
198 public override string this [string name, string namespaceURI] {
199 get { return GetAttribute(name, namespaceURI); }
202 public override bool MoveToAttribute(string name) {
204 if (FindAttribute(name, out ordinal)) {
205 Debug.Assert(ordinal >= 0);
206 SetAttribute(ordinal);
210 Debug.Assert(ordinal == -1);
215 public override bool MoveToAttribute(string localName, string namespaceURI) {
217 if (FindAttribute(localName, namespaceURI, out ordinal)) {
218 Debug.Assert(ordinal >= 0);
219 SetAttribute(ordinal);
223 Debug.Assert(ordinal == -1);
228 public override void MoveToAttribute(int i) {
229 if (i < 0 || this.attributeCount <= i) {
230 throw new ArgumentOutOfRangeException("i");
235 public override bool MoveToFirstAttribute() {
236 if (this.attributeCount <= 0) {
237 Debug.Assert(this.attributeCount == 0);
246 public override bool MoveToNextAttribute() {
247 if (this.currentIndex + 1 < this.attributeCount) {
248 SetAttribute(this.currentIndex + 1);
254 public override bool MoveToElement() {
255 if (NodeType == XmlNodeType.Attribute || this.currentInfo == this.attributeValue) {
262 // Moving through the Stream
264 public override bool Read() {
265 Debug.Assert(this.processor != null || this.state == ReadState.Closed);
267 if (this.state != ReadState.Interactive) {
268 if (this.state == ReadState.Initial) {
269 state = ReadState.Interactive;
276 while (true) { // while -- to ignor empty whitespace nodes.
277 if (this.haveRecord) {
278 this.processor.ResetOutput();
279 this.haveRecord = false;
282 this.processor.Execute();
284 if (this.haveRecord) {
286 // check text nodes on whitespaces;
287 switch (this.NodeType) {
288 case XmlNodeType.Text :
289 if (xmlCharType.IsOnlyWhitespace(this.Value)) {
290 this.currentInfo.NodeType = XmlNodeType.Whitespace;
291 goto case XmlNodeType.Whitespace;
293 Debug.Assert(this.Value.Length != 0, "It whould be Whitespace in this case");
295 case XmlNodeType.Whitespace :
296 if(this.Value.Length == 0) {
297 continue; // ignoring emty text nodes
299 if (this.XmlSpace == XmlSpace.Preserve) {
300 this.currentInfo.NodeType = XmlNodeType.SignificantWhitespace;
306 Debug.Assert(this.processor.ExecutionDone);
307 this.state = ReadState.EndOfFile;
311 return this.haveRecord;
315 public override bool EOF {
316 get { return this.state == ReadState.EndOfFile; }
319 public override void Close() {
320 this.processor = null;
321 this.state = ReadState.Closed;
325 public override ReadState ReadState {
326 get { return this.state; }
329 // Whole Content Read Methods
330 public override string ReadString() {
331 string result = string.Empty;
333 if (NodeType == XmlNodeType.Element || NodeType == XmlNodeType.Attribute || this.currentInfo == this.attributeValue) {
334 if(this.mainNode.IsEmptyTag) {
338 throw new InvalidOperationException(Res.GetString(Res.Xml_InvalidOperation));
342 StringBuilder sb = null;
347 case XmlNodeType.Text:
348 case XmlNodeType.Whitespace:
349 case XmlNodeType.SignificantWhitespace:
350 // case XmlNodeType.CharacterEntity:
356 sb = new StringBuilder(result);
358 sb.Append(this.Value);
361 throw new InvalidOperationException(Res.GetString(Res.Xml_InvalidOperation));
364 return (sb == null) ? result : sb.ToString();
369 public override string ReadInnerXml() {
370 if (ReadState == ReadState.Interactive) {
371 if (NodeType == XmlNodeType.Element && ! IsEmptyElement) {
372 StringOutput output = new StringOutput(this.processor);
373 output.OmitXmlDecl();
376 Read(); // skeep begin Element
377 while (depth < Depth) { // process content
378 Debug.Assert(this.builder != null);
379 output.RecordDone(this.builder);
382 Debug.Assert(NodeType == XmlNodeType.EndElement);
383 Read(); // skeep end element
386 return output.Result;
388 else if(NodeType == XmlNodeType.Attribute) {
389 return encoder.AtributeInnerXml(Value);
398 public override string ReadOuterXml() {
399 if (ReadState == ReadState.Interactive) {
400 if (NodeType == XmlNodeType.Element) {
401 StringOutput output = new StringOutput(this.processor);
402 output.OmitXmlDecl();
403 bool emptyElement = IsEmptyElement;
405 // process current record
406 output.RecordDone(this.builder);
408 // process internal elements & text nodes
409 while(depth < Depth) {
410 Debug.Assert(this.builder != null);
411 output.RecordDone(this.builder);
414 // process end element
415 if (! emptyElement) {
416 output.RecordDone(this.builder);
421 return output.Result;
423 else if(NodeType == XmlNodeType.Attribute) {
424 return encoder.AtributeOuterXml(Name, Value);
434 // Nametable and Namespace Helpers
437 public override XmlNameTable NameTable {
439 Debug.Assert(this.nameTable != null);
440 return this.nameTable;
444 public override string LookupNamespace(string prefix) {
445 prefix = this.nameTable.Get(prefix);
447 if (this.manager != null && prefix != null) {
448 return this.manager.ResolveNamespace(prefix);
453 public override void ResolveEntity() {
454 Debug.Assert(NodeType != XmlNodeType.EntityReference);
456 if (NodeType != XmlNodeType.EntityReference) {
457 throw new InvalidOperationException(Res.GetString(Res.Xml_InvalidOperation));
461 public override bool ReadAttributeValue() {
462 if (ReadState != ReadState.Interactive || NodeType != XmlNodeType.Attribute) {
466 if (this.attributeValue == null) {
467 this.attributeValue = new BuilderInfo();
468 this.attributeValue.NodeType = XmlNodeType.Text;
470 if (this.currentInfo == this.attributeValue) {
474 this.attributeValue.Value = this.currentInfo.Value;
475 this.attributeValue.Depth = this.currentInfo.Depth + 1;
476 this.currentInfo = this.attributeValue;
482 // RecordOutput interface method implementation
485 public Processor.OutputResult RecordDone(RecordBuilder record) {
486 this.builder = record;
487 this.mainNode = record.MainNode;
488 this.attributeList = record.AttributeList;
489 this.attributeCount = record.AttributeCount;
490 this.manager = record.Manager;
492 this.haveRecord = true;
495 return Processor.OutputResult.Interrupt;
498 public void TheEnd() {
499 // nothing here, was taken care of by RecordBuilder
503 // Implementation internals
506 private void SetMainNode() {
507 this.currentIndex = -1;
508 this.currentInfo = this.mainNode;
511 private void SetAttribute(int attrib) {
512 Debug.Assert(0 <= attrib && attrib < this.attributeCount);
513 Debug.Assert(0 <= attrib && attrib < this.attributeList.Count);
514 Debug.Assert(this.attributeList[attrib] is BuilderInfo);
516 this.currentIndex = attrib;
517 this.currentInfo = (BuilderInfo) this.attributeList[attrib];
520 private BuilderInfo GetBuilderInfo(int attrib) {
521 if (attrib < 0 || this.attributeCount <= attrib) {
522 throw new ArgumentOutOfRangeException("attrib");
525 Debug.Assert(this.attributeList[attrib] is BuilderInfo);
527 return(BuilderInfo) this.attributeList[attrib];
530 private bool FindAttribute(String localName, String namespaceURI, out int attrIndex) {
531 if (namespaceURI == null) {
532 namespaceURI = string.Empty;
534 if (localName == null) {
535 localName = string.Empty;
538 for (int index = 0; index < this.attributeCount; index ++) {
539 Debug.Assert(this.attributeList[index] is BuilderInfo);
541 BuilderInfo attribute = (BuilderInfo) this.attributeList[index];
542 if (attribute.NamespaceURI == namespaceURI && attribute.LocalName == localName) {
552 private bool FindAttribute(String name, out int attrIndex) {
557 for (int index = 0; index < this.attributeCount; index ++) {
558 Debug.Assert(this.attributeList[index] is BuilderInfo);
560 BuilderInfo attribute = (BuilderInfo) this.attributeList[index];
561 if (attribute.Name == name) {
571 private void Reset() {
572 this.currentIndex = -1;
573 this.currentInfo = s_DefaultInfo;
574 this.mainNode = s_DefaultInfo;
578 [System.Diagnostics.Conditional("DEBUG")]
579 private void CheckCurrentInfo() {
580 Debug.Assert(this.currentInfo != null);
581 Debug.Assert(this.attributeCount == 0 || this.attributeList != null);
582 Debug.Assert((this.currentIndex == -1) == (this.currentInfo == this.mainNode));
583 Debug.Assert((this.currentIndex == -1) || (this.currentInfo == this.attributeValue || this.attributeList[this.currentIndex] is BuilderInfo && this.attributeList[this.currentIndex] == this.currentInfo));
586 private class XmlEncoder {
587 private StringBuilder buffer = null;
588 private XmlTextEncoder encoder = null;
590 private void Init() {
591 buffer = new StringBuilder();
592 encoder = new XmlTextEncoder(new StringWriter(buffer, CultureInfo.InvariantCulture));
595 public string AtributeInnerXml(string value) {
596 if(encoder == null) Init();
597 buffer .Length = 0; // clean buffer
598 encoder.StartAttribute(/*save:*/false);
599 encoder.Write(value);
600 encoder.EndAttribute();
601 return buffer.ToString();
604 public string AtributeOuterXml(string name, string value) {
605 if(encoder == null) Init();
606 buffer .Length = 0; // clean buffer
607 buffer .Append(name);
609 buffer .Append(QuoteChar);
610 encoder.StartAttribute(/*save:*/false);
611 encoder.Write(value);
612 encoder.EndAttribute();
613 buffer .Append(QuoteChar);
614 return buffer.ToString();
617 public char QuoteChar {