/// <summary> /// Renders the input reader using the context into the output writer. /// To be used when a template is dynamically constructed, or want to /// use Velocity as a token replacer. /// </summary> /// <param name="context">context to use in rendering input string</param> /// <param name="out"> Writer in which to render the output</param> /// <param name="logTag"> string to be used as the template name for log messages in case of error</param> /// <param name="reader">Reader containing the VTL to be rendered</param> /// <returns>true if successful, false otherwise. If false, see Velocity runtime log</returns> public static bool Evaluate(IContext context, TextWriter writer, String logTag, TextReader reader) { SimpleNode nodeTree = null; try { nodeTree = RuntimeSingleton.parse(reader, logTag); } catch (ParseException pex) { throw new ParseErrorException(pex.Message); } /* * now we want to init and render */ if (nodeTree != null) { InternalContextAdapterImpl ica = new InternalContextAdapterImpl(context); ica.PushCurrentTemplateName(logTag); try { try { nodeTree.init(ica, RuntimeSingleton.RuntimeServices); } catch (Exception e) { RuntimeSingleton.error("Velocity.evaluate() : init exception for tag = " + logTag + " : " + e); } /* * now render, and let any exceptions fly */ nodeTree.render(ica, writer); } finally { ica.PopCurrentTemplateName(); } return(true); } return(false); }
internal bool Render(DvslNode node, IContext context, TextWriter writer) { /* * find if we have an AST where the xpath expression mathes * for this node */ XmlNode dom4jnode = (XmlNode)node.NodeImpl; XPathNavigator nav = dom4jnode.CreateNavigator(); SimpleNode sn = null; for (int i = 0; i < xpathList.Count; i++) { Hashtable m = (Hashtable)xpathList[i]; XPathExpression expr = nav.Compile((String)m["xpath"]); if (nav.Matches((String)m["xpath"])) { sn = (SimpleNode)m["ast"]; break; } } // if we found something, render if (sn != null) { InternalContextAdapterImpl ica = new InternalContextAdapterImpl(context); ica.PushCurrentTemplateName(node.Name); try { sn.render(ica, writer); } finally { ica.PopCurrentTemplateName(); } return(true); } return(false); }
/// <summary> Return name of this Velocimacro. /// </summary> /// <summary> Velocimacros are always LINE /// type directives. /// </summary> /// <summary> sets the directive name of this VM /// </summary> /// <summary> sets the array of arguments specified in the macro definition /// </summary> /// <summary> returns the number of ars needed for this VM /// </summary> /// <summary> Sets the orignal macro body. This is simply the cat of the macroArray, but the /// Macro object creates this once during parsing, and everyone shares it. /// Note : it must not be modified. /// </summary> /// <summary> Renders the macro using the context /// </summary> public override bool render(InternalContextAdapter context, TextWriter writer, INode node) { try { /* * it's possible the tree hasn't been parsed yet, so get * the VMManager to parse and init it */ if (nodeTree != null) { if (!init_Renamed_Field) { nodeTree.init(context, rsvc); init_Renamed_Field = true; } /* * wrap the current context and add the VMProxyArg objects */ VMContext vmc = new VMContext(context, rsvc); for (int i = 1; i < argArray.Length; i++) { /* * we can do this as VMProxyArgs don't change state. They change * the context. */ VMProxyArg arg = (VMProxyArg)proxyArgHash[argArray[i]]; vmc.AddVMProxyArg(arg); } /* * now render the VM */ nodeTree.render(vmc, writer); } else { rsvc.error("VM error : " + macroName + ". Null AST"); } } catch (Exception e) { /* * if it's a MIE, it came from the render.... throw it... */ if (e is MethodInvocationException) { throw (MethodInvocationException)e; } rsvc.error("VelocimacroProxy.render() : exception VM = #" + macroName + "() : " + StringUtils.stackTrace(e)); } return(true); }
/// <summary> returns the value of the reference. Generally, this is only /// called for dynamic proxies, as the static ones should have /// been stored in the VMContext's localcontext store /// * /// </summary> /// <param name="context">Context to use for getting current value /// </param> /// <returns>Object value /// * /// /// </returns> public Object getObject(InternalContextAdapter context) { try { /* * we need to output based on our type */ Object retObject = null; if (type == ParserTreeConstants.JJTREFERENCE) { /* * two cases : scalar reference ($foo) or multi-level ($foo.bar....) */ if (numTreeChildren == 0) { /* * if I am a single-level reference, can I not get get it out of my context? */ retObject = context.Get(singleLevelRef); } else { /* * I need to let the AST produce it for me. */ retObject = nodeTree.execute(null, context); } } else if (type == ParserTreeConstants.JJTOBJECTARRAY) { retObject = nodeTree.Value(context); } else if (type == ParserTreeConstants.JJTINTEGERRANGE) { retObject = nodeTree.Value(context); } else if (type == ParserTreeConstants.JJTTRUE) { retObject = staticObject; } else if (type == ParserTreeConstants.JJTFALSE) { retObject = staticObject; } else if (type == ParserTreeConstants.JJTSTRINGLITERAL) { retObject = nodeTree.Value(context); } else if (type == ParserTreeConstants.JJTNUMBERLITERAL) { retObject = staticObject; } else if (type == ParserTreeConstants.JJTTEXT) { /* * this really shouldn't happen. text is just a thowaway arg for #foreach() */ try { StringWriter writer = new StringWriter(); nodeTree.render(context, writer); retObject = writer; } catch (Exception e) { rsvc.error("VMProxyArg.getObject() : error rendering reference : " + e); } } else if (type == GENERALSTATIC) { retObject = staticObject; } else { rsvc.error("Unsupported VM arg type : VM arg = " + callerReference + " type = " + type + "( VMProxyArg.getObject() )"); } return(retObject); } catch (MethodInvocationException mie) { /* * not ideal, but otherwise we propogate out to the * VMContext, and the Context interface's put/get * don't throw. So this is a the best compromise * I can think of */ rsvc.error("VMProxyArg.getObject() : method invocation error getting value : " + mie); return(null); } }