Click here to Skip to main content
15,891,864 members
Articles / Web Development / HTML

Email Templates

Rate me:
Please Sign up or sign in to vote.
4.51/5 (44 votes)
29 Jul 2007CPOL6 min read 292.1K   8.1K   170  
In this article, I am going to consider the process of managing and sending emails inside a .NET application.
Imports System
Imports System.IO
Imports System.Collections
Imports System.Collections.Generic

Namespace TemplateParser

    Public Class Parser

        Private _strTemplateBlock As String
        Private _hstValues As Hashtable
        Private _ErrorMessage As New Hashtable()
        Private _ParsedBlock As String

        Private _Blocks = New Dictionary(Of String, Parser)

        Private VariableTagBegin As String = "##"
        Private VariableTagEnd As String = "##"

        Private ModificatorTag As String = ":"
        Private ModificatorParamSep As String = ","

        Private ConditionTagIfBegin As String = "##If--"
        Private ConditionTagIfEnd As String = "##"
        Private ConditionTagElseBegin As String = "##Else--"
        Private ConditionTagElseEnd As String = "##"
        Private ConditionTagEndIfBegin As String = "##EndIf--"
        Private ConditionTagEndIfEnd As String = "##"

        Private BlockTagBeginBegin As String = "##BlockBegin--"
        Private BlockTagBeginEnd As String = "##"
        Private BlockTagEndBegin As String = "##BlockEnd--"
        Private BlockTagEndEnd As String = "##"

        Public Property TemplateBlock() As String
            Get
                Return Me._strTemplateBlock
            End Get
            Set(ByVal value As String)
                Me._strTemplateBlock = value
                ParseBlocks()
            End Set
        End Property

        Public Property Variables() As Hashtable
            Get
                Return Me._hstValues
            End Get
            Set(ByVal value As Hashtable)
                Me._hstValues = value
            End Set
        End Property

        Public ReadOnly Property ErrorMessage() As Hashtable
            Get
                Return _ErrorMessage
            End Get
        End Property

        ReadOnly Property Blocks() As Dictionary(Of String, Parser)
            Get
                Return _Blocks
            End Get
        End Property

        ' Creates a new instance of TemplateParser
        Public Sub New()
            Me._strTemplateBlock = ""
        End Sub

        Public Sub New(ByVal FilePath As String)
            ReadTemplateFromFile(FilePath)
            ParseBlocks()
        End Sub

        Public Sub New(ByVal Variables As Hashtable)
            Me._hstValues = Variables
        End Sub

        Public Sub New(ByVal FilePath As String, ByVal Variables As Hashtable)
            ReadTemplateFromFile(FilePath)
            Me._hstValues = Variables
            ParseBlocks()
        End Sub

        ' Setup template from specified file
        Public Sub SetTemplateFromFile(ByVal FilePath As String)
            ReadTemplateFromFile(FilePath)
        End Sub

        ' Setup template as string block
        Public Sub SetTemplate(ByVal TemplateBlock As String)
            Me.TemplateBlock = TemplateBlock
        End Sub

        ' Parse template after setuping Template and Variables
        Public Function Parse() As String
            ParseConditions()
            ParseVariables()
            Return Me._ParsedBlock
        End Function

        'Parse Template Block
        Public Function ParseBlock(ByVal BlockName As String, ByVal Variables As Hashtable) As String
            If Not Me._Blocks.ContainsKey(BlockName) Then
                Throw New ArgumentException([String].Format("Could not find Block with Name '{0}'", BlockName))
            End If

            Me._Blocks(BlockName).Variables = Variables
            Return Me._Blocks(BlockName).Parse()
        End Function

        ' Parse template and save result into specified file
        Public Function ParseToFile(ByVal FilePath As String, ByVal ReplaceIfExists As Boolean) As Boolean
            If File.Exists(FilePath) And Not ReplaceIfExists Then
                Return False
            Else
                Dim sr As StreamWriter = File.CreateText(FilePath)
                sr.Write(Parse())
                sr.Close()
                Return True
            End If
        End Function

        ' Read template content from specified file
        Private Sub ReadTemplateFromFile(ByVal FilePath As String)
            If Not File.Exists(FilePath) Then
                Throw New ArgumentException("Template file does not exist.")
            End If

            Dim reader As New StreamReader(FilePath)
            Me.TemplateBlock = reader.ReadToEnd()
            reader.Close()
        End Sub

        ' Parse all blocks in template
        Private Sub ParseBlocks()
            'int idxPrevious = 0;
            Dim idxCurrent As Integer = Me._strTemplateBlock.IndexOf(Me.BlockTagBeginBegin, idxCurrent)
            While (idxCurrent <> -1)
                Dim BlockName As String
                Dim idxBlockBeginBegin, idxBlockBeginEnd, idxBlockEndBegin As Integer

                idxBlockBeginBegin = idxCurrent
                idxCurrent += Me.BlockTagBeginBegin.Length

                ' Searching for BlockBeginEnd Index
                idxBlockBeginEnd = Me._strTemplateBlock.IndexOf(Me.BlockTagBeginEnd, idxCurrent)
                If idxBlockBeginEnd = -1 Then
                    Throw New Exception("Could not find BlockTagBeginEnd")
                End If
                ' Getting Block Name
                BlockName = Me._strTemplateBlock.Substring(idxCurrent, idxBlockBeginEnd - idxCurrent)
                idxCurrent = idxBlockBeginEnd + Me.BlockTagBeginEnd.Length

                ' Getting End of Block index
                Dim EndBlockStatment As String = Me.BlockTagEndBegin + BlockName + Me.BlockTagEndEnd
                idxBlockEndBegin = Me._strTemplateBlock.IndexOf(EndBlockStatment, idxCurrent)
                If idxBlockEndBegin = -1 Then
                    Throw New Exception("Could not find End of Block with name '" + BlockName + "'")
                End If
                ' Add Block to Dictionary
                Dim block As New Parser()
                block.TemplateBlock = Me._strTemplateBlock.Substring(idxCurrent, idxBlockEndBegin - idxCurrent)
                Me._Blocks.Add(BlockName, block)

                ' Remove Block Declaration From Template
                Me._strTemplateBlock = Me._strTemplateBlock.Remove(idxBlockBeginBegin, idxBlockEndBegin - idxBlockBeginBegin)

                idxCurrent = idxBlockBeginBegin
                idxCurrent = Me._strTemplateBlock.IndexOf(Me.BlockTagBeginBegin, idxCurrent)
            End While
        End Sub

        ' Parse all conditions in template
        Private Sub ParseConditions()
            Dim idxPrevious As Integer = 0
            Dim idxCurrent As Integer = Me._strTemplateBlock.IndexOf(Me.ConditionTagIfBegin, idxCurrent)
            Me._ParsedBlock = ""
            While (idxCurrent <> -1)
                Dim VarName As String
                Dim TrueBlock, FalseBlock As String
                Dim ElseStatment, EndIfStatment As String
                Dim idxIfBegin, idxIfEnd, idxElseBegin, idxEndIfBegin As Integer
                Dim boolValue As Boolean

                idxIfBegin = idxCurrent
                idxCurrent += Me.ConditionTagIfBegin.Length

                ' Searching for EndIf Index
                idxIfEnd = Me._strTemplateBlock.IndexOf(Me.ConditionTagIfEnd, idxCurrent)
                If idxIfEnd = -1 Then
                    Throw New Exception("Could not find ConditionTagIfEnd")
                End If
                ' Getting Value Name
                VarName = Me._strTemplateBlock.Substring(idxCurrent, idxIfEnd - idxCurrent)

                idxCurrent = idxIfEnd + Me.ConditionTagIfEnd.Length

                ' Compare ElseIf and EndIf Indexes
                ElseStatment = Me.ConditionTagElseBegin + VarName + Me.ConditionTagElseEnd
                EndIfStatment = Me.ConditionTagEndIfBegin + VarName + Me.ConditionTagEndIfEnd
                idxElseBegin = Me._strTemplateBlock.IndexOf(ElseStatment, idxCurrent)
                idxEndIfBegin = Me._strTemplateBlock.IndexOf(EndIfStatment, idxCurrent)
                If idxElseBegin > idxEndIfBegin Then
                    Throw New Exception("Condition Else Tag placed after Condition Tag EndIf for '" + VarName + "'")
                End If
                ' Getting True and False Condition Blocks
                If idxElseBegin <> -1 Then
                    TrueBlock = Me._strTemplateBlock.Substring(idxCurrent, idxElseBegin - idxCurrent)
                    FalseBlock = Me._strTemplateBlock.Substring(idxElseBegin + ElseStatment.Length, idxEndIfBegin - idxElseBegin - ElseStatment.Length)
                Else
                    TrueBlock = Me._strTemplateBlock.Substring(idxCurrent, idxEndIfBegin - idxCurrent)
                    FalseBlock = ""
                End If

                ' Parse Condition
                Try
                    boolValue = Convert.ToBoolean(Me._hstValues(VarName))
                Catch
                End Try

                Dim BeforeBlock As String = Me._strTemplateBlock.Substring(idxPrevious, idxIfBegin - idxPrevious)

                If Me._hstValues.ContainsKey(VarName) And boolValue Then
                    Me._ParsedBlock += BeforeBlock + TrueBlock.Trim()
                Else
                    Me._ParsedBlock += BeforeBlock + FalseBlock.Trim()
                End If

                idxCurrent = idxEndIfBegin + EndIfStatment.Length
                idxPrevious = idxCurrent

                idxCurrent = Me._strTemplateBlock.IndexOf(Me.ConditionTagIfBegin, idxCurrent)
            End While
            Me._ParsedBlock += Me._strTemplateBlock.Substring(idxPrevious)
        End Sub

        ' Parse all variables in template
        Private Sub ParseVariables()
            Dim idxCurrent As Integer = Me._ParsedBlock.IndexOf(Me.VariableTagBegin, idxCurrent)
            While (idxCurrent <> -1)
                Dim VarName, VarValue As String
                Dim idxVarTagEnd As Integer

                idxVarTagEnd = Me._ParsedBlock.IndexOf(Me.VariableTagEnd, idxCurrent + Me.VariableTagBegin.Length)
                If idxVarTagEnd = -1 Then
                    Throw New Exception([String].Format("Index {0}: could not find Variable End Tag", idxCurrent))
                End If
                ' Getting Variable Name
                VarName = Me._ParsedBlock.Substring(idxCurrent + Me.VariableTagBegin.Length, idxVarTagEnd - idxCurrent - Me.VariableTagBegin.Length)

                ' Checking for Modificators
                Dim VarParts As String() = VarName.Split(Me.ModificatorTag.ToCharArray())
                VarName = VarParts(0)

                ' Getting Variable Value
                ' If Variable doesn't exist in _hstValue then
                ' Variable Value equal empty string
                ' [added 6/6/2006] If variable is null than it will also has empty string
                VarValue = [String].Empty
                If Me._hstValues.ContainsKey(VarName) And Not (Me._hstValues(VarName) Is Nothing) Then
                    VarValue = Me._hstValues(VarName).ToString()
                End If

                ' Apply All Modificators to Variable Value
                Dim i As Integer
                For i = 1 To VarParts.Length - 1
                    Me.ApplyModificator(VarValue, VarParts(i))
                Next i
                ' Replace Variable in Template
                Me._ParsedBlock = Me._ParsedBlock.Substring(0, idxCurrent) + VarValue + Me._ParsedBlock.Substring((idxVarTagEnd + Me.VariableTagEnd.Length))

                ' Add Length of added value to Current index 
                ' to prevent looking for variables in the added value
                ' Fixed Date: April 5, 2006
                idxCurrent += VarValue.Length

                idxCurrent = Me._ParsedBlock.IndexOf(Me.VariableTagBegin, idxCurrent)
            End While
        End Sub

        ' Method for applying modificators to variable value
        Private Sub ApplyModificator(ByRef Value As String, ByVal Modificator As String)
            ' Checking for parameters
            Dim strModificatorName As String = ""
            Dim strParameters As String = ""
            Dim idxStartBrackets, idxEndBrackets As Integer
            idxStartBrackets = Modificator.IndexOf("(")
            If idxStartBrackets <> -1 Then
                idxEndBrackets = Modificator.IndexOf(")", idxStartBrackets)
                If idxEndBrackets = -1 Then
                    Throw New Exception("Incorrect modificator expression")
                Else
                    strModificatorName = Modificator.Substring(0, idxStartBrackets).ToUpper()
                    strParameters = Modificator.Substring(idxStartBrackets + 1, idxEndBrackets - idxStartBrackets - 1)
                End If
            Else
                strModificatorName = Modificator.ToUpper()
            End If
            Dim arrParameters As String() = strParameters.Split(Me.ModificatorParamSep.ToCharArray())
            Dim i As Integer
            For i = 0 To arrParameters.Length - 1
                arrParameters(i) = arrParameters(i).Trim()
            Next i
            Try
                Dim typeModificator As Type = Type.GetType(("TemplateParser.Modificators." + strModificatorName))
                If typeModificator.IsSubclassOf(Type.GetType("TemplateParser.Modificators.Modificator")) Then
                    Dim objModificator As Modificators.Modificator = CType(Activator.CreateInstance(typeModificator), Modificators.Modificator)
                    objModificator.Apply(Value, arrParameters)
                End If
            Catch
            End Try
        End Sub

    End Class

End Namespace

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
Ukraine Ukraine
Alexander is freelance web developer with 4 years experience. He has skills in ASP.NET/MS SQL Server, PHP/MySQL, Ruby On Rails, XHTML, CSS. You can contact with me by seigo.ua@gmail.com. Also check my homepage at www.klalex.com.

Comments and Discussions