File: XmlQueryOutput.cs

package info (click to toggle)
mono 6.14.1%2Bds2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,282,732 kB
  • sloc: cs: 11,182,461; xml: 2,850,281; ansic: 699,123; cpp: 122,919; perl: 58,604; javascript: 30,841; asm: 21,845; makefile: 19,602; sh: 10,973; python: 4,772; pascal: 925; sql: 859; sed: 16; php: 1
file content (1447 lines) | stat: -rw-r--r-- 60,317 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
//------------------------------------------------------------------------------
// <copyright file="XmlQueryOutput.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
// <owner current="true" primary="true">Microsoft</owner>
//------------------------------------------------------------------------------
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.Xml;
using System.Xml.XPath;

namespace System.Xml.Xsl.Runtime {
    using Res = System.Xml.Utils.Res;

    internal enum XmlState {
        WithinSequence = 0,     // Adding items to a top-level sequence
        EnumAttrs,              // Adding attributes to an element
        WithinContent,          // Adding content to an element
        WithinAttr,             // Adding text to an attribute
        WithinNmsp,             // Adding text to an namespace
        WithinComment,          // Adding text to a comment
        WithinPI,               // Adding text to a processing instruction
    };


    /// <summary>
    /// At run-time, a number of checks may need to be made in order to generate the correct sequence of calls
    /// to XmlRawWriter:
    ///   1. Well-formedness: Illegal state transitions, StartContent detection, no-content element detection
    ///   2. Cached attributes: In XSLT, attributes override previously constructed attributes with the same name,
    ///      meaning that attribute names and values cannot be prematurely sent to XmlRawWriter.
    ///   3. Cached namespaces: All namespaces are tracked in order to ensure adequate namespaces and to ensure
    ///      minimal (or something close) namespaces.
    /// </summary>
    [EditorBrowsable(EditorBrowsableState.Never)]
    public sealed class XmlQueryOutput : XmlWriter {
        // Never set these fields directly--instead use corresponding properties
        private XmlRawWriter xwrt;                  // Output to XmlRawWriter--get and set this using the Writer property

        // It is OK to set these properties directly
        private XmlQueryRuntime runtime;            // The XmlQueryRuntime instance that keeps global state
        private XmlAttributeCache attrCache;        // Cache used to detect duplicate attributes
        private int depth;                          // Depth of the currently constructing tree
        private XmlState xstate;                    // Current XML state
        private XmlSequenceWriter seqwrt;           // Current XmlSequenceWriter
        private XmlNamespaceManager nsmgr;          // Output namespace manager
        private int cntNmsp;                        // Number of pending namespaces
        private Dictionary<string, string> conflictPrefixes;         // Remembers prefixes that were auto-generated previously in case they can be reused
        private int prefixIndex;                    // Counter used to auto-generate non-conflicting attribute prefixes
        private string piTarget/*nmspPrefix*/;      // Cache pi target or namespace prefix
        private StringConcat nodeText;              // Cache pi, comment, or namespace text
        private Stack<string> stkNames;             // Keep stack of name parts computed during StartElement
        private XPathNodeType rootType;             // NodeType of the root of the tree

        private Dictionary<string, string> usedPrefixes = new Dictionary<string, string>(); //The prefies that used in the current scope

        /// <summary>
        /// This constructor is internal so that external users cannot construct it (and therefore we do not have to test it separately).
        /// Initialize output state to accept top-level sequences.
        /// </summary>
        internal XmlQueryOutput(XmlQueryRuntime runtime, XmlSequenceWriter seqwrt) {
            this.runtime = runtime;
            this.seqwrt = seqwrt;
            this.xstate = XmlState.WithinSequence;
        }

        /// <summary>
        /// This constructor is internal so that external users cannot construct it (and therefore we do not have to test it separately).
        /// Initialize output state to accept Rtf content (top-level sequences are therefore prohibited).
        /// </summary>
        internal XmlQueryOutput(XmlQueryRuntime runtime, XmlEventCache xwrt) {
            this.runtime = runtime;
            this.xwrt = xwrt;
            this.xstate = XmlState.WithinContent;
            this.depth = 1;
            this.rootType = XPathNodeType.Root;
        }

        /// <summary>
        /// Sequence writer to which output is directed by this class.
        /// </summary>
        internal XmlSequenceWriter SequenceWriter {
            get { return this.seqwrt; }
        }

        /// <summary>
        /// Raw writer to which output is directed by this class.
        /// </summary>
        internal XmlRawWriter Writer {
            get { return this.xwrt; }
            set {
                // If new writer might remove itself from pipeline, have it callback on this method when it's ready to go
                IRemovableWriter removable = value as IRemovableWriter;
                if (removable != null)
                    removable.OnRemoveWriterEvent = SetWrappedWriter;

                this.xwrt = value;
            }
        }

        /// <summary>
        /// This method will be called if "xwrt" is a writer which no longer needs to be part of the pipeline and
        /// wishes to replace itself with a different writer.  For example, the auto-detect writer replaces itself
        /// with the Html or Xml writer once it has determined which output mode to use.
        /// </summary>
        private void SetWrappedWriter(XmlRawWriter writer) {
            // Reuse XmlAttributeCache so that it doesn't have to be recreated every time
            if (Writer is XmlAttributeCache)
                this.attrCache = (XmlAttributeCache) Writer;

            Writer = writer;
        }


        //-----------------------------------------------
        // XmlWriter methods
        //-----------------------------------------------

        /// <summary>
        /// Should never be called.
        /// </summary>
        public override void WriteStartDocument() {
            throw new NotSupportedException();
        }

        /// <summary>
        /// Should never be called.
        /// </summary>
        public override void WriteStartDocument(bool standalone) {
            throw new NotSupportedException();
        }

        /// <summary>
        /// Should never be called.
        /// </summary>
        public override void WriteEndDocument() {
            throw new NotSupportedException();
        }

        /// <summary>
        /// Should never be called.
        /// </summary>
        public override void WriteDocType(string name, string pubid, string sysid, string subset) {
            throw new NotSupportedException();
        }

        /// <summary>
        /// Before calling XmlRawWriter.WriteStartElement(), perform various checks to ensure well-formedness.
        /// </summary>
        public override void WriteStartElement(string prefix, string localName, string ns) {
            Debug.Assert(prefix != null && localName != null && localName.Length != 0 && ns != null, "Invalid argument");
            Debug.Assert(ValidateNames.ValidateName(prefix, localName, ns, XPathNodeType.Element, ValidateNames.Flags.All), "Name validation failed");

            // Xml state transitions
            ConstructWithinContent(XPathNodeType.Element);

            // Call XmlRawWriter.WriteStartElement
            WriteStartElementUnchecked(prefix, localName, ns);

            // Ensure that element's namespace declaration is declared
            WriteNamespaceDeclarationUnchecked(prefix, ns);

            // Cache attributes in order to detect duplicates
            if (this.attrCache == null)
                this.attrCache = new XmlAttributeCache();

            this.attrCache.Init(Writer);
            Writer = this.attrCache;
            this.attrCache = null;

            // Push element names onto a stack
            PushElementNames(prefix, localName, ns);
        }

        /// <summary>
        /// Before calling XmlRawWriter.WriteEndElement(), perform various checks to ensure well-formedness.
        /// </summary>
        public override void WriteEndElement() {
            string prefix, localName, ns;

            // Determine whether element had no content
            if (this.xstate == XmlState.EnumAttrs) {
                // No content, so call StartElementContent now
                StartElementContentUnchecked();
            }

            // Call XmlRawWriter.WriteEndElement
            PopElementNames(out prefix, out localName, out ns);
            WriteEndElementUnchecked(prefix, localName, ns);

            // Xml state transitions
            if (this.depth == 0)
                EndTree();
        }

        /// <summary>
        /// Same as calling WriteEndElement().
        /// </summary>
        public override void WriteFullEndElement() {
            WriteEndElement();
        }

        /// <summary>
        /// Before calling XmlRawWriter.WriteStartAttribute(), perform various checks to ensure well-formedness.
        /// </summary>
        public override void WriteStartAttribute(string prefix, string localName, string ns) {
            Debug.Assert(prefix != null && localName != null && ns != null, "Invalid argument");

            if (prefix.Length == 5 && prefix == "xmlns") {
                // Handle namespace attributes that are not sent directly to WriteNamespaceDeclaration
                WriteStartNamespace(localName);
            }
            else {
                // All other attributes
                Debug.Assert(ValidateNames.ValidateName(prefix, localName, ns, XPathNodeType.Attribute, ValidateNames.Flags.All));

                // Xml state transitions
                ConstructInEnumAttrs(XPathNodeType.Attribute);

                // Check for prefix conflicts and possibly declare prefix
                if (ns.Length != 0 && this.depth != 0)
                    prefix = CheckAttributePrefix(prefix, ns);

                // Output the attribute
                WriteStartAttributeUnchecked(prefix, localName, ns);
            }
        }

        /// <summary>
        /// Before calling XmlRawWriter.WriteEndAttribute(), perform various checks to ensure well-formedness.
        /// </summary>
        public override void WriteEndAttribute() {
            if (this.xstate == XmlState.WithinNmsp) {
                WriteEndNamespace();
            }
            else {
                WriteEndAttributeUnchecked();

                if (this.depth == 0)
                    EndTree();
            }
        }

        /// <summary>
        /// Before writing a comment, perform various checks to ensure well-formedness.
        /// </summary>
        public override void WriteComment(string text) {
            WriteStartComment();
            WriteCommentString(text);
            WriteEndComment();
        }

        /// <summary>
        /// Before writing a processing instruction, perform various checks to ensure well-formedness.
        /// </summary>
        public override void WriteProcessingInstruction(string target, string text) {
            WriteStartProcessingInstruction(target);
            WriteProcessingInstructionString(text);
            WriteEndProcessingInstruction();
        }

        /// <summary>
        /// Should never be called.
        /// </summary>
        public override void WriteEntityRef(string name) {
            throw new NotSupportedException();
        }

        /// <summary>
        /// Should never be called.
        /// </summary>
        public override void WriteCharEntity(char ch) {
            throw new NotSupportedException();
        }

        /// <summary>
        /// Should never be called.
        /// </summary>
        public override void WriteSurrogateCharEntity(char lowChar, char highChar) {
            throw new NotSupportedException();
        }

        /// <summary>
        /// Treat whitespace as regular text.
        /// </summary>
        public override void WriteWhitespace(string ws) {
            throw new NotSupportedException();
        }

        /// <summary>
        /// Before writing text, perform various checks to ensure well-formedness.
        /// </summary>
        public override void WriteString(string text) {
            WriteString(text, false);
        }

        /// <summary>
        /// Before writing text, perform various checks to ensure well-formedness.
        /// </summary>
        public override void WriteChars(char[] buffer, int index, int count) {
            throw new NotSupportedException();
        }

        /// <summary>
        /// Write text, but do not escape special characters.
        /// </summary>
        public override void WriteRaw(char[] buffer, int index, int count) {
            throw new NotSupportedException();
        }

        /// <summary>
        /// Write text, but do not escape special characters.
        /// </summary>
        public override void WriteRaw(string data) {
            WriteString(data, true);
        }

        /// <summary>
        /// Write CData text as regular text.
        /// </summary>
        public override void WriteCData(string text) {
            WriteString(text, false);
        }

        /// <summary>
        /// Should never be called.
        /// </summary>
        public override void WriteBase64(byte[] buffer, int index, int count) {
            throw new NotSupportedException();
        }

        /// <summary>
        /// Should never be called.
        /// </summary>
        public override WriteState WriteState {
            get { throw new NotSupportedException(); }
        }

        /// <summary>
        /// No-op.
        /// </summary>
        public override void Close() {
        }

        /// <summary>
        /// No-op.
        /// </summary>
        public override void Flush() {
        }

        /// <summary>
        /// Should never be called.
        /// </summary>
        public override string LookupPrefix(string ns) {
            throw new NotSupportedException();
        }

        /// <summary>
        /// Should never be called.
        /// </summary>
        public override XmlSpace XmlSpace {
            get { throw new NotSupportedException(); }
        }

        /// <summary>
        /// Should never be called.
        /// </summary>
        public override string XmlLang {
            get { throw new NotSupportedException(); }
        }


        //-----------------------------------------------
        // XmlQueryOutput methods (XmlSequenceWriter)
        //-----------------------------------------------

        /// <summary>
        /// Call XmlSequenceWriter.StartTree() in order to start construction of a new tree.
        /// </summary>
        public void StartTree(XPathNodeType rootType) {
            Debug.Assert(this.xstate == XmlState.WithinSequence, "StartTree cannot be called in the " + this.xstate + " state.");
            Writer = this.seqwrt.StartTree(rootType, this.nsmgr, this.runtime.NameTable);
            this.rootType = rootType;
            this.xstate = (rootType == XPathNodeType.Attribute || rootType == XPathNodeType.Namespace) ? XmlState.EnumAttrs : XmlState.WithinContent;
        }

        /// <summary>
        /// Call XmlSequenceWriter.EndTree().
        /// </summary>
        public void EndTree() {
            Debug.Assert(this.xstate == XmlState.EnumAttrs || this.xstate == XmlState.WithinContent, "EndTree cannot be called in the " + this.xstate + " state.");
            this.seqwrt.EndTree();
            this.xstate = XmlState.WithinSequence;
            Writer = null;
        }


        //-----------------------------------------------
        // XmlQueryOutput methods (XmlRawWriter)
        //-----------------------------------------------

        /// <summary>
        /// Call XmlRawWriter.WriteStartElement() with prefix, local-name, ns, and schema type.
        /// </summary>
        public void WriteStartElementUnchecked(string prefix, string localName, string ns) {
            Debug.Assert(this.xstate == XmlState.WithinContent, "WriteStartElement cannot be called in the " + this.xstate + " state.");
            if (this.nsmgr != null) this.nsmgr.PushScope();
            Writer.WriteStartElement(prefix, localName, ns);
            //reset when enter element
            usedPrefixes.Clear();
            usedPrefixes[prefix] = ns;
            this.xstate = XmlState.EnumAttrs;
            this.depth++;
        }

        /// <summary>
        /// Call XmlRawWriter.WriteStartElement() with empty prefix, ns, and null schema type.
        /// </summary>
        public void WriteStartElementUnchecked(string localName) {
            WriteStartElementUnchecked(string.Empty, localName, string.Empty);
        }

        /// <summary>
        /// Call XmlRawWriter.StartElementContent().
        /// </summary>
        public void StartElementContentUnchecked() {
            Debug.Assert(this.xstate == XmlState.EnumAttrs, "StartElementContent cannot be called in the " + this.xstate + " state.");

            // Output any cached namespaces
            if (this.cntNmsp != 0)
                WriteCachedNamespaces();

            Writer.StartElementContent();
            this.xstate = XmlState.WithinContent;
        }

        /// <summary>
        /// Call XmlRawWriter.WriteEndElement() with prefix, local-name, and ns.
        /// </summary>
        public void WriteEndElementUnchecked(string prefix, string localName, string ns) {
            Debug.Assert(this.xstate == XmlState.EnumAttrs || this.xstate == XmlState.WithinContent, "WriteEndElement cannot be called in the " + this.xstate + " state.");
            Writer.WriteEndElement(prefix, localName, ns);
            this.xstate = XmlState.WithinContent;
            this.depth--;
            if (this.nsmgr != null) this.nsmgr.PopScope();
        }

        /// <summary>
        /// Call XmlRawWriter.WriteEndElement() with empty prefix, ns.
        /// </summary>
        public void WriteEndElementUnchecked(string localName) {
            WriteEndElementUnchecked(string.Empty, localName, string.Empty);
        }

        /// <summary>
        /// XmlRawWriter.WriteStartAttribute() with prefix, local-name, ns, and schema type.
        /// </summary>
        public void WriteStartAttributeUnchecked(string prefix, string localName, string ns) {
            Debug.Assert(this.xstate == XmlState.EnumAttrs, "WriteStartAttribute cannot be called in the " + this.xstate + " state.");
            Writer.WriteStartAttribute(prefix, localName, ns);
            this.xstate = XmlState.WithinAttr;
            this.depth++;
        }

        /// <summary>
        /// XmlRawWriter.WriteStartAttribute() with empty prefix, ns, and null schema type.
        /// </summary>
        public void WriteStartAttributeUnchecked(string localName) {
            WriteStartAttributeUnchecked(string.Empty, localName, string.Empty);
        }

        /// <summary>
        /// XmlRawWriter.WriteEndAttribute().
        /// </summary>
        public void WriteEndAttributeUnchecked() {
            Debug.Assert(this.xstate == XmlState.WithinAttr, "WriteEndAttribute cannot be called in the " + this.xstate + " state.");
            Writer.WriteEndAttribute();
            this.xstate = XmlState.EnumAttrs;
            this.depth--;
        }

        /// <summary>
        /// Add a new namespace declaration -- xmlns:prefix="ns" -- to the set of in-scope declarations.
        /// NOTE: This method should only be called if caller can guarantee that the current state is EnumAttrs
        ///       and that there will be no namespace conflicts in the current scope (e.g. trying to map the
        ///       same prefix to different namespaces within the same element start tag).  If no such
        ///       guarantees exist, then WriteNamespaceDeclaration() should be called instead.
        /// </summary>
        public void WriteNamespaceDeclarationUnchecked(string prefix, string ns) {
            Debug.Assert(prefix != null && ns != null);
            Debug.Assert(this.xstate == XmlState.EnumAttrs, "WriteNamespaceDeclaration cannot be called in the " + this.xstate + " state.");

            // xmlns:foo="" is illegal
            Debug.Assert(prefix.Length == 0 || ns.Length != 0);

            if (this.depth == 0) {
                // At top-level, so write namespace declaration directly to output
                Writer.WriteNamespaceDeclaration(prefix, ns);
                return;
            }

            if (this.nsmgr == null) {
                // If namespace manager has no namespaces, then xmlns="" is in scope by default
                if (ns.Length == 0 && prefix.Length == 0)
                    return;

                this.nsmgr = new XmlNamespaceManager(this.runtime.NameTable);
                this.nsmgr.PushScope();
            }

            if (this.nsmgr.LookupNamespace(prefix) != ns)
                AddNamespace(prefix, ns);

            usedPrefixes[prefix] = ns;
        }

        /// <summary>
        /// Write a text block to the XmlRawWriter.
        /// </summary>
        public void WriteStringUnchecked(string text) {
            Debug.Assert(this.xstate != XmlState.WithinSequence && this.xstate != XmlState.EnumAttrs, "WriteTextBlock cannot be called in the " + this.xstate + " state.");
            Writer.WriteString(text);
        }

        /// <summary>
        /// Write a text block without escaping special characters.
        /// </summary>
        public void WriteRawUnchecked(string text) {
            Debug.Assert(this.xstate != XmlState.WithinSequence && this.xstate != XmlState.EnumAttrs, "WriteTextBlockNoEntities cannot be called in the " + this.xstate + " state.");
            Writer.WriteRaw(text);
        }


        //-----------------------------------------------
        // XmlQueryOutput methods
        //-----------------------------------------------

        /// <summary>
        /// Before calling XmlSequenceWriter.StartTree(), perform checks to ensure well-formedness.
        /// </summary>
        public void WriteStartRoot() {
            Debug.Assert(this.depth == 0, "Root node can only be constructed at top-level.");
            if (this.xstate != XmlState.WithinSequence)
                ThrowInvalidStateError(XPathNodeType.Root);

            StartTree(XPathNodeType.Root);
            this.depth++;
        }

        /// <summary>
        /// Call XmlSequenceWriter.EndTree() and reset state.
        /// </summary>
        public void WriteEndRoot() {
            Debug.Assert(this.depth == 1, "Root node can only be constructed at top-level.");
            this.depth--;
            EndTree();
        }

        /// <summary>
        /// WriteStartElement() with empty prefix, ns.
        /// </summary>
        public void WriteStartElementLocalName(string localName) {
            WriteStartElement(string.Empty, localName, string.Empty);
        }

        /// <summary>
        /// WriteStartAttribute() with empty prefix, ns, and null schema type.
        /// </summary>
        public void WriteStartAttributeLocalName(string localName) {
            WriteStartAttribute(string.Empty, localName, string.Empty);
        }

        /// <summary>
        /// Write an element with a name that is computed from a "prefix:localName" tag name and a set of prefix mappings.
        /// </summary>
        public void WriteStartElementComputed(string tagName, int prefixMappingsIndex) {
            WriteStartComputed(XPathNodeType.Element, tagName, prefixMappingsIndex);
        }

        /// <summary>
        /// Write an element with a name that is computed from a "prefix:localName" tag name and a namespace URI.
        /// </summary>
        public void WriteStartElementComputed(string tagName, string ns) {
            WriteStartComputed(XPathNodeType.Element, tagName, ns);
        }

        /// <summary>
        /// Write an element with a name that is copied from the navigator.
        /// </summary>
        public void WriteStartElementComputed(XPathNavigator navigator) {
            WriteStartComputed(XPathNodeType.Element, navigator);
        }

        /// <summary>
        /// Write an element with a name that is derived from the XmlQualifiedName.
        /// </summary>
        public void WriteStartElementComputed(XmlQualifiedName name) {
            WriteStartComputed(XPathNodeType.Element, name);
        }

        /// <summary>
        /// Write an attribute with a name that is computed from a "prefix:localName" tag name and a set of prefix mappings.
        /// </summary>
        public void WriteStartAttributeComputed(string tagName, int prefixMappingsIndex) {
            WriteStartComputed(XPathNodeType.Attribute, tagName, prefixMappingsIndex);
        }

        /// <summary>
        /// Write an attribute with a name that is computed from a "prefix:localName" tag name and a namespace URI.
        /// </summary>
        public void WriteStartAttributeComputed(string tagName, string ns) {
            WriteStartComputed(XPathNodeType.Attribute, tagName, ns);
        }

        /// <summary>
        /// Write an attribute with a name that is copied from the navigator.
        /// </summary>
        public void WriteStartAttributeComputed(XPathNavigator navigator) {
            WriteStartComputed(XPathNodeType.Attribute, navigator);
        }

        /// <summary>
        /// Write an attribute with a name that is derived from the XmlQualifiedName.
        /// </summary>
        public void WriteStartAttributeComputed(XmlQualifiedName name) {
            WriteStartComputed(XPathNodeType.Attribute, name);
        }

        /// <summary>
        /// Before calling XmlRawWriter.WriteNamespaceDeclaration(), perform various checks to ensure well-formedness.
        /// </summary>
        public void WriteNamespaceDeclaration(string prefix, string ns) {
            string nsExisting;
            Debug.Assert(prefix != null && ns != null);

            ConstructInEnumAttrs(XPathNodeType.Namespace);

            if (this.nsmgr == null) {
                // If namespace manager has not yet been created, then there is no possibility of conflict
                WriteNamespaceDeclarationUnchecked(prefix, ns);
            }
            else {
                nsExisting = this.nsmgr.LookupNamespace(prefix);
                if (ns != nsExisting) {
                    // prefix = "", ns = "", nsExisting --> Look for xmlns="", found xmlns="foo"
                    // prefix = "", ns, nsExisting = null --> Look for xmlns="uri", no uri found
                    // prefix = "", ns, nsExisting = "" --> Look for xmlns="uri", found xmlns=""
                    // prefix = "", ns, nsExisting --> Look for xmlns="uri", found xmlns="uri2"
                    // prefix, ns, nsExisting = null --> Look for xmlns:foo="uri", no uri found
                    // prefix, ns, nsExisting --> Look for xmlns:foo="uri", found xmlns:foo="uri2"

                    // If the prefix is mapped to a uri,
                    if (nsExisting != null) {
                        // Then throw an error except if the prefix trying to redefine is already used
                        if (usedPrefixes.ContainsKey(prefix)) {
                            throw new XslTransformException(Res.XmlIl_NmspConflict, new string[] { prefix.Length == 0 ? "" : ":", prefix, ns, nsExisting });
                        }
                    }

                    // Add namespace to manager and write it to output
                    AddNamespace(prefix, ns);
                }
            }

            if (this.depth == 0)
                EndTree();

            usedPrefixes[prefix] = ns;
        }

        /// <summary>
        /// Before writing a namespace, perform various checks to ensure well-formedness.
        /// </summary>
        public void WriteStartNamespace(string prefix) {
            Debug.Assert(prefix != null, "Invalid argument");

            // Handle namespace attributes that are not sent directly to WriteNamespaceDeclaration
            ConstructInEnumAttrs(XPathNodeType.Namespace);
            this.piTarget/*nmspPrefix*/ = prefix;
            this.nodeText.Clear();

            this.xstate = XmlState.WithinNmsp;
            this.depth++;
        }

        /// <summary>
        /// Cache the namespace's text.
        /// </summary>
        public void WriteNamespaceString(string text) {
            Debug.Assert(this.xstate == XmlState.WithinNmsp, "WriteNamespaceString cannot be called in the " + this.xstate + " state.");
            this.nodeText.ConcatNoDelimiter(text);
        }

        /// <summary>
        /// Before writing a namespace, perform various checks to ensure well-formedness.
        /// </summary>
        public void WriteEndNamespace() {
            Debug.Assert(this.xstate == XmlState.WithinNmsp, "WriteEndNamespace cannot be called in the " + this.xstate + " state.");

            this.xstate = XmlState.EnumAttrs;
            this.depth--;

            // Write cached namespace attribute
            WriteNamespaceDeclaration(this.piTarget/*nmspPrefix*/, this.nodeText.GetResult());

            if (this.depth == 0)
                EndTree();
        }

        /// <summary>
        /// Before writing a comment, perform various checks to ensure well-formedness.
        /// </summary>
        public void WriteStartComment() {
            // Xml state transitions
            ConstructWithinContent(XPathNodeType.Comment);

            this.nodeText.Clear();
            this.xstate = XmlState.WithinComment;
            this.depth++;
        }

        /// <summary>
        /// Cache the comment's text.
        /// </summary>
        public void WriteCommentString(string text) {
            Debug.Assert(this.xstate == XmlState.WithinComment, "WriteCommentString cannot be called in the " + this.xstate + " state.");
            this.nodeText.ConcatNoDelimiter(text);
        }

        /// <summary>
        /// Before writing a comment, perform various checks to ensure well-formedness.
        /// </summary>
        public void WriteEndComment() {
            Debug.Assert(this.xstate == XmlState.WithinComment, "WriteEndComment cannot be called in the " + this.xstate + " state.");

            Writer.WriteComment(this.nodeText.GetResult());

            this.xstate = XmlState.WithinContent;
            this.depth--;

            if (this.depth == 0)
                EndTree();
        }

        /// <summary>
        /// Before writing a processing instruction, perform various checks to ensure well-formedness.
        /// </summary>
        public void WriteStartProcessingInstruction(string target) {
            // Xml state transitions
            ConstructWithinContent(XPathNodeType.ProcessingInstruction);

            // Verify PI name
            ValidateNames.ValidateNameThrow("", target, "", XPathNodeType.ProcessingInstruction, ValidateNames.Flags.AllExceptPrefixMapping);

            this.piTarget = target;
            this.nodeText.Clear();

            this.xstate = XmlState.WithinPI;
            this.depth++;
        }

        /// <summary>
        /// Cache the processing instruction's text.
        /// </summary>
        public void WriteProcessingInstructionString(string text) {
            Debug.Assert(this.xstate == XmlState.WithinPI, "WriteProcessingInstructionString cannot be called in the " + this.xstate + " state.");
            this.nodeText.ConcatNoDelimiter(text);
        }

        /// <summary>
        /// Before writing a processing instruction, perform various checks to ensure well-formedness.
        /// </summary>
        public void WriteEndProcessingInstruction() {
            Debug.Assert(this.xstate == XmlState.WithinPI, "WriteEndProcessingInstruction cannot be called in the " + this.xstate + " state.");

            Writer.WriteProcessingInstruction(this.piTarget, this.nodeText.GetResult());

            this.xstate = XmlState.WithinContent;
            this.depth--;

            // Xml state transitions
            if (this.depth == 0)
                EndTree();
        }

        /// <summary>
        /// Write an item to output.  If currently constructing an Xml tree, then the item is always copied.
        /// At the top-level, the item's identity is preserved unless it's an atomic value.
        /// </summary>
        public void WriteItem(XPathItem item) {
            if (item.IsNode) {
                XPathNavigator navigator = (XPathNavigator) item;

                // If this is a top-level node, write a reference to it; else copy it by value
                if (this.xstate == XmlState.WithinSequence)
                    this.seqwrt.WriteItem(navigator);
                else
                    CopyNode(navigator);
            }
            else {
                // Call WriteItem for atomic values
                Debug.Assert(this.xstate == XmlState.WithinSequence, "Values can only be written at the top-level.");
                this.seqwrt.WriteItem(item);
            }
        }

        /// <summary>
        /// Copy a node by value to output according to Xslt rules:
        ///   1. Identity is never preserved
        ///   2. If the item is an Rtf, preserve serialization hints when copying.
        ///   3. If the item is a Root node, copy the children of the Root
        /// </summary>
        public void XsltCopyOf(XPathNavigator navigator) {
            RtfNavigator navRtf = navigator as RtfNavigator;

            if (navRtf != null) {
                // Copy Rtf
                navRtf.CopyToWriter(this);
            }
            else if (navigator.NodeType == XPathNodeType.Root) {
                // Copy children of root
                if (navigator.MoveToFirstChild()) {
                    do {
                        CopyNode(navigator);
                    }
                    while (navigator.MoveToNext());

                    navigator.MoveToParent();
                }
            }
            else {
                // Copy node
                CopyNode(navigator);
            }
        }

        /// <summary>
        /// Begin shallow copy of the navigator's current node to output.  Returns true if EndCopy
        /// should be called to complete the copy operation.
        /// Automatically copies all in-scope namespaces on elements.
        /// </summary>
        public bool StartCopy(XPathNavigator navigator) {
            // StartDocument is a no-op
            if (navigator.NodeType == XPathNodeType.Root)
                return true;

            if (StartCopy(navigator, true)) {
                Debug.Assert(navigator.NodeType == XPathNodeType.Element, "StartCopy should return true only for Element nodes.");

                // Copy namespaces to output
                CopyNamespaces(navigator, XPathNamespaceScope.ExcludeXml);

                return true;
            }

            return false;
        }

        /// <summary>
        /// End shallow copy of the navigator's current node.  Should be called only for Element and Document nodes.
        /// </summary>
        public void EndCopy(XPathNavigator navigator) {
            if (navigator.NodeType == XPathNodeType.Element)
                WriteEndElement();
            else
                Debug.Assert(navigator.NodeType == XPathNodeType.Root, "EndCopy should only be called for Element and Document nodes.");
        }


        //-----------------------------------------------
        // Helper methods
        //-----------------------------------------------

        /// <summary>
        /// Add an in-scope namespace.
        /// </summary>
        private void AddNamespace(string prefix, string ns) {
            this.nsmgr.AddNamespace(prefix, ns);
            this.cntNmsp++;
            usedPrefixes[prefix] = ns;
        }

        /// <summary>
        /// Before writing text, perform various checks to ensure well-formedness.
        /// </summary>
        private void WriteString(string text, bool disableOutputEscaping) {
            Debug.Assert(text != null, "Invalid argument");

            // Xml state transitions
            switch (this.xstate) {
                case XmlState.WithinSequence:
                    // Start constructing new tree
                    StartTree(XPathNodeType.Text);
                    goto case XmlState.WithinContent;

                case XmlState.WithinContent:
                    if (disableOutputEscaping)
                        WriteRawUnchecked(text);
                    else
                        WriteStringUnchecked(text);
                    break;

                case XmlState.EnumAttrs:
                    // Enumerating attributes, so write text as element content
                    StartElementContentUnchecked();
                    goto case XmlState.WithinContent;

                case XmlState.WithinAttr:
                    WriteStringUnchecked(text);
                    break;

                case XmlState.WithinNmsp:
                    WriteNamespaceString(text);
                    break;

                case XmlState.WithinComment:
                    // Comment text
                    WriteCommentString(text);
                    break;

                case XmlState.WithinPI:
                    // PI text
                    WriteProcessingInstructionString(text);
                    break;

                default:
                    Debug.Assert(false, "Text cannot be output in the " + this.xstate + " state.");
                    break;
            }

            if (this.depth == 0)
                EndTree();
        }

        /// <summary>
        /// Deep copy the subtree that is rooted at this navigator's current position to output.  If the current
        /// item is an element, copy all in-scope namespace nodes.
        /// </summary>
        private void CopyNode(XPathNavigator navigator) {
            XPathNodeType nodeType;
            int depthStart = this.depth;
            Debug.Assert(navigator != null);

            while (true) {
                if (StartCopy(navigator, this.depth == depthStart)) {
                    nodeType = navigator.NodeType;
                    Debug.Assert(nodeType == XPathNodeType.Element, "StartCopy should return true only for Element nodes.");

                    // Copy attributes
                    if (navigator.MoveToFirstAttribute()) {
                        do {
                            StartCopy(navigator, false);
                        }
                        while (navigator.MoveToNextAttribute());
                        navigator.MoveToParent();
                    }

                    // Copy namespaces in document order (navigator returns them in reverse document order)
                    CopyNamespaces(navigator, (this.depth - 1 == depthStart) ? XPathNamespaceScope.ExcludeXml : XPathNamespaceScope.Local);

                    StartElementContentUnchecked();

                    // If children exist, move down to next level
                    if (navigator.MoveToFirstChild())
                        continue;

                    EndCopy(navigator, (this.depth - 1) == depthStart);
                }

                // No children
                while (true) {
                    if (this.depth == depthStart) {
                        // The entire subtree has been copied
                        return;
                    }

                    if (navigator.MoveToNext()) {
                        // Found a sibling, so break to outer loop
                        break;
                    }

                    // No siblings, so move up to previous level
                    navigator.MoveToParent();

                    EndCopy(navigator, (this.depth - 1) == depthStart);
                }
            }
        }

        /// <summary>
        /// Begin shallow copy of the navigator's current node to output.  Returns true if EndCopy
        /// should be called to complete the copy operation.
        /// </summary>
        private bool StartCopy(XPathNavigator navigator, bool callChk) {
            bool mayHaveChildren = false;

            switch (navigator.NodeType) {
                case XPathNodeType.Element:
                    // If checks need to be made, call XmlQueryOutput.WriteStartElement
                    if (callChk) {
                        WriteStartElement(navigator.Prefix, navigator.LocalName, navigator.NamespaceURI);
                    }
                    else {
                        WriteStartElementUnchecked(navigator.Prefix, navigator.LocalName, navigator.NamespaceURI);
                    }

                    mayHaveChildren = true;
                    break;

                case XPathNodeType.Attribute:
                    // If checks need to be made, call XmlQueryOutput.WriteStartAttribute
                    if (callChk) {
                        WriteStartAttribute(navigator.Prefix, navigator.LocalName, navigator.NamespaceURI);
                    }
                    else {
                        WriteStartAttributeUnchecked(navigator.Prefix, navigator.LocalName, navigator.NamespaceURI);
                    }

                    // Write attribute text
                    WriteString(navigator.Value);

                    // If checks need to be made, call XmlQueryOutput.WriteEndAttribute
                    if (callChk) {
                        WriteEndAttribute();
                    }
                    else {
                        WriteEndAttributeUnchecked();
                    }
                    break;

                case XPathNodeType.Namespace:
                    // If checks need to be made, call XmlQueryOutput.WriteNamespaceDeclaration
                    if (callChk) {
                        // Do not allow namespaces to be copied after attributes
                        XmlAttributeCache attrCache = Writer as XmlAttributeCache;
                        if (attrCache != null && attrCache.Count != 0)
                            throw new XslTransformException(Res.XmlIl_NmspAfterAttr, string.Empty);

                        WriteNamespaceDeclaration(navigator.LocalName, navigator.Value);
                    }
                    else {
                        WriteNamespaceDeclarationUnchecked(navigator.LocalName, navigator.Value);
                    }
                    break;

                case XPathNodeType.Text:
                case XPathNodeType.SignificantWhitespace:
                case XPathNodeType.Whitespace:
                    // If checks need to be made, call XmlQueryOutput.WriteString
                    if (callChk) {
                        WriteString(navigator.Value, false);
                    }
                    else {
                        // No flags are set, so this is simple element text (attributes, comments, pi's copy own text)
                        WriteStringUnchecked(navigator.Value);
                    }
                    break;

                case XPathNodeType.Root:
                    // Document node is invalid except at the top-level
                    Debug.Assert(this.xstate != XmlState.WithinSequence, "StartCopy should not called if state is WithinSequence");
                    ThrowInvalidStateError(XPathNodeType.Root);
                    break;

                case XPathNodeType.Comment:
                    WriteStartComment();
                    WriteCommentString(navigator.Value);
                    WriteEndComment();
                    break;

                case XPathNodeType.ProcessingInstruction:
                    WriteStartProcessingInstruction(navigator.LocalName);
                    WriteProcessingInstructionString(navigator.Value);
                    WriteEndProcessingInstruction();
                    break;

                default:
                    Debug.Assert(false);
                    break;
            }

            return mayHaveChildren;
        }

        /// <summary>
        /// End shallow copy of the navigator's current node to output.  This method should only be called if StartCopy
        /// returned true.
        /// </summary>
        private void EndCopy(XPathNavigator navigator, bool callChk) {
            Debug.Assert(navigator.NodeType == XPathNodeType.Element);
            Debug.Assert(this.xstate == XmlState.WithinContent, "EndCopy cannot be called in the " + this.xstate + " state.");

            if (callChk)
                WriteEndElement();
            else
                WriteEndElementUnchecked(navigator.Prefix, navigator.LocalName, navigator.NamespaceURI);
        }

        /// <summary>
        /// Copy all namespaces of the specified type (in-scope, exclude-xml, local) in document order to output.
        /// </summary>
        private void CopyNamespaces(XPathNavigator navigator, XPathNamespaceScope nsScope) {
            Debug.Assert(navigator.NodeType == XPathNodeType.Element, "Only elements have namespaces to copy");

            // Default namespace undeclaration isn't included in navigator's namespace list, so add it now
            if (navigator.NamespaceURI.Length == 0) {
                Debug.Assert(navigator.LocalName.Length != 0, "xmlns:foo='' isn't allowed");
                WriteNamespaceDeclarationUnchecked(string.Empty, string.Empty);
            }

            // Since the namespace list is arranged in reverse-document order, recursively reverse it.
            if (navigator.MoveToFirstNamespace(nsScope)) {
                CopyNamespacesHelper(navigator, nsScope);
                navigator.MoveToParent();
            }
        }

        /// <summary>
        /// Recursive helper function that reverses order of the namespaces retrieved by MoveToFirstNamespace and
        /// MoveToNextNamespace.
        /// </summary>
        private void CopyNamespacesHelper(XPathNavigator navigator, XPathNamespaceScope nsScope) {
            string prefix = navigator.LocalName;
            string ns = navigator.Value;

            if (navigator.MoveToNextNamespace(nsScope))
                CopyNamespacesHelper(navigator, nsScope);

            // No possibility for conflict, since we're copying namespaces from well-formed element
            WriteNamespaceDeclarationUnchecked(prefix, ns);
        }

        /// <summary>
        /// Ensure that state transitions to WithinContent.
        /// </summary>
        private void ConstructWithinContent(XPathNodeType rootType) {
            Debug.Assert(rootType == XPathNodeType.Element || rootType == XPathNodeType.Comment || rootType == XPathNodeType.ProcessingInstruction);

            switch (this.xstate) {
                case XmlState.WithinSequence:
                    // If state is WithinSequence, call XmlSequenceWriter.StartTree
                    StartTree(rootType);
                    this.xstate = XmlState.WithinContent;
                    break;

                case XmlState.WithinContent:
                    // Already within element content
                    break;

                case XmlState.EnumAttrs:
                    // Start element content
                    StartElementContentUnchecked();
                    break;

                default:
                    // Construction is not allowed in this state
                    ThrowInvalidStateError(rootType);
                    break;
            }
        }

        /// <summary>
        /// Ensure that state transitions to EnumAttrs.
        /// </summary>
        private void ConstructInEnumAttrs(XPathNodeType rootType) {
            Debug.Assert(rootType == XPathNodeType.Attribute || rootType == XPathNodeType.Namespace);

            switch (this.xstate) {
                case XmlState.WithinSequence:
                    StartTree(rootType);
                    this.xstate = XmlState.EnumAttrs;
                    break;

                case XmlState.EnumAttrs:
                    // Already in EnumAttrs state
                    break;

                default:
                    // Construction is not allowed in this state
                    ThrowInvalidStateError(rootType);
                    break;
            }
        }

        /// <summary>
        /// Namespace declarations are added to this.nsmgr.  Just before element content has begun, write out
        /// all namespaces that were declared locally on the element.
        /// </summary>
        private void WriteCachedNamespaces() {
            string prefix, ns;

            while (this.cntNmsp != 0) {
                // Output each prefix->ns mapping pair
                Debug.Assert(this.nsmgr != null);
                this.cntNmsp--;
                this.nsmgr.GetNamespaceDeclaration(this.cntNmsp, out prefix, out ns);
                Writer.WriteNamespaceDeclaration(prefix, ns);
            }
        }

        /// <summary>
        /// Return the type of node that is under construction given the specified XmlState.
        /// </summary>
        private XPathNodeType XmlStateToNodeType(XmlState xstate) {
            switch (xstate) {
                case XmlState.EnumAttrs: return XPathNodeType.Element;
                case XmlState.WithinContent: return XPathNodeType.Element;
                case XmlState.WithinAttr: return XPathNodeType.Attribute;
                case XmlState.WithinComment: return XPathNodeType.Comment;
                case XmlState.WithinPI: return XPathNodeType.ProcessingInstruction;
            }

            Debug.Assert(false, xstate.ToString() + " is not a valid XmlState.");
            return XPathNodeType.Element;
        }

        /// <summary>
        /// If attribute's prefix conflicts with other prefixes then redeclare the prefix.  If the prefix has
        /// not yet been declared, then add it to the namespace manager.
        /// </summary>
        private string CheckAttributePrefix(string prefix, string ns) {
            string nsExisting;
            Debug.Assert(prefix.Length != 0 && ns.Length != 0);

            // Ensure that this attribute's prefix does not conflict with previously declared prefixes in this scope
            if (this.nsmgr == null) {
                // If namespace manager has no namespaces, then there is no possibility of conflict
                WriteNamespaceDeclarationUnchecked(prefix, ns);
            }
            else {
                while (true) {
                    // If prefix is already mapped to a different namespace,
                    nsExisting = this.nsmgr.LookupNamespace(prefix);
                    if (nsExisting != ns) {

                        // Then if the prefix is already mapped,
                        if (nsExisting != null) {
                            // Then there is a conflict that must be resolved by finding another prefix
                            // Always find a new prefix, even if the conflict didn't occur in the current scope
                            // This decision allows more aggressive namespace analysis at compile-time
                            prefix = RemapPrefix(prefix, ns, false);
                            continue;
                        }

                        // Add the mapping to the current scope
                        AddNamespace(prefix, ns);
                    }
                    break;
                }
            }

            return prefix;
        }

        /// <summary>
        /// Remaps an element or attribute prefix using the following rules:
        ///
        ///   1. If another in-scope prefix is already mapped to "ns", then use that
        ///   2. Otherwise, if a prefix was previously mapped to "ns" by this method, then use that
        ///   3. Otherwise, generate a new prefix of the form 'xp_??', where ?? is a stringized counter
        ///
        /// These rules tend to reduce the number of unique prefixes used throughout the tree.
        /// </summary>
        private string RemapPrefix(string prefix, string ns, bool isElemPrefix) {
            string genPrefix;
            Debug.Assert(prefix != null && ns != null && ns.Length != 0);

            if (this.conflictPrefixes == null)
                this.conflictPrefixes = new Dictionary<string, string>(16);

            if (this.nsmgr == null) {
                this.nsmgr = new XmlNamespaceManager(this.runtime.NameTable);
                this.nsmgr.PushScope();
            }

            // Rule #1: If another in-scope prefix is already mapped to "ns", then use that
            genPrefix = this.nsmgr.LookupPrefix(ns);
            if (genPrefix != null) {
                // Can't use an empty prefix for an attribute
                if (isElemPrefix || genPrefix.Length != 0)
                    goto ReturnPrefix;
            }

            // Rule #2: Otherwise, if a prefix was previously mapped to "ns" by this method, then use that
            // Make sure that any previous prefix is different than "prefix"
            if (this.conflictPrefixes.TryGetValue(ns, out genPrefix) && genPrefix != prefix) {
                // Can't use an empty prefix for an attribute
                if (isElemPrefix || genPrefix.Length != 0)
                    goto ReturnPrefix;
            }

            // Rule #3: Otherwise, generate a new prefix of the form 'xp_??', where ?? is a stringized counter
            genPrefix = "xp_" + (this.prefixIndex++).ToString(CultureInfo.InvariantCulture);


        ReturnPrefix:
            // Save generated prefix so that it can be possibly be reused later
            this.conflictPrefixes[ns] = genPrefix;

            return genPrefix;
        }

        /// <summary>
        /// Write an element or attribute with a name that is computed from a "prefix:localName" tag name and a set of prefix mappings.
        /// </summary>
        private void WriteStartComputed(XPathNodeType nodeType, string tagName, int prefixMappingsIndex) {
            string prefix, localName, ns;

            // Parse the tag name and map the prefix to a namespace
            runtime.ParseTagName(tagName, prefixMappingsIndex, out prefix, out localName, out ns);

            // Validate the name parts
            prefix = EnsureValidName(prefix, localName, ns, nodeType);

            if (nodeType == XPathNodeType.Element)
                WriteStartElement(prefix, localName, ns);
            else
                WriteStartAttribute(prefix, localName, ns);
        }

        /// <summary>
        /// Write an element or attribute with a name that is computed from a "prefix:localName" tag name and a namespace URI.
        /// </summary>
        private void WriteStartComputed(XPathNodeType nodeType, string tagName, string ns) {
            string prefix, localName;

            // Parse the tagName as a prefix, localName pair
            ValidateNames.ParseQNameThrow(tagName, out prefix, out localName);

            // Validate the name parts
            prefix = EnsureValidName(prefix, localName, ns, nodeType);

            if (nodeType == XPathNodeType.Element)
                WriteStartElement(prefix, localName, ns);
            else
                WriteStartAttribute(prefix, localName, ns);
        }

        /// <summary>
        /// Write an element or attribute with a name that is copied from the navigator.
        /// </summary>
        private void WriteStartComputed(XPathNodeType nodeType, XPathNavigator navigator) {
            string prefix, localName, ns;

            prefix = navigator.Prefix;
            localName = navigator.LocalName;
            ns = navigator.NamespaceURI;

            if (navigator.NodeType != nodeType) {
                // Validate the name parts
                prefix = EnsureValidName(prefix, localName, ns, nodeType);
            }

            if (nodeType == XPathNodeType.Element)
                WriteStartElement(prefix, localName, ns);
            else
                WriteStartAttribute(prefix, localName, ns);
        }

        /// <summary>
        /// Write an element or attribute with a name that is derived from the XmlQualifiedName.
        /// </summary>
        private void WriteStartComputed(XPathNodeType nodeType, XmlQualifiedName name) {
            string prefix;
            Debug.Assert(ValidateNames.ParseNCName(name.Name, 0) == name.Name.Length);

            // Validate the name parts
            prefix = (name.Namespace.Length != 0) ? RemapPrefix(string.Empty, name.Namespace, nodeType == XPathNodeType.Element) : string.Empty;
            prefix = EnsureValidName(prefix, name.Name, name.Namespace, nodeType);

            if (nodeType == XPathNodeType.Element)
                WriteStartElement(prefix, name.Name, name.Namespace);
            else
                WriteStartAttribute(prefix, name.Name, name.Namespace);
        }

        /// <summary>
        /// Ensure that the specified name parts are valid according to Xml 1.0 and Namespace 1.0 rules.  Try to remap
        /// the prefix in order to attain validity.  Throw if validity is not possible.  Otherwise, return the (possibly
        /// remapped) prefix.
        /// </summary>
        private string EnsureValidName(string prefix, string localName, string ns, XPathNodeType nodeType) {
            if (!ValidateNames.ValidateName(prefix, localName, ns, nodeType, ValidateNames.Flags.AllExceptNCNames)) {
                // Name parts are not valid as is.  Try to re-map the prefix.
                prefix = (ns.Length != 0) ? RemapPrefix(string.Empty, ns, nodeType == XPathNodeType.Element) : string.Empty;

                // Throw if validation does not work this time
                ValidateNames.ValidateNameThrow(prefix, localName, ns, nodeType, ValidateNames.Flags.AllExceptNCNames);
            }

            return prefix;
        }

        /// <summary>
        /// Push element name parts onto the stack.
        /// </summary>
        private void PushElementNames(string prefix, string localName, string ns) {
            // Push the name parts onto a stack
            if (this.stkNames == null)
                this.stkNames = new Stack<string>(15);

            this.stkNames.Push(prefix);
            this.stkNames.Push(localName);
            this.stkNames.Push(ns);
        }

        /// <summary>
        /// Pop element name parts from the stack.
        /// </summary>
        private void PopElementNames(out string prefix, out string localName, out string ns) {
            Debug.Assert(this.stkNames != null);

            ns = this.stkNames.Pop();
            localName = this.stkNames.Pop();
            prefix = this.stkNames.Pop();
        }

        /// <summary>
        /// Throw an invalid state transition error.
        /// </summary>
        private void ThrowInvalidStateError(XPathNodeType constructorType) {
            switch (constructorType) {
                case XPathNodeType.Element:
                case XPathNodeType.Root:
                case XPathNodeType.Text:
                case XPathNodeType.Comment:
                case XPathNodeType.ProcessingInstruction:
                    throw new XslTransformException(Res.XmlIl_BadXmlState, new string[] {constructorType.ToString(), XmlStateToNodeType(this.xstate).ToString()});

                case XPathNodeType.Attribute:
                case XPathNodeType.Namespace:
                    if (this.depth == 1)
                        throw new XslTransformException(Res.XmlIl_BadXmlState, new string[] {constructorType.ToString(), this.rootType.ToString()});

                    if (this.xstate == XmlState.WithinContent)
                        throw new XslTransformException(Res.XmlIl_BadXmlStateAttr, string.Empty);

                    goto case XPathNodeType.Element;

                default:
                    throw new XslTransformException(Res.XmlIl_BadXmlState, new string[] {"Unknown", XmlStateToNodeType(this.xstate).ToString()});
            }
        }
    }
}