282 lines
7.6 KiB
C#
282 lines
7.6 KiB
C#
|
//
|
||
|
// XslVariable.cs
|
||
|
//
|
||
|
// Authors:
|
||
|
// Ben Maurer (bmaurer@users.sourceforge.net)
|
||
|
// Atsushi Enomoto (ginga@kit.hi-ho.ne.jp)
|
||
|
//
|
||
|
// (C) 2003 Ben Maurer
|
||
|
// (C) 2003 Atsushi Enomoto
|
||
|
//
|
||
|
|
||
|
//
|
||
|
// Permission is hereby granted, free of charge, to any person obtaining
|
||
|
// a copy of this software and associated documentation files (the
|
||
|
// "Software"), to deal in the Software without restriction, including
|
||
|
// without limitation the rights to use, copy, modify, merge, publish,
|
||
|
// distribute, sublicense, and/or sell copies of the Software, and to
|
||
|
// permit persons to whom the Software is furnished to do so, subject to
|
||
|
// the following conditions:
|
||
|
//
|
||
|
// The above copyright notice and this permission notice shall be
|
||
|
// included in all copies or substantial portions of the Software.
|
||
|
//
|
||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||
|
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||
|
//
|
||
|
|
||
|
using System;
|
||
|
using System.Collections;
|
||
|
using System.Xml;
|
||
|
using System.Xml.XPath;
|
||
|
using System.Xml.Xsl;
|
||
|
using Mono.Xml.XPath;
|
||
|
|
||
|
using QName = System.Xml.XmlQualifiedName;
|
||
|
|
||
|
namespace Mono.Xml.Xsl.Operations {
|
||
|
|
||
|
internal class XslVariableInformation
|
||
|
{
|
||
|
QName name;
|
||
|
XPathExpression select;
|
||
|
XslOperation content;
|
||
|
|
||
|
public XslVariableInformation (Compiler c)
|
||
|
{
|
||
|
|
||
|
c.CheckExtraAttributes (c.Input.LocalName, "name", "select");
|
||
|
|
||
|
c.AssertAttribute ("name");
|
||
|
|
||
|
name = c.ParseQNameAttribute ("name");
|
||
|
try {
|
||
|
XmlConvert.VerifyName (name.Name);
|
||
|
} catch (XmlException ex) {
|
||
|
throw new XsltCompileException ("Variable name is not qualified name", ex, c.Input);
|
||
|
}
|
||
|
|
||
|
string sel = c.GetAttribute ("select");
|
||
|
if (sel != null && sel != "" ) {
|
||
|
select = c.CompileExpression (c.GetAttribute ("select"));
|
||
|
// TODO assert empty
|
||
|
} else if (c.Input.MoveToFirstChild ()) {
|
||
|
content = c.CompileTemplateContent ();
|
||
|
c.Input.MoveToParent ();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public object Evaluate (XslTransformProcessor p)
|
||
|
{
|
||
|
if (select != null) {
|
||
|
object o = p.Evaluate (select);
|
||
|
// To resolve variable references correctly, we
|
||
|
// have to collect all the target nodes here.
|
||
|
// (otherwise, variables might be resolved with
|
||
|
// different level of variable stack in
|
||
|
// XslTransformProcessor).
|
||
|
if (o is XPathNodeIterator) {
|
||
|
ArrayList al = new ArrayList ();
|
||
|
XPathNodeIterator iter = (XPathNodeIterator) o;
|
||
|
while (iter.MoveNext ())
|
||
|
al.Add (iter.Current.Clone ());
|
||
|
o = new ListIterator (al, p.XPathContext);
|
||
|
}
|
||
|
return o;
|
||
|
} else if (content != null) {
|
||
|
DTMXPathDocumentWriter2 w = new DTMXPathDocumentWriter2 (p.Root.NameTable, 200);
|
||
|
Outputter outputter = new GenericOutputter(w, p.Outputs, null, true);
|
||
|
p.PushOutput (outputter);
|
||
|
if (p.CurrentNodeset.CurrentPosition == 0)
|
||
|
p.NodesetMoveNext ();
|
||
|
content.Evaluate (p);
|
||
|
p.PopOutput ();
|
||
|
return w.CreateDocument ().CreateNavigator ();
|
||
|
} else {
|
||
|
return "";
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public QName Name { get { return name; }}
|
||
|
|
||
|
internal XPathExpression Select {
|
||
|
get { return select; }
|
||
|
}
|
||
|
|
||
|
internal XslOperation Content {
|
||
|
get { return content; }
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal abstract class XslGeneralVariable : XslCompiledElement, IXsltContextVariable {
|
||
|
protected XslVariableInformation var;
|
||
|
|
||
|
public XslGeneralVariable (Compiler c) : base (c) {}
|
||
|
|
||
|
protected override void Compile (Compiler c)
|
||
|
{
|
||
|
if (c.Debugger != null)
|
||
|
c.Debugger.DebugCompile (this.DebugInput);
|
||
|
|
||
|
this.var = new XslVariableInformation (c);
|
||
|
}
|
||
|
|
||
|
public override abstract void Evaluate (XslTransformProcessor p);
|
||
|
protected abstract object GetValue (XslTransformProcessor p);
|
||
|
|
||
|
|
||
|
public object Evaluate (XsltContext xsltContext)
|
||
|
{
|
||
|
object value = GetValue (((XsltCompiledContext)xsltContext).Processor);
|
||
|
|
||
|
if (value is XPathNodeIterator)
|
||
|
return new WrapperIterator (((XPathNodeIterator)value).Clone (), xsltContext);
|
||
|
|
||
|
return value;
|
||
|
}
|
||
|
|
||
|
public QName Name {get {return var.Name;}}
|
||
|
public XPathResultType VariableType { get {return XPathResultType.Any;}}
|
||
|
public abstract bool IsLocal { get; }
|
||
|
public abstract bool IsParam { get; }
|
||
|
}
|
||
|
|
||
|
internal class XslGlobalVariable : XslGeneralVariable {
|
||
|
public XslGlobalVariable (Compiler c) : base (c) {}
|
||
|
static object busyObject = new Object ();
|
||
|
|
||
|
|
||
|
public override void Evaluate (XslTransformProcessor p)
|
||
|
{
|
||
|
if (p.Debugger != null)
|
||
|
p.Debugger.DebugExecute (p, this.DebugInput);
|
||
|
|
||
|
Hashtable varInfo = p.globalVariableTable;
|
||
|
|
||
|
if (varInfo.Contains (this)) {
|
||
|
if (varInfo [this] == busyObject)
|
||
|
throw new XsltException ("Circular dependency was detected", null, p.CurrentNode);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
varInfo [this] = busyObject;
|
||
|
varInfo [this] = var.Evaluate (p);
|
||
|
|
||
|
}
|
||
|
|
||
|
protected override object GetValue (XslTransformProcessor p)
|
||
|
{
|
||
|
p.PushNodeset (new SelfIterator (p.Root, p.XPathContext));
|
||
|
p.NodesetMoveNext ();
|
||
|
Evaluate (p);
|
||
|
p.PopNodeset ();
|
||
|
return p.globalVariableTable [this];
|
||
|
}
|
||
|
|
||
|
public override bool IsLocal { get { return false; }}
|
||
|
public override bool IsParam { get { return false; }}
|
||
|
}
|
||
|
|
||
|
internal class XslGlobalParam : XslGlobalVariable {
|
||
|
|
||
|
public XslGlobalParam (Compiler c) : base (c) {}
|
||
|
|
||
|
public void Override (XslTransformProcessor p, object paramVal)
|
||
|
{
|
||
|
Debug.Assert (!p.globalVariableTable.Contains (this), "Shouldn't have been evaluated by this point");
|
||
|
|
||
|
p.globalVariableTable [this] = paramVal;
|
||
|
}
|
||
|
|
||
|
public override bool IsParam { get { return true; }}
|
||
|
}
|
||
|
|
||
|
internal class XslLocalVariable : XslGeneralVariable {
|
||
|
protected int slot;
|
||
|
|
||
|
public XslLocalVariable (Compiler c) : base (c)
|
||
|
{
|
||
|
slot = c.AddVariable (this);
|
||
|
}
|
||
|
|
||
|
public override void Evaluate (XslTransformProcessor p)
|
||
|
{
|
||
|
if (p.Debugger != null)
|
||
|
p.Debugger.DebugExecute (p, this.DebugInput);
|
||
|
|
||
|
p.SetStackItem (slot, var.Evaluate (p));
|
||
|
}
|
||
|
|
||
|
protected override object GetValue (XslTransformProcessor p)
|
||
|
{
|
||
|
return p.GetStackItem (slot);
|
||
|
}
|
||
|
|
||
|
public bool IsEvaluated (XslTransformProcessor p)
|
||
|
{
|
||
|
return p.GetStackItem (slot) != null;
|
||
|
}
|
||
|
|
||
|
public override bool IsLocal { get { return true; }}
|
||
|
public override bool IsParam { get { return false; }}
|
||
|
}
|
||
|
|
||
|
internal class XslLocalParam : XslLocalVariable {
|
||
|
|
||
|
public XslLocalParam (Compiler c) : base (c) {}
|
||
|
|
||
|
public override void Evaluate (XslTransformProcessor p)
|
||
|
{
|
||
|
if (p.Debugger != null)
|
||
|
p.Debugger.DebugExecute (p, this.DebugInput);
|
||
|
|
||
|
if (p.GetStackItem (slot) != null)
|
||
|
return; // evaluated already
|
||
|
|
||
|
if (p.Arguments != null &&
|
||
|
var.Select == null &&
|
||
|
var.Content == null) {
|
||
|
object val = p.Arguments.GetParam (Name.Name,
|
||
|
Name.Namespace);
|
||
|
if (val != null) {
|
||
|
Override (p, val);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
base.Evaluate (p);
|
||
|
}
|
||
|
|
||
|
public void Override (XslTransformProcessor p, object paramVal)
|
||
|
{
|
||
|
p.SetStackItem (slot, paramVal);
|
||
|
}
|
||
|
|
||
|
public override bool IsParam { get { return true; }}
|
||
|
}
|
||
|
|
||
|
internal class XPathVariableBinding : Expression {
|
||
|
XslGeneralVariable v;
|
||
|
public XPathVariableBinding (XslGeneralVariable v)
|
||
|
{
|
||
|
this.v = v;
|
||
|
}
|
||
|
public override String ToString () { return "$" + v.Name.ToString (); }
|
||
|
public override XPathResultType ReturnType { get { return XPathResultType.Any; }}
|
||
|
public override XPathResultType GetReturnType (BaseIterator iter)
|
||
|
{
|
||
|
return XPathResultType.Any;
|
||
|
}
|
||
|
|
||
|
public override object Evaluate (BaseIterator iter)
|
||
|
{
|
||
|
return v.Evaluate (iter.NamespaceManager as XsltContext);
|
||
|
}
|
||
|
}
|
||
|
}
|