Template engine?

Just starting out? Need help? Post your questions and find answers here.
LeadGuit
New User
New User
Posts: 9
Joined: Wed Jun 15, 2022 9:40 pm

Template engine?

Post by LeadGuit »

Hi,
Is there a kind of "template engine" in PB? Thinking of something like e.g. Jinja or similar. Essentially creating a HTML, TXT or other file where you put in variables to replace at runtime like "Hello {{name}}".
I'm currently not intending to use it for web purposes, but more for generating things like invoices or cue sheets etc.

Best,
Mat
User avatar
mk-soft
Always Here
Always Here
Posts: 5338
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Template engine?

Post by mk-soft »

Simple way ...

Code: Select all

;-TOP

Global NewList Names.s()

Global Header.s = "Hello {{Name}}"
Global Titel.s

AddElement(Names())
Names() = "Tom"
AddElement(Names())
Names() = "Jerry"

ForEach Names()
  Titel = ReplaceString(Header, "{{Name}}", Names())
  Debug Titel
Next
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
AZJIO
Addict
Addict
Posts: 1319
Joined: Sun May 14, 2017 1:48 am

Re: Template engine?

Post by AZJIO »

Like this?
LeadGuit
New User
New User
Posts: 9
Joined: Wed Jun 15, 2022 9:40 pm

Re: Template engine?

Post by LeadGuit »

mk-soft wrote: Mon Jun 20, 2022 3:59 pm Simple way ...
Thanks, that's definitely a way for simple use cases. The idea of the template engine would be to out logic I side of the template instead of the code - for simple replacement that here might be the way to go, but conditionals and loops In the template are the main thing I'm looking for.
AZJIO wrote: Mon Jun 20, 2022 4:29 pm Like this?
From what I gather through translation, it seems to go in a similar direction as mk-softs suggestion, if the source is available it would be interesting, especially the docx part.

So as different example, such as template would be like (in Jinja)

Code: Select all

{% for item in collection %}
The item name is: {{item["name"]}}
The price is {{item["price"]}}
{% if item["price"] < 50 %}
Cheap item!
{% endif %}

{% endfor %}
And the resulting render could be something like

Code: Select all

The item name is: Item A
The price is 150

The item name is: B
The price is 30
Cheap Item!
Maybe that narrows it down what I mean ;-)
User avatar
mk-soft
Always Here
Always Here
Posts: 5338
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: Template engine?

Post by mk-soft »

Maybe write a template interpreter.
Here is a small starting point for an interpreter

Code: Select all

;-TOP beginning by mk-soft

; ***************************************************************************************

; Part Of SplitStringArray.pbi
; Link: https://www.purebasic.fr/english/viewtopic.php?t=69557

Procedure SplitParameterArray(String.s, Array Result.s(1))
  Protected *String.character 
  Protected *Start, *End, exit, lock, do, len, temp.s, cnt, c1
  Protected level
  
  Dim Result(0)
  
  *String = @String
  If *String = 0
    ProcedureReturn 0
  EndIf
  
  *Start = *String
  *End = *String
  c1 = 0
  
  Repeat
    If *String\c = 0
      exit = #True
      *End = *String
    Else
      If *String\c = '"'
        If Not lock
          lock = #True
        Else
          lock = #False
        EndIf
      EndIf
      If Not lock
        If *String\c = '('
          If level = 0
            If #True ; Get Functionname
              len = (*String - *Start) / SizeOf(character)
              If Len > 0
                temp = PeekS(*Start, len)
                ReplaceString(temp, #TAB$, " ", #PB_String_InPlace)
                temp = Trim(temp)
                cnt = CountString(temp, " ")
                If cnt
                  temp = StringField(temp, cnt + 1, " ")
                EndIf
                Result(c1) = temp
              EndIf
            EndIf
            *Start = *String + SizeOf(character)
          EndIf
          level + 1
        ElseIf *String\c = ')'
          level - 1
          If level = 0
            do = #True
            exit = #True
            *End = *String
          EndIf
        ElseIf *String\c = ',' And level = 1
          do = #True
          *End = *String
        EndIf
      EndIf
    EndIf
    If do
      c1 + 1
      If ArraySize(Result()) < c1
        ReDim Result(c1 + 10)
      EndIf
      len = (*End - *Start) / SizeOf(character)
      If Len > 0
        Result(c1) = Trim(PeekS(*Start, len))
      Else
        Result(c1) = ""
      EndIf
      *Start = *String + SizeOf(character)
      do = #False
    EndIf
    *String + SizeOf(character)
  Until exit
  
  ReDim Result(c1)
  ProcedureReturn c1
  
EndProcedure

; ***************************************************************************************

Structure udtCollection
  CollectionName.s
  Map itemText.s()
  Map itemValue.d()
EndStructure

Global NewList Collection.udtCollection()

Procedure.s TemplateInterpreter(Text.s, *Collection.udtCollection)
  Protected r1.s, pos1, pos2, temp.s, cnt
  Dim param.s(0)
  
  With *Collection
    Repeat
      pos1 = FindString(text, "{{")
      If pos1
        r1 + Left(text, pos1 - 1)
        pos2 = FindString(text, "}}", pos1)
        If pos2
          temp = Mid(Text, pos1 + 2, pos2 - pos1 -2)
          cnt = SplitParameterArray(temp, param())
          If cnt >= 1
            Select param(0)
              Case "itemText"
                If FindMapElement(\itemText(), param(1))
                  r1 + \itemText()
                EndIf
              Case "itemValue"
                If FindMapElement(\itemValue(), param(1))
                  Select cnt
                    Case 1
                      r1 + StrD(\itemValue())
                    Case 2
                      r1 + StrD(\itemValue(), Val(param(2)))
                      
                  EndSelect
                EndIf  
                    
            EndSelect
          EndIf
          Text = Mid(text, pos2 + 2)
          
        EndIf
      Else
        r1 + text
        Break
      EndIf
    ForEver
  EndWith
  
  ProcedureReturn r1
EndProcedure

; ----

;Test

AddElement(Collection())
With Collection()
  \itemText("name") = "Apple"
  \itemValue("price") = 13.99
EndWith

AddElement(Collection())
With Collection()
  \itemText("name") = "bears"
  \itemValue("price") = 9.80
EndWith

sVal.s = "The item name is: {{itemText(name)}} " + #LF$ +
         "The price is {{itemValue(price,2)}}" + #LF$ + #LF$

ForEach Collection()
  Debug TemplateInterpreter(sVal, Collection())
Next

My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
LeadGuit
New User
New User
Posts: 9
Joined: Wed Jun 15, 2022 9:40 pm

Re: Template engine?

Post by LeadGuit »

mk-soft wrote: Mon Jun 20, 2022 8:10 pm Maybe write a template interpreter.
Here is a small starting point for an interpreter
Thank you so much! So I'll take it that there is no (known) template engine available?
Then I'll try my hand at writing my own with your starting point (or try a different direction for the few projects I have in mind).
Thank you again :-)
Post Reply