1 //------------------------------------------------------------------------------
2 // <copyright file="XsltLoader.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 // <owner current="true" primary="true">Microsoft</owner>
6 //------------------------------------------------------------------------------
10 using System
.Collections
;
11 using System
.Collections
.Generic
;
12 using System
.Collections
.Specialized
;
13 using System
.Diagnostics
;
14 using System
.Reflection
;
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
;
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
;
56 readerSettings
= new QueryReaderSettings(reader
);
59 // We should take DefaultReaderSettings from Compiler.Settings.DefaultReaderSettings.
61 string uri
= stylesheet
as string;
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
)) {
77 IXPathNavigable navigable
= stylesheet
as IXPathNavigable
;
78 if (navigable
!= null) {
79 reader
= XPathNavigatorReader
.Create(navigable
.CreateNavigator());
80 readerSettings
= new QueryReaderSettings(reader
.NameTable
);
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
);
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
);
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
);
153 private bool V1
{ get {
154 Debug
.Assert(compiler
.Version
!= 0, "Version should be already decided at this point");
155 return compiler
.Version
== 1;
158 private bool V2 { get { return ! V1; }
}
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
);
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) {
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
;
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
) {
232 catch (Exception e
) {
233 if (!XmlException
.IsCatchableException(e
)) {
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
);
246 documentUriInUse
.Remove(baseUri
);
248 curStylesheet
= prevStylesheet
;
250 return thisStylesheet
;
253 private void LoadDocument() {
254 if (!input
.FindStylesheetElement()) {
255 ReportError(/*[XT_002]*/Res
.Xslt_WrongStylesheetElement
);
258 Debug
.Assert(input
.NodeType
== XmlNodeType
.Element
);
259 if (input
.IsXsltNamespace()) {
261 input
.IsKeyword(atoms
.Stylesheet
) ||
262 input
.IsKeyword(atoms
.Transform
)
264 LoadRealStylesheet();
266 ReportError(/*[XT_002]*/Res
.Xslt_WrongStylesheetElement
);
270 LoadSimplifiedStylesheet();
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);
286 SetLineInfo(curTemplate
, lre
.SourceLine
);
288 List
<XslNode
> content
= new List
<XslNode
>();
290 SetContent(curTemplate
, content
);
291 if (!curStylesheet
.AddTemplate(curTemplate
)) {
292 Debug
.Fail("AddTemplate() returned false for simplified stylesheet");
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()) {
315 bool isImport
= false;
316 switch (input
.NodeType
) {
317 case XmlNodeType
.Element
:
318 if (input
.IsXsltNamespace()) {
319 if (input
.IsKeyword(atoms
.Import
)) {
321 ReportError(/*[XT0200]*/Res
.Xslt_NotAtTop
, input
.QualifiedName
, parentName
);
327 } else if (input
.IsKeyword(atoms
.Include
)) {
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
)) {
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
);
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
)) {
358 input
.GetVersionAttribute();
359 if (!input
.ForwardCompatibility
) {
360 ReportError(/*[XT_003]*/Res
.Xslt_UnexpectedElement
, input
.QualifiedName
, parentName
);
364 } else if (input
.IsNs(atoms
.UrnMsxsl
) && input
.IsKeyword(atoms
.Script
)) {
365 LoadMsScript(ctxInfo
.nsList
);
367 if (input
.IsNullNamespace()) {
368 ReportError(/*[XT0130]*/Res
.Xslt_NullNsAtTopLevel
, input
.LocalName
);
370 // Ignoring non-recognized namespace per XSLT spec 2.2
376 case XmlNodeType
.Whitespace
:
377 case XmlNodeType
.SignificantWhitespace
:
380 Debug
.Assert(input
.NodeType
== XmlNodeType
.Text
);
381 ReportError(/*[XT0120]*/Res
.Xslt_TextNodesNotAllowed
, parentName
);
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
);
405 curStylesheet
.ImportHrefs
.Add(uri
);
408 // The error was already reported. Ignore the instruction
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
);
429 LoadStylesheet(uri
, /*include:*/ true);
432 // The error was already reported. Ignore the instruction
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);
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);
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
;
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
) {
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
;
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
) {
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
);
666 // The error will be reported in QilGenerator while compiling this attribute set.
669 case XslNodeType
.List
:
670 CheckUseAttrubuteSetInList(xslNode
.Content
);
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
;
684 case CycleCheck
.Completed
:
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
);
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;
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
);
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
);
738 // First definition of key with that name
739 List
<Key
> defList
= new List
<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();
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")) {
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
);
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
));
819 // Add format to the global collection
820 DecimalFormatDecl format
= new DecimalFormatDecl(name
, infinity
, nan
, new string(characters
));
821 compiler
.DecimalFormats
.Add(format
);
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");
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");
850 resultPrefix
= input
.Value
== "#default" ? string.Empty
: input
.Value
;
851 resultNsUri
= input
.LookupXmlNamespace(resultPrefix
);
857 if (stylesheetNsUri
== null || resultNsUri
== null) {
858 // At least one of attributes is missing or invalid
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");
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()) {
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());
905 ReportError(/*[XT_006]*/Res
.Xslt_UnexpectedElement
, input
.QualifiedName
, parentName
);
909 case XmlNodeType
.Whitespace
:
910 case XmlNodeType
.SignificantWhitespace
:
913 Debug
.Assert(input
.NodeType
== XmlNodeType
.Text
);
914 ReportError(/*[XT_006]*/Res
.Xslt_TextNodesNotAllowed
, parentName
);
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);
956 CheckError(! input
.AttributeExists(1, "name"), /*[XT_007]*/Res
.Xslt_BothMatchNameAbsent
);
957 CheckError( input
.AttributeExists(3, "mode"), /*[XT_008]*/Res
.Xslt_ModeWithoutMatch
);
959 if (input
.AttributeExists(2, "priority")) {
961 ReportWarning(/*[XT_008]*/Res
.Xslt_PriorityWithoutMatch
);
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);
978 LoadEndTag(LoadInstructions(InstructionFlags
.AllowParam
)), ctxInfo
981 if (!curStylesheet
.AddTemplate(curTemplate
)) {
982 ReportError(/*[XT0660]*/Res
.Xslt_DupTemplateName
, curTemplate
.Name
.QualifiedName
);
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()) {
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");
1019 ReportError(/*[XT_006]*/Res
.Xslt_UnexpectedElement
, input
.QualifiedName
, parentName
);
1023 case XmlNodeType
.Whitespace
:
1024 case XmlNodeType
.SignificantWhitespace
:
1027 Debug
.Assert(input
.NodeType
== XmlNodeType
.Text
);
1028 ReportError(/*[XT_006]*/Res
.Xslt_TextNodesNotAllowed
, parentName
);
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
);
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
);
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
);
1085 scriptNs
= input
.LookupXmlNamespace(input
.Value
);
1086 if (scriptNs
== XmlReservedNs
.NsXslt
) {
1087 ReportError(/*[XT_036]*/Res
.Xslt_ScriptXsltNamespace
);
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;
1107 ScriptClass scriptClass
;
1108 StringBuilder scriptCode
= new StringBuilder();
1109 string uriString
= input
.Uri
;
1111 int lastEndLine
= 0;
1113 scriptClass
= compiler
.Scripts
.GetScriptClass(scriptNs
, language
, (IErrorHelper
)this);
1114 if (scriptClass
== null) {
1119 QName parentName
= input
.ElementName
;
1120 if (input
.MoveToFirstChild()) {
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
;
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
);
1144 } else if (input
.IsKeyword(atoms
.Assembly
)) {
1145 LoadMsAssembly(scriptClass
);
1146 } else if (input
.IsKeyword(atoms
.Using
)) {
1147 LoadMsUsing(scriptClass
);
1150 ReportError(/*[XT_012]*/Res
.Xslt_UnexpectedElement
, input
.QualifiedName
, parentName
);
1156 input
.NodeType
== XmlNodeType
.SignificantWhitespace
||
1157 input
.NodeType
== XmlNodeType
.Whitespace
1159 // Skip leading whitespaces
1160 if (scriptCode
.Length
!= 0) {
1161 goto case XmlNodeType
.Text
;
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
);
1191 string asmLocation
= null;
1194 asmLocation
= Assembly
.Load(name
).Location
;
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";
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
);
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
);
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
{
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()) {
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
) {
1284 (flags
& instrFlag
) == 0 ? /*[XT_013]*/Res
.Xslt_UnexpectedElement
:
1285 !atTop
? /*[XT_014]*/Res
.Xslt_NotAtTop
:
1288 if (error
!= null) {
1289 ReportError(error
, input
.QualifiedName
, parentName
);
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
++) :
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() :
1328 /*default:*/ LoadUnknownXsltInstruction(parentName
)
1332 result
= LoadLiteralResultElement(/*asStylesheet:*/false);
1335 case XmlNodeType
.SignificantWhitespace
:
1336 result
= SetLineInfo(f
.Text(input
.Value
), input
.BuildLineInfo());
1338 case XmlNodeType
.Whitespace
:
1341 Debug
.Assert(input
.NodeType
== XmlNodeType
.Text
);
1343 goto case XmlNodeType
.SignificantWhitespace
;
1345 AddInstruction(content
, result
);
1346 } while (input
.MoveToNextSibling());
1348 --loadInstructionsDepth
;
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()) {
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
)) {
1370 ReportError(/*[XT_016]*/Res
.Xslt_UnexpectedElement
, input
.QualifiedName
, parentName
);
1374 case XmlNodeType
.Whitespace
:
1375 case XmlNodeType
.SignificantWhitespace
:
1378 Debug
.Assert(input
.NodeType
== XmlNodeType
.Text
);
1379 ReportError(/*[XT_016]*/Res
.Xslt_TextNodesNotAllowed
, parentName
);
1382 } while (input
.MoveToNextSibling());
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
);
1396 List
<XslNode
> content
= LoadWithParams(InstructionFlags
.None
);
1398 ctxInfo
.SaveExtendedLineInfo(input
);
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
);
1406 return SetInfo(f
.Error(XslLoadException
.CreateMessage(contentInfo
, /*[XT0260]*/Res
.Xslt_NotEmptyContents
, atoms
.ApplyImports
)), null, ctxInfo
);
1411 if (content
.Count
!= 0) ReportNYI("xsl:apply-imports/xsl:with-param");
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) {
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
),
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);
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();
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;
1525 QName parentName
= input
.ElementName
;
1526 if (input
.MoveToFirstChild()) {
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
)) {
1534 ReportError(/*[XT_018]*/Res
.Xslt_WhenAfterOtherwise
);
1541 } else if (Ref
.Equal(input
.LocalName
, atoms
.Otherwise
)) {
1543 ReportError(/*[XT_019]*/Res
.Xslt_DupOtherwise
);
1548 node
= XslOtherwise();
1553 ReportError(/*[XT_020]*/Res
.Xslt_UnexpectedElement
, input
.QualifiedName
, parentName
);
1557 AddInstruction(content
, node
);
1559 case XmlNodeType
.Whitespace
:
1560 case XmlNodeType
.SignificantWhitespace
:
1563 Debug
.Assert(input
.NodeType
== XmlNodeType
.Text
);
1564 ReportError(/*[XT_020]*/Res
.Xslt_TextNodesNotAllowed
, parentName
);
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
),
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;
1646 if (!input
.ForwardCompatibility
) {
1647 ReportError(/*[XT_022]*/Res
.Xslt_InvalidAttrValue
, "level", input
.Value
);
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) {
1669 f
.Number(level
, count
, from, value,
1670 format
, lang
, letterValue
, groupingSeparator
, groupingSize
,
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
;
1695 ReportNYI("xsl:value-of/@separator");
1698 List
<XslNode
> content
= null;
1701 if (select == null) {
1703 return SetInfo(f
.Error(XslLoadException
.CreateMessage(ctxInfo
.lineInfo
, Res
.Xslt_MissingAttribute
, "select")), null, ctxInfo
);
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/*");
1715 return SetInfo(f
.XslNode(doe
? XslNodeType
.ValueOfDoe
: XslNodeType
.ValueOf
, null, select, input
.XslVersion
),
1720 // required tunnel select
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
:
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
;
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());
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
);
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
);
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()) {
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
));
1865 Debug
.Assert(input
.NodeType
== XmlNodeType
.Element
);
1866 ReportError(/*[XT_023]*/Res
.Xslt_UnexpectedElement
, input
.QualifiedName
, parentName
);
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;
1968 content
= LoadContent(select != null);
1969 if (content
.Count
!= 0) {
1970 ReportNYI("xsl:sort/*");
1975 if (select == null /*&& content.Count == 0*/) {
1979 return SetInfo(f
.Sort(select, lang
, dataType
, order
, caseOrder
, input
.XslVersion
),
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());
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) {
2019 ReportNYI("xsl:analyze-string");
2021 XslNode matching
= null;
2022 XslNode nonMatching
= null;
2023 QName parentName
= input
.ElementName
;
2024 if (input
.MoveToFirstChild()) {
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
)) {
2043 ReportError(/*[XT_017]*/Res
.Xslt_UnexpectedElement
, input
.QualifiedName
, parentName
);
2047 case XmlNodeType
.Whitespace
:
2048 case XmlNodeType
.SignificantWhitespace
:
2051 Debug
.Assert(input
.NodeType
== XmlNodeType
.Text
);
2052 ReportError(/*[XT_017]*/Res
.Xslt_TextNodesNotAllowed
, parentName
);
2055 } while (input
.MoveToNextSibling());
2057 CheckError(matching
== nonMatching
, /*[XTSE1130]*/Res
.Xslt_AnalyzeStringEmpty
);
2059 ctxInfo
.SaveExtendedLineInfo(input
);
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");
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
);
2102 ReportNYI("xsl:perform-sort");
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
);
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();
2146 ReportNYI("xsl:next-match");
2148 List
<XslNode
> content
= LoadWithParams(InstructionFlags
.AllowFallback
);
2149 ctxInfo
.SaveExtendedLineInfo(input
);
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()) {
2166 switch (input
.NodeType
) {
2167 case XmlNodeType
.Element
:
2168 if (input
.IsXsltKeyword(atoms
.Fallback
)) {
2171 ReportError(/*[XT_017]*/Res
.Xslt_UnexpectedElement
, input
.QualifiedName
, parentName
);
2175 case XmlNodeType
.Whitespace
:
2176 case XmlNodeType
.SignificantWhitespace
:
2179 Debug
.Assert(input
.NodeType
== XmlNodeType
.Text
);
2180 ReportError(/*[XT_017]*/Res
.Xslt_TextNodesNotAllowed
, parentName
);
2183 } while (input
.MoveToNextSibling());
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");
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")) {
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");
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
));
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
);
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()));
2370 private XslNode
LoadUnknownXsltInstruction(string parentName
) {
2371 input
.GetVersionAttribute();
2372 if (!input
.ForwardCompatibility
) {
2373 ReportError(/*[XT_026]*/Res
.Xslt_UnexpectedElement
, input
.QualifiedName
, parentName
);
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()) {
2391 if (input
.IsXsltKeyword(atoms
.Fallback
)) {
2392 ContextInfo ctxInfo
= input
.GetAttributes();
2393 fallbacksArray
.Add(SetInfo(f
.List(), LoadInstructions(), ctxInfo
));
2397 } while (input
.MoveToNextSibling());
2400 // Generate runtime error if there is no fallbacks
2401 if (fallbacksArray
.Count
== 0) {
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
) {
2414 // input.IsXsltKeyword(atoms.ApplyTemplates) ||
2415 // input.IsXsltKeyword(atoms.Template) && V1
2417 if (! input
.MoveToXsltAttribute(attNum
, "mode")) {
2420 // mode is always optional attribute
2421 compiler
.EnterForwardsCompatible();
2422 string qname
= input
.Value
;
2424 if (!V1
&& qname
== "#default") {
2426 } else if (!V1
&& qname
== "#current") {
2427 ReportNYI("xsl:apply-templates[@mode='#current']");
2429 } else if (!V1
&& qname
== "#all") {
2430 ReportError(Res
.Xslt_ModeListAll
);
2433 mode
= CreateXPathQName(qname
);
2435 if (!compiler
.ExitForwardsCompatible(input
.ForwardCompatibility
)) {
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")) {
2449 string modeList
= input
.Value
;
2450 if (modeList
== "#all") {
2451 ReportNYI("xsl:template[@mode='#all']");
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
);
2462 foreach (string qname
in list
) {
2464 if (qname
== "#default") {
2466 } else if (qname
== "#current") {
2467 ReportNYI("xsl:apply-templates[@mode='#current']");
2469 } else if (qname
== "#all") {
2470 ReportError(Res
.Xslt_ModeListAll
);
2473 mode
= CreateXPathQName(qname
);
2476 foreach (QilName m
in modes
) {
2477 dup
|= m
.Equals(mode
);
2480 ReportError(Res
.Xslt_ModeListDup
, qname
);
2487 if (!compiler
.ExitForwardsCompatible(input
.ForwardCompatibility
)) {
2489 modes
.Add(nullMode
);
2491 if (1 < modes
.Count
) {
2492 ReportNYI("Multipe modes");
2495 if (modes
.Count
== 0) {
2502 private string ParseCollationAttribute(int attNum
) {
2503 if (input
.MoveToXsltAttribute(attNum
, "collation")) {
2504 ReportNYI("@collation");
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();
2518 if (!compiler
.ParseQName(qname
, out prefix
, out localName
, (IErrorHelper
)this)) {
2519 namespaceName
= compiler
.CreatePhantomNamespace();
2522 if (ignoreDefaultNs
&& prefix
.Length
== 0) {
2523 namespaceName
= string.Empty
;
2525 namespaceName
= input
.LookupXmlNamespace(prefix
);
2526 if (namespaceName
== null) {
2527 namespaceName
= compiler
.CreatePhantomNamespace();
2534 // Does not suppress errors
2535 private QilName
ParseQNameAttribute(int attNum
) {
2536 bool required
= input
.IsRequiredAttribute(attNum
);
2537 QilName result
= null;
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
);
2548 compiler
.ExitForwardsCompatible(input
.ForwardCompatibility
);
2550 if (result
== null && required
) {
2551 result
= f
.QName(compiler
.PhantomNCName
, compiler
.CreatePhantomNamespace(), compiler
.PhantomNCName
);
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")) {
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
;
2589 namespaceName
= input
.LookupXmlNamespace(prefix
);
2590 if (namespaceName
== null) {
2591 namespaceName
= compiler
.CreatePhantomNamespace();
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
)) {
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;
2617 ReportError(/*[XT1570]*/Res
.Xslt_InvalidAttrValue
, "method", attValue
);
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
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
)) {
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];
2669 if (input
.IsRequiredAttribute(attNum
) || !input
.ForwardCompatibility
) {
2670 ReportError(/*[XT_029]*/Res
.Xslt_CharAttribute
, attName
);
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
;
2685 if (!input
.ForwardCompatibility
) {
2686 ReportError(/*[XT_028]*/Res
.Xslt_BistateAttribute
, attName
, "yes", "no");
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") {
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
;
2729 if (compiler
.inputTypeAnnotations
== null) {
2730 compiler
.inputTypeAnnotations
= value;
2732 CheckError(compiler
.inputTypeAnnotations
!= value, /*[XTSE0265]*/Res
.Xslt_InputTypeAnnotations
);
2736 if (!input
.ForwardCompatibility
) {
2737 ReportError(/*[???]*/Res
.Xslt_InvalidAttrValue
, "input-type-annotations", value);
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()) {
2763 // NOTE: XmlNodeType.SignificantWhitespace are not allowed here
2764 if (input
.NodeType
!= XmlNodeType
.Whitespace
) {
2765 if (result
== null) {
2766 result
= input
.BuildNameLineInfo();
2770 } while (input
.MoveToNextSibling());
2775 private static XslNode
SetLineInfo(XslNode node
, ISourceLineInfo lineInfo
) {
2776 Debug
.Assert(node
!= null);
2777 node
.SourceLine
= lineInfo
;
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
);
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) {
2808 if (thisList
== null) {
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
2824 thisList
= new NsDecl(thisList
, parentList
.Prefix
, parentList
.NsUri
);
2826 parentList
= parentList
.Prev
;
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
) {
2849 compiler
.ReportError(input
.BuildNameLineInfo(), res
, args
);