1 //------------------------------------------------------------------------------
2 // <copyright file="RecordBuilder.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 // <owner current="true" primary="true">Microsoft</owner>
6 //------------------------------------------------------------------------------
7 
8 namespace System.Xml.Xsl.XsltOld {
9     using Res = System.Xml.Utils.Res;
10     using System;
11     using System.Diagnostics;
12     using System.Text;
13     using System.Xml;
14     using System.Xml.XPath;
15     using System.Collections;
16 
17     internal sealed class RecordBuilder {
18         private int             outputState;
19         private RecordBuilder   next;
20 
21         RecordOutput            output;
22 
23         // Atomization:
24         private XmlNameTable    nameTable;
25         private OutKeywords     atoms;
26 
27         // Namespace manager for output
28         private OutputScopeManager  scopeManager;
29 
30         // Main node + Fields Collection
31         private BuilderInfo     mainNode           = new BuilderInfo();
32         private ArrayList       attributeList      = new ArrayList();
33         private int             attributeCount;
34         private ArrayList       namespaceList      = new ArrayList();
35         private int             namespaceCount;
36         private BuilderInfo     dummy = new BuilderInfo();
37 
38         // Current position in the list
39         private BuilderInfo     currentInfo;
40         // Builder state
41         private bool            popScope;
42         private int             recordState;
43         private int             recordDepth;
44 
45         private const int       NoRecord    = 0;      // No part of a new record was generated (old record was cleared out)
46         private const int       SomeRecord  = 1;      // Record was generated partially        (can be eventually record)
47         private const int       HaveRecord  = 2;      // Record was fully generated
48 
49         private const char      s_Minus         = '-';
50         private const string    s_Space         = " ";
51         private const string    s_SpaceMinus    = " -";
52         private const char      s_Question      = '?';
53         private const char      s_Greater       = '>';
54         private const string    s_SpaceGreater  = " >";
55 
56         private const string    PrefixFormat    = "xp_{0}";
57 
RecordBuilder(RecordOutput output, XmlNameTable nameTable)58         internal RecordBuilder(RecordOutput output, XmlNameTable nameTable) {
59             Debug.Assert(output != null);
60             this.output    = output;
61             this.nameTable = nameTable != null ? nameTable : new NameTable();
62             this.atoms     = new OutKeywords(this.nameTable);
63             this.scopeManager   = new OutputScopeManager(this.nameTable, this.atoms);
64         }
65 
66         //
67         // Internal properties
68         //
69 
70         internal int OutputState {
71             get { return this.outputState; }
72             set { this.outputState = value; }
73         }
74 
75         internal RecordBuilder Next {
76             get { return this.next; }
77             set { this.next = value; }
78         }
79 
80         internal RecordOutput Output {
81             get { return this.output; }
82         }
83 
84         internal BuilderInfo MainNode {
85             get { return this.mainNode; }
86         }
87 
88         internal ArrayList AttributeList {
89             get { return this.attributeList; }
90         }
91 
92         internal int AttributeCount {
93             get { return this.attributeCount; }
94         }
95 
96         internal OutputScopeManager Manager {
97             get { return this.scopeManager; }
98         }
99 
ValueAppend(string s, bool disableOutputEscaping)100         private void ValueAppend(string s, bool disableOutputEscaping) {
101             this.currentInfo.ValueAppend(s, disableOutputEscaping);
102         }
103 
CanOutput(int state)104         private bool CanOutput(int state) {
105             Debug.Assert(this.recordState != HaveRecord);
106 
107             // If we have no record cached or the next event doesn't start new record, we are OK
108 
109             if (this.recordState == NoRecord || (state & StateMachine.BeginRecord) == 0) {
110                 return true;
111             }
112             else {
113                 this.recordState = HaveRecord;
114                 FinalizeRecord();
115                 SetEmptyFlag(state);
116                 return this.output.RecordDone(this) == Processor.OutputResult.Continue;
117             }
118         }
119 
BeginEvent(int state, XPathNodeType nodeType, string prefix, string name, string nspace, bool empty, Object htmlProps, bool search)120         internal Processor.OutputResult BeginEvent(int state, XPathNodeType nodeType, string prefix, string name, string nspace, bool empty, Object htmlProps, bool search) {
121             if (! CanOutput(state)) {
122                 return Processor.OutputResult.Overflow;
123             }
124 
125             Debug.Assert(this.recordState == NoRecord || (state & StateMachine.BeginRecord) == 0);
126 
127             AdjustDepth(state);
128             ResetRecord(state);
129             PopElementScope();
130 
131             prefix = (prefix != null) ? this.nameTable.Add(prefix) : this.atoms.Empty;
132             name   = (name   != null) ? this.nameTable.Add(name)   : this.atoms.Empty;
133             nspace = (nspace != null) ? this.nameTable.Add(nspace) : this.atoms.Empty;
134 
135             switch (nodeType) {
136             case XPathNodeType.Element:
137                 this.mainNode.htmlProps = htmlProps as HtmlElementProps;
138                 this.mainNode.search = search;
139                 BeginElement(prefix, name, nspace, empty);
140                 break;
141             case XPathNodeType.Attribute:
142                 BeginAttribute(prefix, name, nspace, htmlProps, search);
143                 break;
144             case XPathNodeType.Namespace:
145                 BeginNamespace(name, nspace);
146                 break;
147             case XPathNodeType.Text:
148                 break;
149             case XPathNodeType.ProcessingInstruction:
150                 if (BeginProcessingInstruction(prefix, name, nspace) == false) {
151                     return Processor.OutputResult.Error;
152                 }
153                 break;
154             case XPathNodeType.Comment:
155                 BeginComment();
156                 break;
157             case XPathNodeType.Root:
158                 break;
159             case XPathNodeType.Whitespace:
160             case XPathNodeType.SignificantWhitespace:
161             case XPathNodeType.All:
162                 break;
163             }
164 
165             return CheckRecordBegin(state);
166         }
167 
TextEvent(int state, string text, bool disableOutputEscaping)168         internal Processor.OutputResult TextEvent(int state, string text, bool disableOutputEscaping) {
169             if (! CanOutput(state)) {
170                 return Processor.OutputResult.Overflow;
171             }
172 
173             Debug.Assert(this.recordState == NoRecord || (state & StateMachine.BeginRecord) == 0);
174 
175             AdjustDepth(state);
176             ResetRecord(state);
177             PopElementScope();
178 
179             if ((state & StateMachine.BeginRecord) != 0) {
180                 this.currentInfo.Depth      = this.recordDepth;
181                 this.currentInfo.NodeType   = XmlNodeType.Text;
182             }
183 
184             ValueAppend(text, disableOutputEscaping);
185 
186             return CheckRecordBegin(state);
187         }
188 
EndEvent(int state, XPathNodeType nodeType)189         internal Processor.OutputResult EndEvent(int state, XPathNodeType nodeType) {
190             if (! CanOutput(state)) {
191                 return Processor.OutputResult.Overflow;
192             }
193 
194             AdjustDepth(state);
195             PopElementScope();
196             this.popScope = (state & StateMachine.PopScope) != 0;
197 
198             if ((state & StateMachine.EmptyTag) != 0 && this.mainNode.IsEmptyTag == true) {
199                 return Processor.OutputResult.Continue;
200             }
201 
202             ResetRecord(state);
203 
204             if ((state & StateMachine.BeginRecord) != 0) {
205                 if(nodeType == XPathNodeType.Element) {
206                     EndElement();
207                 }
208             }
209 
210             return CheckRecordEnd(state);
211         }
212 
Reset()213         internal void Reset() {
214             if (this.recordState == HaveRecord) {
215                 this.recordState = NoRecord;
216             }
217         }
218 
TheEnd()219         internal void TheEnd() {
220             if (this.recordState == SomeRecord) {
221                 this.recordState = HaveRecord;
222                 FinalizeRecord();
223                 this.output.RecordDone(this);
224             }
225             this.output.TheEnd();
226         }
227 
228         //
229         // Utility implementation methods
230         //
231 
FindAttribute(string name, string nspace, ref string prefix)232         private int FindAttribute(string name, string nspace, ref string prefix) {
233             Debug.Assert(this.attributeCount <= this.attributeList.Count);
234 
235             for (int attrib = 0; attrib < this.attributeCount; attrib ++) {
236                 Debug.Assert(this.attributeList[attrib] != null && this.attributeList[attrib] is BuilderInfo);
237 
238                 BuilderInfo attribute = (BuilderInfo) this.attributeList[attrib];
239 
240                 if (Ref.Equal(attribute.LocalName, name)) {
241                     if (Ref.Equal(attribute.NamespaceURI, nspace)) {
242                         return attrib;
243                     }
244                     if (Ref.Equal(attribute.Prefix, prefix)) {
245                         // prefix conflict. Should be renamed.
246                         prefix = string.Empty;
247                     }
248                 }
249 
250             }
251 
252             return -1;
253         }
254 
BeginElement(string prefix, string name, string nspace, bool empty)255         private void BeginElement(string prefix, string name, string nspace, bool empty) {
256             Debug.Assert(this.attributeCount == 0);
257 
258             this.currentInfo.NodeType     = XmlNodeType.Element;
259             this.currentInfo.Prefix       = prefix;
260             this.currentInfo.LocalName    = name;
261             this.currentInfo.NamespaceURI = nspace;
262             this.currentInfo.Depth        = this.recordDepth;
263             this.currentInfo.IsEmptyTag   = empty;
264 
265             this.scopeManager.PushScope(name, nspace, prefix);
266         }
267 
EndElement()268         private void EndElement() {
269             Debug.Assert(this.attributeCount == 0);
270             OutputScope elementScope = this.scopeManager.CurrentElementScope;
271 
272             this.currentInfo.NodeType     = XmlNodeType.EndElement;
273             this.currentInfo.Prefix       = elementScope.Prefix;
274             this.currentInfo.LocalName    = elementScope.Name;
275             this.currentInfo.NamespaceURI = elementScope.Namespace;
276             this.currentInfo.Depth        = this.recordDepth;
277         }
278 
NewAttribute()279         private int NewAttribute() {
280             if (this.attributeCount >= this.attributeList.Count) {
281                 Debug.Assert(this.attributeCount == this.attributeList.Count);
282                 this.attributeList.Add(new BuilderInfo());
283             }
284             return this.attributeCount ++;
285         }
286 
BeginAttribute(string prefix, string name, string nspace, Object htmlAttrProps, bool search)287         private void BeginAttribute(string prefix, string name, string nspace, Object htmlAttrProps, bool search) {
288             int attrib = FindAttribute(name, nspace, ref prefix);
289 
290             if (attrib == -1) {
291                 attrib = NewAttribute();
292             }
293 
294             Debug.Assert(this.attributeList[attrib] != null && this.attributeList[attrib] is BuilderInfo);
295 
296             BuilderInfo attribute = (BuilderInfo) this.attributeList[attrib];
297             attribute.Initialize(prefix, name, nspace);
298             attribute.Depth = this.recordDepth;
299             attribute.NodeType = XmlNodeType.Attribute;
300             attribute.htmlAttrProps = htmlAttrProps as HtmlAttributeProps;
301             attribute.search = search;
302             this.currentInfo  = attribute;
303         }
304 
BeginNamespace(string name, string nspace)305         private void BeginNamespace(string name, string nspace) {
306             bool thisScope = false;
307             if (Ref.Equal(name, this.atoms.Empty)) {
308                 if (Ref.Equal(nspace, this.scopeManager.DefaultNamespace)) {
309                     // Main Node is OK
310                 }
311                 else if (Ref.Equal(this.mainNode.NamespaceURI, this.atoms.Empty)) {
312                     // http://www.w3.org/1999/11/REC-xslt-19991116-errata/ E25
313                     // Should throw an error but ingnoring it in Everett.
314                     // Would be a breaking change
315                 }
316                 else {
317                     DeclareNamespace(nspace, name);
318                 }
319             }
320             else {
321                 string nspaceDeclared = this.scopeManager.ResolveNamespace(name, out thisScope);
322                 if (nspaceDeclared != null) {
323                     if (! Ref.Equal(nspace, nspaceDeclared)) {
324                         if(!thisScope) {
325                             DeclareNamespace(nspace, name);
326                         }
327                     }
328                 }
329                 else {
330                      DeclareNamespace(nspace, name);
331                 }
332             }
333             this.currentInfo = dummy;
334             currentInfo.NodeType = XmlNodeType.Attribute;
335         }
336 
BeginProcessingInstruction(string prefix, string name, string nspace)337         private bool BeginProcessingInstruction(string prefix, string name, string nspace) {
338             this.currentInfo.NodeType     = XmlNodeType.ProcessingInstruction;
339             this.currentInfo.Prefix       = prefix;
340             this.currentInfo.LocalName    = name;
341             this.currentInfo.NamespaceURI = nspace;
342             this.currentInfo.Depth  = this.recordDepth;
343             return true;
344         }
345 
BeginComment()346         private void BeginComment() {
347             this.currentInfo.NodeType   = XmlNodeType.Comment;
348             this.currentInfo.Depth = this.recordDepth;
349         }
350 
AdjustDepth(int state)351         private void AdjustDepth(int state) {
352             switch (state & StateMachine.DepthMask) {
353             case StateMachine.DepthUp:
354                 this.recordDepth ++;
355                 break;
356             case StateMachine.DepthDown:
357                 this.recordDepth --;
358                 break;
359             default:
360                 break;
361             }
362         }
363 
ResetRecord(int state)364         private void ResetRecord(int state) {
365             Debug.Assert(this.recordState == NoRecord || this.recordState == SomeRecord);
366 
367             if ((state & StateMachine.BeginRecord) != 0) {
368                 this.attributeCount     = 0;
369                 this.namespaceCount     = 0;
370                 this.currentInfo        = this.mainNode;
371 
372                 this.currentInfo.Initialize(this.atoms.Empty, this.atoms.Empty, this.atoms.Empty);
373                 this.currentInfo.NodeType      = XmlNodeType.None;
374                 this.currentInfo.IsEmptyTag    = false;
375                 this.currentInfo.htmlProps     = null;
376                 this.currentInfo.htmlAttrProps = null;
377             }
378         }
379 
PopElementScope()380         private void PopElementScope() {
381             if (this.popScope) {
382                 this.scopeManager.PopScope();
383                 this.popScope = false;
384             }
385         }
386 
CheckRecordBegin(int state)387         private Processor.OutputResult CheckRecordBegin(int state) {
388             Debug.Assert(this.recordState == NoRecord || this.recordState == SomeRecord);
389 
390             if ((state & StateMachine.EndRecord) != 0) {
391                 this.recordState = HaveRecord;
392                 FinalizeRecord();
393                 SetEmptyFlag(state);
394                 return this.output.RecordDone(this);
395             }
396             else {
397                 this.recordState = SomeRecord;
398                 return Processor.OutputResult.Continue;
399             }
400         }
401 
CheckRecordEnd(int state)402         private Processor.OutputResult CheckRecordEnd(int state) {
403             Debug.Assert(this.recordState == NoRecord || this.recordState == SomeRecord);
404 
405             if ((state & StateMachine.EndRecord) != 0) {
406                 this.recordState = HaveRecord;
407                 FinalizeRecord();
408                 SetEmptyFlag(state);
409                 return this.output.RecordDone(this);
410             }
411             else {
412                 // For end event, if there is no end token, don't force token
413                 return Processor.OutputResult.Continue;
414             }
415         }
416 
SetEmptyFlag(int state)417         private void SetEmptyFlag(int state) {
418             Debug.Assert(this.mainNode != null);
419 
420             if ((state & StateMachine.BeginChild) != 0) {
421                 this.mainNode.IsEmptyTag = false;
422             }
423         }
424 
425 
AnalyzeSpaceLang()426         private void AnalyzeSpaceLang() {
427             Debug.Assert(this.mainNode.NodeType == XmlNodeType.Element);
428 
429             for (int attr = 0; attr < this.attributeCount; attr ++) {
430                 Debug.Assert(this.attributeList[attr] is BuilderInfo);
431                 BuilderInfo info = (BuilderInfo) this.attributeList[attr];
432 
433                 if (Ref.Equal(info.Prefix, this.atoms.Xml)) {
434                     OutputScope scope = this.scopeManager.CurrentElementScope;
435 
436                     if (Ref.Equal(info.LocalName, this.atoms.Lang)) {
437                         scope.Lang  = info.Value;
438                     }
439                     else if (Ref.Equal(info.LocalName, this.atoms.Space)) {
440                         scope.Space = TranslateXmlSpace(info.Value);
441                     }
442                 }
443             }
444         }
445 
FixupElement()446         private void FixupElement() {
447             Debug.Assert(this.mainNode.NodeType == XmlNodeType.Element);
448 
449             if (Ref.Equal(this.mainNode.NamespaceURI, this.atoms.Empty)) {
450                 this.mainNode.Prefix = this.atoms.Empty;
451             }
452 
453             if (Ref.Equal(this.mainNode.Prefix, this.atoms.Empty)) {
454                 if (Ref.Equal(this.mainNode.NamespaceURI, this.scopeManager.DefaultNamespace)) {
455                     // Main Node is OK
456                 }
457                 else {
458                     DeclareNamespace(this.mainNode.NamespaceURI, this.mainNode.Prefix);
459                 }
460             }
461             else {
462                 bool   thisScope = false;
463                 string nspace = this.scopeManager.ResolveNamespace(this.mainNode.Prefix, out thisScope);
464                 if (nspace != null) {
465                     if (! Ref.Equal(this.mainNode.NamespaceURI, nspace)) {
466                         if (thisScope) {    // Prefix conflict
467                             this.mainNode.Prefix = GetPrefixForNamespace(this.mainNode.NamespaceURI);
468                         }
469                         else {
470                             DeclareNamespace(this.mainNode.NamespaceURI, this.mainNode.Prefix);
471                         }
472                     }
473                 }
474                 else {
475                     DeclareNamespace(this.mainNode.NamespaceURI, this.mainNode.Prefix);
476                 }
477             }
478 
479             OutputScope elementScope = this.scopeManager.CurrentElementScope;
480             elementScope.Prefix      = this.mainNode.Prefix;
481         }
482 
FixupAttributes(int attributeCount)483         private void FixupAttributes(int attributeCount) {
484             for (int attr = 0; attr < attributeCount; attr ++) {
485                 Debug.Assert(this.attributeList[attr] is BuilderInfo);
486                 BuilderInfo info = (BuilderInfo) this.attributeList[attr];
487 
488 
489                 if (Ref.Equal(info.NamespaceURI, this.atoms.Empty)) {
490                     info.Prefix = this.atoms.Empty;
491                 }
492                 else {
493                     if (Ref.Equal(info.Prefix, this.atoms.Empty)) {
494                         info.Prefix = GetPrefixForNamespace(info.NamespaceURI);
495                     }
496                     else {
497                         bool thisScope = false;
498                         string nspace = this.scopeManager.ResolveNamespace(info.Prefix, out thisScope);
499                         if (nspace != null) {
500                             if (! Ref.Equal(info.NamespaceURI, nspace)) {
501                                 if(thisScope) { // prefix conflict
502                                     info.Prefix = GetPrefixForNamespace(info.NamespaceURI);
503                                 }
504                                 else {
505                                     DeclareNamespace(info.NamespaceURI, info.Prefix);
506                                 }
507                             }
508                         }
509                         else {
510                             DeclareNamespace(info.NamespaceURI, info.Prefix);
511                         }
512                     }
513                 }
514             }
515         }
516 
AppendNamespaces()517         private void AppendNamespaces() {
518             for (int i = this.namespaceCount - 1; i >= 0; i --) {
519                 BuilderInfo attribute = (BuilderInfo) this.attributeList[NewAttribute()];
520                 attribute.Initialize((BuilderInfo)this.namespaceList[i]);
521             }
522         }
523 
AnalyzeComment()524         private void AnalyzeComment() {
525             Debug.Assert(this.mainNode.NodeType == XmlNodeType.Comment);
526             Debug.Assert((object) this.currentInfo == (object) this.mainNode);
527 
528             StringBuilder newComment = null;
529             string        comment    = this.mainNode.Value;
530             bool          minus      = false;
531             int index = 0, begin = 0;
532 
533             for (; index < comment.Length; index ++) {
534                 switch (comment[index]) {
535                     case s_Minus:
536                         if (minus) {
537                             if (newComment == null)
538                                 newComment = new StringBuilder(comment, begin, index, 2 * comment.Length);
539                             else
540                                 newComment.Append(comment, begin, index - begin);
541 
542                             newComment.Append(s_SpaceMinus);
543                             begin = index + 1;
544                         }
545                         minus = true;
546                         break;
547                     default:
548                         minus = false;
549                         break;
550                 }
551             }
552 
553             if (newComment != null) {
554                 if (begin < comment.Length)
555                     newComment.Append(comment, begin, comment.Length - begin);
556 
557                 if (minus)
558                     newComment.Append(s_Space);
559 
560                 this.mainNode.Value = newComment.ToString();
561             }
562             else if (minus) {
563                 this.mainNode.ValueAppend(s_Space, false);
564             }
565         }
566 
AnalyzeProcessingInstruction()567         private void AnalyzeProcessingInstruction() {
568             Debug.Assert(this.mainNode.NodeType == XmlNodeType.ProcessingInstruction || this.mainNode.NodeType == XmlNodeType.XmlDeclaration);
569             //Debug.Assert((object) this.currentInfo == (object) this.mainNode);
570 
571             StringBuilder newPI    = null;
572             string        pi       = this.mainNode.Value;
573             bool          question = false;
574             int index = 0, begin = 0;
575 
576             for (; index < pi.Length; index ++) {
577                 switch (pi[index]) {
578                 case s_Question:
579                     question = true;
580                     break;
581                 case s_Greater:
582                     if (question) {
583                         if (newPI == null) {
584                             newPI = new StringBuilder(pi, begin, index, 2 * pi.Length);
585                         }
586                         else {
587                             newPI.Append(pi, begin, index - begin);
588                         }
589                         newPI.Append(s_SpaceGreater);
590                         begin = index + 1;
591                     }
592                     question = false;
593                     break;
594                 default:
595                     question = false;
596                     break;
597                 }
598             }
599 
600             if (newPI != null) {
601                 if (begin < pi.Length) {
602                     newPI.Append(pi, begin, pi.Length - begin);
603                 }
604                 this.mainNode.Value = newPI.ToString();
605             }
606         }
607 
FinalizeRecord()608         private void FinalizeRecord() {
609             switch (this.mainNode.NodeType) {
610             case XmlNodeType.Element:
611                 // Save count since FixupElement can add attribute...
612                 int attributeCount = this.attributeCount;
613 
614                 FixupElement();
615                 FixupAttributes(attributeCount);
616                 AnalyzeSpaceLang();
617                 AppendNamespaces();
618                 break;
619             case XmlNodeType.Comment:
620                 AnalyzeComment();
621                 break;
622             case XmlNodeType.ProcessingInstruction:
623                 AnalyzeProcessingInstruction();
624                 break;
625             }
626         }
627 
NewNamespace()628         private int NewNamespace() {
629             if (this.namespaceCount >= this.namespaceList.Count) {
630                 Debug.Assert(this.namespaceCount == this.namespaceList.Count);
631                 this.namespaceList.Add(new BuilderInfo());
632             }
633             return this.namespaceCount ++;
634         }
635 
DeclareNamespace(string nspace, string prefix)636         private void DeclareNamespace(string nspace, string prefix) {
637             int index = NewNamespace();
638 
639             Debug.Assert(this.namespaceList[index] != null && this.namespaceList[index] is BuilderInfo);
640 
641             BuilderInfo ns = (BuilderInfo) this.namespaceList[index];
642             if (prefix == this.atoms.Empty) {
643                 ns.Initialize(this.atoms.Empty, this.atoms.Xmlns, this.atoms.XmlnsNamespace);
644             }
645             else {
646                 ns.Initialize(this.atoms.Xmlns, prefix, this.atoms.XmlnsNamespace);
647             }
648             ns.Depth = this.recordDepth;
649             ns.NodeType = XmlNodeType.Attribute;
650             ns.Value = nspace;
651 
652             this.scopeManager.PushNamespace(prefix, nspace);
653         }
654 
DeclareNewNamespace(string nspace)655         private string DeclareNewNamespace(string nspace) {
656             string prefix = this.scopeManager.GeneratePrefix(PrefixFormat);
657             DeclareNamespace(nspace, prefix);
658             return prefix;
659         }
660 
GetPrefixForNamespace(string nspace)661         internal string GetPrefixForNamespace(string nspace) {
662             string prefix = null;
663 
664             if (this.scopeManager.FindPrefix(nspace, out prefix)) {
665                 Debug.Assert(prefix != null && prefix.Length > 0);
666                 return prefix;
667             }
668             else {
669                 return DeclareNewNamespace(nspace);
670             }
671         }
672 
TranslateXmlSpace(string space)673         private static XmlSpace TranslateXmlSpace(string space) {
674             if (space == "default") {
675                 return XmlSpace.Default;
676             }
677             else if (space == "preserve") {
678                 return XmlSpace.Preserve;
679             }
680             else {
681                 return XmlSpace.None;
682             }
683         }
684     }
685 }
686