/// <summary> /// Initializes a new instance of the <see cref="CSF.Zpt.Rendering.RenderingContext"/> class. /// </summary> /// <param name="metalContext">The METAL context.</param> /// <param name="talContext">The TAL context.</param> /// <param name="element">The ZPT element for which this context is created.</param> /// <param name="options">The rendering options.</param> /// <param name="sourceAnnotationRoot">The source annotation root path.</param> public RenderingContext(IModel metalContext, IModel talContext, IZptElement element, IRenderingSettings options, string sourceAnnotationRoot = null) { if(metalContext == null) { throw new ArgumentNullException(nameof(metalContext)); } if(talContext == null) { throw new ArgumentNullException(nameof(talContext)); } if(element == null) { throw new ArgumentNullException(nameof(element)); } if(options == null) { throw new ArgumentNullException(nameof(options)); } _metalContext = metalContext; _talContext = talContext; _element = element; _renderingOptions = options; _sourceAnnotationRoot = sourceAnnotationRoot; _originalAttributes = _element.GetAttributes(); }
/// <summary> /// Renders the current document, returning an <see cref="IZptElement"/> representing the rendered result. /// </summary> /// <returns>The result of the rendering process.</returns> /// <param name="model">An object to which the ZPT document is to be applied.</param> /// <param name="element">The original element to be rendered.</param> /// <param name="options">The rendering options to use. If <c>null</c> then default options are used.</param> /// <param name="contextConfigurator">An optional action to perform upon the root <see cref="IModelValueContainer"/>, to configure it.</param> public IZptElement RenderElement(object model, IZptElement element, IRenderingSettings options, Action<IModelValueContainer> contextConfigurator) { if(options == null) { throw new ArgumentNullException(nameof(options)); } if(element == null) { throw new ArgumentNullException(nameof(element)); } var output = element; var context = options.CreateRootContext(output, model); ZptConstants.TraceSource.TraceInformation(Resources.LogMessageFormats.RenderingDocument, (output.SourceFile != null)? output.SourceFile.FullName : "<unknown>", nameof(ZptDocument), nameof(RenderElement)); if(contextConfigurator != null) { contextConfigurator(context); } try { foreach(var visitor in options.ContextVisitors) { var contexts = visitor.VisitContext(context); if(contexts.Count() != 1) { string message = String.Format(Resources.ExceptionMessages.WrongCountOfReturnedContexts, typeof(IContextVisitor).Name, typeof(RenderingContext).Name); throw new RenderingException(message); } context = contexts.Single(); } } catch(Exception ex) { ZptConstants.TraceSource.TraceEvent(System.Diagnostics.TraceEventType.Error, 3, Resources.LogMessageFormats.UnexpectedRenderingException, nameof(ZptDocument), nameof(RenderElement), ex.ToString()); throw; } return context.Element; }
/// <summary> /// Initializes a new instance of the <see cref="CSF.Zpt.Rendering.RepetitionInfo"/> class. /// </summary> /// <param name="name">Name.</param> /// <param name="index">Index.</param> /// <param name="count">Count.</param> /// <param name="value">Value.</param> /// <param name="element">Element.</param> public RepetitionInfo(string name, int index, int count, object value, IZptElement element) { if(name == null) { throw new ArgumentNullException(nameof(name)); } this.Name = name; this.Index = index; this.Count = count; this.Value = value; this.AssociatedElement = element; }
/// <summary> /// Gets an array of <see cref="RepetitionInfo"/> which represents the repetitions of the element. /// </summary> /// <returns>The repetitions.</returns> /// <param name="sequence">The source sequence.</param> /// <param name="element">The source element.</param> /// <param name="repeatVariableName">Repeat variable name.</param> private IRepetitionInfo[] GetRepetitions(IEnumerable sequence, IZptElement element, string repeatVariableName) { var sequenceArray = sequence .Cast<object>() .ToArray(); int i = 0; return sequenceArray .Select(x => new RepetitionInfo(repeatVariableName, i++, sequenceArray.Length, x, element.Clone())) .Cast<IRepetitionInfo>() .ToArray(); }
public void Setup() { _defaultSettings = RenderingSettings.Default; _rootElement = Mock.Of<IZptElement>(); _renderedElement = Mock.Of<IZptElement>(); _elementRenderer = new Mock<IElementRenderer>(); _sut = new Mock<ZptDocument>(_elementRenderer.Object) { CallBase = true }; _sut.Protected().Setup<IRenderingSettings>("GetDefaultOptions").Returns(_defaultSettings); _sut.Protected().Setup<IZptElement>("GetRootElement").Returns(_rootElement); }
public IRenderingContext Create(IZptElement element, IRenderingSettings options, object model) { throw new NotImplementedException(); }
/// <summary> /// Replaces the current element in its respective DOM with the given replacement. /// </summary> /// <returns>A reference to the replacement element, in its new DOM.</returns> /// <param name="replacement">Replacement.</param> public override IZptElement ReplaceWith(IZptElement replacement) { var repl = ConvertTo<ZptXmlElement>(replacement); XmlNode importedNode; if(this.Node.ParentNode != null) { importedNode = this.Node.OwnerDocument.ImportNode(repl.Node, true); this.GetParent().ReplaceChild(importedNode, this.Node); } else { var newDocument = new XmlDocument(); importedNode = newDocument.ImportNode(repl.Node, true); newDocument.AppendChild(importedNode); } return new ZptXmlElement(importedNode, repl.SourceFile, this.OwnerDocument, isImported: true); }
/// <summary> /// Inserts a new child element into the current element's child elements. The new child will be the previous /// sibling before a given existing child. /// </summary> /// <returns>The newly-added element.</returns> /// <param name="existing">An existing child element, before which the child will be inserted.</param> /// <param name="newChild">The new child element to insert.</param> public override IZptElement InsertBefore(IZptElement existing, IZptElement newChild) { ZptXmlElement existingElement = ConvertTo<ZptXmlElement>(existing), newChildElement = ConvertTo<ZptXmlElement>(newChild); var importedNode = this.Node.OwnerDocument.ImportNode(newChildElement.Node, true); var output = this.Node.InsertBefore(importedNode, existingElement.Node); return new ZptXmlElement(output, newChild.SourceFile, this.OwnerDocument, isImported: true); }
/// <summary> /// Creates a new root <see cref="IRenderingContext"/> instance. /// </summary> /// <returns>The root rendering context.</returns> public virtual IRenderingContext CreateRootContext(IZptElement element) { return this.CreateRootContext(element, null); }
/// <summary> /// Parses the value of a 'tal:repeat' attribute and exposes the variable name and expression. /// </summary> /// <param name="attribute">Attribute.</param> /// <param name="variableName">Variable name.</param> /// <param name="expression">Expression.</param> /// <param name="element">The element which contains the attribute.</param> private void ParseAttributeValue(IZptAttribute attribute, out string variableName, out string expression, IZptElement element) { var attribMatch = AttributeMatcher.Match(attribute.Value); if(!attribMatch.Success) { string message = String.Format(ExceptionMessages.ZptAttributeParsingError, ZptConstants.Tal.Namespace, ZptConstants.Tal.RepeatAttribute, attribute.Value, element.Name); throw new ParserException(message) { SourceAttributeName = ZptConstants.Tal.RepeatAttribute, SourceElementName = element.Name, SourceAttributeValue = attribute.Value }; } variableName = attribMatch.Groups[1].Value; expression = attribMatch.Groups[2].Value; }
/// <summary> /// Replaces the current element in its respective DOM with the given replacement. /// </summary> /// <returns>A reference to the replacement element, in its new DOM.</returns> /// <param name="replacement">Replacement.</param> public override IZptElement ReplaceWith(IZptElement replacement) { var repl = ConvertTo<ZptXmlLinqElement>(replacement); var cloned = ((ZptXmlLinqElement) repl.Clone()).Node; if(this.Node.Parent != null) { this.Node.ReplaceWith(cloned); } else { this.Node.Document.Root.ReplaceWith(cloned); } return new ZptXmlLinqElement(cloned, repl.SourceFile, this.OwnerDocument, isImported: true); }
/// <summary> /// Renders an element to the given <c>System.IO.TextWriter</c>. /// </summary> /// <param name="writer">The text writer to render to.</param> /// <param name="element">The element to render.</param> /// <param name="options">The rendering options to use. If <c>null</c> then default options are used.</param> protected override void Render(TextWriter writer, IZptElement element, IRenderingSettings options) { if(writer == null) { throw new ArgumentNullException(nameof(writer)); } if(element == null) { throw new ArgumentNullException(nameof(element)); } var xmlElement = ConvertElement<ZptXmlLinqElement>(element); var settings = new XmlWriterSettings(); settings.Indent = true; settings.Encoding = options.OutputEncoding; settings.OmitXmlDeclaration = options.OmitXmlDeclaration; using(var xmlWriter = XmlTextWriter.Create(writer, settings)) { xmlElement.Node.Document.Save(xmlWriter); } }
/// <summary> /// Create a context instance. /// </summary> public virtual IRenderingContext Create(IZptElement element, IRenderingSettings options, object model) { if(element == null) { throw new ArgumentNullException(nameof(element)); } if(options == null) { throw new ArgumentNullException(nameof(options)); } NamedObjectWrapper metalKeywordOptions = new NamedObjectWrapper(MetalKeywordOptions), talKeywordOptions = new NamedObjectWrapper(TalKeywordOptions); IModel metalModel = new TalesModel(this.EvaluatorRegistry, metalKeywordOptions, modelObject: model), talModel = new TalesModel(this.EvaluatorRegistry, talKeywordOptions, modelObject: model); PopulateMetalModel(metalModel); PopulateTalModel(talModel); return new RenderingContext(metalModel, talModel, element, options, this.RootDocumentPath); }
/// <summary> /// Create a context instance. /// </summary> public virtual IRenderingContext Create(IZptElement element, IRenderingSettings options) { return Create(element, options, null); }
/// <summary> /// Replaces the current element in its respective DOM with the given replacement. /// </summary> /// <returns>A reference to the replacement element, in its new DOM.</returns> /// <param name="replacement">Replacement.</param> public override IZptElement ReplaceWith(IZptElement replacement) { var repl = ConvertTo<ZptHtmlElement>(replacement); try { var parent = this.GetParent(); return new ZptHtmlElement(parent.ReplaceChild(repl.Node, this.Node), repl.SourceFile, OwnerDocument, isImported: true); } catch(InvalidOperationException) { this.Node.Remove(); return new ZptHtmlElement(repl.Node, repl.SourceFile, OwnerDocument, isImported: true); } }
/// <summary> /// Inserts a new child element into the current element's child elements. The new child will be the previous /// sibling before a given existing child. /// </summary> /// <returns>The newly-added element.</returns> /// <param name="existing">An existing child element, before which the child will be inserted.</param> /// <param name="newChild">The new child element to insert.</param> public override IZptElement InsertBefore(IZptElement existing, IZptElement newChild) { ZptHtmlElement existingElement = ConvertTo<ZptHtmlElement>(existing), newChildElement = ConvertTo<ZptHtmlElement>(newChild); HtmlNode existingNode = existingElement.Node; var prevNode = existingNode.PreviousSibling; if(prevNode.NodeType == HtmlNodeType.Text) { var lastLine = prevNode.InnerText .Split(new[] { "\r\n", "\n" }, StringSplitOptions.None) .Last(); if(String.IsNullOrWhiteSpace(lastLine)) { var newLine = this.Node.OwnerDocument.CreateTextNode(String.Concat(System.Environment.NewLine, lastLine)); existingNode = this.Node.InsertBefore(newLine, existingNode); } } var output = this.Node.InsertBefore(newChildElement.Node, existingNode); return new ZptHtmlElement(output, newChild.SourceFile, this.OwnerDocument, isImported: true); }
/// <summary> /// Creates a new root <see cref="IRenderingContext"/> instance. /// </summary> /// <param name="element">The root ZPT element</param> /// <param name="model">The model to render</param> /// <returns>The root rendering context.</returns> public virtual IRenderingContext CreateRootContext(IZptElement element, object model) { if(element == null) { throw new ArgumentNullException(nameof(element)); } return this.ContextFactory.Create(element, this, model); }
/// <summary> /// Inserts a new child element into the current element's child elements. The new child will be the previous /// sibling before a given existing child. /// </summary> /// <returns>The newly-added element.</returns> /// <param name="existing">An existing child element, before which the child will be inserted.</param> /// <param name="newChild">The new child element to insert.</param> public override IZptElement InsertBefore(IZptElement existing, IZptElement newChild) { ZptXmlLinqElement existingElement = ConvertTo<ZptXmlLinqElement>(existing), newChildElement = ConvertTo<ZptXmlLinqElement>(newChild); existingElement.Node.AddBeforeSelf(newChildElement.Node); return new ZptXmlLinqElement(newChildElement.Node, newChild.SourceFile, this.OwnerDocument, isImported: true); }
/// <summary> /// Determines whether this instance is from same document as the specified element. /// </summary> /// <returns><c>true</c> if this instance is from same document as the specified element; otherwise, <c>false</c>.</returns> /// <param name="other">The element to test.</param> public override bool IsFromSameDocumentAs(IZptElement other) { if(other == null) { throw new ArgumentNullException(nameof(other)); } var typedOther = ConvertTo<ZptXmlLinqElement>(other); return this.Node.Document == typedOther.Node.Document; }
/// <summary> /// Renders an element to the given <c>System.IO.TextWriter</c>. /// </summary> /// <param name="writer">The text writer to render to.</param> /// <param name="element">The element to render.</param> /// <param name="options">The rendering options to use. If <c>null</c> then default options are used.</param> protected override void Render(TextWriter writer, IZptElement element, IRenderingSettings options) { if(writer == null) { throw new ArgumentNullException(nameof(writer)); } if(element == null) { throw new ArgumentNullException(nameof(element)); } var htmlElement = ConvertElement<ZptHtmlElement>(element); htmlElement.Node.WriteTo(writer); }
/// <summary> /// Creates and returns a new sibling rendering context. /// </summary> /// <returns>The sibling context.</returns> /// <param name="element">The ZPT element for which the new context is to be created.</param> /// <param name="cloneAttributes">A value indicating whether or not the element's attributes should be cloned or not.</param> public virtual IRenderingContext CreateSiblingContext(IZptElement element, bool cloneAttributes = false) { if(element == null) { throw new ArgumentNullException(nameof(element)); } var output = new RenderingContext(this.MetalModel.CreateSiblingModel(), this.TalModel.CreateSiblingModel(), element, this.RenderingOptions, this.SourceAnnotationRootPath); if(cloneAttributes) { output.OriginalAttributes = this.OriginalAttributes; } return output; }
/// <summary> /// Attempts to get a object instance from the root of the current model, but only searches local variable /// definitions. /// </summary> /// <returns> /// <c>true</c>, if a root item was found matching the given <paramref name="name"/>, <c>false</c> otherwise. /// </returns> /// <param name="name">The name of the desired item.</param> /// <param name="element">The ZPT element.</param> /// <param name="result"> /// Exposes the found object if this method returns <c>true</c>. The value is undefined if this method returns /// <c>false</c>. /// </param> public virtual bool TryGetLocalRootObject(string name, IZptElement element, out object result) { bool output; if(base.LocalDefinitions.ContainsKey(name)) { output = true; result = base.LocalDefinitions[name]; } else { output = false; result = null; } return output; }
/// <summary> /// Extends a given macro and then makes substitutions into the source context. /// </summary> /// <returns>The resultant rendering context after the substitutions are performed.</returns> /// <param name="context">The rendering context.</param> /// <param name="macro">The macro element to extend and use for substitutions.</param> public virtual IRenderingContext ExtendAndSubstitute(IRenderingContext context, IZptElement macro) { IList<IRenderingContext> discarded = new List<IRenderingContext>(); return ExtendAndSubstitute(context, macro, ref discarded, _normalSubstituter); }
/// <summary> /// Extends a given macro and then makes substitutions into the source context. /// </summary> /// <returns>The resultant rendering context after the substitutions are performed.</returns> /// <param name="context">The rendering context.</param> /// <param name="macro">The macro element to extend and use for substitutions.</param> /// <param name="macroStack">The collection of macros passed through to get to this point.</param> /// <param name="substitutionStrategy">The macro substitution strategy to use.</param> public virtual IRenderingContext ExtendAndSubstitute(IRenderingContext context, IZptElement macro, ref IList<IRenderingContext> macroStack, IMacroSubstituter substitutionStrategy) { if(context == null) { throw new ArgumentNullException(nameof(context)); } if(macro == null) { throw new ArgumentNullException(nameof(macro)); } if(macroStack == null) { throw new ArgumentNullException(nameof(macroStack)); } if(substitutionStrategy == null) { throw new ArgumentNullException(nameof(substitutionStrategy)); } var macroContext = context.CreateSiblingContext(macro); macroStack.Add(macroContext); var extendedContext = GetFullyExtendedContext(macroContext, ref macroStack); return substitutionStrategy.MakeSubstitutions(context, extendedContext, macroStack); }