Updates referencesource to .NET 4.7
[mono-project.git] / mcs / class / referencesource / System.Data.SqlXml / System / Xml / Xsl / Xslt / XsltLoader.cs
blobc2037e36f1d423a51d14b1e959261ae592d6f8ce
1 //------------------------------------------------------------------------------
2 // <copyright file="XsltLoader.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
4 // </copyright>
5 // <owner current="true" primary="true">Microsoft</owner>
6 //------------------------------------------------------------------------------
8 //#define XSLT2
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;
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;
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
39 internal static QilName nullMode = f.QName(string.Empty);
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;
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;
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.
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);
72 readerSettings = new QueryReaderSettings(new NameTable());
73 using (reader = CreateReader(resolvedUri, origResolver)) {
74 Load(reader);
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");
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
95 private void Load(XmlReader reader) {
96 this.atoms = new KeywordsTable(reader.NameTable);
97 AtomizeAttributes();
98 LoadStylesheet(reader, /*include:*/false);
102 void AtomizeAttributes(XsltAttribute[] attributes) {
103 for(int i = 0; i < attributes.Length; i ++) {
104 attributes[i].name = atoms.NameTable.Add(attributes[i].name);
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
153 private bool V1 { get {
154 Debug.Assert(compiler.Version != 0, "Version should be already decided at this point");
155 return compiler.Version == 1;
157 #if XSLT2
158 private bool V2 { get { return ! V1; } }
159 #endif
161 // Import/Include XsltInput management
163 private HybridDictionary documentUriInUse = new HybridDictionary();
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);
173 return resolvedUri;
176 private XmlReader CreateReader(Uri uri, XmlResolver xmlResolver) {
177 object input = xmlResolver.GetEntity(uri, null, null);
179 Stream stream = input as Stream;
180 if (stream != null) {
181 return readerSettings.CreateReader(stream, uri.ToString());
184 XmlReader reader = input as XmlReader;
185 if (reader != null) {
186 return reader;
189 IXPathNavigable navigable = input as IXPathNavigable;
190 if (navigable != null) {
191 return XPathNavigatorReader.Create(navigable.CreateNavigator());
194 throw new XslLoadException(Res.Xslt_CannotLoadStylesheet, uri.ToString(), input == null ? "null" : input.GetType().ToString());
197 private Stylesheet LoadStylesheet(Uri uri, bool include) {
198 using (XmlReader reader = CreateReader(uri, this.xmlResolver)) {
199 return LoadStylesheet(reader, include);
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);
209 Stylesheet prevStylesheet = curStylesheet;
210 XsltInput prevInput = input;
211 Stylesheet thisStylesheet = include ? curStylesheet : compiler.CreateStylesheet();
213 input = new XsltInput(reader, compiler, atoms);
214 curStylesheet = thisStylesheet;
216 try {
217 LoadDocument();
218 if (!include) {
219 compiler.MergeWithStylesheet(curStylesheet);
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);
229 catch (XslLoadException) {
230 throw;
232 catch (Exception e) {
233 if (!XmlException.IsCatchableException(e)) {
234 throw;
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()
243 throw new XslLoadException(e, lineInfo);
245 finally {
246 documentUriInUse.Remove(baseUri);
247 input = prevInput;
248 curStylesheet = prevStylesheet;
250 return thisStylesheet;
253 private void LoadDocument() {
254 if (!input.FindStylesheetElement()) {
255 ReportError(/*[XT_002]*/Res.Xslt_WrongStylesheetElement);
256 return;
258 Debug.Assert(input.NodeType == XmlNodeType.Element);
259 if (input.IsXsltNamespace()) {
260 if (
261 input.IsKeyword(atoms.Stylesheet) ||
262 input.IsKeyword(atoms.Transform)
264 LoadRealStylesheet();
265 } else {
266 ReportError(/*[XT_002]*/Res.Xslt_WrongStylesheetElement);
267 input.SkipNode();
269 } else {
270 LoadSimplifiedStylesheet();
272 input.Finish();
275 private void LoadSimplifiedStylesheet() {
276 Debug.Assert(!input.IsXsltNamespace());
277 Debug.Assert(curTemplate == null);
279 // Prefix will be fixed later in LoadLiteralResultElement()
280 curTemplate = f.Template(/*name:*/null, /*match:*/"/", /*mode:*/nullMode, /*priority:*/double.NaN, input.XslVersion);
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);
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");
295 curTemplate = null;
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),
304 private void LoadRealStylesheet() {
305 Debug.Assert(input.IsXsltNamespace() && (input.IsKeyword(atoms.Stylesheet) || input.IsKeyword(atoms.Transform)));
306 ContextInfo ctxInfo = input.GetAttributes(stylesheetAttributes);
308 ParseValidationAttribute(2, /*defVal:*/true);
309 ParseInputTypeAnnotationsAttribute(3);
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();
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);
362 input.SkipNode();
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);
370 // Ignoring non-recognized namespace per XSLT spec 2.2
371 input.SkipNode();
373 atTop = isImport;
374 break;
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;
384 } while (input.MoveToNextSibling());
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);
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);
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);
407 } else {
408 // The error was already reported. Ignore the instruction
411 CheckNoContent();
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);
421 if (input.MoveToXsltAttribute(0, "href")) {
423 Uri uri = ResolveUri(input.Value, input.BaseUri);
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);
431 } else {
432 // The error was already reported. Ignore the instruction
435 CheckNoContent();
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);
443 if (input.MoveToXsltAttribute(0, atoms.Elements)) {
444 ParseWhitespaceRules(input.Value, false);
446 CheckNoContent();
449 private void LoadPreserveSpace(NsDecl stylesheetNsList) {
450 ContextInfo ctxInfo = input.GetAttributes(loadStripSpaceAttributes);
451 ctxInfo.nsList = MergeNamespaces(ctxInfo.nsList, stylesheetNsList);
453 if (input.MoveToXsltAttribute(0, atoms.Elements)) {
454 ParseWhitespaceRules(input.Value, true);
456 CheckNoContent();
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)
478 private void LoadOutput() {
479 ContextInfo ctxInfo = input.GetAttributes(outputAttributes);
481 Output output = compiler.Output;
482 XmlWriterSettings settings = output.Settings;
483 int currentPrec = compiler.CurrentPrecedence;
484 TriState triState;
486 QilName name = ParseQNameAttribute(0);
487 if (name != null) ReportNYI("xsl:output/@name");
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");
498 settings.OutputMethod = outputMethod;
499 output.Method = method;
500 output.MethodPrec = currentPrec;
505 TriState byteOrderMask = ParseYesNoAttribute(2, "byte-order-mark");
506 if (byteOrderMask != TriState.Unknown) ReportNYI("xsl:output/@byte-order-mark");
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]));
516 if (compiler.ExitForwardsCompatible(input.ForwardCompatibility)) {
517 settings.CDataSectionElements.AddRange(list);
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");
526 settings.DocTypePublic = input.Value;
527 output.DocTypePublicPrec = currentPrec;
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");
536 settings.DocTypeSystem = input.Value;
537 output.DocTypeSystemPrec = currentPrec;
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");
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);
560 bool escapeUriAttributes = ParseYesNoAttribute(7, "escape-uri-attributes") != TriState.False;
561 if (! escapeUriAttributes) ReportNYI("xsl:output/@escape-uri-attributes == flase()");
563 bool includeContentType = ParseYesNoAttribute(8, "include-content-type") != TriState.False;
564 if (!includeContentType) ReportNYI("xsl:output/@include-content-type == flase()");
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");
573 settings.Indent = indent;
574 output.IndentPrec = currentPrec;
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");
583 settings.MediaType = input.Value;
584 output.MediaTypePrec = currentPrec;
588 if (input.MoveToXsltAttribute(11, "normalization-form")) {
589 ReportNYI("xsl:output/@normalization-form");
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");
599 settings.OmitXmlDeclaration = omitXmlDeclaration;
600 output.OmitXmlDeclarationPrec = currentPrec;
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");
611 settings.Standalone = standalone;
612 output.StandalonePrec = currentPrec;
616 bool undeclarePrefixes = ParseYesNoAttribute(14, "undeclare-prefixes") == TriState.True;
617 if (undeclarePrefixes) ReportNYI("xsl:output/@undeclare-prefixes == true()");
619 List<QilName> useCharacterMaps = ParseUseCharacterMaps(15);
620 if (useCharacterMaps.Count != 0) ReportNYI("xsl:output/@use-character-maps");
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");
629 output.Version = input.Value;
630 output.VersionPrec = currentPrec;
634 CheckNoContent();
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"
642 private void ProcessOutputSettings() {
643 Output output = compiler.Output;
644 XmlWriterSettings settings = output.Settings;
646 // version is ignored, indent="no" by default
647 if (settings.OutputMethod == XmlOutputMethod.Html && output.IndentPrec == Output.NeverDeclaredPrec) {
648 settings.Indent = true;
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;
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.
668 break;
669 case XslNodeType.List:
670 CheckUseAttrubuteSetInList(xslNode.Content);
671 break;
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;
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)
700 private void LoadKey(NsDecl stylesheetNsList) {
701 ContextInfo ctxInfo = input.GetAttributes(keyAttributes);
702 ctxInfo.nsList = MergeNamespaces(ctxInfo.nsList, stylesheetNsList);
704 QilName keyName = ParseQNameAttribute( 0);
705 string match = ParseStringAttribute( 1, "match");
706 string use = ParseStringAttribute( 2, "use");
707 string collation = ParseCollationAttribute(3);
709 input.MoveToElement();
711 List<XslNode> content = null;
713 if (V1) {
714 if (use == null) {
715 input.SkipNode();
716 } else {
717 CheckNoContent();
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);
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]");
732 Key key = (Key)SetInfo(f.Key(keyName, match, use, input.XslVersion), null, ctxInfo);
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);
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)
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);
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();
770 } else {
771 // Use name="" for the default decimal-format
772 name = new XmlQualifiedName();
775 string infinity = DecimalFormatDecl.Default.InfinitySymbol;
776 if (input.MoveToXsltAttribute(1, "infinity")) {
777 infinity = input.Value;
780 string nan = DecimalFormatDecl.Default.NanSymbol;
781 if (input.MoveToXsltAttribute(2, "NaN")) {
782 nan = input.Value;
785 char[] DefaultValues = DecimalFormatDecl.Default.Characters;
786 char[] characters = new char[NumCharAttrs];
787 Debug.Assert(NumCharAttrs == DefaultValues.Length);
789 for (int idx = 0; idx < NumCharAttrs; idx++) {
790 characters[idx] = ParseCharAttribute(3 + idx, decimalFormatAttributes[3 + idx].name, DefaultValues[idx]);
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;
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]));
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);
823 CheckNoContent();
826 XsltAttribute[] namespaceAliasAttributes = {
827 new XsltAttribute("stylesheet-prefix", V1Req | V2Req),
828 new XsltAttribute("result-prefix" , V1Req | V2Req)
830 private void LoadNamespaceAlias(NsDecl stylesheetNsList) {
831 ContextInfo ctxInfo = input.GetAttributes(namespaceAliasAttributes);
832 ctxInfo.nsList = MergeNamespaces(ctxInfo.nsList, stylesheetNsList);
834 string stylesheetNsUri = null;
835 string resultPrefix = null;
836 string resultNsUri = null;
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);
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);
855 CheckNoContent();
857 if (stylesheetNsUri == null || resultNsUri == null) {
858 // At least one of attributes is missing or invalid
859 return;
861 if (compiler.SetNsAlias(stylesheetNsUri, resultNsUri, resultPrefix, curStylesheet.ImportPrecedence)) {
862 // Namespace alias redefinition
863 input.MoveToElement();
864 ReportWarning(/*[XT0810]*/Res.Xslt_DupNsAlias, stylesheetNsUri);
868 XsltAttribute[] attributeSetAttributes = {
869 new XsltAttribute("name" , V1Req | V2Req),
870 new XsltAttribute("use-attribute-sets", V1Opt | V2Opt)
872 private void LoadAttributeSet(NsDecl stylesheetNsList) {
873 ContextInfo ctxInfo = input.GetAttributes(attributeSetAttributes);
874 ctxInfo.nsList = MergeNamespaces(ctxInfo.nsList, stylesheetNsList);
876 QilName setName = ParseQNameAttribute(0);
877 Debug.Assert(setName != null, "Required attribute always != null");
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);
891 List<XslNode> content = new List<XslNode>();
892 if (input.MoveToXsltAttribute(1, "use-attribute-sets")) {
893 AddUseAttributeSets(content);
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();
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;
917 } while (input.MoveToNextSibling());
919 set.AddContent(SetInfo(f.List(), LoadEndTag(content), ctxInfo));
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);
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)
939 private void LoadTemplate(NsDecl stylesheetNsList) {
940 Debug.Assert(curTemplate == null);
941 ContextInfo ctxInfo = input.GetAttributes(templateAttributes);
942 ctxInfo.nsList = MergeNamespaces(ctxInfo.nsList, stylesheetNsList);
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);
953 QilName mode = V1 ? ParseModeAttribute(3) : ParseModeListAttribute(3);
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);
968 if (input.MoveToXsltAttribute(4, "as")) {
969 ReportNYI("xsl:template/@as");
972 curTemplate = f.Template(name, match, mode, priority, input.XslVersion);
974 // Template without match considered to not have mode and can't call xsl:apply-imports
975 input.CanHaveApplyImports = (match != null);
977 SetInfo(curTemplate,
978 LoadEndTag(LoadInstructions(InstructionFlags.AllowParam)), ctxInfo
981 if (!curStylesheet.AddTemplate(curTemplate)) {
982 ReportError(/*[XT0660]*/Res.Xslt_DupTemplateName, curTemplate.Name.QualifiedName);
984 curTemplate = null;
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)
993 XsltAttribute[] outputCharacterAttributes = {
994 new XsltAttribute("character", V2Req),
995 new XsltAttribute("string" , V2Req)
997 private void LoadCharacterMap(NsDecl stylesheetNsList) {
998 ContextInfo ctxInfo = input.GetAttributes(characterMapAttributes);
999 ctxInfo.nsList = MergeNamespaces(ctxInfo.nsList, stylesheetNsList);
1001 QilName name = ParseQNameAttribute(0);
1002 List<QilName> useCharacterMaps = ParseUseCharacterMaps(1);
1004 ReportNYI("xsl:character-map");
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();
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;
1031 } while (input.MoveToNextSibling());
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)
1041 private void LoadFunction(NsDecl stylesheetNsList) {
1042 Debug.Assert(curTemplate == null);
1043 ContextInfo ctxInfo = input.GetAttributes(functionAttributes);
1044 ctxInfo.nsList = MergeNamespaces(ctxInfo.nsList, stylesheetNsList);
1046 QilName name = ParseQNameAttribute(0);
1047 string asType = ParseStringAttribute(1, "as");
1048 bool over = ParseYesNoAttribute(2, "override") == TriState.True;
1050 ReportNYI("xsl:function");
1052 Debug.Assert(input.CanHaveApplyImports == false);
1054 curFunction = new Object();
1055 LoadInstructions(InstructionFlags.AllowParam);
1056 curFunction = null;
1059 //: http://www.w3.org/TR/xslt20/#element-import-schema
1060 XsltAttribute[] importSchemaAttributes = {
1061 new XsltAttribute("namespace" , V2Opt),
1062 new XsltAttribute("schema-location", V2Opt)
1064 private void LoadImportSchema() {
1065 ContextInfo ctxInfo = input.GetAttributes(importSchemaAttributes);
1066 ReportError(/*[XTSE1650]*/Res.Xslt_SchemaDeclaration, input.ElementName);
1067 input.SkipNode();
1069 #endif
1071 XsltAttribute[] scriptAttributes = {
1072 new XsltAttribute("implements-prefix", V1Req | V2Req),
1073 new XsltAttribute("language" , V1Opt | V2Opt)
1075 private void LoadMsScript(NsDecl stylesheetNsList) {
1076 ContextInfo ctxInfo = input.GetAttributes(scriptAttributes);
1077 ctxInfo.nsList = MergeNamespaces(ctxInfo.nsList, stylesheetNsList);
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;
1093 if (scriptNs == null) {
1094 scriptNs = compiler.CreatePhantomNamespace();
1096 string language = ParseStringAttribute(1, "language");
1097 if (language == null) {
1098 language = "jscript";
1101 if (! compiler.Settings.EnableScript) {
1102 compiler.Scripts.ScriptClasses[scriptNs] = null;
1103 input.SkipNode();
1104 return;
1107 ScriptClass scriptClass;
1108 StringBuilder scriptCode = new StringBuilder();
1109 string uriString = input.Uri;
1110 int lineNumber = 0;
1111 int lastEndLine = 0;
1113 scriptClass = compiler.Scripts.GetScriptClass(scriptNs, language, (IErrorHelper)this);
1114 if (scriptClass == null) {
1115 input.SkipNode();
1116 return;
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);
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);
1149 } else {
1150 ReportError(/*[XT_012]*/Res.Xslt_UnexpectedElement, input.QualifiedName, parentName);
1151 input.SkipNode();
1153 break;
1154 default:
1155 Debug.Assert(
1156 input.NodeType == XmlNodeType.SignificantWhitespace ||
1157 input.NodeType == XmlNodeType.Whitespace
1159 // Skip leading whitespaces
1160 if (scriptCode.Length != 0) {
1161 goto case XmlNodeType.Text;
1163 break;
1165 } while (input.MoveToNextSibling());
1168 if (scriptCode.Length == 0) {
1169 lineNumber = input.Start.Line;
1171 scriptClass.AddScriptBlock(scriptCode.ToString(), uriString, lineNumber, input.Start);
1174 XsltAttribute[] assemblyAttributes = {
1175 new XsltAttribute("name", V1Opt | V2Opt),
1176 new XsltAttribute("href", V1Opt | V2Opt)
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);
1185 string name = ParseStringAttribute(0, "name");
1186 string href = ParseStringAttribute(1, "href");
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;
1196 catch {
1197 AssemblyName asmName = new AssemblyName(name);
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;
1207 } else {
1208 Debug.Assert(href != null);
1209 asmLocation = Assembly.LoadFrom(ResolveUri(href, input.BaseUri).ToString()).Location;
1210 scriptClass.refAssembliesByHref = true;
1213 if (asmLocation != null) {
1214 scriptClass.refAssemblies.Add(asmLocation);
1218 CheckNoContent();
1221 XsltAttribute[] usingAttributes = {
1222 new XsltAttribute("namespace", V1Req | V2Req)
1224 private void LoadMsUsing(ScriptClass scriptClass) {
1225 input.GetAttributes(usingAttributes);
1227 if (input.MoveToXsltAttribute(0, "namespace")) {
1228 scriptClass.nsImports.Add(input.Value);
1230 CheckNoContent();
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!
1238 private enum InstructionFlags {
1239 None = 0x00,
1240 AllowParam = 0x01,
1241 AllowSort = 0x02,
1242 AllowFallback = 0x04,
1245 private List<XslNode> LoadInstructions() {
1246 return LoadInstructions(new List<XslNode>(), InstructionFlags.None);
1249 private List<XslNode> LoadInstructions(InstructionFlags flags) {
1250 return LoadInstructions(new List<XslNode>(), flags);
1253 private List<XslNode> LoadInstructions(List<XslNode> content) {
1254 return LoadInstructions(content, InstructionFlags.None);
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);
1265 QName parentName = input.ElementName;
1266 if (input.MoveToFirstChild()) {
1267 bool atTop = true;
1268 int sortNumber = 0;
1269 XslNode result;
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
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
1288 if (error != null) {
1289 ReportError(error, input.QualifiedName, parentName);
1290 atTop = false;
1291 input.SkipNode();
1292 continue;
1294 } else {
1295 atTop = false;
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)
1330 } else {
1331 atTop = false;
1332 result = LoadLiteralResultElement(/*asStylesheet:*/false);
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;
1345 AddInstruction(content, result);
1346 } while (input.MoveToNextSibling());
1348 --loadInstructionsDepth;
1349 return content;
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();
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;
1382 } while (input.MoveToNextSibling());
1384 return content;
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;
1396 List<XslNode> content = LoadWithParams(InstructionFlags.None);
1398 ctxInfo.SaveExtendedLineInfo(input);
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);
1409 content = null;
1410 } else {
1411 if (content.Count != 0) ReportNYI("xsl:apply-imports/xsl:with-param");
1412 content = null;
1415 return SetInfo(f.ApplyImports(/*Mode:*/curTemplate.Mode, curStylesheet, input.XslVersion), content, ctxInfo);
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)
1423 private XslNode XslApplyTemplates() {
1424 ContextInfo ctxInfo = input.GetAttributes(applyTemplatesAttributes);
1426 string select = ParseStringAttribute(0, "select");
1427 if (select == null) {
1428 select = "node()";
1430 QilName mode = ParseModeAttribute(1);
1432 List<XslNode> content = LoadWithParams(InstructionFlags.AllowSort);
1433 ctxInfo.SaveExtendedLineInfo(input);
1434 return SetInfo(f.ApplyTemplates(mode, select, ctxInfo, input.XslVersion),
1435 content, ctxInfo
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)
1444 private XslNode XslCallTemplate() {
1445 ContextInfo ctxInfo = input.GetAttributes(callTemplateAttributes);
1446 QilName name = ParseQNameAttribute(0);
1448 List<XslNode> content = LoadWithParams(InstructionFlags.None);
1449 ctxInfo.SaveExtendedLineInfo(input);
1450 return SetInfo(f.CallTemplate(name, ctxInfo), content, ctxInfo);
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)
1462 private XslNode XslCopy() {
1463 ContextInfo ctxInfo = input.GetAttributes(copyAttributes);
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']");
1470 List<XslNode> content = new List<XslNode>();
1471 if (input.MoveToXsltAttribute(2, "use-attribute-sets")) {
1472 AddUseAttributeSets(content);
1475 ParseTypeAttribute(3);
1476 ParseValidationAttribute(4, /*defVal:*/false);
1478 return SetInfo(f.Copy(), LoadEndTag(LoadInstructions(content)), ctxInfo);
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)
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']");
1493 ParseTypeAttribute(2);
1494 ParseValidationAttribute(3, /*defVal:*/false);
1496 CheckNoContent();
1497 return SetInfo(f.CopyOf(select, input.XslVersion), null, ctxInfo);
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;
1508 XsltAttribute[] ifAttributes = {
1509 new XsltAttribute("test", V1Req | V2Req)
1511 private XslNode XslIf() {
1512 ContextInfo ctxInfo = input.GetAttributes(ifAttributes);
1513 string test = ParseStringAttribute(0, "test");
1515 return SetInfo(f.If(test, input.XslVersion), LoadInstructions(), ctxInfo);
1518 private XslNode XslChoose() {
1519 ContextInfo ctxInfo = input.GetAttributes();
1521 List<XslNode> content = new List<XslNode>();
1522 bool otherwise = false;
1523 bool when = false;
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();
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();
1552 if (node == null) {
1553 ReportError(/*[XT_020]*/Res.Xslt_UnexpectedElement, input.QualifiedName, parentName);
1554 input.SkipNode();
1555 continue;
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;
1567 } while (input.MoveToNextSibling());
1569 CheckError(!when, /*[XT_021]*/Res.Xslt_NoWhen);
1570 return SetInfo(f.Choose(), content, ctxInfo);
1573 private XslNode XslOtherwise() {
1574 ContextInfo ctxInfo = input.GetAttributes();
1575 return SetInfo(f.Otherwise(), LoadInstructions(), ctxInfo);
1578 XsltAttribute[] forEachAttributes = {
1579 new XsltAttribute("select", V1Req | V2Req)
1581 private XslNode XslForEach() {
1582 ContextInfo ctxInfo = input.GetAttributes(forEachAttributes);
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);
1590 return SetInfo(f.ForEach(select, ctxInfo, input.XslVersion),
1591 content, ctxInfo
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)
1601 private XslNode XslMessage() {
1602 ContextInfo ctxInfo = input.GetAttributes(messageAttributes);
1604 string select = ParseStringAttribute(0, "select");
1605 bool terminate = ParseYesNoAttribute(1, /*attName:*/"terminate") == TriState.True;
1607 List<XslNode> content = LoadInstructions();
1608 if (content.Count != 0) {
1609 content = LoadEndTag(content);
1611 if (select != null) {
1612 content.Insert(0, f.CopyOf(select, input.XslVersion));
1615 return SetInfo(f.Message(terminate), content, ctxInfo);
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)
1633 private XslNode XslNumber() {
1634 ContextInfo ctxInfo = input.GetAttributes(numberAttributes);
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);
1649 break;
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" );
1662 // Default values for xsl:number : level="single" format="1"
1663 if (format == null) {
1664 format = "1";
1667 CheckNoContent();
1668 return SetInfo(
1669 f.Number(level, count, from, value,
1670 format, lang, letterValue, groupingSeparator, groupingSize,
1671 input.XslVersion
1673 null, ctxInfo
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)
1683 private XslNode XslValueOf() {
1684 ContextInfo ctxInfo = input.GetAttributes(valueOfAttributes);
1686 string select = ParseStringAttribute(0, "select");
1687 string separator = ParseStringAttribute(1, "separator");
1688 bool doe = ParseYesNoAttribute(2, /*attName:*/"disable-output-escaping") == TriState.True;
1690 if (separator == null) {
1691 if (!input.BackwardCompatibility) {
1692 separator = select != null ? " " : string.Empty;
1694 } else {
1695 ReportNYI("xsl:value-of/@separator");
1698 List<XslNode> content = null;
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);
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;
1715 return SetInfo(f.XslNode(doe ? XslNodeType.ValueOfDoe : XslNodeType.ValueOf, null, select, input.XslVersion),
1716 null, ctxInfo
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)
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)
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)
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
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
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());
1774 required = TriState.True;
1775 } else {
1776 if (required == TriState.True) ReportNYI("xsl:param/@required == true()");
1779 if (asType != null) {
1780 ReportNYI("xsl:param/@as");
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());
1789 } else {
1790 if (tunnel == TriState.True) ReportNYI("xsl:param/@tunnel == true()");
1794 List<XslNode> content = LoadContent(select != null);
1795 CheckError((required == TriState.True) && (select != null || content.Count != 0), /*[???]*/Res.Xslt_RequiredAndSelect, name.ToString());
1797 VarPar result = f.VarPar(nodeType, name, select, input.XslVersion);
1798 SetInfo(result, content, ctxInfo);
1799 return result;
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)
1807 private XslNode XslComment() {
1808 ContextInfo ctxInfo = input.GetAttributes(commentAttributes);
1809 string select = ParseStringAttribute(0, "select");
1810 if (select != null) ReportNYI("xsl:comment/@select");
1812 return SetInfo(f.Comment(), LoadContent(select != null), ctxInfo);
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);
1823 return content;
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)
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");
1838 return SetInfo(f.PI(name, input.XslVersion), LoadContent(select != null), ctxInfo);
1841 // http://www.w3.org/TR/xslt#section-Creating-Text
1842 XsltAttribute[] textAttributes = {
1843 new XsltAttribute("disable-output-escaping", V1Opt | V2Opt)
1845 private XslNode XslText() {
1846 ContextInfo ctxInfo = input.GetAttributes(textAttributes);
1848 bool doe = ParseYesNoAttribute(0, /*attName:*/ "disable-output-escaping") == TriState.True;
1849 SerializationHints hints = doe ? SerializationHints.DisableOutputEscaping : SerializationHints.None;
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>();
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;
1870 } while (input.MoveToNextSibling());
1873 // Empty xsl:text elements will be ignored
1874 return SetInfo(f.List(), content, ctxInfo);
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)
1887 private XslNode XslElement() {
1888 ContextInfo ctxInfo = input.GetAttributes(elementAttributes);
1890 string name = ParseNCNameAttribute(0); ;
1891 string ns = ParseStringAttribute(1, "namespace");
1892 CheckError(ns == XmlReservedNs.NsXmlNs, /*[XT_024]*/Res.Xslt_ReservedNS, ns);
1894 bool inheritNamespaces = ParseYesNoAttribute(2, "inherit-namespaces") != TriState.False;
1895 if (!inheritNamespaces) ReportNYI("xsl:copy[@inherit-namespaces = 'no']");
1897 ParseTypeAttribute(4);
1898 ParseValidationAttribute(5, /*defVal:*/false);
1900 List<XslNode> content = new List<XslNode>();
1901 if (input.MoveToXsltAttribute(3, "use-attribute-sets")) {
1902 AddUseAttributeSets(content);
1904 return SetInfo(f.Element(name, ns, input.XslVersion),
1905 LoadEndTag(LoadInstructions(content)), ctxInfo
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)
1919 private XslNode XslAttribute() {
1920 ContextInfo ctxInfo = input.GetAttributes(attributeAttributes);
1922 string name = ParseNCNameAttribute(0);
1923 string ns = ParseStringAttribute(1, "namespace");
1924 CheckError(ns == XmlReservedNs.NsXmlNs, /*[XT_024]*/Res.Xslt_ReservedNS, ns);
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);
1932 ParseTypeAttribute(4);
1933 ParseValidationAttribute(5, /*defVal:*/false);
1935 return SetInfo(f.Attribute(name, ns, input.XslVersion), LoadContent(select != null), ctxInfo);
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)
1949 private XslNode XslSort(int sortNumber) {
1950 ContextInfo ctxInfo = input.GetAttributes(sortAttributes);
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" );
1960 if (stable != TriState.Unknown) {
1961 CheckError(sortNumber != 0, Res.Xslt_SortStable);
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;
1975 if (select == null /*&& content.Count == 0*/) {
1976 select = ".";
1979 return SetInfo(f.Sort(select, lang, dataType, order, caseOrder, input.XslVersion),
1980 null, ctxInfo
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)
1990 private XslNode XslDocument() {
1991 ContextInfo ctxInfo = input.GetAttributes(documentAttributes);
1993 ParseTypeAttribute(0);
1994 ParseValidationAttribute(1, /*defVal:*/false);
1996 ReportNYI("xsl:document");
1998 List<XslNode> content = LoadEndTag(LoadInstructions());
2000 return null;
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)
2009 private XslNode XslAnalyzeString() {
2010 ContextInfo ctxInfo = input.GetAttributes(analyzeStringAttributes);
2012 string select = ParseStringAttribute(0, "select");
2013 string regex = ParseStringAttribute(1, "regex" );
2014 string flags = ParseStringAttribute(2, "flags" );
2015 if (flags == null) {
2016 flags = "";
2019 ReportNYI("xsl:analyze-string");
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();
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;
2055 } while (input.MoveToNextSibling());
2057 CheckError(matching == nonMatching, /*[XTSE1130]*/Res.Xslt_AnalyzeStringEmpty);
2059 ctxInfo.SaveExtendedLineInfo(input);
2061 return null;
2064 // http://www.w3.org/TR/xslt20/#element-namespace
2065 XsltAttribute[] namespaceAttributes = {
2066 new XsltAttribute("name" , V2Req),
2067 new XsltAttribute("select", V2Opt)
2069 private XslNode XslNamespace() {
2070 ContextInfo ctxInfo = input.GetAttributes(namespaceAttributes);
2071 string name = ParseNCNameAttribute(0);
2072 string select= ParseStringAttribute(1, "select");
2074 List<XslNode> content = LoadContent(select != null);
2075 CheckError(select == null && content.Count == 0, /*[???]*/Res.Xslt_NoSelectNoContent, input.ElementName);
2077 ReportNYI("xsl:namespace");
2079 return null;
2082 // http://www.w3.org/TR/xslt20/#element-perform-sort
2083 XsltAttribute[] performSortAttributes = {
2084 new XsltAttribute("select", V2Opt)
2086 private XslNode XslPerformSort() {
2087 ContextInfo ctxInfo = input.GetAttributes(performSortAttributes);
2088 string select = ParseStringAttribute(0, "select");
2090 List<XslNode> content = LoadInstructions(InstructionFlags.AllowSort);
2091 ctxInfo.SaveExtendedLineInfo(input);
2093 if (select != null) {
2094 foreach (XslNode node in content) {
2095 if (node.NodeType != XslNodeType.Sort) {
2096 ReportError(Res.Xslt_PerformSortCntSel);
2097 break;
2102 ReportNYI("xsl:perform-sort");
2103 return null;
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)
2115 private XslNode XslForEachGroup() {
2116 ContextInfo ctxInfo = input.GetAttributes(forEachGroupAttributes);
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);
2125 ReportNYI("xsl:for-each-group");
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);
2132 return null;
2135 // http://www.w3.org/TR/xslt20/#element-next-match
2136 private XslNode XslNextMatch() {
2137 ContextInfo ctxInfo = input.GetAttributes();
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;
2146 ReportNYI("xsl:next-match");
2148 List<XslNode> content = LoadWithParams(InstructionFlags.AllowFallback);
2149 ctxInfo.SaveExtendedLineInfo(input);
2151 return null;
2154 // http://www.w3.org/TR/xslt20/#element-sequence
2155 XsltAttribute[] sequenceAttributes = {
2156 new XsltAttribute("select", V2Req)
2158 private XslNode XslSequence() {
2159 ContextInfo ctxInfo = input.GetAttributes(sequenceAttributes);
2160 string select = ParseStringAttribute(0, "select");
2161 ReportNYI("xsl:sequence");
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();
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;
2183 } while (input.MoveToNextSibling());
2185 return null;
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
2212 private XslNode XslResultDocument() {
2213 ContextInfo ctxInfo = input.GetAttributes(resultDocumentAttributes);
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");
2235 ReportNYI("xsl:result-document");
2237 if (format != null) ReportNYI("xsl:result-document/@format");
2239 if (href == null) {
2240 href = string.Empty;
2242 // attHref is a BaseUri of new output tree. It should be resolved relative to "base output URI"
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;
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]));
2261 if (compiler.ExitForwardsCompatible(input.ForwardCompatibility)) {
2262 foreach (XmlQualifiedName qname in list) {
2263 settings.CDataSectionElements.Add(qname);
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);
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()");
2284 if (docTypePublic != null) {
2285 settings.DocTypePublic = docTypePublic;
2288 if (docTypeSystem != null) {
2289 settings.DocTypeSystem = docTypeSystem;
2291 if (mediaType != null) {
2292 settings.MediaType = mediaType;
2295 if (useCharacterMaps != null) ReportNYI("xsl:result-document/@use-character-maps");
2297 if (outputVersion != null) {
2300 ReportNYI("xsl:result-document/@output-version");
2303 LoadInstructions();
2304 return null;
2306 #endif
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;
2315 ContextInfo ctxInfo = input.GetLiteralAttributes(asStylesheet);
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);
2322 List<XslNode> content = new List<XslNode>();
2324 for (int i = 1; input.MoveToLiteralAttribute(i); i++) {
2325 if (input.IsXsltNamespace() && input.IsKeyword(atoms.UseAttributeSets)) {
2326 AddUseAttributeSets(content);
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()
2340 content = LoadEndTag(LoadInstructions(content));
2341 return SetInfo(f.LiteralElement(f.QName(name, nsUri, prefix)), content, ctxInfo);
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;
2355 private static void AddInstruction(List<XslNode> content, XslNode instruction) {
2356 Debug.Assert(content != null);
2357 if (instruction != null) {
2358 content.Add(instruction);
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()));
2367 return content;
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);
2383 private List<XslNode> LoadFallbacks(string instrName) {
2384 input.MoveToElement();
2385 ISourceLineInfo extElmLineInfo = input.BuildNameLineInfo();
2386 List<XslNode> fallbacksArray = new List<XslNode>();
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();
2397 } while (input.MoveToNextSibling());
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))
2406 return fallbacksArray;
2409 // ------------------ little helper methods ---------------------
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;
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);
2435 if (!compiler.ExitForwardsCompatible(input.ForwardCompatibility)) {
2436 mode = nullMode;
2438 return mode;
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;
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);
2457 compiler.EnterForwardsCompatible(); // mode is always optional attribute
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);
2475 bool dup = false;
2476 foreach (QilName m in modes) {
2477 dup |= m.Equals(mode);
2479 if (dup) {
2480 ReportError(Res.Xslt_ModeListDup, qname);
2481 } else {
2482 modes.Add(mode);
2487 if (!compiler.ExitForwardsCompatible(input.ForwardCompatibility)) {
2488 modes.Clear();
2489 modes.Add(nullMode);
2491 if (1 < modes.Count) {
2492 ReportNYI("Multipe modes");
2493 return nullMode;
2495 if (modes.Count == 0) {
2496 return nullMode;
2498 return modes[0];
2502 private string ParseCollationAttribute(int attNum) {
2503 if (input.MoveToXsltAttribute(attNum, "collation")) {
2504 ReportNYI("@collation");
2506 return null;
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;
2518 if (!compiler.ParseQName(qname, out prefix, out localName, (IErrorHelper)this)) {
2519 namespaceName = compiler.CreatePhantomNamespace();
2520 return false;
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;
2531 return true;
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();
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);
2547 if (!required) {
2548 compiler.ExitForwardsCompatible(input.ForwardCompatibility);
2550 if (result == null && required) {
2551 result = f.QName(compiler.PhantomNCName, compiler.CreatePhantomNamespace(), compiler.PhantomNCName);
2553 return result;
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;
2561 return compiler.PhantomNCName;
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);
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);
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();
2594 int index = (
2595 (localName == null ? 1 : 0) +
2596 (namespaceName == null ? 1 : 0)
2598 curStylesheet.AddWhitespaceRule(index, new WhitespaceRule(localName, namespaceName, preserveSpace));
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;
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;
2620 } else {
2621 if (!input.ForwardCompatibility) {
2622 ReportWarning(/*[XT1570]*/Res.Xslt_InvalidMethod, attValue);
2625 return new XmlQualifiedName(localName, namespaceName);
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()");
2633 compiler.EnterForwardsCompatible();
2634 foreach (string qname in XmlConvert.SplitString(input.Value)) {
2635 AddInstruction(list, SetLineInfo(f.UseAttributeSet(CreateXPathQName(qname)), input.BuildLineInfo()));
2637 if (!compiler.ExitForwardsCompatible(input.ForwardCompatibility)) {
2638 // There were errors in the list, ignore the whole list
2639 list.Clear();
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));
2650 if (!compiler.ExitForwardsCompatible(input.ForwardCompatibility)) {
2651 useCharacterMaps.Clear(); // There were errors in the list, ignore the whole list
2654 return useCharacterMaps;
2657 private string ParseStringAttribute(int attNum, string attName) {
2658 if (input.MoveToXsltAttribute(attNum, attName)) {
2659 return input.Value;
2661 return null;
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);
2674 return defVal;
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");
2688 break;
2691 return TriState.Unknown;
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");
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
2713 ReportError(/*[???]*/Res.Xslt_SchemaAttributeValue, attributeName, value);
2714 } else if (!input.ForwardCompatibility) {
2715 ReportError(/*[???]*/Res.Xslt_InvalidAttrValue, attributeName, value);
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);
2734 break;
2735 default:
2736 if (!input.ForwardCompatibility) {
2737 ReportError(/*[???]*/Res.Xslt_InvalidAttrValue, "input-type-annotations", value);
2739 break;
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();
2751 if (errorLineInfo != null) {
2752 compiler.ReportError(errorLineInfo, /*[XT0260]*/Res.Xslt_NotEmptyContents, parentName);
2756 // Returns ISourceLineInfo of the first violating (non-whitespace) node, or null otherwise
2757 private ISourceLineInfo SkipEmptyContent() {
2758 ISourceLineInfo result = null;
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();
2768 input.SkipNode();
2770 } while (input.MoveToNextSibling());
2772 return result;
2775 private static XslNode SetLineInfo(XslNode node, ISourceLineInfo lineInfo) {
2776 Debug.Assert(node != null);
2777 node.SourceLine = lineInfo;
2778 return node;
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.
2786 node.SetContent(content);
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;
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;
2808 if (thisList == null) {
2809 return parentList;
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;
2823 if (!duplicate) {
2824 thisList = new NsDecl(thisList, parentList.Prefix, parentList.NsUri);
2826 parentList = parentList.Prev;
2828 return thisList;
2831 // -------------------------------- IErrorHelper --------------------------------
2833 public void ReportError(string res, params string[] args) {
2834 compiler.ReportError(input.BuildNameLineInfo(), res, args);
2837 public void ReportWarning(string res, params string[] args) {
2838 compiler.ReportWarning(input.BuildNameLineInfo(), res, args);
2841 private void ReportNYI(string arg) {
2842 if (! input.ForwardCompatibility) {
2843 ReportError(Res.Xslt_NotYetImplemented, arg);
2847 public void CheckError(bool cond, string res, params string[] args) {
2848 if (cond) {
2849 compiler.ReportError(input.BuildNameLineInfo(), res, args);