Einfache Template "Engine" (als Interface)

Hier könnt Ihr gute, von Euch geschriebene Codes posten. Sie müssen auf jeden Fall funktionieren und sollten möglichst effizient, elegant und beispielhaft oder einfach nur cool sein.
Benutzeravatar
Deluxe0321
Beiträge: 336
Registriert: 19.05.2006 00:31
Kontaktdaten:

Einfache Template "Engine" (als Interface)

Beitrag von Deluxe0321 »

Servus,
ich habe vor kurzem eine kleine Template "Engine" geschrieben (wenn man das so nennen kann), um mir eine schnelle und einfache Möglichkeit zu geben
Content entsprechend zu füllen. Der Code ist realtiv simpel gestrickt, aber dafür recht schnell. Es werden Variablen und Schleifen im Template unterstüzt.

Wie sollte das ganze verwendet werden?
- Template Laden (Datei/String/Memory)
- Content Hinzufügen (ContentID.i = AddContent(ID.i))
- Content Setzten (SetContent(ContentID.i,"VARIABLE","ERSETZTE MIT")
Bei Schleifen ist es grundlegend das selbe Prinzip, jedoch muss die SchleifenID verwendet werden (GetLoopID("SCHLEIFEN_NAME")).
Für jedes "Feld" muss das oben geschriebene erneut ausgeführt werden.

Template Variable:
{tp:var:meinVariableNamen}

Template Schleife:
Start: {tp:loop:mylooptitle:start}
-- DEIN CONTENT z.B. {tp:var:meinVariableNamen_inschleife}
Ende: {tp:loop:mylooptitle:end}

Es sind auch "Schleifen in Schleifen" möglich, ich habe dazu entsprechend ein Beispielcode hinzugefügt.

Hoffe das ist für euch brauchbar, ich nutze es Regelmäßig.

Code: Alles auswählen

EnableExplicit

CompilerIf Defined(FileToStringEx,#PB_Procedure)
CompilerElse
  ; read the file in to the memory and convert it to a string
  Procedure.s FileToStringEx(File.s)
    Protected *memory, String.s, Bom.i, FileID.i
    If FileSize(File.s) > -1
      FileID.i = ReadFile(#PB_Any,File.s)
      Bom.i = ReadStringFormat(FileID.i)
      If FileID.i
        *memory = AllocateMemory(FileSize(File.s))
        If *memory
          ReadData(FileID.i,*memory,FileSize(File.s)) 
          String.s = PeekS(*memory,FileSize(File.s),Bom.i)
          FreeMemory(*memory)
          CloseFile(FileID.i)
        EndIf
        ProcedureReturn String.s
      EndIf
    EndIf
  EndProcedure
CompilerEndIf 

Structure easy_template_fieldcontent
  *Content
  *Element
EndStructure

Structure easy_template_fields
  ID.i
  Name.s
  LoopName.s
  IsHolder.b
  List Content.easy_template_fieldcontent()
EndStructure

Structure easy_template_templateholder
  ID.i
  ParentID.i
  Name.s
  Content.s
  List Fields.easy_template_fields()
EndStructure

Structure easy_template_data
  *Field
  Content.s
  List SelfRef.i()
EndStructure

Structure easy_template_dataholder
  ContentID.i
  TemplateID.i
  *Template
  List Elements.easy_template_data()
EndStructure

Structure easy_template_link
  FieldName.s
  TemplateName.s
  TemplateID.i
  *Template
  *Field
EndStructure

Structure easy_template_fix_fields
  List Fields.easy_template_link() 
EndStructure

Structure easy_template
  ___procs.i
  List Template.easy_template_templateholder()
  List TemplateLink.easy_template_link()
  List Content.easy_template_dataholder()
EndStructure

Interface EasyTemplate
  AddField(ID.i, Name.s, isHolder.b = #False, LoopElementName.s = "")
  RelinkFields(ID.i,*fields.easy_template_fix_fields)
  LoadString(Content.s,ParentID.i = -1,TemplateName.s = "")
  LoadMemory(*Memory,Size.i,ParentID.i = -1)
  LoadFile(File.s,ParentID.i = -1)
  GetLoopID(TemplateID.i,LoopName.s)
  AddContent(TemplateID.i)
  SetContent(ContentID.i,Name.s,Value.s)
  Build.s(TemplateID.i,*ContentRef = 0)
  Destroy()
EndInterface

Procedure.i EasyTemplate_AddField(*this.easy_template,ID.i,Name.s,isHolder.b = #False,LoopElementName.s = "")
  Protected Found.b,IsContentID.b,IsID.b
  If ListSize(*this\Template())
    ForEach *this\Template()
      If *this\Template()\ID.i = ID.i
        IsID.b = #True
        ForEach *this\Template()\Fields()
          If *this\Template()\Fields()\Name.s = Name.s
            Found.b = #True
            Break
          EndIf
        Next
        Break
      EndIf
    Next
    If Not Found.b And IsID.b
      AddElement(*this\Template()\Fields())
      *this\Template()\Fields()\Name.s = Name.s
      *this\Template()\Fields()\isHolder.b = isHolder.b
      *this\Template()\Fields()\LoopName = LoopElementName.s
      ;Debug "Added: "+ Name.s
      ProcedureReturn #True
    EndIf
  EndIf
EndProcedure

Procedure.i EasyTemplate_RelinkFields(*this.easy_template,ID.i,*fields.easy_template_fix_fields)
  Protected *curr
  If ListSize(*this\Template()) And ID.i And *fields
    ForEach *this\Template()
      If *this\Template()\ID.i = ID.i
        ForEach *this\Template()\Fields()
          AddElement(*fields\Fields())
          *fields\Fields()\FieldName.s = *this\Template()\Fields()\Name.s
          *fields\Fields()\Field = @*this\Template()\Fields()
          *fields\Fields()\Template = @*this\Template()
          *fields\Fields()\TemplateName.s = *this\Template()\Name.s
          *fields\Fields()\TemplateID.i   = *this\Template()\ID.i
        Next
      EndIf
     
      If *this\Template()\ParentID.i = ID.i
        *curr = @*this\Template()
        EasyTemplate_RelinkFields(*this,*this\Template()\ID.i,*fields)
        ChangeCurrentElement(*this\Template(),*curr)
      EndIf
       
    Next
  EndIf
EndProcedure

Procedure.i EasyTemplate_LoadString(*this.easy_template,Content.s,ParentID.i = -1,TemplateName.s = "")
  Protected Dim Extract.s(0), Extraction.s, LoopPart.s, EndElement.s
  Protected Expression.i, *CurrElement, Size.i, ElementID.i, On.i, ChildElement.i
  Protected StartPos.i,EndPos.i
  Protected fields.easy_template_fix_fields
 
  Expression.i = CreateRegularExpression(#PB_Any,"{tp:[^}]*}")
  If Content.s And Expression.i
    Size.i = ExtractRegularExpression(Expression.i,Content.s,Extract())
    FreeRegularExpression(Expression.i)
    If Size.i
      ElementID.i = Random(ElapsedMilliseconds()) + ListSize(*this\Template())
      AddElement(*this\Template())
      *this\Template()\ID.i = ElementID.i
      If Not ParentID.i = -1
        *this\Template()\ParentID.i = ParentID.i
        *this\Template()\Name.s = TemplateName.s
      EndIf 
      *CurrElement = *this\Template()
      For On.i=0 To Size.i - 1
        Extraction.s = RemoveString(RemoveString(Extract(On.i),"{"),"}")
        Select LCase(StringField(Extraction.s,2,":"))
          Case "var"
            EasyTemplate_AddField(*this,ElementID.i,StringField(Extraction.s,3,":"))  
          Case "loop"
            If LCase(StringField(Extraction.s,4,":")) = "start"
              ;Debug "Found LOOP! --> "+Extract(On.i)
              StartPos.i = FindString(Content.s,Extract(On.i))
              EndPos.i   = FindString(Content.s,"{tp:loop:"+StringField(Extraction.s,3,":")+":end}",StartPos.i)
              If EndPos.i
                LoopPart.s = Mid(Content.s,StartPos.i+Len(Extract(On.i)),EndPos.i - (StartPos.i + Len(Extract(On.i))))  
                ChildElement.i = EasyTemplate_LoadString(*this,LoopPart.s,ElementID.i,StringField(Extraction.s,3,":"))
                Content.s = ReplaceString(Content.s,Extract(On.i)+LoopPart.s+"{tp:loop:"+StringField(Extraction.s,3,":")+":end}","{tp:holder:"+Str(ChildElement.i)+"}")
                EasyTemplate_AddField(*this,ElementID.i,Str(ChildElement.i),#True,StringField(Extraction.s,3,":"))
                EndElement.s = "{tp:loop:"+StringField(Extraction.s,3,":")+":end}"
                Repeat
                  If Extract(On.i) = EndElement.s
                    Break 
                  Else
                    If Not (On.i + 1) > (Size.i - 1)
                      On.i + 1
                    Else
                      Break
                    EndIf
                  EndIf   
                ForEver
              EndIf
            EndIf
        EndSelect
      Next
      ChangeCurrentElement(*this\Template(),*CurrElement)
       *this\Template()\Content.s = Content.s
       If ParentID.i = -1
         EasyTemplate_RelinkFields(*this,ElementID.i,@fields)
         If ListSize(fields\Fields())
           ChangeCurrentElement(*this\Template(),*CurrElement)
           CopyList(fields\Fields(),*this\TemplateLink())
         EndIf
       EndIf
      ProcedureReturn ElementID.i
    EndIf
  EndIf
EndProcedure

Procedure.i EasyTemplate_LoadMemory(*this.easy_template,*Memory,Size.i,ParentID.i = -1)
  Protected String.s
  If *Memory > 0 And *this
    String.s = PeekS(*Memory,Size.i)
    If String.s
      ProcedureReturn EasyTemplate_LoadString(*this,String.s,ParentID.i)   
    EndIf
  EndIf
EndProcedure

Procedure.i EasyTemplate_LoadFile(*this.easy_template,File.s,ParentID.i = -1)
  Protected Content.s
  If FileSize(File.s) > 0 And *this
    Content.s = FileToStringEx(File.s)
    If Content.s
      ProcedureReturn EasyTemplate_LoadString(*this,Content.s,ParentID.i)
    EndIf
  EndIf
EndProcedure

Procedure.i EasyTemplate_GetLoopID(*this.easy_template,TemplateID.i,LoopName.s)
  If *this
    If TemplateID.i > 0 And ListSize(*this\Template()) And ListSize(*this\TemplateLink())
     
      ForEach *this\TemplateLink()
        If *this\TemplateLink()\TemplateName.s = LoopName.s
          If *this\TemplateLink()\Template
            ChangeCurrentElement(@*this\Template(),*this\TemplateLink()\Template)
            ProcedureReturn *this\Template()\ID.i
          EndIf
        EndIf
      Next   
     
    EndIf
  EndIf
EndProcedure

Procedure.i EasyTemplate_AddContent(*this.easy_template,TemplateID.i)
  Protected *ID, ContentID.i, *Content
  If TemplateID.i > 0 And *this
    ForEach *this\TemplateLink()
     
      If *this\TemplateLink()\TemplateID = TemplateID.i
        If *this\TemplateLink()\Template
          AddElement(*this\Content())
          *ID = *this\TemplateLink()\Template
          ContentID.i = ListSize(*this\Content())
          *Content = @*this\Content()
          *this\Content()\ContentID.i = ContentID.i
          *this\Content()\TemplateID.i = TemplateID.i
          *this\Content()\Template = *ID
         
          ChangeCurrentElement(*this\Template(),*ID)
          ForEach *this\Template()\Fields()
            AddElement(*this\Content()\Elements())
              *this\Content()\Elements()\Field = @*this\Template()\Fields()
            AddElement(*this\Template()\Fields()\Content())
              *this\Template()\Fields()\Content()\Element = @*this\Content()\Elements()
              *this\Template()\Fields()\Content()\Content = @*this\Content()
          Next
         
          ForEach *this\TemplateLink()
            If *this\TemplateLink()\FieldName.s = Str(TemplateID.i)
              ChangeCurrentElement(*this\Template(),*this\TemplateLink()\Template)
              ChangeCurrentElement(*this\Template()\Fields(),*this\TemplateLink()\Field)
              If *this\Template()\Fields()\IsHolder
                If *this\Template()\Fields()\Content()\Content And *this\Template()\Fields()\Content()\Element
                  ChangeCurrentElement(*this\Content(),*this\Template()\Fields()\Content()\Content)
                  ChangeCurrentElement(*this\Content()\Elements(),*this\Template()\Fields()\Content()\Element)
                  AddElement(*this\Content()\Elements()\SelfRef())
                    *this\Content()\Elements()\SelfRef() = *Content
                EndIf
              EndIf
              Break
            EndIf
          Next
           
          ProcedureReturn ContentID.i
        EndIf
        Break
      EndIf
    Next
  EndIf
EndProcedure

Procedure.i EasyTemplate_SetContent(*this.easy_template,ContentID.i,Name.s,Value.s)
  If *this
    If ListSize(*this\Content()) And Name.s
      ForEach *this\Content()
        If *this\Content()\ContentID.i = ContentID.i
          ChangeCurrentElement(*this\Template(),*this\Content()\Template)
          ForEach *this\Content()\Elements()
            If *this\Content()\Elements()\Field
              ChangeCurrentElement(*this\Template()\Fields(),*this\Content()\Elements()\Field)
              If *this\Template()\Fields()\Name.s = Name.s
                *this\Content()\Elements()\Content.s = Value.s
                ProcedureReturn #True
              EndIf
            EndIf
          Next
        EndIf
      Next
    EndIf
  EndIf
EndProcedure

Procedure.s EasyTemplate_Build(*this.easy_template, TemplateID.i,*ContentRef = 0)
  Protected Content.s,Replacer.s
  Protected ValueHolder.s
  Protected NewList *SelfRef(), *currContent, *currElement, *currField, *currTemplate
  Protected ChildID.i
 
  If Not *this
    ProcedureReturn "ERROR!" 
  EndIf
 
  If TemplateID.i And ListSize(*this\Template())
    ForEach *this\Template()
      If *this\Template()\ID.i = TemplateID.i
        Content.s = *this\Template()\Content.s
        If *ContentRef > 0
          ChangeCurrentElement(*this\Content(),*ContentRef)
          ForEach *this\Content()\Elements()
            ChangeCurrentElement(*this\Template()\Fields(),*this\Content()\Elements()\Field)
            If Not *this\Template()\Fields()\IsHolder.b
              Replacer.s = "{tp:var:"+*this\Template()\Fields()\Name.s+"}"
              ValueHolder.s = *this\Content()\Elements()\Content.s
            Else
              Replacer.s = "{tp:holder:"+*this\Template()\Fields()\Name.s+"}"
              ChildID.i = Val(*this\Template()\Fields()\Name.s)
              *currContent = @*this\Content()
              *currElement = @*this\Content()\Elements()
              CopyList(*this\Content()\Elements()\SelfRef(),*SelfRef())
              ForEach *SelfRef()
                ValueHolder.s + EasyTemplate_Build(*this,ChildID.i,*SelfRef())
              Next
              ChangeCurrentElement(*this\Content(),*currContent)
              ChangeCurrentElement(*this\Content()\Elements(),*currElement)
            EndIf
            Content.s = ReplaceString(Content.s,Replacer.s,ValueHolder.s)
            ValueHolder.s = ""
          Next
          ProcedureReturn Content.s
        Else
          ForEach *this\Template()\Fields()
            If Not *this\Template()\Fields()\IsHolder.b
              Replacer.s = "{tp:var:"+*this\Template()\Fields()\Name.s+"}"
              ForEach *this\Template()\Fields()\Content()
                ChangeCurrentElement(*this\Content(),*this\Template()\Fields()\Content()\Content)
                ChangeCurrentElement(*this\Content()\Elements(),*this\Template()\Fields()\Content()\Element)
                ValueHolder.s + *this\Content()\Elements()\Content.s
              Next
            Else
              *currTemplate = *this\Template()
              *currField    = *this\Template()\Fields()
              Replacer.s = "{tp:holder:"+*this\Template()\Fields()\Name.s+"}"
              ChildID.i = Val(*this\Template()\Fields()\Name.s)
              ForEach *this\Template()\Fields()\Content()
                ChangeCurrentElement(*this\Content(),*this\Template()\Fields()\Content()\Content)
                ChangeCurrentElement(*this\Content()\Elements(),*this\Template()\Fields()\Content()\Element)
                CopyList(*this\Content()\Elements()\SelfRef(),*SelfRef())
                ForEach *SelfRef()
                  ValueHolder.s + EasyTemplate_Build(*this,ChildID.i,*SelfRef())
                Next             
                ChangeCurrentElement(*this\Template(),*currTemplate)
                ChangeCurrentElement(*this\Template()\Fields(),*currField)             
              Next           
            EndIf
            Content.s = ReplaceString(Content.s,Replacer.s,ValueHolder.s)
            ValueHolder.s = "" 
          Next
        EndIf
        Break
      EndIf
    Next
  EndIf
  Debug Content.s
  ProcedureReturn Content.s
EndProcedure

Procedure.i EasyTemplate_Destroy(*this.easy_template)
  ClearStructure(*this,easy_template)
  InitializeStructure(*this,easy_template)
  Debug "destroyed all template information.."
EndProcedure

Procedure New_EasyTemplate()
   Protected *this.easy_template
  
   *this = AllocateMemory(SizeOf(easy_template))
   If *this
     InitializeStructure(*this, easy_template)
      *this\___procs.i = ?__easy_template_int
   EndIf
  
   ProcedureReturn *this 
EndProcedure

DataSection
  __easy_template_int:
  Data.i @EasyTemplate_AddField()
  Data.i @EasyTemplate_RelinkFields()
  Data.i @EasyTemplate_LoadString()
  Data.i @EasyTemplate_LoadMemory()
  Data.i @EasyTemplate_LoadFile()
  Data.i @EasyTemplate_GetLoopID()
  Data.i @EasyTemplate_AddContent()
  Data.i @EasyTemplate_SetContent()
  Data.i @EasyTemplate_Build()
  Data.i @EasyTemplate_Destroy()
EndDataSection

DisableExplicit

;test
;____________________________________________________________________________________

Template.s = "This is a test template"+#CRLF$+#CRLF$
Template.s + "We can do Loops,{tp:loop:mylooptitle:start}"+#CRLF$
Template.s + "this is line {tp:var:mycountervar}"+#CRLF$
Template.s + "a loop in a loop too {tp:loop:myinnerloop:start}"+#CRLF$
Template.s + "{tp:var:innerloopcontent} {tp:loop:myinnerloop:end}"+#CRLF$
Template.s + "{tp:loop:mylooptitle:end}"+#CRLF$+#CRLF$
Template.s + "Today is: {tp:var:date}"

;create the template
*easy.EasyTemplate = New_EasyTemplate()

;load content
ID.i = *easy\LoadString(Template.s)
If ID.i
  ;we want to add content!
  MainContentID.i = *easy\AddContent(ID.i) 
  If MainContentID.i
    *easy\SetContent(MainContentID.i,"date",FormatDate("%mm/%dd/%yyyy", Date()))
  EndIf
 
  ;get the loop ID's
  MyLoop.i = *easy\GetLoopID(ID.i,"mylooptitle")
  MyInnerLoop.i = *easy\GetLoopID(ID.i,"myinnerloop")
 
  ;fill the main loop "mylooptitle"
  If MyLoop.i
    For a=0 To 100
      MyLoopContent.i = *easy\AddContent(MyLoop.i)
      *easy\SetContent(MyLoopContent.i,"mycountervar",Str(a))
     
      ;fill the inner loop "myinnerloop"
      For B=0 To 5
        MyInnerLoopContent.i = *easy\AddContent(MyInnerLoop.i) 
        *easy\SetContent(MyInnerLoopContent.i,"innerloopcontent","Random Value: "+Str(Random(1000)))
      Next
   
    Next
  EndIf
 
  ;let's build it!
  Content.s = *easy\Build(ID.i)
 
  ;to much content for the (windows) debugger, let's save it to the clipboard
  If Content.s
    SetClipboardText(Content.s) 
  EndIf
  *easy\Destroy()
EndIf
Beste Grüße,
Deluxe0321
Ich habe keine Lösung, aber ich bewundere das Problem.