1 //------------------------------------------------------------------------------
2 // <copyright file="TemplateAction.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 // <owner current="true" primary="true">Microsoft</owner>
6 //------------------------------------------------------------------------------
8 namespace System.Xml.Xsl.XsltOld {
9 using Res = System.Xml.Utils.Res;
11 using System.Diagnostics;
12 using System.Collections;
14 using System.Xml.XPath;
15 using MS.Internal.Xml.XPath;
16 using System.Globalization;
18 internal class TemplateAction : TemplateBaseAction {
19 private int matchKey = Compiler.InvalidQueryKey;
20 private XmlQualifiedName name;
21 private double priority = double.NaN;
22 private XmlQualifiedName mode;
23 private int templateId;
24 private bool replaceNSAliasesDone;
26 internal int MatchKey {
27 get { return this.matchKey; }
30 internal XmlQualifiedName Name {
31 get { return this.name; }
34 internal double Priority {
35 get { return this.priority; }
38 internal XmlQualifiedName Mode {
39 get { return this.mode; }
42 internal int TemplateId {
43 get { return this.templateId; }
45 Debug.Assert(this.templateId == 0);
46 this.templateId = value;
50 internal override void Compile(Compiler compiler) {
51 CompileAttributes(compiler);
52 if (this.matchKey == Compiler.InvalidQueryKey) {
53 if (this.name == null) {
54 throw XsltException.Create(Res.Xslt_TemplateNoAttrib);
56 if (this.mode != null ) {
57 throw XsltException.Create(Res.Xslt_InvalidModeAttribute);
60 compiler.BeginTemplate(this);
62 if (compiler.Recurse()) {
63 CompileParameters(compiler);
64 CompileTemplate(compiler);
69 compiler.EndTemplate();
70 AnalyzePriority(compiler);
73 internal virtual void CompileSingle(Compiler compiler) {
74 this.matchKey = compiler.AddQuery("/", /*allowVars:*/false, /*allowKey:*/true, /*pattern*/true);
75 this.priority = Compiler.RootPriority;
77 CompileOnceTemplate(compiler);
80 internal override bool CompileAttribute(Compiler compiler) {
81 string name = compiler.Input.LocalName;
82 string value = compiler.Input.Value;
84 if (Ref.Equal(name, compiler.Atoms.Match)) {
85 Debug.Assert(this.matchKey == Compiler.InvalidQueryKey);
86 this.matchKey = compiler.AddQuery(value, /*allowVars:*/false, /*allowKey:*/true, /*pattern*/true);
88 else if (Ref.Equal(name, compiler.Atoms.Name)) {
89 Debug.Assert(this.name == null);
90 this.name = compiler.CreateXPathQName(value);
92 else if (Ref.Equal(name, compiler.Atoms.Priority)) {
93 Debug.Assert(Double.IsNaN(this.priority));
94 this.priority = XmlConvert.ToXPathDouble(value);
95 if (double.IsNaN(this.priority) && ! compiler.ForwardCompatibility) {
96 throw XsltException.Create(Res.Xslt_InvalidAttrValue, "priority", value);
99 else if (Ref.Equal(name, compiler.Atoms.Mode)) {
100 Debug.Assert(this.mode == null);
101 if (compiler.AllowBuiltInMode && value == "*") {
102 this.mode = Compiler.BuiltInMode;
105 this.mode = compiler.CreateXPathQName(value);
115 private void AnalyzePriority(Compiler compiler) {
116 NavigatorInput input = compiler.Input;
118 if (!Double.IsNaN(this.priority) || this.matchKey == Compiler.InvalidQueryKey) {
122 TheQuery theQuery = (TheQuery)compiler.QueryStore[this.MatchKey];
123 CompiledXpathExpr expr = (CompiledXpathExpr)theQuery.CompiledQuery;
124 Query query = expr.QueryTree;
126 while ((union = query as UnionExpr) != null) {
127 Debug.Assert(!(union.qy2 is UnionExpr), "only qy1 can be union");
128 TemplateAction copy = this.CloneWithoutName();
129 compiler.QueryStore.Add(new TheQuery(
130 new CompiledXpathExpr(union.qy2, expr.Expression, false),
131 theQuery._ScopeManager
133 copy.matchKey = compiler.QueryStore.Count - 1;
134 copy.priority = union.qy2.XsltDefaultPriority;
135 compiler.AddTemplate(copy);
139 if (expr.QueryTree != query) {
140 // query was splitted and we need create new TheQuery for this template
141 compiler.QueryStore[this.MatchKey] = new TheQuery(
142 new CompiledXpathExpr(query, expr.Expression, false),
143 theQuery._ScopeManager
146 this.priority = query.XsltDefaultPriority;
149 protected void CompileParameters(Compiler compiler) {
150 NavigatorInput input = compiler.Input;
152 switch(input.NodeType) {
153 case XPathNodeType.Element:
154 if (Ref.Equal(input.NamespaceURI, input.Atoms.UriXsl) &&
155 Ref.Equal(input.LocalName, input.Atoms.Param)) {
156 compiler.PushNamespaceScope();
157 AddAction(compiler.CreateVariableAction(VariableType.LocalParameter));
164 case XPathNodeType.Text:
166 case XPathNodeType.SignificantWhitespace:
167 this.AddEvent(compiler.CreateTextEvent());
173 while (input.Advance());
177 // Priority calculation plus template splitting
180 private TemplateAction CloneWithoutName() {
181 TemplateAction clone = new TemplateAction(); {
182 clone.containedActions = this.containedActions;
183 clone.mode = this.mode;
184 clone.variableCount = this.variableCount;
185 clone.replaceNSAliasesDone = true; // We shouldn't replace NS in clones.
190 internal override void ReplaceNamespaceAlias(Compiler compiler) {
191 // if template has both name and match it will be twice caled by stylesheet to replace NS aliases.
192 if (! replaceNSAliasesDone) {
193 base.ReplaceNamespaceAlias(compiler);
194 replaceNSAliasesDone = true;
201 internal override void Execute(Processor processor, ActionFrame frame) {
202 Debug.Assert(processor != null && frame != null);
204 switch (frame.State) {
206 if (this.variableCount > 0) {
207 frame.AllocateVariables(this.variableCount);
209 if (this.containedActions != null && this.containedActions.Count > 0) {
210 processor.PushActionFrame(frame);
211 frame.State = ProcessingChildren;
216 break; // Allow children to run
217 case ProcessingChildren:
221 Debug.Fail("Invalid Container action execution state");