|
//------------------------------------------------------------------------------
// <copyright file="VariableAction.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// <owner current="true" primary="true">Microsoft</owner>
//------------------------------------------------------------------------------
using System.Diagnostics;
using System.Xml.XPath;
namespace System.Xml.Xsl.XsltOld {
using Res = System.Xml.Utils.Res;
internal enum VariableType {
GlobalVariable,
GlobalParameter,
LocalVariable,
LocalParameter,
WithParameter,
}
internal class VariableAction : ContainerAction, IXsltContextVariable {
public static object BeingComputedMark = new object();
private const int ValueCalculated = 2;
protected XmlQualifiedName name;
protected string nameStr;
protected string baseUri;
protected int selectKey = Compiler.InvalidQueryKey;
protected int stylesheetid;
protected VariableType varType;
private int varKey;
internal int Stylesheetid {
get { return this.stylesheetid; }
}
internal XmlQualifiedName Name {
get { return this.name; }
}
internal string NameStr {
get { return this.nameStr; }
}
internal VariableType VarType {
get { return this.varType; }
}
internal int VarKey {
get { return this.varKey; }
}
internal bool IsGlobal {
get { return this.varType == VariableType.GlobalVariable || this.varType == VariableType.GlobalParameter; }
}
internal VariableAction(VariableType type) {
this.varType = type;
}
internal override void Compile(Compiler compiler) {
this.stylesheetid = compiler.Stylesheetid;
this.baseUri = compiler.Input.BaseURI;
CompileAttributes(compiler);
CheckRequiredAttribute(compiler, this.name, "name");
if (compiler.Recurse()) {
CompileTemplate(compiler);
compiler.ToParent();
if (this.selectKey != Compiler.InvalidQueryKey && this.containedActions != null) {
throw XsltException.Create(Res.Xslt_VariableCntSel2, this.nameStr);
}
}
if (this.containedActions != null) {
baseUri = baseUri + '#' + compiler.GetUnicRtfId();
} else {
baseUri = null;
}
this.varKey = compiler.InsertVariable(this);
}
internal override bool CompileAttribute(Compiler compiler) {
string name = compiler.Input.LocalName;
string value = compiler.Input.Value;
if (Ref.Equal(name, compiler.Atoms.Name)) {
Debug.Assert(this.name == null && this.nameStr == null);
this.nameStr = value;
this.name = compiler.CreateXPathQName(this.nameStr);
}
else if (Ref.Equal(name, compiler.Atoms.Select)) {
this.selectKey = compiler.AddQuery(value);
}
else {
return false;
}
return true;
}
internal override void Execute(Processor processor, ActionFrame frame) {
Debug.Assert(processor != null && frame != null && frame.State != ValueCalculated);
object value = null;
switch(frame.State) {
case Initialized:
if (IsGlobal) {
if (frame.GetVariable(this.varKey) != null) { // This var was calculated already
frame.Finished();
break;
}
// Mark that the variable is being computed to check for circular references
frame.SetVariable(this.varKey, BeingComputedMark);
}
// If this is a parameter, check whether the caller has passed the value
if (this.varType == VariableType.GlobalParameter) {
value = processor.GetGlobalParameter(this.name);
} else if (this.varType == VariableType.LocalParameter) {
value = processor.GetParameter(this.name);
}
if (value != null) {
goto case ValueCalculated;
}
// If value was not passed, check the 'select' attribute
if (this.selectKey != Compiler.InvalidQueryKey) {
value = processor.RunQuery(frame, this.selectKey);
goto case ValueCalculated;
}
// If there is no 'select' attribute and the content is empty, use the empty string
if (this.containedActions == null) {
value = string.Empty;
goto case ValueCalculated;
}
// RTF case
NavigatorOutput output = new NavigatorOutput(this.baseUri);
processor.PushOutput(output);
processor.PushActionFrame(frame);
frame.State = ProcessingChildren;
break;
case ProcessingChildren:
RecordOutput recOutput = processor.PopOutput();
Debug.Assert(recOutput is NavigatorOutput);
value = ((NavigatorOutput)recOutput).Navigator;
goto case ValueCalculated;
case ValueCalculated:
Debug.Assert(value != null);
frame.SetVariable(this.varKey, value);
frame.Finished();
break;
default:
Debug.Fail("Invalid execution state inside VariableAction.Execute");
break;
}
}
// ---------------------- IXsltContextVariable --------------------
XPathResultType IXsltContextVariable.VariableType {
get { return XPathResultType.Any; }
}
object IXsltContextVariable.Evaluate(XsltContext xsltContext) {
return ((XsltCompileContext)xsltContext).EvaluateVariable(this);
}
bool IXsltContextVariable.IsLocal {
get { return this.varType == VariableType.LocalVariable || this.varType == VariableType.LocalParameter; }
}
bool IXsltContextVariable.IsParam {
get { return this.varType == VariableType.LocalParameter || this.varType == VariableType.GlobalParameter; }
}
}
}
|