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