1 //------------------------------------------------------------------------------
2 // <copyright file="VariableAction.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 // <owner current="true" primary="true">Microsoft</owner>
6 //------------------------------------------------------------------------------
7 
8 using System.Diagnostics;
9 using System.Xml.XPath;
10 
11 namespace System.Xml.Xsl.XsltOld {
12     using Res = System.Xml.Utils.Res;
13 
14     internal enum VariableType {
15         GlobalVariable,
16         GlobalParameter,
17         LocalVariable,
18         LocalParameter,
19         WithParameter,
20     }
21 
22     internal class VariableAction : ContainerAction, IXsltContextVariable {
23         public static object BeingComputedMark = new object();
24         private const int ValueCalculated = 2;
25 
26         protected XmlQualifiedName  name;
27         protected string            nameStr;
28         protected string            baseUri;
29         protected int               selectKey = Compiler.InvalidQueryKey;
30         protected int               stylesheetid;
31         protected VariableType      varType;
32         private   int               varKey;
33 
34         internal int Stylesheetid {
35             get { return this.stylesheetid; }
36         }
37         internal XmlQualifiedName Name {
38             get { return this.name; }
39         }
40         internal string NameStr {
41             get { return this.nameStr; }
42         }
43         internal VariableType VarType {
44             get { return this.varType; }
45         }
46         internal int VarKey {
47             get { return this.varKey; }
48         }
49         internal bool IsGlobal {
50             get { return this.varType == VariableType.GlobalVariable || this.varType == VariableType.GlobalParameter; }
51         }
52 
VariableAction(VariableType type)53         internal VariableAction(VariableType type) {
54             this.varType = type;
55         }
56 
Compile(Compiler compiler)57         internal override void Compile(Compiler compiler) {
58             this.stylesheetid = compiler.Stylesheetid;
59             this.baseUri      = compiler.Input.BaseURI;
60             CompileAttributes(compiler);
61             CheckRequiredAttribute(compiler, this.name, "name");
62 
63 
64             if (compiler.Recurse()) {
65                 CompileTemplate(compiler);
66                 compiler.ToParent();
67 
68                 if (this.selectKey != Compiler.InvalidQueryKey && this.containedActions != null) {
69                     throw XsltException.Create(Res.Xslt_VariableCntSel2, this.nameStr);
70                 }
71             }
72             if (this.containedActions != null) {
73                 baseUri = baseUri + '#' + compiler.GetUnicRtfId();
74             } else {
75                 baseUri = null;
76             }
77 
78             this.varKey = compiler.InsertVariable(this);
79         }
80 
CompileAttribute(Compiler compiler)81         internal override bool CompileAttribute(Compiler compiler) {
82             string name   = compiler.Input.LocalName;
83             string value  = compiler.Input.Value;
84 
85             if (Ref.Equal(name, compiler.Atoms.Name)) {
86                 Debug.Assert(this.name == null && this.nameStr == null);
87                 this.nameStr = value;
88                 this.name    = compiler.CreateXPathQName(this.nameStr);
89             }
90             else if (Ref.Equal(name, compiler.Atoms.Select)) {
91                 this.selectKey = compiler.AddQuery(value);
92             }
93             else {
94                 return false;
95             }
96 
97             return true;
98         }
99 
Execute(Processor processor, ActionFrame frame)100         internal override void Execute(Processor processor, ActionFrame frame) {
101             Debug.Assert(processor != null && frame != null && frame.State != ValueCalculated);
102             object value = null;
103 
104             switch(frame.State) {
105             case Initialized:
106                 if (IsGlobal) {
107                     if (frame.GetVariable(this.varKey) != null) { // This var was calculated already
108                         frame.Finished();
109                         break;
110                     }
111                     // Mark that the variable is being computed to check for circular references
112                     frame.SetVariable(this.varKey, BeingComputedMark);
113                 }
114                 // If this is a parameter, check whether the caller has passed the value
115                 if (this.varType == VariableType.GlobalParameter) {
116                     value = processor.GetGlobalParameter(this.name);
117                 } else if (this.varType == VariableType.LocalParameter) {
118                     value = processor.GetParameter(this.name);
119                 }
120                 if (value != null) {
121                     goto case ValueCalculated;
122                 }
123 
124                 // If value was not passed, check the 'select' attribute
125                 if (this.selectKey != Compiler.InvalidQueryKey) {
126                     value = processor.RunQuery(frame, this.selectKey);
127                     goto case ValueCalculated;
128                 }
129 
130                 // If there is no 'select' attribute and the content is empty, use the empty string
131                 if (this.containedActions == null) {
132                     value = string.Empty;
133                     goto case ValueCalculated;
134                 }
135 
136                 // RTF case
137                 NavigatorOutput output = new NavigatorOutput(this.baseUri);
138                 processor.PushOutput(output);
139                 processor.PushActionFrame(frame);
140                 frame.State = ProcessingChildren;
141                 break;
142 
143             case ProcessingChildren:
144                 RecordOutput recOutput = processor.PopOutput();
145                 Debug.Assert(recOutput is NavigatorOutput);
146                 value = ((NavigatorOutput)recOutput).Navigator;
147                 goto case ValueCalculated;
148 
149             case ValueCalculated:
150                 Debug.Assert(value != null);
151                 frame.SetVariable(this.varKey, value);
152                 frame.Finished();
153                 break;
154 
155             default:
156                 Debug.Fail("Invalid execution state inside VariableAction.Execute");
157     		    break;
158             }
159         }
160 
161         // ---------------------- IXsltContextVariable --------------------
162 
163         XPathResultType IXsltContextVariable.VariableType {
164             get { return XPathResultType.Any; }
165         }
IXsltContextVariable.Evaluate(XsltContext xsltContext)166         object IXsltContextVariable.Evaluate(XsltContext xsltContext) {
167             return ((XsltCompileContext)xsltContext).EvaluateVariable(this);
168         }
169         bool   IXsltContextVariable.IsLocal {
170             get { return this.varType == VariableType.LocalVariable  || this.varType == VariableType.LocalParameter;  }
171         }
172         bool   IXsltContextVariable.IsParam {
173             get { return this.varType == VariableType.LocalParameter || this.varType == VariableType.GlobalParameter; }
174         }
175     }
176 }
177