diff --git a/Template.cs b/Template.cs index 83b8229..683a865 100644 --- a/Template.cs +++ b/Template.cs @@ -117,6 +117,7 @@ namespace ln.templates Template = template; ExpressionContext = new Expression.Context(null, null); ExpressionContext.AddMappedValue("__template__", template.SourceFilename); + ExpressionContext.AddMappedValue("__provider__", template.Provider); } public Context(Context parent,String framedContent) { diff --git a/html/DocumentElement.cs b/html/DocumentElement.cs new file mode 100644 index 0000000..a80f486 --- /dev/null +++ b/html/DocumentElement.cs @@ -0,0 +1,31 @@ +// /** +// * File: DocumentElement.cs +// * Author: haraldwolff +// * +// * This file and it's content is copyrighted by the Author and / or copyright holder. +// * Any use wihtout proper permission is illegal and may lead to legal actions. +// * +// * +// **/ +using System; +using System.IO; + +namespace ln.templates.html +{ + public class DocumentElement : Element + { + public DocumentElement() + :base("#document") + { + } + + public override void Render(TextWriter writer) + { + writer.Write(""); + + foreach (Element element in Children) + element.Render(writer); + } + + } +} diff --git a/html/Element.cs b/html/Element.cs new file mode 100644 index 0000000..0e91436 --- /dev/null +++ b/html/Element.cs @@ -0,0 +1,93 @@ +// /** +// * File: Element.cs +// * Author: haraldwolff +// * +// * This file and it's content is copyrighted by the Author and / or copyright holder. +// * Any use wihtout proper permission is illegal and may lead to legal actions. +// * +// * +// **/ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +namespace ln.templates.html +{ + public class Element + { + public string Name { get; } + public Element Parent { get; private set; } + + public bool IsVoid => IsVoidElement(Name); + + List children = new List(); + Dictionary attributes = new Dictionary(); + public IEnumerable> Attributes => attributes; + + public Element(string elementName) + { + Name = elementName; + } + public Element(string elementName,IEnumerable> attributes) + :this(elementName) + { + foreach (KeyValuePair keyValuePair in attributes) + this.attributes[keyValuePair.Key] = keyValuePair.Value; + } + + public virtual bool HasAttribute(string attributeName) => attributes.ContainsKey(attributeName); + public virtual string GetAttribute(string attributeName) => attributes[attributeName]; + public virtual void SetAttribute(string attributeName, string attributeValue) => attributes[attributeName] = attributeValue; + + public IEnumerable Children => children; + public void AppendChild(Element element) + { + if (element.Parent != null) + element.Parent.RemoveChild(element); + + children.Add(element); + element.Parent = this; + } + public void RemoveChild(Element element) + { + if (element.Parent != this) + throw new KeyNotFoundException(); + + children.Remove(element); + element.Parent = null; + } + + public virtual void Render(TextWriter writer) + { + writer.Write("<{0}", Name); + foreach (KeyValuePair attributePair in attributes) + writer.Write(" {0}=\"{1}\"", attributePair.Key, attributePair.Value); + writer.Write(">"); + + if (!IsVoid) + { + foreach (Element element in children) + element.Render(writer); + + writer.Write("",Name); + } + } + + public override string ToString() + { + StringWriter stringWriter = new StringWriter(); + Render(stringWriter); + return stringWriter.ToString(); + } + + + + static HashSet voidElementNames = new HashSet(){ + "!doctype", + "area","base", "br", "col", "embed", "hr", "img", "input", "link", "meta", "param", "source", "track", "wbr" + }; + public static string[] VoidElementNames => voidElementNames.ToArray(); + public bool IsVoidElement(string elementName) => voidElementNames.Contains(elementName); + + } +} diff --git a/html/ElementReader.cs b/html/ElementReader.cs new file mode 100644 index 0000000..90a2690 --- /dev/null +++ b/html/ElementReader.cs @@ -0,0 +1,69 @@ +// /** +// * File: ElementReader.cs +// * Author: haraldwolff +// * +// * This file and it's content is copyrighted by the Author and / or copyright holder. +// * Any use wihtout proper permission is illegal and may lead to legal actions. +// * +// * +// **/ +using System; +using System.Collections.Generic; +namespace ln.templates.html +{ + public class ElementReader : HtmlReader + { + Stack elements = new Stack(); + + public Element CurrentElement => elements.Peek(); + public virtual DocumentElement Document { get; } + + public ElementReader() + { + Document = CreateDocument(); + elements.Push(Document); + } + + public virtual DocumentElement CreateDocument() => new DocumentElement(); + + public virtual Element CreateElement(string tagName) + { + switch (tagName.ToUpper()) + { + default: + return new Element(tagName); + } + } + public virtual Element CreateTextElement(string text) => new TextElement(text); + + void Push(Element element) + { + CurrentElement.AppendChild(element); + elements.Push(element); + } + + void Pop() + { + elements.Pop(); + } + + public override void OpenTag(string tagName) + { + Push(CreateElement(tagName)); + } + public override void CloseTag(string tagName) + { + Pop(); + } + public override void Attribute(string attributeName, string attributeValue) + { + CurrentElement.SetAttribute(attributeName, attributeValue); + } + public override void Text(string text) + { + CurrentElement.AppendChild( + CreateTextElement(text) + ); + } + } +} diff --git a/html/ExpressionElement.cs b/html/ExpressionElement.cs new file mode 100644 index 0000000..435beab --- /dev/null +++ b/html/ExpressionElement.cs @@ -0,0 +1,40 @@ +// /** +// * File: ExpressionElement.cs +// * Author: haraldwolff +// * +// * This file and it's content is copyrighted by the Author and / or copyright holder. +// * Any use wihtout proper permission is illegal and may lead to legal actions. +// * +// * +// **/ +using ln.templates.script; +using System.IO; + +namespace ln.templates.html +{ + public class ExpressionElement : TemplateElement + { + public string ExpressionText { get; } + public NewExpression Expression { get; } + + public ExpressionElement(string expression) + :base("#expression") + { + ExpressionText = expression; + Expression = new NewExpression(ExpressionText); + } + + public override void Render(TextWriter writer) + { + writer.Write("{{{{{0}}}}}", ExpressionText); + } + + public override void RenderTemplate(RenderContext renderContext) + { + object o = Expression.Resolve(renderContext); + renderContext.ContentWriter.Write(o?.ToString()); + } + + + } +} diff --git a/html/HtmlReader.cs b/html/HtmlReader.cs new file mode 100644 index 0000000..3a61eb7 --- /dev/null +++ b/html/HtmlReader.cs @@ -0,0 +1,170 @@ +// /** +// * File: Parser.cs +// * Author: haraldwolff +// * +// * This file and it's content is copyrighted by the Author and / or copyright holder. +// * Any use wihtout proper permission is illegal and may lead to legal actions. +// * +// * +// **/ +using System; +using System.IO; +using System.Collections.Generic; +using System.Text; +namespace ln.templates.html +{ + public class HtmlReader + { + public HtmlReader() + { + } + + public void Read(string source) => Read(new StringReader(source)); + public void Read(Stream sourceStream) + { + using (StreamReader streamReader = new StreamReader(sourceStream)) + Read(streamReader); + } + + public void Read(TextReader textReader) + { + while (textReader.Peek() != -1) + { + switch (textReader.Peek()) + { + case '<': + ReadTag(textReader); + break; + default: + ReadText(textReader); + break; + } + } + } + public void ReadTag(TextReader textReader) + { + if (textReader.Read() != '<') + throw new FormatException("Expected <"); + + bool closing = false; + + if (textReader.Peek()=='/') + { + textReader.Read(); + closing = true; + } + + if (textReader.Peek()=='!') + { + textReader.Read(); + string doctype = ReadTagName(textReader); + if (!doctype.Equals("DOCTYPE")) + throw new FormatException("Expected DOCTYPE"); + + string type = ReadAttributeName(textReader); + DOCTYPE(type); + + if (textReader.Read() != '>') + throw new FormatException("Expected >"); + + return; + } + string tagName = ReadTagName(textReader); + + if (closing) + { + CloseTag(tagName); + } + else + { + OpenTag(tagName); + + while (TestChar((char)textReader.Peek(), (ch) => !char.IsWhiteSpace(ch) && (ch != '\0') && (ch != '"') && (ch != '\'') && (ch != '>') && (ch != '/') && (ch != '='))) + { + string attributeName = ReadAttributeName(textReader); + string attributeValue = ""; + if (textReader.Peek() == '=') + { + textReader.Read(); + attributeValue = ReadAttributeValue(textReader); + } + Attribute(attributeName, attributeValue); + } + + if (textReader.Peek()=='/') + { + textReader.Read(); + CloseTag(tagName); + } + } + + if (textReader.Read() != '>') + throw new FormatException("Expected >"); + } + + bool TestChar(char ch, Func condition) => condition(ch); + public string ReadToken(TextReader textReader, Func condition) + { + StringBuilder characters = new StringBuilder(); + while (condition((char)textReader.Peek()) && textReader.Peek() != -1) + { + characters.Append((char)textReader.Read()); + } + + return characters.ToString(); + } + public string ReadTokenLWS(TextReader textReader, Func condition) + { + string token = ReadToken(textReader, condition); + ReadToken(textReader, char.IsWhiteSpace); + return token; + } + void ReadLWS(TextReader textReader) => ReadToken(textReader, char.IsWhiteSpace); + + public string ReadTagName(TextReader textReader) => ReadTokenLWS(textReader, (ch) => char.IsLetterOrDigit(ch)); + public string ReadAttributeName(TextReader textReader) => ReadTokenLWS(textReader, (ch) => !char.IsWhiteSpace(ch) && (ch != '\0') && (ch != '"') && (ch != '\'') && (ch != '>') && (ch != '/') && (ch != '=')); + public string ReadAttributeValue(TextReader textReader) + { + switch (textReader.Peek()) + { + case '"': + return ReadTokenLWS(textReader, (ch) => ch != '"'); + case '\'': + return ReadTokenLWS(textReader, (ch)=> ch != '\''); + default: + return ReadTokenLWS(textReader, (ch) => !char.IsWhiteSpace(ch) && (ch != '"') && (ch != '\'') && (ch != '<') && (ch != '>') && (ch != '`')); + } + } + + + + + public void ReadText(TextReader textReader) + { + StringBuilder stringBuilder = new StringBuilder(); + while (textReader.Peek() != '<') + stringBuilder.Append((char)textReader.Read()); + + Text(stringBuilder.ToString()); + } + + public virtual void DOCTYPE(string type) + { + } + + public virtual void OpenTag(string tagName) + { + } + public virtual void CloseTag(string tagName) + { + } + public virtual void Attribute(string attributeName,string attributeValue) + { + } + public virtual void Text(string text) + { + } + + + } +} diff --git a/html/RenderContext.cs b/html/RenderContext.cs new file mode 100644 index 0000000..ac4c412 --- /dev/null +++ b/html/RenderContext.cs @@ -0,0 +1,33 @@ +// /** +// * File: RenderContext.cs +// * Author: haraldwolff +// * +// * This file and it's content is copyrighted by the Author and / or copyright holder. +// * Any use wihtout proper permission is illegal and may lead to legal actions. +// * +// * +// **/ +using System; +using System.IO; +using System.Collections.Generic; +using ln.templates.script; +namespace ln.templates.html +{ + public class RenderContext : IScriptContext + { + public TextWriter ContentWriter { get; } + + Dictionary scriptObjects = new Dictionary(); + public IEnumerable ScriptObjectNames => scriptObjects.Keys; + + public RenderContext(TextWriter contentWriter) + { + ContentWriter = contentWriter; + } + + Dictionary values = new Dictionary(); + + public object GetScriptObject(string itemName) => scriptObjects[itemName]; + public void SetScriptObject(string itemName, object value) => scriptObjects[itemName] = value; + } +} diff --git a/html/TemplateDocument.cs b/html/TemplateDocument.cs new file mode 100644 index 0000000..63ef224 --- /dev/null +++ b/html/TemplateDocument.cs @@ -0,0 +1,38 @@ +// /** +// * File: TemplateDocument.cs +// * Author: haraldwolff +// * +// * This file and it's content is copyrighted by the Author and / or copyright holder. +// * Any use wihtout proper permission is illegal and may lead to legal actions. +// * +// * +// **/ +using System; +using System.IO; +namespace ln.templates.html +{ + public class TemplateDocument : DocumentElement + { + public TemplateDocument() + { + } + + public void RenderTemplate(TextWriter contentWriter) => RenderTemplate(new RenderContext(contentWriter)); + public void RenderTemplate(RenderContext renderContext) + { + renderContext.ContentWriter.Write(""); + + foreach (Element element in Children) + { + if (element is TemplateElement templateElement) + { + templateElement.RenderTemplate(renderContext); + } else + { + renderContext.ContentWriter.Write(element.ToString()); + } + } + + } + } +} diff --git a/html/TemplateElement.cs b/html/TemplateElement.cs new file mode 100644 index 0000000..3e45807 --- /dev/null +++ b/html/TemplateElement.cs @@ -0,0 +1,67 @@ +// /** +// * File: TemplateElement.cs +// * Author: haraldwolff +// * +// * This file and it's content is copyrighted by the Author and / or copyright holder. +// * Any use wihtout proper permission is illegal and may lead to legal actions. +// * +// * +// **/ +using System; +using System.IO; +using System.Collections.Generic; + +namespace ln.templates.html +{ + public class TemplateElement : Element + { + Dictionary expressions = new Dictionary(); + Dictionary loops = new Dictionary(); + List conditions = new List(); + + + public TemplateElement(string tagName) + :base(tagName) + { + } + + public override void SetAttribute(string attributeName, string attributeValue) + { + if (attributeName.StartsWith("v-for:",StringComparison.InvariantCultureIgnoreCase)) + loops.Add(attributeName.Substring(6), new Expression(attributeValue)); + else if (attributeName.Equals("v-if",StringComparison.InvariantCultureIgnoreCase)) + conditions.Add(new Expression(attributeValue)); + else if (attributeName[0] == ':') + expressions.Add(attributeName.Substring(1), new Expression(attributeValue)); + else + base.SetAttribute(attributeName, attributeValue); + } + + public virtual void RenderTemplate(RenderContext renderContext) + { + + + renderContext.ContentWriter.Write("<{0}", Name); + foreach (KeyValuePair attributePair in Attributes) + renderContext.ContentWriter.Write(" {0}=\"{1}\"", attributePair.Key, attributePair.Value); + renderContext.ContentWriter.Write(">"); + + if (!IsVoid) + { + foreach (Element element in Children) + { + if (element is TemplateElement templateElement) + { + templateElement.RenderTemplate(renderContext); + } + else + { + renderContext.ContentWriter.Write(element.ToString()); + } + } + renderContext.ContentWriter.Write("", Name); + } + } + + } +} diff --git a/html/TemplateReader.cs b/html/TemplateReader.cs new file mode 100644 index 0000000..6704231 --- /dev/null +++ b/html/TemplateReader.cs @@ -0,0 +1,70 @@ +// /** +// * File: TemplateReader.cs +// * Author: haraldwolff +// * +// * This file and it's content is copyrighted by the Author and / or copyright holder. +// * Any use wihtout proper permission is illegal and may lead to legal actions. +// * +// * +// **/ +using System; +using System.IO; +namespace ln.templates.html +{ + public class TemplateReader : ElementReader + { + + public virtual TemplateDocument TemplateDocument => Document as TemplateDocument; + + public TemplateReader() + { + } + + public override DocumentElement CreateDocument() => new TemplateDocument(); + public override Element CreateElement(string tagName) => new TemplateElement(tagName); + + public override void Text(string text) + { + if (text.Contains("{{")) + { + int pOpen = 0; + int pClose = 0; + + while (pOpen < text.Length) + { + pOpen = text.IndexOf("{{", pClose); + if (pOpen == -1) + pOpen = text.Length; + + string preText = text.Substring(pClose, pOpen - pClose); + if (preText.Length > 0) + { + CurrentElement.AppendChild(CreateTextElement(preText)); + } + + if (pOpen == text.Length) + break; + + pOpen += 2; + + pClose = text.IndexOf("}}", pOpen); + if (pClose == -1) + throw new FormatException("missing }}"); + + string expr = text.Substring(pOpen, pClose - pOpen - 1); + + pClose += 2; + + CurrentElement.AppendChild(new ExpressionElement(expr)); + } + + } else + { + CurrentElement.AppendChild( + CreateTextElement(text) + ); + } + } + + } +} diff --git a/html/TextElement.cs b/html/TextElement.cs new file mode 100644 index 0000000..8541eec --- /dev/null +++ b/html/TextElement.cs @@ -0,0 +1,30 @@ +// /** +// * File: TextElement.cs +// * Author: haraldwolff +// * +// * This file and it's content is copyrighted by the Author and / or copyright holder. +// * Any use wihtout proper permission is illegal and may lead to legal actions. +// * +// * +// **/ +using System; +using System.IO; + +namespace ln.templates.html +{ + public class TextElement : Element + { + public string Text { get; } + + public TextElement(string text) + :base("#text") + { + Text = text; + } + + public override void Render(TextWriter writer) + { + writer.Write(Text); + } + } +} diff --git a/ln.templates.csproj b/ln.templates.csproj index a54ade8..ce94b2d 100644 --- a/ln.templates.csproj +++ b/ln.templates.csproj @@ -1,5 +1,6 @@ + Debug AnyCPU @@ -29,6 +30,112 @@ + + ..\packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll + + + ..\packages\System.Text.Encoding.CodePages.4.5.1\lib\net461\System.Text.Encoding.CodePages.dll + + + nunit + + + ..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll + + + ..\packages\System.Collections.Immutable.1.5.0\lib\netstandard2.0\System.Collections.Immutable.dll + + + ..\packages\System.Numerics.Vectors.4.4.0\lib\net46\System.Numerics.Vectors.dll + + + + + ..\packages\System.Reflection.Metadata.1.6.0\lib\netstandard2.0\System.Reflection.Metadata.dll + + + ..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll + + + ..\packages\System.Threading.Tasks.Extensions.4.5.3\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll + + + + ..\packages\System.Console.4.3.0\lib\net46\System.Console.dll + + + ..\packages\System.Diagnostics.FileVersionInfo.4.3.0\lib\net46\System.Diagnostics.FileVersionInfo.dll + + + ..\packages\System.Diagnostics.StackTrace.4.3.0\lib\net46\System.Diagnostics.StackTrace.dll + + + ..\packages\System.IO.4.3.0\lib\net462\System.IO.dll + + + ..\packages\System.IO.Compression.4.3.0\lib\net46\System.IO.Compression.dll + + + ..\packages\System.IO.FileSystem.Primitives.4.3.0\lib\net46\System.IO.FileSystem.Primitives.dll + + + ..\packages\System.IO.FileSystem.4.3.0\lib\net46\System.IO.FileSystem.dll + + + ..\packages\System.Linq.4.3.0\lib\net463\System.Linq.dll + + + ..\packages\System.Linq.Expressions.4.3.0\lib\net463\System.Linq.Expressions.dll + + + ..\packages\System.Reflection.4.3.0\lib\net462\System.Reflection.dll + + + ..\packages\System.Runtime.4.3.0\lib\net462\System.Runtime.dll + + + + ..\packages\System.Runtime.Extensions.4.3.0\lib\net462\System.Runtime.Extensions.dll + + + ..\packages\System.Runtime.InteropServices.4.3.0\lib\net463\System.Runtime.InteropServices.dll + + + ..\packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll + + + ..\packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll + + + ..\packages\System.Security.Cryptography.Algorithms.4.3.0\lib\net463\System.Security.Cryptography.Algorithms.dll + + + ..\packages\System.Security.Cryptography.X509Certificates.4.3.0\lib\net461\System.Security.Cryptography.X509Certificates.dll + + + ..\packages\System.Threading.Thread.4.3.0\lib\net46\System.Threading.Thread.dll + + + ..\packages\System.ValueTuple.4.3.0\lib\netstandard1.0\System.ValueTuple.dll + + + ..\packages\System.Xml.ReaderWriter.4.3.0\lib\net46\System.Xml.ReaderWriter.dll + + + + ..\packages\System.Xml.XmlDocument.4.3.0\lib\net46\System.Xml.XmlDocument.dll + + + ..\packages\System.Xml.XPath.4.3.0\lib\net46\System.Xml.XPath.dll + + + ..\packages\System.Xml.XPath.XDocument.4.3.0\lib\net46\System.Xml.XPath.XDocument.dll + + + ..\packages\Jint.2.11.58\lib\net451\Jint.dll + + + @@ -43,9 +150,34 @@ + + + + + + + + + + + + + + + + + + + + + + + {8D9AB9A5-E513-4BA7-A450-534F6456BF28} + ln.types + \ No newline at end of file diff --git a/packages.config b/packages.config new file mode 100644 index 0000000..1d9ae5d --- /dev/null +++ b/packages.config @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/script/IScriptContext.cs b/script/IScriptContext.cs new file mode 100644 index 0000000..72d89ed --- /dev/null +++ b/script/IScriptContext.cs @@ -0,0 +1,20 @@ +// /** +// * File: IScriptContext.cs +// * Author: haraldwolff +// * +// * This file and it's content is copyrighted by the Author and / or copyright holder. +// * Any use wihtout proper permission is illegal and may lead to legal actions. +// * +// * +// **/ +using System; +using System.Collections.Generic; +namespace ln.templates.script +{ + public interface IScriptContext + { + IEnumerable ScriptObjectNames { get; } + object GetScriptObject(string itemName); + void SetScriptObject(string itemName, object value); + } +} diff --git a/script/NewExpression.cs b/script/NewExpression.cs new file mode 100644 index 0000000..baf1242 --- /dev/null +++ b/script/NewExpression.cs @@ -0,0 +1,61 @@ +// /** +// * File: NewExpression.cs +// * Author: haraldwolff +// * +// * This file and it's content is copyrighted by the Author and / or copyright holder. +// * Any use wihtout proper permission is illegal and may lead to legal actions. +// * +// * +// **/ +using System; +using Jint; +using Jint.Native.String; + +namespace ln.templates.script +{ + public class NewExpression + { + public string ExpressionText { get; } + + + public NewExpression(string expression) + { + ExpressionText = expression; + } + + + public virtual object Resolve(IScriptContext scriptContext) + { + Engine engine = new Engine(); + foreach (string itemName in scriptContext.ScriptObjectNames) + engine.SetValue(itemName, scriptContext.GetScriptObject(itemName)); + + return engine.Eval.Call(null, new Jint.Native.JsValue[] { ExpressionText }); + } + + public virtual bool IsTrue(IScriptContext scriptContext) + { + object resolved = Resolve(scriptContext); + if (resolved == null) + return false; + if (resolved is bool b) + return b; + if (resolved is string s) + return s.Length > 0; + if (resolved is int i) + return i != 0; + if (resolved is long l) + return l != 0; + if (resolved is short sh) + return sh != 0; + if (resolved is byte by) + return by != 0; + if (resolved is float f) + return Math.Abs(f) > float.Epsilon; + if (resolved is double d) + return Math.Abs(d) > double.Epsilon; + + return true; + } + } +} diff --git a/test/HtmlTests.cs b/test/HtmlTests.cs new file mode 100644 index 0000000..50a0af0 --- /dev/null +++ b/test/HtmlTests.cs @@ -0,0 +1,37 @@ +// /** +// * File: HtmlTests.cs +// * Author: haraldwolff +// * +// * This file and it's content is copyrighted by the Author and / or copyright holder. +// * Any use wihtout proper permission is illegal and may lead to legal actions. +// * +// * +// **/ +using NUnit.Framework; +using System; +using ln.templates.html; +using System.IO; +namespace ln.templates.test +{ + [TestFixture()] + public class HtmlTests + { + [Test()] + public void TestCase() + { + ln.templates.html.TemplateReader templateReader = new ln.templates.html.TemplateReader(); + templateReader.Read("\n\n\n Hello\n\n\n

Welcome to this example.

\n

{{ 'Ich bin ein ScriptText!' }}

\n

DateTime: {{ Date }}

\n

Ein bisschen JavaScript: {{ 5 + ' mal ' + 5 + ' = ' + (5*5) }}

\n\n"); + + Console.WriteLine("Source rendered:\n{0}", templateReader.Document.ToString()); + + StringWriter stringWriter = new StringWriter(); + RenderContext renderContext = new RenderContext(stringWriter); + + renderContext.SetScriptObject("Date", DateTime.Now); + + templateReader.TemplateDocument.RenderTemplate(renderContext); + + Console.WriteLine("Template rendered:\n{0}", stringWriter.ToString()); + } + } +}