Update Reference Sources to .NET Framework 4.6.1
[mono.git] / mcs / class / referencesource / System.Data.SqlXml / System / Xml / Xsl / Xslt / XsltLoader.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="XsltLoader.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 // <owner current="true" primary="true">[....]</owner>
6 //------------------------------------------------------------------------------
7
8 //#define XSLT2
9
10 using System.Collections;
11 using System.Collections.Generic;
12 using System.Collections.Specialized;
13 using System.Diagnostics;
14 using System.Reflection;
15 using System.Text;
16 using System.IO;
17 using System.Xml.XPath;
18 using System.Xml.Xsl.Qil;
19 using System.Runtime.Versioning;
20
21 namespace System.Xml.Xsl.Xslt {
22     using ContextInfo   = XsltInput.ContextInfo;
23     using f             = AstFactory;
24     using Res           = System.Xml.Utils.Res;
25     using TypeFactory   = XmlQueryTypeFactory;
26     using QName         = XsltInput.DelayedQName;
27     using XsltAttribute = XsltInput.XsltAttribute;
28
29     internal class XsltLoader : IErrorHelper {
30         private Compiler                compiler;
31         private XmlResolver             xmlResolver;
32         private QueryReaderSettings     readerSettings;
33         private KeywordsTable           atoms;          // XSLT keywords atomized with QueryReaderSettings.NameTabel
34         private XsltInput               input;          // Current input stream
35         private Stylesheet              curStylesheet;  // Current stylesheet
36         private Template                curTemplate;    // Current template
37         private object                  curFunction;    // Current function
38
39         internal static QilName         nullMode        = f.QName(string.Empty);
40
41         // Flags which control attribute versioning
42         public static int V1Opt = 1;
43         public static int V1Req = 2;
44         public static int V2Opt = 4;
45         public static int V2Req = 8;
46
47         [ResourceConsumption(ResourceScope.Machine)]
48         [ResourceExposure(ResourceScope.Machine)]
49         public void Load(Compiler compiler, object stylesheet, XmlResolver xmlResolver) {
50             Debug.Assert(compiler != null);
51             this.compiler = compiler;
52             this.xmlResolver = xmlResolver ?? XmlNullResolver.Singleton;
53
54             XmlReader reader = stylesheet as XmlReader;
55             if (reader != null) {
56                 readerSettings = new QueryReaderSettings(reader);
57                 Load(reader);
58             } else {
59                 // We should take DefaultReaderSettings from Compiler.Settings.DefaultReaderSettings.
60
61                 string uri = stylesheet as string;
62                 if (uri != null) {
63                     // If xmlResolver == null, then the original uri will be resolved using XmlUrlResolver
64                     XmlResolver origResolver = xmlResolver;
65                     if (xmlResolver == null || xmlResolver == XmlNullResolver.Singleton)
66                         origResolver = new XmlUrlResolver();
67                     Uri resolvedUri = origResolver.ResolveUri(null, uri);
68                     if (resolvedUri == null) {
69                         throw new XslLoadException(Res.Xslt_CantResolve, uri);
70                     }
71
72                     readerSettings = new QueryReaderSettings(new NameTable());
73                     using (reader = CreateReader(resolvedUri, origResolver)) {
74                         Load(reader);
75                     }
76                 } else {
77                     IXPathNavigable navigable = stylesheet as IXPathNavigable;
78                     if (navigable != null) {
79                         reader = XPathNavigatorReader.Create(navigable.CreateNavigator());
80                         readerSettings = new QueryReaderSettings(reader.NameTable);
81                         Load(reader);
82                     } else {
83                         Debug.Fail("Should never get here");
84                     }
85                 }
86             }
87             Debug.Assert(compiler.Root != null);
88             compiler.StartApplyTemplates = f.ApplyTemplates(nullMode);
89             ProcessOutputSettings();
90             foreach (AttributeSet attSet in compiler.AttributeSets.Values) {
91                 CheckAttributeSetsDfs(attSet); // Check attribute sets for circular references using dfs marking method
92             }
93         }
94
95         private void Load(XmlReader reader) {
96             this.atoms = new KeywordsTable(reader.NameTable);
97             AtomizeAttributes();
98             LoadStylesheet(reader, /*include:*/false);
99         }
100
101
102         void AtomizeAttributes(XsltAttribute[] attributes) {
103             for(int i = 0; i < attributes.Length; i ++) {
104                 attributes[i].name = atoms.NameTable.Add(attributes[i].name);
105             }
106         }
107         void AtomizeAttributes() {
108             AtomizeAttributes(stylesheetAttributes);
109             AtomizeAttributes(importIncludeAttributes);
110             AtomizeAttributes(loadStripSpaceAttributes);
111             AtomizeAttributes(outputAttributes);
112             AtomizeAttributes(keyAttributes);
113             AtomizeAttributes(decimalFormatAttributes);
114             AtomizeAttributes(namespaceAliasAttributes);
115             AtomizeAttributes(attributeSetAttributes);
116             AtomizeAttributes(templateAttributes);
117             AtomizeAttributes(scriptAttributes);
118             AtomizeAttributes(assemblyAttributes);
119             AtomizeAttributes(usingAttributes);
120             AtomizeAttributes(applyTemplatesAttributes);
121             AtomizeAttributes(callTemplateAttributes);
122             AtomizeAttributes(copyAttributes);
123             AtomizeAttributes(copyOfAttributes);
124             AtomizeAttributes(ifAttributes);
125             AtomizeAttributes(forEachAttributes);
126             AtomizeAttributes(messageAttributes);
127             AtomizeAttributes(numberAttributes);
128             AtomizeAttributes(valueOfAttributes);
129             AtomizeAttributes(variableAttributes);
130             AtomizeAttributes(paramAttributes);
131             AtomizeAttributes(withParamAttributes);
132             AtomizeAttributes(commentAttributes);
133             AtomizeAttributes(processingInstructionAttributes);
134             AtomizeAttributes(textAttributes);
135             AtomizeAttributes(elementAttributes);
136             AtomizeAttributes(attributeAttributes);
137             AtomizeAttributes(sortAttributes);
138 #if XSLT2
139             AtomizeAttributes(characterMapAttributes);
140             AtomizeAttributes(outputCharacterAttributes);
141             AtomizeAttributes(functionAttributes);
142             AtomizeAttributes(importSchemaAttributes);
143             AtomizeAttributes(documentAttributes);
144             AtomizeAttributes(analyzeStringAttributes);
145             AtomizeAttributes(namespaceAttributes);
146             AtomizeAttributes(performSortAttributes);
147             AtomizeAttributes(forEachGroupAttributes);
148             AtomizeAttributes(sequenceAttributes);
149             AtomizeAttributes(resultDocumentAttributes);
150 #endif
151         }
152
153         private bool V1 { get {
154                 Debug.Assert(compiler.Version != 0, "Version should be already decided at this point");
155                 return compiler.Version == 1;
156         }}
157 #if XSLT2
158         private bool V2 { get { return ! V1; } }
159 #endif
160
161         // Import/Include XsltInput management
162
163         private HybridDictionary documentUriInUse = new HybridDictionary();
164
165         [ResourceConsumption(ResourceScope.Machine)]
166         [ResourceExposure(ResourceScope.Machine)]        
167         private Uri ResolveUri(string relativeUri, string baseUri) {
168             Uri resolvedBaseUri = (baseUri.Length != 0) ? xmlResolver.ResolveUri(null, baseUri) : null;
169             Uri resolvedUri = xmlResolver.ResolveUri(resolvedBaseUri, relativeUri);
170             if (resolvedUri == null) {
171                 throw new XslLoadException(Res.Xslt_CantResolve, relativeUri);
172             }
173             return resolvedUri;
174         }
175
176         private XmlReader CreateReader(Uri uri, XmlResolver xmlResolver) {
177             object input = xmlResolver.GetEntity(uri, null, null);
178
179             Stream stream = input as Stream;
180             if (stream != null) {
181                 return readerSettings.CreateReader(stream, uri.ToString());
182             }
183
184             XmlReader reader = input as XmlReader;
185             if (reader != null) {
186                 return reader;
187             }
188
189             IXPathNavigable navigable = input as IXPathNavigable;
190             if (navigable != null) {
191                 return XPathNavigatorReader.Create(navigable.CreateNavigator());
192             }
193
194             throw new XslLoadException(Res.Xslt_CannotLoadStylesheet, uri.ToString(), input == null ? "null" : input.GetType().ToString());
195         }
196
197         private Stylesheet LoadStylesheet(Uri uri, bool include) {
198             using (XmlReader reader = CreateReader(uri, this.xmlResolver)) {
199                 return LoadStylesheet(reader, include);
200             }
201         }
202
203         private Stylesheet LoadStylesheet(XmlReader reader, bool include) {
204             string baseUri = reader.BaseURI;
205             Debug.Assert(!documentUriInUse.Contains(baseUri), "Circular references must be checked while processing xsl:include and xsl:import");
206             documentUriInUse.Add(baseUri, null);
207             compiler.AddModule(baseUri);
208
209             Stylesheet  prevStylesheet  = curStylesheet;
210             XsltInput   prevInput       = input;
211             Stylesheet  thisStylesheet  = include ? curStylesheet : compiler.CreateStylesheet();
212
213             input = new XsltInput(reader, compiler, atoms);
214             curStylesheet = thisStylesheet;
215
216             try {
217                 LoadDocument();
218                 if (!include) {
219                     compiler.MergeWithStylesheet(curStylesheet);
220
221                     List<Uri> importHrefs = curStylesheet.ImportHrefs;
222                     curStylesheet.Imports = new Stylesheet[importHrefs.Count];
223                     // Imports should be compiled in the reverse order. Template lookup logic relies on that.
224                     for (int i = importHrefs.Count; 0 <= --i; ) {
225                         curStylesheet.Imports[i] = LoadStylesheet(importHrefs[i], /*include:*/false);
226                     }
227                 }
228             }
229             catch (XslLoadException) {
230                 throw;
231             }
232             catch (Exception e) {
233                 if (!XmlException.IsCatchableException(e)) {
234                     throw;
235                 }
236                 // Note that XmlResolver or XmlReader may throw XmlException with SourceUri == null.
237                 // In that case we report current line information from XsltInput.
238                 XmlException ex = e as XmlException;
239                 ISourceLineInfo lineInfo = (ex != null && ex.SourceUri != null ?
240                     new SourceLineInfo(ex.SourceUri, ex.LineNumber, ex.LinePosition, ex.LineNumber, ex.LinePosition) :
241                     input.BuildReaderLineInfo()
242                 );
243                 throw new XslLoadException(e, lineInfo);
244             }
245             finally {
246                 documentUriInUse.Remove(baseUri);
247                 input         = prevInput;
248                 curStylesheet = prevStylesheet;
249             }
250             return thisStylesheet;
251         }
252
253         private void LoadDocument() {
254             if (!input.FindStylesheetElement()) {
255                 ReportError(/*[XT_002]*/Res.Xslt_WrongStylesheetElement);
256                 return;
257             }
258             Debug.Assert(input.NodeType == XmlNodeType.Element);
259             if (input.IsXsltNamespace()) {
260                 if (
261                     input.IsKeyword(atoms.Stylesheet) ||
262                     input.IsKeyword(atoms.Transform)
263                 ) {
264                     LoadRealStylesheet();
265                 } else {
266                     ReportError(/*[XT_002]*/Res.Xslt_WrongStylesheetElement);
267                     input.SkipNode();
268                 }
269             } else {
270                 LoadSimplifiedStylesheet();
271             }
272             input.Finish();
273         }
274
275         private void LoadSimplifiedStylesheet() {
276             Debug.Assert(!input.IsXsltNamespace());
277             Debug.Assert(curTemplate == null);
278
279             // Prefix will be fixed later in LoadLiteralResultElement()
280             curTemplate = f.Template(/*name:*/null, /*match:*/"/", /*mode:*/nullMode, /*priority:*/double.NaN, input.XslVersion);
281
282             // This template has mode=null match="/" and no imports
283             input.CanHaveApplyImports = true;
284             XslNode lre = LoadLiteralResultElement(/*asStylesheet:*/true);
285             if (lre != null) {
286                 SetLineInfo(curTemplate, lre.SourceLine);
287
288                 List<XslNode> content = new List<XslNode>();
289                 content.Add(lre);
290                 SetContent(curTemplate, content);
291                 if (!curStylesheet.AddTemplate(curTemplate)) {
292                     Debug.Fail("AddTemplate() returned false for simplified stylesheet");
293                 }
294             }
295             curTemplate = null;
296         }
297
298         XsltAttribute[] stylesheetAttributes = {
299             new XsltAttribute("version"               , V1Req | V2Req),
300             new XsltAttribute("id"                    , V1Opt | V2Opt),
301             new XsltAttribute("default-validation"    ,         V2Opt),
302             new XsltAttribute("input-type-annotations",         V2Opt),
303         };
304         private void LoadRealStylesheet() {
305             Debug.Assert(input.IsXsltNamespace() && (input.IsKeyword(atoms.Stylesheet) || input.IsKeyword(atoms.Transform)));
306             ContextInfo ctxInfo = input.GetAttributes(stylesheetAttributes);
307
308             ParseValidationAttribute(2, /*defVal:*/true);
309             ParseInputTypeAnnotationsAttribute(3);
310
311             QName parentName = input.ElementName;
312             if (input.MoveToFirstChild()) {
313                 bool atTop = true;
314                 do {
315                     bool isImport = false;
316                     switch (input.NodeType) {
317                     case XmlNodeType.Element:
318                         if (input.IsXsltNamespace()) {
319                             if (input.IsKeyword(atoms.Import)) {
320                                 if (!atTop) {
321                                     ReportError(/*[XT0200]*/Res.Xslt_NotAtTop, input.QualifiedName, parentName);
322                                     input.SkipNode();
323                                 } else {
324                                     isImport = true;
325                                     LoadImport();
326                                 }
327                             } else if (input.IsKeyword(atoms.Include)) {
328                                 LoadInclude();
329                             } else if (input.IsKeyword(atoms.StripSpace)) {
330                                 LoadStripSpace(ctxInfo.nsList);
331                             } else if (input.IsKeyword(atoms.PreserveSpace)) {
332                                 LoadPreserveSpace(ctxInfo.nsList);
333                             } else if (input.IsKeyword(atoms.Output)) {
334                                 LoadOutput();
335                             } else if (input.IsKeyword(atoms.Key)) {
336                                 LoadKey(ctxInfo.nsList);
337                             } else if (input.IsKeyword(atoms.DecimalFormat)) {
338                                 LoadDecimalFormat(ctxInfo.nsList);
339                             } else if (input.IsKeyword(atoms.NamespaceAlias)) {
340                                 LoadNamespaceAlias(ctxInfo.nsList);
341                             } else if (input.IsKeyword(atoms.AttributeSet)) {
342                                 LoadAttributeSet(ctxInfo.nsList);
343                             } else if (input.IsKeyword(atoms.Variable)) {
344                                 LoadGlobalVariableOrParameter(ctxInfo.nsList, XslNodeType.Variable);
345                             } else if (input.IsKeyword(atoms.Param)) {
346                                 LoadGlobalVariableOrParameter(ctxInfo.nsList, XslNodeType.Param);
347                             } else if (input.IsKeyword(atoms.Template)) {
348                                 LoadTemplate(ctxInfo.nsList);
349 #if XSLT2
350                             } else if (V2 && input.IsKeyword(atoms.CharacterMap)) {
351                                 LoadCharacterMap(ctxInfo.nsList);
352                             } else if (V2 && input.IsKeyword(atoms.Function)) {
353                                 LoadFunction(ctxInfo.nsList);
354                             } else if (V2 && input.IsKeyword(atoms.ImportSchema)) {
355                                 LoadImportSchema();
356 #endif
357                             } else {
358                                 input.GetVersionAttribute();
359                                 if (!input.ForwardCompatibility) {
360                                     ReportError(/*[XT_003]*/Res.Xslt_UnexpectedElement, input.QualifiedName, parentName);
361                                 }
362                                 input.SkipNode();
363                             }
364                         } else if (input.IsNs(atoms.UrnMsxsl) && input.IsKeyword(atoms.Script)) {
365                             LoadMsScript(ctxInfo.nsList);
366                         } else {
367                             if (input.IsNullNamespace()) {
368                                 ReportError(/*[XT0130]*/Res.Xslt_NullNsAtTopLevel, input.LocalName);
369                             }
370                             // Ignoring non-recognized namespace per XSLT spec 2.2
371                             input.SkipNode();
372                         }
373                         atTop = isImport;
374                         break;
375
376                     case XmlNodeType.Whitespace:
377                     case XmlNodeType.SignificantWhitespace:
378                         break;
379                     default:
380                         Debug.Assert(input.NodeType == XmlNodeType.Text);
381                         ReportError(/*[XT0120]*/Res.Xslt_TextNodesNotAllowed, parentName);
382                         break;
383                     }
384                 } while (input.MoveToNextSibling());
385             }
386         }
387
388
389         XsltAttribute[] importIncludeAttributes = {new XsltAttribute("href" , V1Req | V2Req)};
390         // SxS: This method reads resource names from source document and does not expose any resources to the caller.
391         // It's OK to suppress the SxS warning.
392         [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
393         [ResourceExposure(ResourceScope.None)]
394         private void LoadImport() {
395             ContextInfo ctxInfo = input.GetAttributes(importIncludeAttributes);
396
397             if (input.MoveToXsltAttribute(0, "href")) {
398                 // Resolve href right away using the current BaseUri (it might change later)
399                 Uri uri = ResolveUri(input.Value, input.BaseUri);
400
401                 // Check for circular references
402                 if (documentUriInUse.Contains(uri.ToString())) {
403                     ReportError(/*[XT0210]*/Res.Xslt_CircularInclude, input.Value);
404                 } else {
405                     curStylesheet.ImportHrefs.Add(uri);
406                 }
407             } else {
408                 // The error was already reported. Ignore the instruction
409             }
410
411             CheckNoContent();
412         }
413
414         // SxS: This method reads resource names from source document and does not expose any resources to the caller.
415         // It's OK to suppress the SxS warning.
416         [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
417         [ResourceExposure(ResourceScope.None)]
418         private void LoadInclude() {
419             ContextInfo ctxInfo = input.GetAttributes(importIncludeAttributes);
420
421             if (input.MoveToXsltAttribute(0, "href")) {
422
423                 Uri uri = ResolveUri(input.Value, input.BaseUri);
424
425                 // Check for circular references
426                 if (documentUriInUse.Contains(uri.ToString())) {
427                     ReportError(/*[XT0180]*/Res.Xslt_CircularInclude, input.Value);
428                 } else {
429                     LoadStylesheet(uri, /*include:*/ true);
430                 }
431             } else {
432                 // The error was already reported. Ignore the instruction
433             }
434
435             CheckNoContent();
436         }
437
438         XsltAttribute[] loadStripSpaceAttributes = {new XsltAttribute("elements" , V1Req | V2Req)};
439         private void LoadStripSpace(NsDecl stylesheetNsList) {
440             ContextInfo ctxInfo = input.GetAttributes(loadStripSpaceAttributes);
441             ctxInfo.nsList = MergeNamespaces(ctxInfo.nsList, stylesheetNsList);
442
443             if (input.MoveToXsltAttribute(0, atoms.Elements)) {
444                 ParseWhitespaceRules(input.Value, false);
445             }
446             CheckNoContent();
447         }
448
449         private void LoadPreserveSpace(NsDecl stylesheetNsList) {
450             ContextInfo ctxInfo = input.GetAttributes(loadStripSpaceAttributes);
451             ctxInfo.nsList = MergeNamespaces(ctxInfo.nsList, stylesheetNsList);
452
453             if (input.MoveToXsltAttribute(0, atoms.Elements)) {
454                 ParseWhitespaceRules(input.Value, true);
455             }
456             CheckNoContent();
457         }
458
459         XsltAttribute[] outputAttributes = {
460             new XsltAttribute("name"                  ,         V2Opt),
461             new XsltAttribute("method"                , V1Opt | V2Opt),
462             new XsltAttribute("byte-order-mark"       ,         V2Opt),
463             new XsltAttribute("cdata-section-elements", V1Opt | V2Opt),
464             new XsltAttribute("doctype-public"        , V1Opt | V2Opt),
465             new XsltAttribute("doctype-system"        , V1Opt | V2Opt),
466             new XsltAttribute("encoding"              , V1Opt | V2Opt),
467             new XsltAttribute("escape-uri-attributes" ,         V2Opt),
468             new XsltAttribute("include-content-type"  ,         V2Opt),
469             new XsltAttribute("indent"                , V1Opt | V2Opt),
470             new XsltAttribute("media-type"            , V1Opt | V2Opt),
471             new XsltAttribute("normalization-form"    ,         V2Opt),
472             new XsltAttribute("omit-xml-declaration"  , V1Opt | V2Opt),
473             new XsltAttribute("standalone"            , V1Opt | V2Opt),
474             new XsltAttribute("undeclare-prefixes"    ,         V2Opt),
475             new XsltAttribute("use-character-maps"    ,         V2Opt),
476             new XsltAttribute("version"               , V1Opt | V2Opt)
477         };
478         private void LoadOutput() {
479             ContextInfo ctxInfo = input.GetAttributes(outputAttributes);
480
481             Output output = compiler.Output;
482             XmlWriterSettings settings = output.Settings;
483             int currentPrec = compiler.CurrentPrecedence;
484             TriState triState;
485
486             QilName name = ParseQNameAttribute(0);
487             if (name != null) ReportNYI("xsl:output/@name");
488
489             if (input.MoveToXsltAttribute(1, "method")) {
490                 if (output.MethodPrec <= currentPrec) {
491                     compiler.EnterForwardsCompatible();
492                     XmlOutputMethod outputMethod;
493                     XmlQualifiedName method = ParseOutputMethod(input.Value, out outputMethod);
494                     if (compiler.ExitForwardsCompatible(input.ForwardCompatibility) && method != null) {
495                         if (currentPrec == output.MethodPrec && !output.Method.Equals(method)) {
496                             ReportWarning(/*[XT1560]*/Res.Xslt_AttributeRedefinition, "method");
497                         }
498                         settings.OutputMethod = outputMethod;
499                         output.Method = method;
500                         output.MethodPrec = currentPrec;
501                     }
502                 }
503             }
504
505             TriState byteOrderMask = ParseYesNoAttribute(2, "byte-order-mark");
506             if (byteOrderMask != TriState.Unknown) ReportNYI("xsl:output/@byte-order-mark");
507
508             if (input.MoveToXsltAttribute(3, "cdata-section-elements")) {
509                 // Do not check the import precedence, the effective value is the union of all specified values
510                 compiler.EnterForwardsCompatible();
511                 string[] qnames = XmlConvert.SplitString(input.Value);
512                 List<XmlQualifiedName> list = new List<XmlQualifiedName>();
513                 for (int i = 0; i < qnames.Length; i++) {
514                     list.Add(ResolveQName(/*ignoreDefaultNs:*/false, qnames[i]));
515                 }
516                 if (compiler.ExitForwardsCompatible(input.ForwardCompatibility)) {
517                     settings.CDataSectionElements.AddRange(list);
518                 }
519             }
520
521             if (input.MoveToXsltAttribute(4, "doctype-public")) {
522                 if (output.DocTypePublicPrec <= currentPrec) {
523                     if (currentPrec == output.DocTypePublicPrec && settings.DocTypePublic != input.Value) {
524                         ReportWarning(/*[XT1560]*/Res.Xslt_AttributeRedefinition, "doctype-public");
525                     }
526                     settings.DocTypePublic = input.Value;
527                     output.DocTypePublicPrec = currentPrec;
528                 }
529             }
530
531             if (input.MoveToXsltAttribute(5, "doctype-system")) {
532                 if (output.DocTypeSystemPrec <= currentPrec) {
533                     if (currentPrec == output.DocTypeSystemPrec && settings.DocTypeSystem != input.Value) {
534                         ReportWarning(/*[XT1560]*/Res.Xslt_AttributeRedefinition, "doctype-system");
535                     }
536                     settings.DocTypeSystem = input.Value;
537                     output.DocTypeSystemPrec = currentPrec;
538                 }
539             }
540
541             if (input.MoveToXsltAttribute(6, "encoding")) {
542                 if (output.EncodingPrec <= currentPrec) {
543                     try {
544                         // Encoding.GetEncoding() should never throw NotSupportedException, only ArgumentException
545                         Encoding encoding = Encoding.GetEncoding(input.Value);
546                         if (currentPrec == output.EncodingPrec && output.Encoding != input.Value) {
547                             ReportWarning(/*[XT1560]*/Res.Xslt_AttributeRedefinition, "encoding");
548                         }
549                         settings.Encoding = encoding;
550                         output.Encoding = input.Value;
551                         output.EncodingPrec = currentPrec;
552                     } catch (ArgumentException) {
553                         if (!input.ForwardCompatibility) {
554                             ReportWarning(/*[XT_004]*/Res.Xslt_InvalidEncoding, input.Value);
555                         }
556                     }
557                 }
558             }
559
560             bool escapeUriAttributes = ParseYesNoAttribute(7, "escape-uri-attributes") != TriState.False;
561             if (! escapeUriAttributes) ReportNYI("xsl:output/@escape-uri-attributes == flase()");
562
563             bool includeContentType = ParseYesNoAttribute(8, "include-content-type") != TriState.False;
564             if (!includeContentType) ReportNYI("xsl:output/@include-content-type == flase()");
565
566             triState = ParseYesNoAttribute(9, "indent");
567             if (triState != TriState.Unknown) {
568                 if (output.IndentPrec <= currentPrec) {
569                     bool indent = (triState == TriState.True);
570                     if (currentPrec == output.IndentPrec && settings.Indent != indent) {
571                         ReportWarning(/*[XT1560]*/Res.Xslt_AttributeRedefinition, "indent");
572                     }
573                     settings.Indent = indent;
574                     output.IndentPrec = currentPrec;
575                 }
576             }
577
578             if (input.MoveToXsltAttribute(10, "media-type")) {
579                 if (output.MediaTypePrec <= currentPrec) {
580                     if (currentPrec == output.MediaTypePrec && settings.MediaType != input.Value) {
581                         ReportWarning(/*[XT1560]*/Res.Xslt_AttributeRedefinition, "media-type");
582                     }
583                     settings.MediaType = input.Value;
584                     output.MediaTypePrec = currentPrec;
585                 }
586             }
587
588             if (input.MoveToXsltAttribute(11, "normalization-form")) {
589                 ReportNYI("xsl:output/@normalization-form");
590             }
591
592             triState = ParseYesNoAttribute(12, "omit-xml-declaration");
593             if (triState != TriState.Unknown) {
594                 if (output.OmitXmlDeclarationPrec <= currentPrec) {
595                     bool omitXmlDeclaration = (triState == TriState.True);
596                     if (currentPrec == output.OmitXmlDeclarationPrec && settings.OmitXmlDeclaration != omitXmlDeclaration) {
597                         ReportWarning(/*[XT1560]*/Res.Xslt_AttributeRedefinition, "omit-xml-declaration");
598                     }
599                     settings.OmitXmlDeclaration = omitXmlDeclaration;
600                     output.OmitXmlDeclarationPrec = currentPrec;
601                 }
602             }
603
604             triState = ParseYesNoAttribute(13, "standalone");
605             if (triState != TriState.Unknown) {
606                 if (output.StandalonePrec <= currentPrec) {
607                     XmlStandalone standalone = (triState == TriState.True) ? XmlStandalone.Yes : XmlStandalone.No;
608                     if (currentPrec == output.StandalonePrec && settings.Standalone != standalone) {
609                         ReportWarning(/*[XT1560]*/Res.Xslt_AttributeRedefinition, "standalone");
610                     }
611                     settings.Standalone = standalone;
612                     output.StandalonePrec = currentPrec;
613                 }
614             }
615
616             bool undeclarePrefixes = ParseYesNoAttribute(14, "undeclare-prefixes") == TriState.True;
617             if (undeclarePrefixes) ReportNYI("xsl:output/@undeclare-prefixes == true()");
618
619             List<QilName> useCharacterMaps = ParseUseCharacterMaps(15);
620             if (useCharacterMaps.Count != 0) ReportNYI("xsl:output/@use-character-maps");
621
622             if (input.MoveToXsltAttribute(16, "version")) {
623                 if (output.VersionPrec <= currentPrec) {
624                     if (currentPrec == output.VersionPrec && output.Version != input.Value) {
625                         ReportWarning(/*[XT1560]*/Res.Xslt_AttributeRedefinition, "version");
626                     }
627                     // 
628
629                     output.Version = input.Value;
630                     output.VersionPrec = currentPrec;
631                 }
632             }
633
634             CheckNoContent();
635         }
636
637         /*
638             Default values for method="xml" :   version="1.0"   indent="no"     media-type="text/xml"
639             Default values for method="html":   version="4.0"   indent="yes"    media-type="text/html"
640             Default values for method="text":                                   media-type="text/plain"
641         */
642         private void ProcessOutputSettings() {
643             Output output = compiler.Output;
644             XmlWriterSettings settings = output.Settings;
645
646             // version is ignored, indent="no" by default
647             if (settings.OutputMethod == XmlOutputMethod.Html && output.IndentPrec == Output.NeverDeclaredPrec) {
648                 settings.Indent = true;
649             }
650             if (output.MediaTypePrec == Output.NeverDeclaredPrec) {
651                 settings.MediaType =
652                     settings.OutputMethod == XmlOutputMethod.Xml  ? "text/xml" :
653                     settings.OutputMethod == XmlOutputMethod.Html ? "text/html" :
654                     settings.OutputMethod == XmlOutputMethod.Text ? "text/plain" : null;
655             }
656         }
657
658         private void CheckUseAttrubuteSetInList(IList<XslNode> list) {
659             foreach (XslNode xslNode in list) {
660                 switch (xslNode.NodeType) {
661                 case XslNodeType.UseAttributeSet:
662                     AttributeSet usedAttSet;
663                     if (compiler.AttributeSets.TryGetValue(xslNode.Name, out usedAttSet)) {
664                         CheckAttributeSetsDfs(usedAttSet);
665                     } else {
666                         // The error will be reported in QilGenerator while compiling this attribute set.
667                     }
668                     break;
669                 case XslNodeType.List:
670                     CheckUseAttrubuteSetInList(xslNode.Content);
671                     break;
672                 }
673             }
674         }
675
676         private void CheckAttributeSetsDfs(AttributeSet attSet) {
677             Debug.Assert(attSet != null);
678             switch (attSet.CycleCheck) {
679             case CycleCheck.NotStarted:
680                 attSet.CycleCheck = CycleCheck.Processing;
681                 CheckUseAttrubuteSetInList(attSet.Content);
682                 attSet.CycleCheck = CycleCheck.Completed;
683                 break;
684             case CycleCheck.Completed:
685                 break;
686             default:
687                 Debug.Assert(attSet.CycleCheck == CycleCheck.Processing);
688                 Debug.Assert(attSet.Content[0].SourceLine != null);
689                 compiler.ReportError(/*[XT0720]*/attSet.Content[0].SourceLine, Res.Xslt_CircularAttributeSet, attSet.Name.QualifiedName);
690                 break;
691             }
692         }
693
694         XsltAttribute[] keyAttributes = {
695             new XsltAttribute("name"     , V1Req | V2Req),
696             new XsltAttribute("match"    , V1Req | V2Req),
697             new XsltAttribute("use"      , V1Req | V2Opt),
698             new XsltAttribute("collation",         V2Opt)
699         };
700         private void LoadKey(NsDecl stylesheetNsList) {
701             ContextInfo ctxInfo = input.GetAttributes(keyAttributes);
702             ctxInfo.nsList = MergeNamespaces(ctxInfo.nsList, stylesheetNsList);
703
704             QilName keyName   = ParseQNameAttribute(    0);
705             string  match     = ParseStringAttribute(   1, "match");
706             string  use       = ParseStringAttribute(   2, "use");
707             string  collation = ParseCollationAttribute(3);
708
709             input.MoveToElement();
710
711             List<XslNode> content = null;
712
713             if (V1) {
714                 if (use == null) {
715                     input.SkipNode();
716                 } else {
717                     CheckNoContent();
718                 }
719             } else {
720                 content = LoadInstructions();
721                 // Load the end tag only if the content is not empty
722                 if (content.Count != 0) {
723                     content = LoadEndTag(content);
724                 }
725                 if ((use == null) == (content.Count == 0)) {
726                     ReportError(/*[XTSE1205]*/Res.Xslt_KeyCntUse);
727                 } else {
728                     if (use == null) ReportNYI("xsl:key[count(@use) = 0]");
729                 }
730             }
731
732             Key key = (Key)SetInfo(f.Key(keyName, match, use, input.XslVersion), null, ctxInfo);
733
734             if (compiler.Keys.Contains(keyName)) {
735                 // Add to the list of previous definitions
736                 compiler.Keys[keyName].Add(key);
737             } else {
738                 // First definition of key with that name
739                 List<Key> defList = new List<Key>();
740                 defList.Add(key);
741                 compiler.Keys.Add(defList);
742             }
743         }
744
745         XsltAttribute[] decimalFormatAttributes = {
746             new XsltAttribute("name"              , V1Opt | V2Opt),
747             new XsltAttribute("infinity"          , V1Opt | V2Opt),
748             new XsltAttribute("NaN"               , V1Opt | V2Opt),
749             new XsltAttribute("decimal-separator" , V1Opt | V2Opt),
750             new XsltAttribute("grouping-separator", V1Opt | V2Opt),
751             new XsltAttribute("percent"           , V1Opt | V2Opt),
752             new XsltAttribute("per-mille"         , V1Opt | V2Opt),
753             new XsltAttribute("zero-digit"        , V1Opt | V2Opt),
754             new XsltAttribute("digit"             , V1Opt | V2Opt),
755             new XsltAttribute("pattern-separator" , V1Opt | V2Opt),
756             new XsltAttribute("minus-sign"        , V1Opt | V2Opt)
757         };
758         private void LoadDecimalFormat(NsDecl stylesheetNsList) {
759             const int NumCharAttrs = 8, NumSignAttrs = 7;
760             ContextInfo ctxInfo = input.GetAttributes(decimalFormatAttributes);
761             ctxInfo.nsList = MergeNamespaces(ctxInfo.nsList, stylesheetNsList);
762
763             XmlQualifiedName name;
764             if (input.MoveToXsltAttribute(0, "name")) {
765                 compiler.EnterForwardsCompatible();
766                 name = ResolveQName(/*ignoreDefaultNs:*/true, input.Value);
767                 if (!compiler.ExitForwardsCompatible(input.ForwardCompatibility)) {
768                     name = new XmlQualifiedName();
769                 }
770             } else {
771                 // Use name="" for the default decimal-format
772                 name = new XmlQualifiedName();
773             }
774
775             string infinity = DecimalFormatDecl.Default.InfinitySymbol;
776             if (input.MoveToXsltAttribute(1, "infinity")) {
777                 infinity = input.Value;
778             }
779
780             string nan = DecimalFormatDecl.Default.NanSymbol;
781             if (input.MoveToXsltAttribute(2, "NaN")) {
782                 nan = input.Value;
783             }
784
785             char[] DefaultValues = DecimalFormatDecl.Default.Characters;
786             char[] characters = new char[NumCharAttrs];
787             Debug.Assert(NumCharAttrs == DefaultValues.Length);
788
789             for (int idx = 0; idx < NumCharAttrs; idx++) {
790                 characters[idx] = ParseCharAttribute(3 + idx, decimalFormatAttributes[3 + idx].name, DefaultValues[idx]);
791             }
792
793             // Check all NumSignAttrs signs are distinct
794             for (int i = 0; i < NumSignAttrs; i++) {
795                 for (int j = i+1; j < NumSignAttrs; j++) {
796                     if (characters[i] == characters[j]) {
797                         // Try move to second attribute and if it is missing to first.
798                         bool dummy = input.MoveToXsltAttribute(3 + j, decimalFormatAttributes[3 + j].name) || input.MoveToXsltAttribute(3 + i, decimalFormatAttributes[3 + i].name);
799                         Debug.Assert(dummy, "One of the atts should have lineInfo. if both are defualt they can't conflict.");
800                         ReportError(/*[XT1300]*/Res.Xslt_DecimalFormatSignsNotDistinct, decimalFormatAttributes[3 + i].name, decimalFormatAttributes[3 + j].name);
801                         break;
802                     }
803                 }
804             }
805
806             if (compiler.DecimalFormats.Contains(name)) {
807                 // Check all attributes have the same values
808                 DecimalFormatDecl format = compiler.DecimalFormats[name];
809                 input.MoveToXsltAttribute(1, "infinity");
810                 CheckError(infinity != format.InfinitySymbol, /*[XT1290]*/Res.Xslt_DecimalFormatRedefined, "infinity", infinity);
811                 input.MoveToXsltAttribute(2, "NaN");
812                 CheckError(nan != format.NanSymbol, /*[XT1290]*/Res.Xslt_DecimalFormatRedefined, "NaN", nan);
813                 for (int idx = 0; idx < NumCharAttrs; idx++) {
814                     input.MoveToXsltAttribute(3 + idx, decimalFormatAttributes[3 + idx].name);
815                     CheckError(characters[idx] != format.Characters[idx], /*[XT1290]*/Res.Xslt_DecimalFormatRedefined, decimalFormatAttributes[3 + idx].name, char.ToString(characters[idx]));
816                 }
817                 Debug.Assert(name.Equals(format.Name));
818             } else {
819                 // Add format to the global collection
820                 DecimalFormatDecl format = new DecimalFormatDecl(name, infinity, nan, new string(characters));
821                 compiler.DecimalFormats.Add(format);
822             }
823             CheckNoContent();
824         }
825
826         XsltAttribute[] namespaceAliasAttributes = {
827             new XsltAttribute("stylesheet-prefix", V1Req | V2Req),
828             new XsltAttribute("result-prefix"    , V1Req | V2Req)
829         };
830         private void LoadNamespaceAlias(NsDecl stylesheetNsList) {
831             ContextInfo ctxInfo = input.GetAttributes(namespaceAliasAttributes);
832             ctxInfo.nsList = MergeNamespaces(ctxInfo.nsList, stylesheetNsList);
833
834             string stylesheetNsUri  = null;
835             string resultPrefix = null;
836             string resultNsUri  = null;
837
838             if (input.MoveToXsltAttribute(0, "stylesheet-prefix")) {
839                 if (input.Value.Length == 0) {
840                     ReportError(/*[XT_005]*/Res.Xslt_EmptyNsAlias, "stylesheet-prefix");
841                 } else {
842                     stylesheetNsUri = input.LookupXmlNamespace(input.Value == "#default" ? string.Empty : input.Value);
843                 }
844             }
845
846             if (input.MoveToXsltAttribute(1, "result-prefix")) {
847                 if (input.Value.Length == 0) {
848                     ReportError(/*[XT_005]*/Res.Xslt_EmptyNsAlias, "result-prefix");
849                 } else {
850                     resultPrefix = input.Value == "#default" ? string.Empty : input.Value;
851                     resultNsUri = input.LookupXmlNamespace(resultPrefix);
852                 }
853             }
854
855             CheckNoContent();
856
857             if (stylesheetNsUri == null || resultNsUri == null) {
858                 // At least one of attributes is missing or invalid
859                 return;
860             }
861             if (compiler.SetNsAlias(stylesheetNsUri, resultNsUri, resultPrefix, curStylesheet.ImportPrecedence)) {
862                 // Namespace alias redefinition
863                 input.MoveToElement();
864                 ReportWarning(/*[XT0810]*/Res.Xslt_DupNsAlias, stylesheetNsUri);
865             }
866         }
867
868         XsltAttribute[] attributeSetAttributes = {
869             new XsltAttribute("name"            , V1Req | V2Req),
870             new XsltAttribute("use-attribute-sets", V1Opt | V2Opt)
871         };
872         private void LoadAttributeSet(NsDecl stylesheetNsList) {
873             ContextInfo ctxInfo = input.GetAttributes(attributeSetAttributes);
874             ctxInfo.nsList = MergeNamespaces(ctxInfo.nsList, stylesheetNsList);
875
876             QilName setName = ParseQNameAttribute(0);
877             Debug.Assert(setName != null, "Required attribute always != null");
878
879             AttributeSet set;
880             if (!curStylesheet.AttributeSets.TryGetValue(setName, out set)) {
881                 set = f.AttributeSet(setName);
882                 // First definition for setName within this stylesheet
883                 curStylesheet.AttributeSets[setName] = set;
884                 if (!compiler.AttributeSets.ContainsKey(setName)) {
885                     // First definition for setName overall, adding it to the list here
886                     // to ensure stable order of prototemplate functions in QilExpression
887                     compiler.AllTemplates.Add(set);
888                 }
889             }
890
891             List<XslNode> content = new List<XslNode>();
892             if (input.MoveToXsltAttribute(1, "use-attribute-sets")) {
893                 AddUseAttributeSets(content);
894             }
895
896             QName parentName = input.ElementName;
897             if (input.MoveToFirstChild()) {
898                 do {
899                     switch (input.NodeType) {
900                     case XmlNodeType.Element:
901                         // Only xsl:attribute's are allowed here
902                         if (input.IsXsltKeyword(atoms.Attribute)) {
903                             AddInstruction(content, XslAttribute());
904                         } else {
905                             ReportError(/*[XT_006]*/Res.Xslt_UnexpectedElement, input.QualifiedName, parentName);
906                             input.SkipNode();
907                         }
908                         break;
909                     case XmlNodeType.Whitespace:
910                     case XmlNodeType.SignificantWhitespace:
911                         break;
912                     default:
913                         Debug.Assert(input.NodeType == XmlNodeType.Text);
914                         ReportError(/*[XT_006]*/Res.Xslt_TextNodesNotAllowed, parentName);
915                         break;
916                     }
917                 } while (input.MoveToNextSibling());
918             }
919             set.AddContent(SetInfo(f.List(), LoadEndTag(content), ctxInfo));
920         }
921
922         private void LoadGlobalVariableOrParameter(NsDecl stylesheetNsList, XslNodeType nodeType) {
923             Debug.Assert(curTemplate == null);
924             Debug.Assert(input.CanHaveApplyImports == false);
925             VarPar var = XslVarPar();
926             // Preserving namespaces to parse content later
927             var.Namespaces = MergeNamespaces(var.Namespaces, stylesheetNsList);
928             CheckError(!curStylesheet.AddVarPar(var), /*[XT0630]*/Res.Xslt_DupGlobalVariable, var.Name.QualifiedName);
929         }
930
931         //: http://www.w3.org/TR/xslt#section-Defining-Template-Rules
932         XsltAttribute[] templateAttributes = {
933             new XsltAttribute("match"   , V1Opt | V2Opt),
934             new XsltAttribute("name"    , V1Opt | V2Opt),
935             new XsltAttribute("priority", V1Opt | V2Opt),
936             new XsltAttribute("mode"    , V1Opt | V2Opt),
937             new XsltAttribute("as"      ,         V2Opt)
938         };
939         private void LoadTemplate(NsDecl stylesheetNsList) {
940             Debug.Assert(curTemplate == null);
941             ContextInfo ctxInfo = input.GetAttributes(templateAttributes);
942             ctxInfo.nsList = MergeNamespaces(ctxInfo.nsList, stylesheetNsList);
943
944             string match = ParseStringAttribute(0, "match");
945             QilName name = ParseQNameAttribute(1);
946             double priority = double.NaN;
947             if (input.MoveToXsltAttribute(2, "priority")) {
948                 priority = XPathConvert.StringToDouble(input.Value);
949                 if (double.IsNaN(priority) && !input.ForwardCompatibility) {
950                     ReportError(/*[XT0530]*/Res.Xslt_InvalidAttrValue, "priority", input.Value);
951                 }
952             }
953             QilName mode = V1 ? ParseModeAttribute(3) : ParseModeListAttribute(3);
954
955             if (match == null) {
956                 CheckError(! input.AttributeExists(1, "name"), /*[XT_007]*/Res.Xslt_BothMatchNameAbsent);
957                 CheckError(  input.AttributeExists(3, "mode"), /*[XT_008]*/Res.Xslt_ModeWithoutMatch   );
958                 mode = nullMode;
959                 if (input.AttributeExists(2, "priority")) {
960                     if (V1) {
961                         ReportWarning(/*[XT_008]*/Res.Xslt_PriorityWithoutMatch);
962                     } else {
963                         ReportError  (/*[XT_008]*/Res.Xslt_PriorityWithoutMatch);
964                     }
965                 }
966             }
967
968             if (input.MoveToXsltAttribute(4, "as")) {
969                 ReportNYI("xsl:template/@as");
970             }
971
972             curTemplate = f.Template(name, match, mode, priority, input.XslVersion);
973
974             // Template without match considered to not have mode and can't call xsl:apply-imports
975             input.CanHaveApplyImports = (match != null);
976
977             SetInfo(curTemplate,
978                 LoadEndTag(LoadInstructions(InstructionFlags.AllowParam)), ctxInfo
979             );
980
981             if (!curStylesheet.AddTemplate(curTemplate)) {
982                 ReportError(/*[XT0660]*/Res.Xslt_DupTemplateName, curTemplate.Name.QualifiedName);
983             }
984             curTemplate = null;
985         }
986
987 #if XSLT2
988         //: http://www.w3.org/TR/xslt20/#element-character-map
989         XsltAttribute[] characterMapAttributes = {
990             new XsltAttribute("name"            , V2Req),
991             new XsltAttribute("use-character-maps", V2Opt)
992         };
993         XsltAttribute[] outputCharacterAttributes = {
994             new XsltAttribute("character", V2Req),
995             new XsltAttribute("string"   , V2Req)
996         };
997         private void LoadCharacterMap(NsDecl stylesheetNsList) {
998             ContextInfo ctxInfo = input.GetAttributes(characterMapAttributes);
999             ctxInfo.nsList = MergeNamespaces(ctxInfo.nsList, stylesheetNsList);
1000
1001             QilName name = ParseQNameAttribute(0);
1002             List<QilName> useCharacterMaps = ParseUseCharacterMaps(1);
1003
1004             ReportNYI("xsl:character-map");
1005
1006             QName parentName = input.ElementName;
1007             if (input.MoveToFirstChild()) {
1008                 do {
1009                     switch (input.NodeType) {
1010                     case XmlNodeType.Element:
1011                         // Only xsl:output-character are allowed here
1012                         if (input.IsXsltKeyword(atoms.OutputCharacter)) {
1013                             input.GetAttributes(outputCharacterAttributes);
1014                             ReportNYI("xsl:output-character");
1015                             char ch  = ParseCharAttribute(0, "character", /*defVal:*/(char)0);
1016                             string s = ParseStringAttribute(1, "string");
1017                             CheckNoContent();
1018                         } else {
1019                             ReportError(/*[XT_006]*/Res.Xslt_UnexpectedElement, input.QualifiedName, parentName);
1020                             input.SkipNode();
1021                         }
1022                         break;
1023                     case XmlNodeType.Whitespace:
1024                     case XmlNodeType.SignificantWhitespace:
1025                         break;
1026                     default:
1027                         Debug.Assert(input.NodeType == XmlNodeType.Text);
1028                         ReportError(/*[XT_006]*/Res.Xslt_TextNodesNotAllowed, parentName);
1029                         break;
1030                     }
1031                 } while (input.MoveToNextSibling());
1032             }
1033         }
1034
1035         //: http://www.w3.org/TR/xslt20/#stylesheet-functions
1036         XsltAttribute[] functionAttributes = {
1037             new XsltAttribute("name"    , V2Req),
1038             new XsltAttribute("as"      , V2Opt),
1039             new XsltAttribute("override", V2Opt)
1040         };
1041         private void LoadFunction(NsDecl stylesheetNsList) {
1042             Debug.Assert(curTemplate == null);
1043             ContextInfo ctxInfo = input.GetAttributes(functionAttributes);
1044             ctxInfo.nsList = MergeNamespaces(ctxInfo.nsList, stylesheetNsList);
1045
1046             QilName name  = ParseQNameAttribute(0);
1047             string asType = ParseStringAttribute(1, "as");
1048             bool over     = ParseYesNoAttribute(2, "override") == TriState.True;
1049
1050             ReportNYI("xsl:function");
1051
1052             Debug.Assert(input.CanHaveApplyImports == false);
1053
1054             curFunction = new Object();
1055             LoadInstructions(InstructionFlags.AllowParam);
1056             curFunction = null;
1057         }
1058
1059         //: http://www.w3.org/TR/xslt20/#element-import-schema
1060         XsltAttribute[] importSchemaAttributes = {
1061             new XsltAttribute("namespace"     , V2Opt),
1062             new XsltAttribute("schema-location", V2Opt)
1063         };
1064         private void LoadImportSchema() {
1065             ContextInfo ctxInfo = input.GetAttributes(importSchemaAttributes);
1066             ReportError(/*[XTSE1650]*/Res.Xslt_SchemaDeclaration, input.ElementName);
1067             input.SkipNode();
1068         }
1069 #endif
1070
1071         XsltAttribute[] scriptAttributes = {
1072             new XsltAttribute("implements-prefix", V1Req | V2Req),
1073             new XsltAttribute("language"         , V1Opt | V2Opt)
1074         };
1075         private void LoadMsScript(NsDecl stylesheetNsList) {
1076             ContextInfo ctxInfo = input.GetAttributes(scriptAttributes);
1077             ctxInfo.nsList = MergeNamespaces(ctxInfo.nsList, stylesheetNsList);
1078
1079
1080             string scriptNs = null;
1081             if (input.MoveToXsltAttribute(0, "implements-prefix")) {
1082                 if (input.Value.Length == 0) {
1083                     ReportError(/*[XT_009]*/Res.Xslt_EmptyAttrValue, "implements-prefix", input.Value);
1084                 } else {
1085                     scriptNs = input.LookupXmlNamespace(input.Value);
1086                     if (scriptNs == XmlReservedNs.NsXslt) {
1087                         ReportError(/*[XT_036]*/Res.Xslt_ScriptXsltNamespace);
1088                         scriptNs = null;
1089                     }
1090                 }
1091             }
1092
1093             if (scriptNs == null) {
1094                 scriptNs = compiler.CreatePhantomNamespace();
1095             }
1096             string language = ParseStringAttribute(1, "language");
1097             if (language == null) {
1098                 language = "jscript";
1099             }
1100
1101             if (! compiler.Settings.EnableScript) {
1102                 compiler.Scripts.ScriptClasses[scriptNs] = null;
1103                 input.SkipNode();
1104                 return;
1105             }
1106
1107             ScriptClass     scriptClass;
1108             StringBuilder   scriptCode  = new StringBuilder();
1109             string          uriString   = input.Uri;
1110             int             lineNumber  = 0;
1111             int             lastEndLine = 0;
1112
1113             scriptClass = compiler.Scripts.GetScriptClass(scriptNs, language, (IErrorHelper)this);
1114             if (scriptClass == null) {
1115                 input.SkipNode();
1116                 return;
1117             }
1118
1119             QName parentName = input.ElementName;
1120             if (input.MoveToFirstChild()) {
1121                 do {
1122                     switch (input.NodeType) {
1123                     case XmlNodeType.Text:
1124                         int startLine = input.Start.Line;
1125                         int endLine   = input.End.Line;
1126                         if (scriptCode.Length == 0) {
1127                             lineNumber = startLine;
1128                         } else if (lastEndLine < startLine) {
1129                             // A multiline comment, a PI, or an unrecognized element encountered within
1130                             // this script block. Insert missed '\n' characters here; otherwise line numbers
1131                             // in error messages and in the debugger will be ----ed up. This action may spoil
1132                             // the script if the current position is situated in the middle of some identifier
1133                             // or string literal; however we hope users will not put XML nodes there.
1134                             scriptCode.Append('\n', startLine - lastEndLine);
1135                         }
1136                         scriptCode.Append(input.Value);
1137                         lastEndLine = endLine;
1138                         break;
1139                     case XmlNodeType.Element:
1140                         if (input.IsNs(atoms.UrnMsxsl) && (input.IsKeyword(atoms.Assembly) || input.IsKeyword(atoms.Using))) {
1141                             if (scriptCode.Length != 0) {
1142                                 ReportError(/*[XT_012]*/Res.Xslt_ScriptNotAtTop, input.QualifiedName);
1143                                 input.SkipNode();
1144                             } else if (input.IsKeyword(atoms.Assembly)) {
1145                                 LoadMsAssembly(scriptClass);
1146                             } else if (input.IsKeyword(atoms.Using)) {
1147                                 LoadMsUsing(scriptClass);
1148                             }
1149                         } else {
1150                             ReportError(/*[XT_012]*/Res.Xslt_UnexpectedElement, input.QualifiedName, parentName);
1151                             input.SkipNode();
1152                         }
1153                         break;
1154                     default:
1155                         Debug.Assert(
1156                             input.NodeType == XmlNodeType.SignificantWhitespace ||
1157                             input.NodeType == XmlNodeType.Whitespace
1158                         );
1159                         // Skip leading whitespaces
1160                         if (scriptCode.Length != 0) {
1161                             goto case XmlNodeType.Text;
1162                         }
1163                         break;
1164                     }
1165                 } while (input.MoveToNextSibling());
1166             }
1167
1168             if (scriptCode.Length == 0) {
1169                 lineNumber = input.Start.Line;
1170             }
1171             scriptClass.AddScriptBlock(scriptCode.ToString(), uriString, lineNumber, input.Start);
1172         }
1173
1174         XsltAttribute[] assemblyAttributes = {
1175             new XsltAttribute("name", V1Opt | V2Opt),
1176             new XsltAttribute("href", V1Opt | V2Opt)
1177         };
1178         // SxS: This method reads resource names from source document and does not expose any resources to the caller.
1179         // It's OK to suppress the SxS warning.
1180         [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
1181         [ResourceExposure(ResourceScope.None)]
1182         private void LoadMsAssembly(ScriptClass scriptClass) {
1183             input.GetAttributes(assemblyAttributes);
1184
1185             string name = ParseStringAttribute(0, "name");
1186             string href = ParseStringAttribute(1, "href");
1187
1188             if ((name != null) == (href != null)) {
1189                 ReportError(/*[XT_046]*/Res.Xslt_AssemblyNameHref);
1190             } else {
1191                 string asmLocation = null;
1192                 if (name != null) {
1193                     try {
1194                         asmLocation = Assembly.Load(name).Location;
1195                     }
1196                     catch {
1197                         AssemblyName asmName = new AssemblyName(name);
1198
1199                         // If the assembly is simply named, let CodeDomProvider and Fusion resolve it
1200                         byte[] publicKeyToken = asmName.GetPublicKeyToken();
1201                         if ((publicKeyToken == null || publicKeyToken.Length == 0) && asmName.Version == null) {
1202                             asmLocation = asmName.Name + ".dll";
1203                         } else {
1204                             throw;
1205                         }
1206                     }
1207                 } else {
1208                     Debug.Assert(href != null);
1209                     asmLocation = Assembly.LoadFrom(ResolveUri(href, input.BaseUri).ToString()).Location;
1210                     scriptClass.refAssembliesByHref = true;
1211                 }
1212
1213                 if (asmLocation != null) {
1214                     scriptClass.refAssemblies.Add(asmLocation);
1215                 }
1216             }
1217
1218             CheckNoContent();
1219         }
1220
1221         XsltAttribute[] usingAttributes = {
1222             new XsltAttribute("namespace", V1Req | V2Req)
1223         };
1224         private void LoadMsUsing(ScriptClass scriptClass) {
1225             input.GetAttributes(usingAttributes);
1226
1227             if (input.MoveToXsltAttribute(0, "namespace")) {
1228                 scriptClass.nsImports.Add(input.Value);
1229             }
1230             CheckNoContent();
1231         }
1232
1233         // ----------------- Template level methods --------------------------
1234         // Each instruction in AST tree has nsdecl list attuched to it.
1235         // Load*() methods do this treek. Xsl*() methods rely on LoadOneInstruction() to do this.
1236         // ToDo: check how LoadUnknown*() follows this gideline!
1237
1238         private enum InstructionFlags {
1239             None          = 0x00,
1240             AllowParam    = 0x01,
1241             AllowSort     = 0x02,
1242             AllowFallback = 0x04,
1243         }
1244
1245         private List<XslNode> LoadInstructions() {
1246             return LoadInstructions(new List<XslNode>(), InstructionFlags.None);
1247         }
1248
1249         private List<XslNode> LoadInstructions(InstructionFlags flags) {
1250             return LoadInstructions(new List<XslNode>(), flags);
1251         }
1252
1253         private List<XslNode> LoadInstructions(List<XslNode> content) {
1254             return LoadInstructions(content, InstructionFlags.None);
1255         }
1256
1257         const int MAX_LOADINSTRUCTIONS_DEPTH = 1024;
1258         private int loadInstructionsDepth = 0;
1259         private List<XslNode> LoadInstructions(List<XslNode> content, InstructionFlags flags) {
1260             if (++loadInstructionsDepth > MAX_LOADINSTRUCTIONS_DEPTH) {
1261                 if (System.Xml.XmlConfiguration.XsltConfigSection.LimitXPathComplexity) {
1262                     throw XslLoadException.Create(Res.Xslt_InputTooComplex);
1263                 }
1264             }
1265             QName parentName = input.ElementName;
1266             if (input.MoveToFirstChild()) {
1267                 bool    atTop = true;
1268                 int     sortNumber = 0;
1269                 XslNode result;
1270
1271                 do {
1272                     switch (input.NodeType) {
1273                     case XmlNodeType.Element:
1274                         string nspace = input.NamespaceUri;
1275                         string name   = input.LocalName;
1276                         if (nspace == atoms.UriXsl) {
1277                             InstructionFlags instrFlag = (
1278                                 Ref.Equal(name, atoms.Param) ? InstructionFlags.AllowParam :
1279                                 Ref.Equal(name, atoms.Sort ) ? InstructionFlags.AllowSort  :
1280                                 /*else */ InstructionFlags.None
1281                             );
1282                             if (instrFlag != InstructionFlags.None) {
1283                                 string error = (
1284                                     (flags & instrFlag) == 0 ? /*[XT_013]*/Res.Xslt_UnexpectedElement :
1285                                     !atTop                   ? /*[XT_014]*/Res.Xslt_NotAtTop :
1286                                     /*else*/ null
1287                                 );
1288                                 if (error != null) {
1289                                     ReportError(error, input.QualifiedName, parentName);
1290                                     atTop = false;
1291                                     input.SkipNode();
1292                                     continue;
1293                                 }
1294                             } else {
1295                                 atTop = false;
1296                             }
1297                             result = (
1298                                 Ref.Equal(name, atoms.ApplyImports         ) ? XslApplyImports() :
1299                                 Ref.Equal(name, atoms.ApplyTemplates       ) ? XslApplyTemplates() :
1300                                 Ref.Equal(name, atoms.CallTemplate         ) ? XslCallTemplate() :
1301                                 Ref.Equal(name, atoms.Copy                 ) ? XslCopy() :
1302                                 Ref.Equal(name, atoms.CopyOf               ) ? XslCopyOf() :
1303                                 Ref.Equal(name, atoms.Fallback             ) ? XslFallback() :
1304                                 Ref.Equal(name, atoms.If                   ) ? XslIf() :
1305                                 Ref.Equal(name, atoms.Choose               ) ? XslChoose() :
1306                                 Ref.Equal(name, atoms.ForEach              ) ? XslForEach() :
1307                                 Ref.Equal(name, atoms.Message              ) ? XslMessage() :
1308                                 Ref.Equal(name, atoms.Number               ) ? XslNumber() :
1309                                 Ref.Equal(name, atoms.ValueOf              ) ? XslValueOf() :
1310                                 Ref.Equal(name, atoms.Comment              ) ? XslComment() :
1311                                 Ref.Equal(name, atoms.ProcessingInstruction) ? XslProcessingInstruction() :
1312                                 Ref.Equal(name, atoms.Text                 ) ? XslText() :
1313                                 Ref.Equal(name, atoms.Element              ) ? XslElement() :
1314                                 Ref.Equal(name, atoms.Attribute            ) ? XslAttribute() :
1315                                 Ref.Equal(name, atoms.Variable             ) ? XslVarPar() :
1316                                 Ref.Equal(name, atoms.Param                ) ? XslVarPar() :
1317                                 Ref.Equal(name, atoms.Sort                 ) ? XslSort(sortNumber ++) :
1318 #if XSLT2
1319                                 V2 && Ref.Equal(name, atoms.AnalyzeString  ) ? XslAnalyzeString() :
1320                                 V2 && Ref.Equal(name, "namespace"      ) ? XslNamespace() :
1321                                 V2 && Ref.Equal(name, atoms.PerformSort    ) ? XslPerformSort() :
1322                                 V2 && Ref.Equal(name, atoms.Document       ) ? XslDocument() :
1323                                 V2 && Ref.Equal(name, atoms.ForEachGroup   ) ? XslForEachGroup() :
1324                                 V2 && Ref.Equal(name, atoms.NextMatch      ) ? XslNextMatch() :
1325                                 V2 && Ref.Equal(name, atoms.Sequence       ) ? XslSequence() :
1326                                 V2 && Ref.Equal(name, atoms.ResultDocument ) ? XslResultDocument() :
1327 #endif
1328                                 /*default:*/                                   LoadUnknownXsltInstruction(parentName)
1329                             );
1330                         } else {
1331                             atTop = false;
1332                             result = LoadLiteralResultElement(/*asStylesheet:*/false);
1333                         }
1334                         break;
1335                     case XmlNodeType.SignificantWhitespace:
1336                         result = SetLineInfo(f.Text(input.Value), input.BuildLineInfo());
1337                         break;
1338                     case XmlNodeType.Whitespace:
1339                         continue;
1340                     default:
1341                         Debug.Assert(input.NodeType == XmlNodeType.Text);
1342                         atTop = false;
1343                         goto case XmlNodeType.SignificantWhitespace;
1344                     }
1345                     AddInstruction(content, result);
1346                 } while (input.MoveToNextSibling());
1347             }
1348             --loadInstructionsDepth;
1349             return content;
1350         }
1351
1352         private List<XslNode> LoadWithParams(InstructionFlags flags) {
1353             QName parentName = input.ElementName;
1354             List<XslNode> content = new List<XslNode>();
1355             /* Process children */
1356             if (input.MoveToFirstChild()) {
1357                 int sortNumber = 0;
1358                 do {
1359                     switch (input.NodeType) {
1360                     case XmlNodeType.Element:
1361                         if (input.IsXsltKeyword(atoms.WithParam)) {
1362                             XslNode withParam = XslVarPar();
1363                             CheckWithParam(content, withParam);
1364                             AddInstruction(content, withParam);
1365                         } else if (flags == InstructionFlags.AllowSort && input.IsXsltKeyword(atoms.Sort)) {
1366                             AddInstruction(content, XslSort(sortNumber++));
1367                         } else if (flags == InstructionFlags.AllowFallback && input.IsXsltKeyword(atoms.Fallback)) {
1368                             XslFallback();
1369                         } else {
1370                             ReportError(/*[XT_016]*/Res.Xslt_UnexpectedElement, input.QualifiedName, parentName);
1371                             input.SkipNode();
1372                         }
1373                         break;
1374                     case XmlNodeType.Whitespace:
1375                     case XmlNodeType.SignificantWhitespace:
1376                         break;
1377                     default:
1378                         Debug.Assert(input.NodeType == XmlNodeType.Text);
1379                         ReportError(/*[XT_016]*/Res.Xslt_TextNodesNotAllowed, parentName);
1380                         break;
1381                     }
1382                 } while (input.MoveToNextSibling());
1383             }
1384             return content;
1385         }
1386
1387         // http://www.w3.org/TR/xslt#apply-imports
1388         private XslNode XslApplyImports() {
1389             ContextInfo ctxInfo = input.GetAttributes();
1390             if (!input.CanHaveApplyImports) {
1391                 ReportError(/*[XT_015]*/Res.Xslt_InvalidApplyImports);
1392                 input.SkipNode();
1393                 return null;
1394             }
1395
1396             List<XslNode> content = LoadWithParams(InstructionFlags.None);
1397
1398             ctxInfo.SaveExtendedLineInfo(input);
1399
1400             if (V1) {
1401                 if (content.Count != 0) {
1402                     ISourceLineInfo contentInfo = content[0].SourceLine;
1403                     if (!input.ForwardCompatibility) {
1404                         compiler.ReportError(contentInfo, /*[XT0260]*/Res.Xslt_NotEmptyContents, atoms.ApplyImports);
1405                     } else {
1406                         return SetInfo(f.Error(XslLoadException.CreateMessage(contentInfo, /*[XT0260]*/Res.Xslt_NotEmptyContents, atoms.ApplyImports)), null, ctxInfo);
1407                     }
1408                 }
1409                 content = null;
1410             } else {
1411                 if (content.Count != 0) ReportNYI("xsl:apply-imports/xsl:with-param");
1412                 content = null;
1413             }
1414
1415             return SetInfo(f.ApplyImports(/*Mode:*/curTemplate.Mode, curStylesheet, input.XslVersion), content, ctxInfo);
1416         }
1417
1418         // http://www.w3.org/TR/xslt#section-Applying-Template-Rules
1419         XsltAttribute[] applyTemplatesAttributes = {
1420             new XsltAttribute("select", V1Opt | V2Opt),
1421             new XsltAttribute("mode"  , V1Opt | V2Opt)
1422         };
1423         private XslNode XslApplyTemplates() {
1424             ContextInfo ctxInfo = input.GetAttributes(applyTemplatesAttributes);
1425
1426             string select = ParseStringAttribute(0, "select");
1427             if (select == null) {
1428                 select = "node()";
1429             }
1430             QilName mode = ParseModeAttribute(1);
1431
1432             List<XslNode> content = LoadWithParams(InstructionFlags.AllowSort);
1433             ctxInfo.SaveExtendedLineInfo(input);
1434             return SetInfo(f.ApplyTemplates(mode, select, ctxInfo, input.XslVersion),
1435                 content, ctxInfo
1436             );
1437         }
1438
1439         // http://www.w3.org/TR/xslt#named-templates
1440         // http://www.w3.org/TR/xslt#element-call-template
1441         XsltAttribute[] callTemplateAttributes = {
1442             new XsltAttribute("name", V1Req | V2Req)
1443         };
1444         private XslNode XslCallTemplate() {
1445             ContextInfo ctxInfo = input.GetAttributes(callTemplateAttributes);
1446             QilName name = ParseQNameAttribute(0);
1447
1448             List<XslNode> content = LoadWithParams(InstructionFlags.None);
1449             ctxInfo.SaveExtendedLineInfo(input);
1450             return SetInfo(f.CallTemplate(name, ctxInfo), content, ctxInfo);
1451         }
1452
1453         // http://www.w3.org/TR/xslt#copying
1454         // http://www.w3.org/TR/xslt20/#element-copy
1455         XsltAttribute[] copyAttributes = {
1456             new XsltAttribute("copy-namespaces"   ,         V2Opt),
1457             new XsltAttribute("inherit-namespaces",         V2Opt),
1458             new XsltAttribute("use-attribute-sets", V1Opt | V2Opt),
1459             new XsltAttribute("type"              ,         V2Opt),
1460             new XsltAttribute("validation"        ,         V2Opt)
1461         };
1462         private XslNode XslCopy() {
1463             ContextInfo ctxInfo = input.GetAttributes(copyAttributes);
1464
1465             bool copyNamespaces    = ParseYesNoAttribute(0, "copy-namespaces"   ) != TriState.False;
1466             bool inheritNamespaces = ParseYesNoAttribute(1, "inherit-namespaces") != TriState.False;
1467             if (! copyNamespaces   ) ReportNYI("xsl:copy[@copy-namespaces    = 'no']");
1468             if (! inheritNamespaces) ReportNYI("xsl:copy[@inherit-namespaces = 'no']");
1469
1470             List<XslNode> content = new List<XslNode>();
1471             if (input.MoveToXsltAttribute(2, "use-attribute-sets")) {
1472                 AddUseAttributeSets(content);
1473             }
1474
1475             ParseTypeAttribute(3);
1476             ParseValidationAttribute(4, /*defVal:*/false);
1477
1478             return SetInfo(f.Copy(), LoadEndTag(LoadInstructions(content)), ctxInfo);
1479         }
1480
1481         XsltAttribute[] copyOfAttributes = {
1482             new XsltAttribute("select"         , V1Req | V2Req),
1483             new XsltAttribute("copy-namespaces",         V2Opt),
1484             new XsltAttribute("type"           ,         V2Opt),
1485             new XsltAttribute("validation"     ,         V2Opt)
1486         };
1487         private XslNode XslCopyOf() {
1488             ContextInfo ctxInfo = input.GetAttributes(copyOfAttributes);
1489             string select = ParseStringAttribute(0, "select");
1490             bool copyNamespaces = ParseYesNoAttribute(1, "copy-namespaces") != TriState.False;
1491             if (!copyNamespaces) ReportNYI("xsl:copy-of[@copy-namespaces    = 'no']");
1492
1493             ParseTypeAttribute(2);
1494             ParseValidationAttribute(3, /*defVal:*/false);
1495
1496             CheckNoContent();
1497             return SetInfo(f.CopyOf(select, input.XslVersion), null, ctxInfo);
1498         }
1499
1500         // http://www.w3.org/TR/xslt#fallback
1501         // See LoadFallbacks() for real fallback implementation
1502         private XslNode XslFallback() {
1503             input.GetAttributes();
1504             input.SkipNode();
1505             return null;
1506         }
1507
1508         XsltAttribute[] ifAttributes = {
1509             new XsltAttribute("test", V1Req | V2Req)
1510         };
1511         private XslNode XslIf() {
1512             ContextInfo ctxInfo = input.GetAttributes(ifAttributes);
1513             string test = ParseStringAttribute(0, "test");
1514
1515             return SetInfo(f.If(test, input.XslVersion), LoadInstructions(), ctxInfo);
1516         }
1517
1518         private XslNode XslChoose() {
1519             ContextInfo ctxInfo = input.GetAttributes();
1520
1521             List<XslNode> content   = new List<XslNode>();
1522             bool        otherwise = false;
1523             bool        when      = false;
1524
1525             QName parentName = input.ElementName;
1526             if (input.MoveToFirstChild()) {
1527                 do {
1528                     switch (input.NodeType) {
1529                     case XmlNodeType.Element:
1530                         XslNode node = null;
1531                         if (Ref.Equal(input.NamespaceUri, atoms.UriXsl)) {
1532                             if (Ref.Equal(input.LocalName, atoms.When)) {
1533                                 if (otherwise) {
1534                                     ReportError(/*[XT_018]*/Res.Xslt_WhenAfterOtherwise);
1535                                     input.SkipNode();
1536                                     continue;
1537                                 } else {
1538                                     when = true;
1539                                     node = XslIf();
1540                                 }
1541                             } else if (Ref.Equal(input.LocalName, atoms.Otherwise)) {
1542                                 if (otherwise) {
1543                                     ReportError(/*[XT_019]*/Res.Xslt_DupOtherwise);
1544                                     input.SkipNode();
1545                                     continue;
1546                                 } else {
1547                                     otherwise = true;
1548                                     node = XslOtherwise();
1549                                 }
1550                             }
1551                         }
1552                         if (node == null) {
1553                             ReportError(/*[XT_020]*/Res.Xslt_UnexpectedElement, input.QualifiedName, parentName);
1554                             input.SkipNode();
1555                             continue;
1556                         }
1557                         AddInstruction(content, node);
1558                         break;
1559                     case XmlNodeType.Whitespace:
1560                     case XmlNodeType.SignificantWhitespace:
1561                         break;
1562                     default:
1563                         Debug.Assert(input.NodeType == XmlNodeType.Text);
1564                         ReportError(/*[XT_020]*/Res.Xslt_TextNodesNotAllowed, parentName);
1565                         break;
1566                     }
1567                 } while (input.MoveToNextSibling());
1568             }
1569             CheckError(!when, /*[XT_021]*/Res.Xslt_NoWhen);
1570             return SetInfo(f.Choose(), content, ctxInfo);
1571         }
1572
1573         private XslNode XslOtherwise() {
1574             ContextInfo ctxInfo = input.GetAttributes();
1575             return SetInfo(f.Otherwise(), LoadInstructions(), ctxInfo);
1576         }
1577
1578         XsltAttribute[] forEachAttributes = {
1579             new XsltAttribute("select", V1Req | V2Req)
1580         };
1581         private XslNode XslForEach() {
1582             ContextInfo ctxInfo = input.GetAttributes(forEachAttributes);
1583
1584             string select = ParseStringAttribute(0, "select");
1585             // The current template rule becomes null, so we must not allow xsl:apply-import's within this element
1586             input.CanHaveApplyImports = false;
1587             List<XslNode> content = LoadInstructions(InstructionFlags.AllowSort);
1588             ctxInfo.SaveExtendedLineInfo(input);
1589
1590             return SetInfo(f.ForEach(select, ctxInfo, input.XslVersion),
1591                 content, ctxInfo
1592             );
1593         }
1594
1595         // http://www.w3.org/TR/xslt#message
1596         // http://www.w3.org/TR/xslt20/#element-message
1597         XsltAttribute[] messageAttributes = {
1598             new XsltAttribute("select"   ,         V2Opt),
1599             new XsltAttribute("terminate", V1Opt | V2Opt)
1600         };
1601         private XslNode XslMessage() {
1602             ContextInfo ctxInfo = input.GetAttributes(messageAttributes);
1603
1604             string select = ParseStringAttribute(0, "select");
1605             bool terminate = ParseYesNoAttribute(1, /*attName:*/"terminate") == TriState.True;
1606
1607             List<XslNode> content = LoadInstructions();
1608             if (content.Count != 0) {
1609                 content = LoadEndTag(content);
1610             }
1611             if (select != null) {
1612                 content.Insert(0, f.CopyOf(select, input.XslVersion));
1613             }
1614
1615             return SetInfo(f.Message(terminate), content, ctxInfo);
1616         }
1617
1618         // http://www.w3.org/TR/xslt#number
1619         // http://www.w3.org/TR/xslt20/#element-number
1620         XsltAttribute[] numberAttributes = {
1621             new XsltAttribute("value"             , V1Opt | V2Opt),
1622             new XsltAttribute("select"            ,         V2Opt),
1623             new XsltAttribute("level"             , V1Opt | V2Opt),
1624             new XsltAttribute("count"             , V1Opt | V2Opt),
1625             new XsltAttribute("from"              , V1Opt | V2Opt),
1626             new XsltAttribute("format"            , V1Opt | V2Opt),
1627             new XsltAttribute("lang"              , V1Opt | V2Opt),
1628             new XsltAttribute("letter-value"      , V1Opt | V2Opt),
1629             new XsltAttribute("ordinal"           ,         V2Opt),
1630             new XsltAttribute("grouping-separator", V1Opt | V2Opt),
1631             new XsltAttribute("grouping-size"     , V1Opt | V2Opt)
1632         };
1633         private XslNode XslNumber() {
1634             ContextInfo ctxInfo = input.GetAttributes(numberAttributes);
1635
1636             string value  = ParseStringAttribute(0, "value");
1637             string select = ParseStringAttribute(1, "select");
1638             if (select != null) ReportNYI("xsl:number/@select");
1639             NumberLevel level = NumberLevel.Single;
1640             if (input.MoveToXsltAttribute(2, "level")) {
1641                 switch (input.Value) {
1642                 case "single"  : level = NumberLevel.Single  ; break;
1643                 case "multiple": level = NumberLevel.Multiple; break;
1644                 case "any"     : level = NumberLevel.Any     ; break;
1645                 default:
1646                     if (!input.ForwardCompatibility) {
1647                         ReportError(/*[XT_022]*/Res.Xslt_InvalidAttrValue, "level", input.Value);
1648                     }
1649                     break;
1650                 }
1651             }
1652             string count             = ParseStringAttribute(3, "count" );
1653             string from              = ParseStringAttribute(4, "from"  );
1654             string format            = ParseStringAttribute(5, "format");
1655             string lang              = ParseStringAttribute(6, "lang"  );
1656             string letterValue       = ParseStringAttribute(7, "letter-value");
1657             string ordinal           = ParseStringAttribute(8, "ordinal");
1658             if (!string.IsNullOrEmpty(ordinal)) ReportNYI("xsl:number/@ordinal");
1659             string groupingSeparator = ParseStringAttribute(9, "grouping-separator");
1660             string groupingSize      = ParseStringAttribute(10, "grouping-size"  );
1661
1662             // Default values for xsl:number :  level="single"  format="1"
1663             if (format == null) {
1664                 format = "1";
1665             }
1666
1667             CheckNoContent();
1668             return SetInfo(
1669                 f.Number(level, count, from, value,
1670                     format, lang, letterValue, groupingSeparator, groupingSize,
1671                     input.XslVersion
1672                 ),
1673                 null, ctxInfo
1674             );
1675         }
1676
1677         // http://www.w3.org/TR/xslt#value-of
1678         XsltAttribute[] valueOfAttributes = {
1679             new XsltAttribute("select"                 , V1Req | V2Opt),
1680             new XsltAttribute("separator"              ,         V2Opt),
1681             new XsltAttribute("disable-output-escaping", V1Opt | V2Opt)
1682         };
1683         private XslNode XslValueOf() {
1684             ContextInfo ctxInfo = input.GetAttributes(valueOfAttributes);
1685
1686             string select    = ParseStringAttribute(0, "select");
1687             string separator = ParseStringAttribute(1, "separator");
1688             bool doe = ParseYesNoAttribute(2, /*attName:*/"disable-output-escaping") == TriState.True;
1689
1690             if (separator == null) {
1691                 if (!input.BackwardCompatibility) {
1692                     separator = select != null ? " " : string.Empty;
1693                 }
1694             } else {
1695                 ReportNYI("xsl:value-of/@separator");
1696             }
1697
1698             List<XslNode> content = null;
1699
1700             if (V1) {
1701                 if (select == null) {
1702                     input.SkipNode();
1703                     return SetInfo(f.Error(XslLoadException.CreateMessage(ctxInfo.lineInfo, Res.Xslt_MissingAttribute, "select")), null, ctxInfo);
1704                 }
1705                 CheckNoContent();
1706             } else {
1707                 content = LoadContent(select != null);
1708                 CheckError(select == null && content.Count == 0, /*[???]*/Res.Xslt_NoSelectNoContent, input.ElementName);
1709                 if (content.Count != 0) {
1710                     ReportNYI("xsl:value-of/*");
1711                     content = null;
1712                 }
1713             }
1714
1715             return SetInfo(f.XslNode(doe ? XslNodeType.ValueOfDoe : XslNodeType.ValueOf, null, select, input.XslVersion),
1716                 null, ctxInfo
1717             );
1718         }
1719
1720         //                    required tunnel select
1721         // variable              -        -      +
1722         // with-param            -        +      +
1723         // stylesheet/param      +        -      +
1724         // template/param        +        +      +
1725         // function/param        -        -      -
1726         // xsl:variable     http://www.w3.org/TR/xslt#local-variables
1727         // xsl:param        http://www.w3.org/TR/xslt#element-param
1728         // xsl:with-param   http://www.w3.org/TR/xslt#element-with-param
1729         XsltAttribute[] variableAttributes = {
1730             new XsltAttribute("name"    , V1Req | V2Req),
1731             new XsltAttribute("select"  , V1Opt | V2Opt),
1732             new XsltAttribute("as"      ,         V2Opt),
1733             new XsltAttribute("required",             0),
1734             new XsltAttribute("tunnel"  ,             0)
1735         };
1736         XsltAttribute[] paramAttributes = {
1737             new XsltAttribute("name"    , V1Req | V2Req),
1738             new XsltAttribute("select"  , V1Opt | V2Opt),
1739             new XsltAttribute("as"      ,         V2Opt),
1740             new XsltAttribute("required",         V2Opt),
1741             new XsltAttribute("tunnel"  ,         V2Opt)
1742         };
1743         XsltAttribute[] withParamAttributes = {
1744             new XsltAttribute("name"    , V1Req | V2Req),
1745             new XsltAttribute("select"  , V1Opt | V2Opt),
1746             new XsltAttribute("as"      ,         V2Opt),
1747             new XsltAttribute("required",             0),
1748             new XsltAttribute("tunnel"  ,         V2Opt)
1749         };
1750         private VarPar XslVarPar() {
1751             string localName = input.LocalName;
1752             XslNodeType nodeType = (
1753                 Ref.Equal(localName, atoms.Variable ) ? XslNodeType.Variable  :
1754                 Ref.Equal(localName, atoms.Param    ) ? XslNodeType.Param     :
1755                 Ref.Equal(localName, atoms.WithParam) ? XslNodeType.WithParam :
1756                 XslNodeType.Unknown
1757             );
1758             Debug.Assert(nodeType != XslNodeType.Unknown);
1759             bool isParam = Ref.Equal(localName, atoms.Param);
1760             ContextInfo ctxInfo = input.GetAttributes(
1761                 nodeType == XslNodeType.Variable ? variableAttributes :
1762                 nodeType == XslNodeType.Param    ? paramAttributes   :
1763                 /*default:*/                       withParamAttributes
1764             );
1765
1766             QilName name  = ParseQNameAttribute(0);
1767             string select = ParseStringAttribute(1, "select");
1768             string asType = ParseStringAttribute(2, "as");
1769             TriState required = ParseYesNoAttribute(3, "required");
1770             if (nodeType == XslNodeType.Param && curFunction != null) {
1771                 if (!input.ForwardCompatibility) {
1772                     CheckError(required != TriState.Unknown, /*[???]*/Res.Xslt_RequiredOnFunction, name.ToString());
1773                 }
1774                 required = TriState.True;
1775             } else {
1776                 if (required == TriState.True) ReportNYI("xsl:param/@required == true()");
1777             }
1778
1779             if (asType != null) {
1780                 ReportNYI("xsl:param/@as");
1781             }
1782
1783             TriState tunnel = ParseYesNoAttribute(4, "tunnel");
1784             if (tunnel != TriState.Unknown) {
1785                 if (nodeType == XslNodeType.Param && curTemplate == null) {
1786                     if (!input.ForwardCompatibility) {
1787                         ReportError(/*[???]*/Res.Xslt_NonTemplateTunnel, name.ToString());
1788                     }
1789                 } else {
1790                     if (tunnel == TriState.True) ReportNYI("xsl:param/@tunnel == true()");
1791                 }
1792             }
1793
1794             List<XslNode> content = LoadContent(select != null);
1795             CheckError((required == TriState.True) && (select != null || content.Count != 0), /*[???]*/Res.Xslt_RequiredAndSelect, name.ToString());
1796
1797             VarPar result = f.VarPar(nodeType, name, select, input.XslVersion);
1798             SetInfo(result, content, ctxInfo);
1799             return result;
1800         }
1801
1802         // http://www.w3.org/TR/xslt#section-Creating-Comments
1803         // http://www.w3.org/TR/xslt20/#element-comment
1804         XsltAttribute[] commentAttributes = {
1805             new XsltAttribute("select", V2Opt)
1806         };
1807         private XslNode XslComment() {
1808             ContextInfo ctxInfo = input.GetAttributes(commentAttributes);
1809             string select = ParseStringAttribute(0, "select");
1810             if (select != null) ReportNYI("xsl:comment/@select");
1811
1812             return SetInfo(f.Comment(), LoadContent(select != null), ctxInfo);
1813         }
1814
1815         private List<XslNode> LoadContent(bool hasSelect) {
1816             QName parentName = input.ElementName;
1817             List<XslNode> content = LoadInstructions();
1818             CheckError(hasSelect && content.Count != 0, /*[XT0620]*/Res.Xslt_ElementCntSel, parentName);
1819             // Load the end tag only if the content is not empty
1820             if (content.Count != 0) {
1821                 content = LoadEndTag(content);
1822             }
1823             return content;
1824         }
1825
1826         // http://www.w3.org/TR/xslt#section-Creating-Processing-Instructions
1827         // http://www.w3.org/TR/xslt20/#element-processing-instruction
1828         XsltAttribute[] processingInstructionAttributes = {
1829             new XsltAttribute("name"  , V1Req | V2Req),
1830             new XsltAttribute("select",         V2Opt)
1831         };
1832         private XslNode XslProcessingInstruction() {
1833             ContextInfo ctxInfo = input.GetAttributes(processingInstructionAttributes);
1834             string name = ParseNCNameAttribute(0);
1835             string select = ParseStringAttribute(1, "select");
1836             if (select != null) ReportNYI("xsl:processing-instruction/@select");
1837
1838             return SetInfo(f.PI(name, input.XslVersion), LoadContent(select != null), ctxInfo);
1839         }
1840
1841         // http://www.w3.org/TR/xslt#section-Creating-Text
1842         XsltAttribute[] textAttributes = {
1843             new XsltAttribute("disable-output-escaping", V1Opt | V2Opt)
1844         };
1845         private XslNode XslText() {
1846             ContextInfo ctxInfo = input.GetAttributes(textAttributes);
1847
1848             bool doe = ParseYesNoAttribute(0, /*attName:*/ "disable-output-escaping") == TriState.True;
1849             SerializationHints hints = doe ? SerializationHints.DisableOutputEscaping : SerializationHints.None;
1850
1851             // We are not using StringBuilder here because in most cases there will be just one text node.
1852             List<XslNode> content = new List<XslNode>();
1853
1854             QName parentName = input.ElementName;
1855             if (input.MoveToFirstChild()) {
1856                 do {
1857                     switch (input.NodeType) {
1858                     case XmlNodeType.Text:
1859                     case XmlNodeType.Whitespace:
1860                     case XmlNodeType.SignificantWhitespace:
1861                         // xsl:text may contain multiple child text nodes separated by comments and PIs, which are ignored by XsltInput
1862                         content.Add(f.Text(input.Value, hints));
1863                         break;
1864                     default:
1865                         Debug.Assert(input.NodeType == XmlNodeType.Element);
1866                         ReportError(/*[XT_023]*/Res.Xslt_UnexpectedElement, input.QualifiedName, parentName);
1867                         input.SkipNode();
1868                         break;
1869                     }
1870                 } while (input.MoveToNextSibling());
1871             }
1872
1873             // Empty xsl:text elements will be ignored
1874             return SetInfo(f.List(), content, ctxInfo);
1875         }
1876
1877         // http://www.w3.org/TR/xslt#section-Creating-Elements-with-xsl:element
1878         // http://www.w3.org/TR/xslt20/#element-element
1879         XsltAttribute[] elementAttributes = {
1880             new XsltAttribute("name"             , V1Req | V2Req),
1881             new XsltAttribute("namespace"        , V1Opt | V2Opt),
1882             new XsltAttribute("inherit-namespaces",         V2Opt),
1883             new XsltAttribute("use-attribute-sets" , V1Opt | V2Opt),
1884             new XsltAttribute("type"             ,         V2Opt),
1885             new XsltAttribute("validation"       ,         V2Opt)
1886         };
1887         private XslNode XslElement() {
1888             ContextInfo ctxInfo = input.GetAttributes(elementAttributes);
1889
1890             string name = ParseNCNameAttribute(0); ;
1891             string ns = ParseStringAttribute(1, "namespace");
1892             CheckError(ns == XmlReservedNs.NsXmlNs, /*[XT_024]*/Res.Xslt_ReservedNS, ns);
1893
1894             bool inheritNamespaces = ParseYesNoAttribute(2, "inherit-namespaces") != TriState.False;
1895             if (!inheritNamespaces) ReportNYI("xsl:copy[@inherit-namespaces = 'no']");
1896
1897             ParseTypeAttribute(4);
1898             ParseValidationAttribute(5, /*defVal:*/false);
1899
1900             List<XslNode> content = new List<XslNode>();
1901             if (input.MoveToXsltAttribute(3, "use-attribute-sets")) {
1902                 AddUseAttributeSets(content);
1903             }
1904             return SetInfo(f.Element(name, ns, input.XslVersion),
1905                 LoadEndTag(LoadInstructions(content)), ctxInfo
1906             );
1907         }
1908
1909         // http://www.w3.org/TR/xslt#creating-attributes
1910         // http://www.w3.org/TR/xslt20#creating-attributes
1911         XsltAttribute[] attributeAttributes = {
1912             new XsltAttribute("name"      , V1Req | V2Req),
1913             new XsltAttribute("namespace" , V1Opt | V2Opt),
1914             new XsltAttribute("select"    ,         V2Opt),
1915             new XsltAttribute("separator" ,         V2Opt),
1916             new XsltAttribute("type"      ,         V2Opt),
1917             new XsltAttribute("validation",         V2Opt)
1918         };
1919         private XslNode XslAttribute() {
1920             ContextInfo ctxInfo = input.GetAttributes(attributeAttributes);
1921
1922             string name = ParseNCNameAttribute(0);
1923             string ns = ParseStringAttribute(1, "namespace");
1924             CheckError(ns == XmlReservedNs.NsXmlNs, /*[XT_024]*/Res.Xslt_ReservedNS, ns);
1925
1926             string select = ParseStringAttribute(2, "select");
1927             if (select != null) ReportNYI("xsl:attribute/@select");
1928             string separator = ParseStringAttribute(3, "separator");
1929             if (separator != null) ReportNYI("xsl:attribute/@separator");
1930             separator = separator != null ? separator : (select != null ? " " : string.Empty);
1931
1932             ParseTypeAttribute(4);
1933             ParseValidationAttribute(5, /*defVal:*/false);
1934
1935             return SetInfo(f.Attribute(name, ns, input.XslVersion), LoadContent(select != null), ctxInfo);
1936         }
1937
1938         // http://www.w3.org/TR/xslt#sorting
1939         // http://www.w3.org/TR/xslt20/#element-sort
1940         XsltAttribute[] sortAttributes = {
1941             new XsltAttribute("select"    , V1Opt | V2Opt),
1942             new XsltAttribute("lang"      , V1Opt | V2Opt),
1943             new XsltAttribute("order"     , V1Opt | V2Opt),
1944             new XsltAttribute("collation" , V1Opt | V2Opt),
1945             new XsltAttribute("stable"    , V1Opt | V2Opt),
1946             new XsltAttribute("case-order", V1Opt | V2Opt),
1947             new XsltAttribute("data-type" , V1Opt | V2Opt)
1948         };
1949         private XslNode XslSort(int sortNumber) {
1950             ContextInfo ctxInfo = input.GetAttributes(sortAttributes);
1951
1952             string   select    = ParseStringAttribute(   0, "select"    );
1953             string   lang      = ParseStringAttribute(   1, "lang"      );
1954             string   order     = ParseStringAttribute(   2, "order"     );
1955             string   collation = ParseCollationAttribute(3);
1956             TriState stable    = ParseYesNoAttribute (   4, "stable"    );
1957             string   caseOrder = ParseStringAttribute(   5, "case-order");
1958             string   dataType  = ParseStringAttribute(   6, "data-type" );
1959
1960             if (stable != TriState.Unknown) {
1961                 CheckError(sortNumber != 0, Res.Xslt_SortStable);
1962             }
1963
1964             List<XslNode> content = null;
1965             if (V1) {
1966                 CheckNoContent();
1967             } else {
1968                 content = LoadContent(select != null);
1969                 if (content.Count != 0) {
1970                     ReportNYI("xsl:sort/*");
1971                     content = null;
1972                 }
1973             }
1974
1975             if (select == null /*&& content.Count == 0*/) {
1976                 select = ".";
1977             }
1978
1979             return SetInfo(f.Sort(select, lang, dataType, order, caseOrder, input.XslVersion),
1980                 null, ctxInfo
1981             );
1982         }
1983
1984 #if XSLT2
1985         // http://www.w3.org/TR/xslt20/#element-document
1986         XsltAttribute[] documentAttributes = {
1987             new XsltAttribute("type"      , V2Opt),
1988             new XsltAttribute("validation", V2Opt)
1989         };
1990         private XslNode XslDocument() {
1991             ContextInfo ctxInfo = input.GetAttributes(documentAttributes);
1992
1993             ParseTypeAttribute(0);
1994             ParseValidationAttribute(1, /*defVal:*/false);
1995
1996             ReportNYI("xsl:document");
1997
1998             List<XslNode> content = LoadEndTag(LoadInstructions());
1999
2000             return null;
2001         }
2002
2003         // http://www.w3.org/TR/xslt20/#element-analyze-string
2004         XsltAttribute[] analyzeStringAttributes = {
2005             new XsltAttribute("select", V2Req),
2006             new XsltAttribute("regex" , V2Req),
2007             new XsltAttribute("flags" , V2Opt)
2008         };
2009         private XslNode XslAnalyzeString() {
2010             ContextInfo ctxInfo = input.GetAttributes(analyzeStringAttributes);
2011
2012             string select = ParseStringAttribute(0, "select");
2013             string regex  = ParseStringAttribute(1, "regex" );
2014             string flags  = ParseStringAttribute(2, "flags" );
2015             if (flags == null) {
2016                 flags = "";
2017             }
2018
2019             ReportNYI("xsl:analyze-string");
2020
2021             XslNode matching = null;
2022             XslNode nonMatching = null;
2023             QName parentName = input.ElementName;
2024             if (input.MoveToFirstChild()) {
2025                 do {
2026                     switch (input.NodeType) {
2027                     case XmlNodeType.Element:
2028                         if (input.IsXsltKeyword(atoms.MatchingSubstring)) {
2029                             ContextInfo ctxInfoChld = input.GetAttributes();
2030                             CheckError(nonMatching != null, /*[???]*/Res.Xslt_AnalyzeStringChildOrder);
2031                             CheckError(matching    != null, /*[???]*/Res.Xslt_AnalyzeStringDupChild, atoms.MatchingSubstring);
2032                             // The current template rule becomes null, so we must not allow xsl:apply-import's within this element
2033                             input.CanHaveApplyImports = false;
2034                             matching = SetInfo(f.List(), LoadInstructions(), ctxInfoChld);
2035                         } else if (input.IsXsltKeyword(atoms.NonMatchingSubstring)) {
2036                             ContextInfo ctxInfoChld = input.GetAttributes();
2037                             CheckError(nonMatching != null, /*[???]*/Res.Xslt_AnalyzeStringDupChild, atoms.NonMatchingSubstring);
2038                             input.CanHaveApplyImports = false;
2039                             nonMatching = SetInfo(f.List(), LoadInstructions(), ctxInfoChld);
2040                         } else if (input.IsXsltKeyword(atoms.Fallback)) {
2041                             XslFallback();
2042                         } else {
2043                             ReportError(/*[XT_017]*/Res.Xslt_UnexpectedElement, input.QualifiedName, parentName);
2044                             input.SkipNode();
2045                         }
2046                         break;
2047                     case XmlNodeType.Whitespace:
2048                     case XmlNodeType.SignificantWhitespace:
2049                         break;
2050                     default:
2051                         Debug.Assert(input.NodeType == XmlNodeType.Text);
2052                         ReportError(/*[XT_017]*/Res.Xslt_TextNodesNotAllowed, parentName);
2053                         break;
2054                     }
2055                 } while (input.MoveToNextSibling());
2056             }
2057             CheckError(matching == nonMatching, /*[XTSE1130]*/Res.Xslt_AnalyzeStringEmpty);
2058
2059             ctxInfo.SaveExtendedLineInfo(input);
2060
2061             return null;
2062         }
2063
2064         // http://www.w3.org/TR/xslt20/#element-namespace
2065         XsltAttribute[] namespaceAttributes = {
2066             new XsltAttribute("name"  , V2Req),
2067             new XsltAttribute("select", V2Opt)
2068         };
2069         private XslNode XslNamespace() {
2070             ContextInfo ctxInfo = input.GetAttributes(namespaceAttributes);
2071             string name = ParseNCNameAttribute(0);
2072             string select= ParseStringAttribute(1, "select");
2073
2074             List<XslNode> content = LoadContent(select != null);
2075             CheckError(select == null && content.Count == 0, /*[???]*/Res.Xslt_NoSelectNoContent, input.ElementName);
2076
2077             ReportNYI("xsl:namespace");
2078
2079             return null;
2080         }
2081
2082         // http://www.w3.org/TR/xslt20/#element-perform-sort
2083         XsltAttribute[] performSortAttributes = {
2084             new XsltAttribute("select", V2Opt)
2085         };
2086         private XslNode XslPerformSort() {
2087             ContextInfo ctxInfo = input.GetAttributes(performSortAttributes);
2088             string select = ParseStringAttribute(0, "select");
2089
2090             List<XslNode> content = LoadInstructions(InstructionFlags.AllowSort);
2091             ctxInfo.SaveExtendedLineInfo(input);
2092
2093             if (select != null) {
2094                 foreach (XslNode node in content) {
2095                     if (node.NodeType != XslNodeType.Sort) {
2096                         ReportError(Res.Xslt_PerformSortCntSel);
2097                         break;
2098                     }
2099                 }
2100             }
2101
2102             ReportNYI("xsl:perform-sort");
2103             return null;
2104         }
2105
2106         // http://www.w3.org/TR/xslt20/#element-for-each-group
2107         XsltAttribute[] forEachGroupAttributes = {
2108             new XsltAttribute("select"             , V2Req),
2109             new XsltAttribute("group-by"           , V2Opt),
2110             new XsltAttribute("group-adjacent"     , V2Opt),
2111             new XsltAttribute("group-starting-with", V2Opt),
2112             new XsltAttribute("group-ending-with"  , V2Opt),
2113             new XsltAttribute("collation"          , V2Opt)
2114         };
2115         private XslNode XslForEachGroup() {
2116             ContextInfo ctxInfo = input.GetAttributes(forEachGroupAttributes);
2117
2118             string select            = ParseStringAttribute(   0, "select"             );
2119             string groupBy           = ParseStringAttribute(   1, "group-by"           );
2120             string groupAdjacent     = ParseStringAttribute(   2, "group-adjacent"     );
2121             string groupStartingWith = ParseStringAttribute(   3, "group-starting-with");
2122             string groupEndingWith   = ParseStringAttribute(   4, "group-ending-with"  );
2123             string collation         = ParseCollationAttribute(5);
2124
2125             ReportNYI("xsl:for-each-group");
2126
2127             // The current template rule becomes null, so we must not allow xsl:apply-import's within this element
2128             input.CanHaveApplyImports = false;
2129             List<XslNode> content = LoadInstructions(InstructionFlags.AllowSort);
2130             ctxInfo.SaveExtendedLineInfo(input);
2131
2132             return null;
2133         }
2134
2135         // http://www.w3.org/TR/xslt20/#element-next-match
2136         private XslNode XslNextMatch() {
2137             ContextInfo ctxInfo = input.GetAttributes();
2138
2139             // We need to do this dynamic any way:
2140             //if (!input.CanHaveApplyImports) {
2141             //    ReportError(/*[XT_015]*/Res.Xslt_InvalidApplyImports);
2142             //    input.SkipNode();
2143             //    return null;
2144             //}
2145
2146             ReportNYI("xsl:next-match");
2147
2148             List<XslNode> content = LoadWithParams(InstructionFlags.AllowFallback);
2149             ctxInfo.SaveExtendedLineInfo(input);
2150
2151             return null;
2152         }
2153
2154         // http://www.w3.org/TR/xslt20/#element-sequence
2155         XsltAttribute[] sequenceAttributes = {
2156             new XsltAttribute("select", V2Req)
2157         };
2158         private XslNode XslSequence() {
2159             ContextInfo ctxInfo = input.GetAttributes(sequenceAttributes);
2160             string select = ParseStringAttribute(0, "select");
2161             ReportNYI("xsl:sequence");
2162
2163             QName parentName = input.ElementName;
2164             if (input.MoveToFirstChild()) {
2165                 do {
2166                     switch (input.NodeType) {
2167                     case XmlNodeType.Element:
2168                         if (input.IsXsltKeyword(atoms.Fallback)) {
2169                             XslFallback();
2170                         } else {
2171                             ReportError(/*[XT_017]*/Res.Xslt_UnexpectedElement, input.QualifiedName, parentName);
2172                             input.SkipNode();
2173                         }
2174                         break;
2175                     case XmlNodeType.Whitespace:
2176                     case XmlNodeType.SignificantWhitespace:
2177                         break;
2178                     default:
2179                         Debug.Assert(input.NodeType == XmlNodeType.Text);
2180                         ReportError(/*[XT_017]*/Res.Xslt_TextNodesNotAllowed, parentName);
2181                         break;
2182                     }
2183                 } while (input.MoveToNextSibling());
2184             }
2185             return null;
2186         }
2187
2188         // http://www.w3.org/TR/xslt20/#element-result-document
2189         XsltAttribute[] resultDocumentAttributes = {
2190             new XsltAttribute("format"                , V2Opt), // 0
2191             new XsltAttribute("href"                  , V2Opt), // 1
2192             new XsltAttribute("validation"            , V2Opt), // 2
2193             new XsltAttribute("type"                  , V2Opt), // 3
2194             new XsltAttribute("name"                  , V2Opt), // 4
2195             new XsltAttribute("method"                , V2Opt), // 5
2196             new XsltAttribute("byte-order-mark"       , V2Opt), // 6
2197             new XsltAttribute("cdata-section-elements", V2Opt), // 7
2198             new XsltAttribute("doctype-public"        , V2Opt), // 8
2199             new XsltAttribute("doctype-system"        , V2Opt), // 9
2200             new XsltAttribute("encoding"              , V2Opt), // 10
2201             new XsltAttribute("escape-uri-attributes" , V2Opt), // 11
2202             new XsltAttribute("include-content-type"  , V2Opt), // 12
2203             new XsltAttribute("indent"                , V2Opt), // 13
2204             new XsltAttribute("media-type"            , V2Opt), // 14
2205             new XsltAttribute("normalization-form"    , V2Opt), // 15
2206             new XsltAttribute("omit-xml-declaration"  , V2Opt), // 16
2207             new XsltAttribute("standalone"            , V2Opt), // 17
2208             new XsltAttribute("undeclare-prefixes"    , V2Opt), // 18
2209             new XsltAttribute("use-character-maps"    , V2Opt), // 19
2210             new XsltAttribute("output-version"        , V2Opt)  // 20
2211         };
2212         private XslNode XslResultDocument() {
2213             ContextInfo ctxInfo = input.GetAttributes(resultDocumentAttributes);
2214
2215             string format                  = ParseStringAttribute(0 , "format");
2216             XmlWriterSettings settings = new XmlWriterSettings(); // we should use attFormat to determing settings
2217             string href                    = ParseStringAttribute(1 , "href");
2218             ParseValidationAttribute(2, /*defVal:*/false);
2219             ParseTypeAttribute(3);
2220             QilName  name                  = ParseQNameAttribute( 4);
2221             TriState byteOrderMask         = ParseYesNoAttribute( 6 , "byte-order-mark");
2222             string   docTypePublic         = ParseStringAttribute(8 , "doctype-public");
2223             string   docTypeSystem         = ParseStringAttribute(9 , "doctype-system");
2224             bool     escapeUriAttributes   = ParseYesNoAttribute( 11, "escape-uri-attributes") != TriState.False;
2225             bool     includeContentType    = ParseYesNoAttribute( 12, "include-content-type") != TriState.False;
2226             settings.Indent                = ParseYesNoAttribute( 13, "indent") == TriState.True;
2227             string   mediaType             = ParseStringAttribute(14, "media-type");
2228             string   normalizationForm     = ParseStringAttribute(15, "normalization-form");
2229             settings.OmitXmlDeclaration    = ParseYesNoAttribute( 16, "omit-xml-declaration") == TriState.True;
2230             settings.Standalone            = ParseYesNoAttribute( 17, "standalone"        ) == TriState.True ? XmlStandalone.Yes : XmlStandalone.No;
2231             bool undeclarePrefixes         = ParseYesNoAttribute( 18, "undeclare-prefixes") == TriState.True;
2232             List<QilName> useCharacterMaps = ParseUseCharacterMaps(19);
2233             string   outputVersion         = ParseStringAttribute(20, "output-version");
2234
2235             ReportNYI("xsl:result-document");
2236
2237             if (format != null) ReportNYI("xsl:result-document/@format");
2238
2239             if (href == null) {
2240                 href = string.Empty;
2241             }
2242             // attHref is a BaseUri of new output tree. It should be resolved relative to "base output URI"
2243
2244
2245             if (input.MoveToXsltAttribute(5, "method")) {
2246                 compiler.EnterForwardsCompatible();
2247                 XmlOutputMethod   outputMethod;
2248                 ParseOutputMethod(input.Value, out outputMethod);
2249                 if (compiler.ExitForwardsCompatible(input.ForwardCompatibility)) {
2250                     settings.OutputMethod = outputMethod;
2251                 }
2252             }
2253             if (input.MoveToXsltAttribute(7, "cdata-section-elements")) {
2254                 // Do not check the import precedence, the effective value is the union of all specified values
2255                 compiler.EnterForwardsCompatible();
2256                 string[] qnames = XmlConvert.SplitString(input.Value);
2257                 List<XmlQualifiedName> list = new List<XmlQualifiedName>();
2258                 for (int i = 0; i < qnames.Length; i++) {
2259                     list.Add(ResolveQName(/*ignoreDefaultNs:*/false, qnames[i]));
2260                 }
2261                 if (compiler.ExitForwardsCompatible(input.ForwardCompatibility)) {
2262                     foreach (XmlQualifiedName qname in list) {
2263                         settings.CDataSectionElements.Add(qname);
2264                     }
2265                 }
2266             }
2267             if (input.MoveToXsltAttribute(10, "encoding")) {
2268                 try {
2269                     // Encoding.GetEncoding() should never throw NotSupportedException, only ArgumentException
2270                     settings.Encoding = Encoding.GetEncoding(input.Value);
2271                 } catch (ArgumentException) {
2272                     if (!input.ForwardCompatibility) {
2273                         ReportWarning(/*[XT_004]*/Res.Xslt_InvalidEncoding, input.Value);
2274                     }
2275                 }
2276             }
2277
2278             if (byteOrderMask != TriState.Unknown) ReportNYI("xsl:result-document/@byte-order-mark");
2279             if (!escapeUriAttributes) ReportNYI("xsl:result-document/@escape-uri-attributes == flase()");
2280             if (!includeContentType) ReportNYI("xsl:output/@include-content-type == flase()");
2281             if (normalizationForm != null) ReportNYI("xsl:result-document/@normalization-form");
2282             if (undeclarePrefixes) ReportNYI("xsl:result-document/@undeclare-prefixes == true()");
2283
2284             if (docTypePublic != null) {
2285                 settings.DocTypePublic = docTypePublic;
2286             }
2287
2288             if (docTypeSystem != null) {
2289                 settings.DocTypeSystem = docTypeSystem;
2290             }
2291             if (mediaType != null) {
2292                 settings.MediaType = mediaType;
2293             }
2294
2295             if (useCharacterMaps != null) ReportNYI("xsl:result-document/@use-character-maps");
2296
2297             if (outputVersion != null) {
2298                 // 
2299
2300                 ReportNYI("xsl:result-document/@output-version");
2301             }
2302
2303             LoadInstructions();
2304             return null;
2305         }
2306 #endif
2307
2308         // http://www.w3.org/TR/xslt#literal-result-element
2309         private XslNode LoadLiteralResultElement(bool asStylesheet) {
2310             Debug.Assert(input.NodeType == XmlNodeType.Element);
2311             string prefix   = input.Prefix;
2312             string name     = input.LocalName;
2313             string nsUri    = input.NamespaceUri;
2314
2315             ContextInfo ctxInfo = input.GetLiteralAttributes(asStylesheet);
2316
2317             if (input.IsExtensionNamespace(nsUri)) {
2318                 // This is not a literal result element, so drop all attributes we have collected
2319                 return SetInfo(f.List(), LoadFallbacks(name), ctxInfo);
2320             }
2321
2322             List<XslNode> content = new List<XslNode>();
2323
2324             for (int i = 1; input.MoveToLiteralAttribute(i); i++) {
2325                 if (input.IsXsltNamespace() && input.IsKeyword(atoms.UseAttributeSets)) {
2326                     AddUseAttributeSets(content);
2327                 }
2328             }
2329
2330             for (int i = 1; input.MoveToLiteralAttribute(i); i++) {
2331                 if (! input.IsXsltNamespace()) {
2332                     XslNode att = f.LiteralAttribute(f.QName(input.LocalName, input.NamespaceUri, input.Prefix), input.Value, input.XslVersion);
2333                     // QilGenerator takes care of AVTs, and needs line info
2334                     AddInstruction(content, SetLineInfo(att, ctxInfo.lineInfo));
2335                 } else {
2336                     // ignore all other xslt attributes. See XslInput.GetLiteralAttributes()
2337                 }
2338             }
2339
2340             content = LoadEndTag(LoadInstructions(content));
2341             return SetInfo(f.LiteralElement(f.QName(name, nsUri, prefix)), content, ctxInfo);
2342         }
2343
2344         private void CheckWithParam(List<XslNode> content, XslNode withParam) {
2345             Debug.Assert(content != null && withParam != null);
2346             Debug.Assert(withParam.NodeType == XslNodeType.WithParam);
2347             foreach (XslNode node in content) {
2348                 if (node.NodeType == XslNodeType.WithParam && node.Name.Equals(withParam.Name)) {
2349                     ReportError(/*[XT0670]*/Res.Xslt_DuplicateWithParam, withParam.Name.QualifiedName);
2350                     break;
2351                 }
2352             }
2353         }
2354
2355         private static void AddInstruction(List<XslNode> content, XslNode instruction) {
2356             Debug.Assert(content != null);
2357             if (instruction != null) {
2358                 content.Add(instruction);
2359             }
2360         }
2361
2362         private List<XslNode> LoadEndTag(List<XslNode> content) {
2363             Debug.Assert(content != null);
2364             if (compiler.IsDebug && !input.IsEmptyElement) {
2365                 AddInstruction(content, SetLineInfo(f.Nop(), input.BuildLineInfo()));
2366             }
2367             return content;
2368         }
2369
2370         private XslNode LoadUnknownXsltInstruction(string parentName) {
2371             input.GetVersionAttribute();
2372             if (!input.ForwardCompatibility) {
2373                 ReportError(/*[XT_026]*/Res.Xslt_UnexpectedElement, input.QualifiedName, parentName);
2374                 input.SkipNode();
2375                 return null;
2376             } else {
2377                 ContextInfo ctxInfo = input.GetAttributes();
2378                 List<XslNode> fallbacks = LoadFallbacks(input.LocalName);
2379                 return SetInfo(f.List(), fallbacks, ctxInfo);
2380             }
2381         }
2382
2383         private List<XslNode> LoadFallbacks(string instrName) {
2384             input.MoveToElement();
2385             ISourceLineInfo extElmLineInfo = input.BuildNameLineInfo();
2386             List<XslNode> fallbacksArray = new List<XslNode>();
2387             // 
2388             /* Process children */
2389             if (input.MoveToFirstChild()) {
2390                 do {
2391                     if (input.IsXsltKeyword(atoms.Fallback)) {
2392                         ContextInfo ctxInfo = input.GetAttributes();
2393                         fallbacksArray.Add(SetInfo(f.List(), LoadInstructions(), ctxInfo));
2394                     } else {
2395                         input.SkipNode();
2396                     }
2397                 } while (input.MoveToNextSibling());
2398             }
2399
2400             // Generate runtime error if there is no fallbacks
2401             if (fallbacksArray.Count == 0) {
2402                 fallbacksArray.Add(
2403                     f.Error(XslLoadException.CreateMessage(extElmLineInfo, Res.Xslt_UnknownExtensionElement, instrName))
2404                 );
2405             }
2406             return fallbacksArray;
2407         }
2408
2409         // ------------------ little helper methods ---------------------
2410
2411         // Suppresses errors if FCB is enabled
2412         private QilName ParseModeAttribute(int attNum) {
2413             //Debug.Assert(
2414             //    input.IsXsltKeyword(atoms.ApplyTemplates) ||
2415             //    input.IsXsltKeyword(atoms.Template) && V1
2416             //);
2417             if (! input.MoveToXsltAttribute(attNum, "mode")) {
2418                 return nullMode;
2419             }
2420             // mode is always optional attribute
2421             compiler.EnterForwardsCompatible();
2422             string qname = input.Value;
2423             QilName mode;
2424             if (!V1 && qname == "#default") {
2425                 mode = nullMode;
2426             } else if (!V1 && qname == "#current") {
2427                 ReportNYI("xsl:apply-templates[@mode='#current']");
2428                 mode = nullMode;
2429             } else if (!V1 && qname == "#all") {
2430                 ReportError(Res.Xslt_ModeListAll);
2431                 mode = nullMode;
2432             } else {
2433                 mode = CreateXPathQName(qname);
2434             }
2435             if (!compiler.ExitForwardsCompatible(input.ForwardCompatibility)) {
2436                 mode = nullMode;
2437             }
2438             return mode;
2439         }
2440
2441         // Parse mode when it is list. V1: -, V2: xsl:template
2442         // Suppresses errors if FCB is enabled
2443         private QilName ParseModeListAttribute(int attNum) {
2444             //Debug.Assert(input.IsXsltKeyword(atoms.Template) && !V1);
2445             if (! input.MoveToXsltAttribute(attNum, "mode")) {
2446                 return nullMode;
2447             }
2448
2449             string modeList = input.Value;
2450             if (modeList == "#all") {
2451                 ReportNYI("xsl:template[@mode='#all']");
2452                 return nullMode;
2453             } else {
2454                 string[] list = XmlConvert.SplitString(modeList);
2455                 List<QilName> modes = new List<QilName>(list.Length);
2456
2457                 compiler.EnterForwardsCompatible();  // mode is always optional attribute
2458
2459                 if (list.Length == 0) {
2460                     ReportError(Res.Xslt_ModeListEmpty);
2461                 } else {
2462                     foreach (string qname in list) {
2463                         QilName mode;
2464                         if (qname == "#default") {
2465                             mode = nullMode;
2466                         } else if (qname == "#current") {
2467                             ReportNYI("xsl:apply-templates[@mode='#current']");
2468                             break;
2469                         } else if (qname == "#all") {
2470                             ReportError(Res.Xslt_ModeListAll);
2471                             break;
2472                         } else {
2473                             mode = CreateXPathQName(qname);
2474                         }
2475                         bool dup = false;
2476                         foreach (QilName m in modes) {
2477                             dup |= m.Equals(mode);
2478                         }
2479                         if (dup) {
2480                             ReportError(Res.Xslt_ModeListDup, qname);
2481                         } else {
2482                             modes.Add(mode);
2483                         }
2484                     }
2485                 }
2486
2487                 if (!compiler.ExitForwardsCompatible(input.ForwardCompatibility)) {
2488                     modes.Clear();
2489                     modes.Add(nullMode);
2490                 }
2491                 if (1 < modes.Count) {
2492                     ReportNYI("Multipe modes");
2493                     return nullMode;
2494                 }
2495                 if (modes.Count == 0) {
2496                     return nullMode;
2497                 }
2498                 return modes[0];
2499             }
2500         }
2501
2502         private string ParseCollationAttribute(int attNum) {
2503             if (input.MoveToXsltAttribute(attNum, "collation")) {
2504                 ReportNYI("@collation");
2505             }
2506             return null;
2507         }
2508
2509         // Does not suppress errors
2510         private bool ResolveQName(bool ignoreDefaultNs, string qname, out string localName, out string namespaceName, out string prefix) {
2511             if (qname == null) {
2512                 // That means stylesheet is incorrect
2513                 prefix = compiler.PhantomNCName;
2514                 localName = compiler.PhantomNCName;
2515                 namespaceName = compiler.CreatePhantomNamespace();
2516                 return false;
2517             }
2518             if (!compiler.ParseQName(qname, out prefix, out localName, (IErrorHelper)this)) {
2519                 namespaceName = compiler.CreatePhantomNamespace();
2520                 return false;
2521             }
2522             if (ignoreDefaultNs && prefix.Length == 0) {
2523                 namespaceName = string.Empty;
2524             } else {
2525                 namespaceName = input.LookupXmlNamespace(prefix);
2526                 if (namespaceName == null) {
2527                     namespaceName = compiler.CreatePhantomNamespace();
2528                     return false;
2529                 }
2530             }
2531             return true;
2532         }
2533
2534         // Does not suppress errors
2535         private QilName ParseQNameAttribute(int attNum) {
2536             bool required = input.IsRequiredAttribute(attNum);
2537             QilName result = null;
2538             if (!required) {
2539                 compiler.EnterForwardsCompatible();
2540             }
2541             if (input.MoveToXsltAttribute(attNum, "name")) {
2542                 string prefix, localName, namespaceName;
2543                 if (ResolveQName(/*ignoreDefaultNs:*/true, input.Value, out localName, out namespaceName, out prefix)) {
2544                     result = f.QName(localName, namespaceName, prefix);
2545                 }
2546             }
2547             if (!required) {
2548                 compiler.ExitForwardsCompatible(input.ForwardCompatibility);
2549             }
2550             if (result == null && required) {
2551                 result = f.QName(compiler.PhantomNCName, compiler.CreatePhantomNamespace(), compiler.PhantomNCName);
2552             }
2553             return result;
2554         }
2555
2556         private string ParseNCNameAttribute(int attNum) {
2557             Debug.Assert(input.IsRequiredAttribute(attNum), "It happened that @name as NCName is always required attribute");
2558             if (input.MoveToXsltAttribute(attNum, "name")) {
2559                 return input.Value;
2560             }
2561             return compiler.PhantomNCName;
2562         }
2563
2564         // Does not suppress errors
2565         private QilName CreateXPathQName(string qname) {
2566             string prefix, localName, namespaceName;
2567             ResolveQName(/*ignoreDefaultNs:*/true, qname, out localName, out namespaceName, out prefix);
2568             return f.QName(localName, namespaceName, prefix);
2569         }
2570
2571         // Does not suppress errors
2572         private XmlQualifiedName ResolveQName(bool ignoreDefaultNs, string qname) {
2573             string prefix, localName, namespaceName;
2574             ResolveQName(ignoreDefaultNs, qname, out localName, out namespaceName, out prefix);
2575             return new XmlQualifiedName(localName, namespaceName);
2576         }
2577
2578         // Does not suppress errors
2579         private void ParseWhitespaceRules(string elements, bool preserveSpace) {
2580             if (elements != null && elements.Length != 0) {
2581                 string[] tokens = XmlConvert.SplitString(elements);
2582                 for (int i = 0; i < tokens.Length; i++) {
2583                     string prefix, localName, namespaceName;
2584                     if (!compiler.ParseNameTest(tokens[i], out prefix, out localName, (IErrorHelper)this)) {
2585                         namespaceName = compiler.CreatePhantomNamespace();
2586                     } else if (prefix == null || prefix.Length == 0) {
2587                         namespaceName = prefix;
2588                     } else {
2589                         namespaceName = input.LookupXmlNamespace(prefix);
2590                         if (namespaceName == null) {
2591                             namespaceName = compiler.CreatePhantomNamespace();
2592                         }
2593                     }
2594                     int index = (
2595                         (localName     == null ? 1 : 0) +
2596                         (namespaceName == null ? 1 : 0)
2597                     );
2598                     curStylesheet.AddWhitespaceRule(index, new WhitespaceRule(localName, namespaceName, preserveSpace));
2599                 }
2600             }
2601         }
2602
2603         // Does not suppress errors.  In case of error, null is returned.
2604         private XmlQualifiedName ParseOutputMethod(string attValue, out XmlOutputMethod method) {
2605             string prefix, localName, namespaceName;
2606             ResolveQName(/*ignoreDefaultNs:*/true, attValue, out localName, out namespaceName, out prefix);
2607             method = XmlOutputMethod.AutoDetect;
2608
2609             if (compiler.IsPhantomNamespace(namespaceName)) {
2610                 return null;
2611             } else if (prefix.Length == 0) {
2612                 switch (localName) {
2613                 case "xml"  : method = XmlOutputMethod.Xml;  break;
2614                 case "html" : method = XmlOutputMethod.Html; break;
2615                 case "text" : method = XmlOutputMethod.Text; break;
2616                 default:
2617                     ReportError(/*[XT1570]*/Res.Xslt_InvalidAttrValue, "method", attValue);
2618                     return null;
2619                 }
2620             } else {
2621                 if (!input.ForwardCompatibility) {
2622                     ReportWarning(/*[XT1570]*/Res.Xslt_InvalidMethod, attValue);
2623                 }
2624             }
2625             return new XmlQualifiedName(localName, namespaceName);
2626         }
2627
2628         // Suppresses errors if FCB is enabled
2629         private void AddUseAttributeSets(List<XslNode> list) {
2630             Debug.Assert(input.LocalName == "use-attribute-sets", "we are positioned on this attribute");
2631             Debug.Assert(list != null && list.Count == 0, "It happened that we always add use-attribute-sets first. Otherwise we can't call list.Clear()");
2632
2633             compiler.EnterForwardsCompatible();
2634             foreach (string qname in XmlConvert.SplitString(input.Value)) {
2635                 AddInstruction(list, SetLineInfo(f.UseAttributeSet(CreateXPathQName(qname)), input.BuildLineInfo()));
2636             }
2637             if (!compiler.ExitForwardsCompatible(input.ForwardCompatibility)) {
2638                 // There were errors in the list, ignore the whole list
2639                 list.Clear();
2640             }
2641         }
2642
2643         private List<QilName> ParseUseCharacterMaps(int attNum) {
2644             List<QilName> useCharacterMaps = new List<QilName>();
2645             if (input.MoveToXsltAttribute(attNum, "use-character-maps")) {
2646                 compiler.EnterForwardsCompatible();
2647                 foreach (string qname in XmlConvert.SplitString(input.Value)) {
2648                     useCharacterMaps.Add(CreateXPathQName(qname));
2649                 }
2650                 if (!compiler.ExitForwardsCompatible(input.ForwardCompatibility)) {
2651                     useCharacterMaps.Clear(); // There were errors in the list, ignore the whole list
2652                 }
2653             }
2654             return useCharacterMaps;
2655         }
2656
2657         private string ParseStringAttribute(int attNum, string attName) {
2658             if (input.MoveToXsltAttribute(attNum, attName)) {
2659                 return input.Value;
2660             }
2661             return null;
2662         }
2663
2664         private char ParseCharAttribute(int attNum, string attName, char defVal) {
2665             if (input.MoveToXsltAttribute(attNum, attName)) {
2666                 if (input.Value.Length == 1) {
2667                     return input.Value[0];
2668                 } else {
2669                     if (input.IsRequiredAttribute(attNum) || !input.ForwardCompatibility) {
2670                         ReportError(/*[XT_029]*/Res.Xslt_CharAttribute, attName);
2671                     }
2672                 }
2673             }
2674             return defVal;
2675         }
2676
2677         // Suppresses errors if FCB is enabled
2678         private TriState ParseYesNoAttribute(int attNum, string attName) {
2679             Debug.Assert(!input.IsRequiredAttribute(attNum), "All Yes/No attributes are optional.");
2680             if (input.MoveToXsltAttribute(attNum, attName)) {
2681                 switch (input.Value) {
2682                 case "yes" : return TriState.True;
2683                 case "no"  : return TriState.False;
2684                 default:
2685                     if (!input.ForwardCompatibility) {
2686                         ReportError(/*[XT_028]*/Res.Xslt_BistateAttribute, attName, "yes", "no");
2687                     }
2688                     break;
2689                 }
2690             }
2691             return TriState.Unknown;
2692         }
2693
2694         private void ParseTypeAttribute(int attNum) {
2695             Debug.Assert(!input.IsRequiredAttribute(attNum), "All 'type' attributes are optional.");
2696             if (input.MoveToXsltAttribute(attNum, "type")) {
2697                 CheckError(true, /*[???]*/Res.Xslt_SchemaAttribute, "type");
2698             }
2699         }
2700
2701         private void ParseValidationAttribute(int attNum, bool defVal) {
2702             Debug.Assert(!input.IsRequiredAttribute(attNum), "All 'validation' attributes are optional.");
2703             string attributeName = defVal ? atoms.DefaultValidation : "validation";
2704             if (input.MoveToXsltAttribute(attNum, attributeName)) {
2705                 string value = input.Value;
2706                 if (value == "strip") {
2707                     // no error
2708                 } else if (
2709                     value == "preserve" ||
2710                     value == "strict" && !defVal ||
2711                     value == "lax" && !defVal
2712                 ) {
2713                     ReportError(/*[???]*/Res.Xslt_SchemaAttributeValue, attributeName, value);
2714                 } else if (!input.ForwardCompatibility) {
2715                     ReportError(/*[???]*/Res.Xslt_InvalidAttrValue, attributeName, value);
2716                 }
2717             }
2718         }
2719
2720         private void ParseInputTypeAnnotationsAttribute(int attNum) {
2721             Debug.Assert(!input.IsRequiredAttribute(attNum), "All 'input-type-validation' attributes are optional.");
2722             if (input.MoveToXsltAttribute(attNum, "input-type-annotations")) {
2723                 string value = input.Value;
2724                 switch (value) {
2725                 case "unspecified":
2726                     break;
2727                 case "strip":
2728                 case "preserve":
2729                     if (compiler.inputTypeAnnotations == null) {
2730                         compiler.inputTypeAnnotations = value;
2731                     } else {
2732                         CheckError(compiler.inputTypeAnnotations != value, /*[XTSE0265]*/Res.Xslt_InputTypeAnnotations);
2733                     }
2734                     break;
2735                 default:
2736                     if (!input.ForwardCompatibility) {
2737                         ReportError(/*[???]*/Res.Xslt_InvalidAttrValue, "input-type-annotations", value);
2738                     }
2739                     break;
2740                 }
2741             }
2742         }
2743
2744
2745         // ToDo: We don't need separation on SkipEmptyContent() and CheckNoContent(). Merge them back when we are done with parsing.
2746         private void CheckNoContent() {
2747             input.MoveToElement();
2748             QName parentName = input.ElementName;
2749             ISourceLineInfo errorLineInfo = SkipEmptyContent();
2750
2751             if (errorLineInfo != null) {
2752                 compiler.ReportError(errorLineInfo, /*[XT0260]*/Res.Xslt_NotEmptyContents, parentName);
2753             }
2754         }
2755
2756         // Returns ISourceLineInfo of the first violating (non-whitespace) node, or null otherwise
2757         private ISourceLineInfo SkipEmptyContent() {
2758             ISourceLineInfo result = null;
2759
2760             // Really EMPTY means no content at all, but for the sake of compatibility with MSXML we allow whitespaces
2761             if (input.MoveToFirstChild()) {
2762                 do {
2763                     // NOTE: XmlNodeType.SignificantWhitespace are not allowed here
2764                     if (input.NodeType != XmlNodeType.Whitespace) {
2765                         if (result == null) {
2766                             result = input.BuildNameLineInfo();
2767                         }
2768                         input.SkipNode();
2769                     }
2770                 } while (input.MoveToNextSibling());
2771             }
2772             return result;
2773         }
2774
2775         private static XslNode SetLineInfo(XslNode node, ISourceLineInfo lineInfo) {
2776             Debug.Assert(node != null);
2777             node.SourceLine = lineInfo;
2778             return node;
2779         }
2780
2781         private static void SetContent(XslNode node, List<XslNode> content) {
2782             Debug.Assert(node != null);
2783             if (content != null && content.Count == 0) {
2784                 content = null; // Actualy we can reuse this ArrayList.
2785             }
2786             node.SetContent(content);
2787         }
2788
2789         internal static XslNode SetInfo(XslNode to, List<XslNode> content, ContextInfo info) {
2790             Debug.Assert(to != null);
2791             to.Namespaces = info.nsList;
2792             SetContent(to, content);
2793             SetLineInfo(to, info.lineInfo);
2794             return to;
2795         }
2796
2797         // NOTE! We inverting namespace order that is irelevant for namespace of the same node, but
2798         // for included styleseets we don't keep stylesheet as a node and adding it's namespaces to
2799         // each toplevel element by MergeNamespaces().
2800         // Namespaces of stylesheet can be overriden in template and to make this works correclety we
2801         // should attache them after NsDec of top level elements.
2802         // Toplevel element almost never contais NsDecl and in practice node duplication will not happened, but if they have
2803         // we should copy NsDecls of stylesheet localy in toplevel elements.
2804         private static NsDecl MergeNamespaces(NsDecl thisList, NsDecl parentList) {
2805             if (parentList == null) {
2806                 return thisList;
2807             }
2808             if (thisList == null) {
2809                 return parentList;
2810             }
2811             // Clone all nodes and attache them to nodes of thisList;
2812             while (parentList != null) {
2813                 bool duplicate = false;
2814                 for (NsDecl tmp = thisList; tmp != null; tmp = tmp.Prev) {
2815                     if (Ref.Equal(tmp.Prefix, parentList.Prefix) && (
2816                         tmp.Prefix != null ||           // Namespace declaration
2817                         tmp.NsUri == parentList.NsUri   // Extension or excluded namespace
2818                     )) {
2819                         duplicate = true;
2820                         break;
2821                     }
2822                 }
2823                 if (!duplicate) {
2824                     thisList = new NsDecl(thisList, parentList.Prefix, parentList.NsUri);
2825                 }
2826                 parentList = parentList.Prev;
2827             }
2828             return thisList;
2829         }
2830
2831         // -------------------------------- IErrorHelper --------------------------------
2832
2833         public void ReportError(string res, params string[] args) {
2834             compiler.ReportError(input.BuildNameLineInfo(), res, args);
2835         }
2836
2837         public void ReportWarning(string res, params string[] args) {
2838             compiler.ReportWarning(input.BuildNameLineInfo(), res, args);
2839         }
2840
2841         private void ReportNYI(string arg) {
2842             if (! input.ForwardCompatibility) {
2843                 ReportError(Res.Xslt_NotYetImplemented, arg);
2844             }
2845         }
2846
2847         public void CheckError(bool cond, string res, params string[] args) {
2848             if (cond) {
2849                 compiler.ReportError(input.BuildNameLineInfo(), res, args);
2850             }
2851         }
2852     }
2853 }