Skip to main content

SiYuan Database: Template-Spalte (Referenz)

Diese Datei beschreibt, wie die Template-Spalte in SiYuan Databases (Attribute View / AV) funktioniert, welche Daten du im Template zur Verfuegung hast und welche Funktionen du benutzen kannst.

Quellcode-Referenzen:

  • Rendering + Datenmodell: kernel/sql/av.go (renderTemplateField)
  • Template-Funktionen (Sprig + SiYuan): kernel/filesys/template.go (BuiltInTemplateFuncs)
  • SQL-Helferfunktionen: kernel/sql/database.go (SQLTemplateFuncs)

1) Syntax (Go text/template mit .action{...})

Die Template-Spalte nutzt Go text/template, aber mit anderen Delimitern:

  • Start: .action{
  • Ende: }

Beispiele:

Titel: .action{ index . "Name" }
.action{ if gt (len (index . "Tags")) 0 }Tags: .action{ join ", " (index . "Tags") }.action{ end }

Wichtige Hinweise:

  • . (Dot) ist ein Map/Objekt (Datenmodell pro Zeile).
  • Feldzugriff (Identifier-Spaltenname): Wenn der Spaltenname ein gueltiger Go-Identifier ist (z.B. Status, Cost, dueDate), dann .action{ .Status }.
  • Feldzugriff (beliebiger Spaltenname): Sonst (Leerzeichen, Sonderzeichen, Bindestriche), dann .action{ index . "Spaltenname" }.
  • Variablen: .action{ $x := index . "Preis" } ... .action{ $x }
  • Pipes: .action{ index . "Tags" | join ", " | upper }

2) Datenmodell (Welche Daten sind in . enthalten?)

Die Template-Spalte wird pro Datenbank-Zeile gerendert. Im Template-Kontext (.) liegen:

2.1 IAL / Block-Attribute (Strings)

Alle IAL-Attribute des zugehoerigen Blocks werden in das Datenmodell kopiert (z.B. id).

Zusatz: Die Template-Spalte bietet ausserdem zwei eingebaute Zeitvariablen:

  • created (Typ: time.Time): Wird aus dem Block id abgeleitet (erste 14 Zeichen als YYYYMMDDhhmmss).
  • updated (Typ: time.Time): Wird aus dem IAL-Attribut updated geparst.

Beispiel:

ID: .action{ .id }
Created: .action{ date "2006-01-02 15:04" .created }
Updated: .action{ date "2006-01-02 15:04" .updated }

2.2 Spaltenwerte nach Spaltennamen

Jede Spalte ist ueber ihren Spaltennamen im Datenmodell verfuegbar.

Die Typen werden je nach Spaltentyp gemappt (vereinfachte Uebersicht):

Spaltentyp Zugriff Typ im Template
Number index . "Amount" float64
Date index . "Due" time.Time (Start)
Date (Ende) index . "Due_end" time.Time
Multi-Select index . "Tags" []string
Multi-Select (als String) index . "Tags_str" string (gerendert wie UI)
Relation index . "Rel" []string (gerenderte Inhalte)
Rollup index . "Rollup" []float64 oder []string (je nach Inhalt)
Block/Primary Key index . "Name" string (gerendert)
Sonstiges (Text, Select, Checkbox, URL, ... ) index . "..." i.d.R. string (gerendert)

Spezialfall Block/Primary Key:

  • entryCreated (Typ: time.Time) und entryUpdated (Typ: time.Time) werden gesetzt, wenn die Zeile einen Block-Wert hat.

2.3 Raw-Zugriff pro Spalte (*_raw)

Zu jeder Spalte existiert zusaetzlich ein Raw-Eintrag:

  • Spaltenname_raw enthaelt den Rohwert (AV Value Objekt), z.B.:
Type: .action{ (index . "Due_raw").Type }
Raw: .action{ printf "%#v" (index . "Due_raw") }

2.4 Zugriff nach Spalten-ID (id_mod, id_mod_raw)

Zusatzmaps:

  • id_mod: Map von SpaltenID -> gemappter Wert (wie bei Spaltennamen)
  • id_mod_raw: Map von SpaltenID -> Raw-Value

Beispiel:

.action{ $byID := index . "id_mod" }
.action{ index $byID "20240101010101-abcdefg" }

3) Funktionsuebersicht

Die Template-Spalte hat:

  • Go text/template Built-ins
  • Sprig v3 (sprig.TxtFuncMap()), mit wenigen entfernten Funktionen
  • SiYuan Custom-Funktionen (zusaetzlich zu Sprig)
  • SQL-Helferfunktionen (SiYuan)

3.1 Go text/template Built-in Funktionen

Diese Funktionen sind immer verfuegbar (Go text/template):

  • and
  • or
  • not
  • call
  • html
  • index
  • js
  • len
  • print
  • printf
  • println
  • urlquery
  • eq
  • ne
  • lt
  • le
  • gt
  • ge

Wichtige Actions (keine "Funktionen", aber Teil der Sprache):

  • if, else, end
  • range, with
  • Variablen: $x := ...

3.2 SiYuan zusaetzliche Funktionen (ueber Sprig hinaus)

Aus kernel/filesys/template.go:

  • Weekday(date time.Time) int (Sonntag=0 ... Samstag=6)
  • WeekdayCN(date time.Time) string (weekday als chinesisches Zeichen, Variante 1)
  • WeekdayCN2(date time.Time) string (weekday als chinesisches Zeichen, Variante 2)
  • ISOWeek(date time.Time) int
  • ISOYear(date time.Time) int
  • ISOMonth(date time.Time) int
  • ISOWeekDate(day int, date time.Time) time.Time (day: Montag=1 ... Sonntag=7)
  • pow(a, b any) int64
  • powf(a, b any) float64
  • log(a, b any) int64 (Logarithmus von a zur Basis b)
  • logf(a, b any) float64
  • parseTime(dateStr string) time.Time (parst viele Datumsformate; bei Fehler: now)
  • FormatFloat(format string, n float64) string (z.B. FormatFloat "#,###.##" 1234.56)
  • getHPathByID(id string) string (liefert HPath eines Blocks)
  • statBlock(id string) *BlockStatResult (Rueckgabe-Felder: RuneCount, WordCount, LinkCount, ImageCount, RefCount, BlockCount)
  • runeCount(s string) int
  • wordCount(s string) int
  • markdown2text(md string) string (Markdown -> Text)
  • markdown2content(md string) string (Markdown -> Content)

3.3 SQL-Funktionen (SiYuan)

Aus kernel/sql/database.go:

  • querySQL(stmt string) []map[string]any: Fuehrt SQL aus und gibt Zeilen als Maps zurueck (Limit intern).
  • queryBlocks(stmt string, args ...string) []*Block: Ersetzt ? im SQL-String nacheinander durch args (String-Replacement) und laedt Blocks.
  • querySpans(stmt string, args ...string) []*Span: Wie queryBlocks, aber fuer Spans.
  • getBlock(arg any) *Block: arg kann string (Block-ID) oder map mit Key id sein.

Performance-Hinweis: SQL-Funktionen laufen beim Rendering der Template-Spalte (potenziell pro Zeile). Nutze sie sparsam.

3.4 Sprig (Masterminds/sprig v3) Funktionen

SiYuan nutzt sprig.TxtFuncMap() (Sprig v3.3.0 laut kernel/go.mod), mit entfernten Funktionen aus Sicherheitsgruenden:

  • Entfernt: env, expandenv, getHostByName

Sprig-Funktionen (nach Kategorie, Funktionsnamen):

Strings

  • trim
  • trimAll
  • trimSuffix
  • trimPrefix
  • upper
  • lower
  • title
  • untitle
  • repeat
  • substr
  • nospace
  • trunc
  • abbrev
  • abbrevboth
  • initials
  • randAlphaNum
  • randAlpha
  • randNumeric
  • randAscii
  • wrap
  • wrapWith
  • contains
  • hasPrefix
  • hasSuffix
  • quote
  • squote
  • cat
  • indent
  • nindent
  • replace
  • plural
  • snakecase
  • camelcase
  • kebabcase
  • swapcase
  • shuffle
  • regexMatch
  • mustRegexMatch
  • regexFindAll
  • mustRegexFindAll
  • regexFind
  • mustRegexFind
  • regexReplaceAll
  • mustRegexReplaceAll
  • regexReplaceAllLiteral
  • mustRegexReplaceAllLiteral
  • regexSplit
  • mustRegexSplit
  • regexQuoteMeta

String Slices

  • join
  • splitList
  • split
  • splitn
  • sortAlpha

Lists

  • list
  • first
  • mustFirst
  • rest
  • mustRest
  • last
  • mustLast
  • initial
  • mustInitial
  • append
  • mustAppend
  • prepend
  • mustPrepend
  • concat
  • reverse
  • mustReverse
  • uniq
  • mustUniq
  • without
  • mustWithout
  • has
  • mustHas
  • compact
  • mustCompact
  • slice
  • mustSlice
  • chunk

Dicts

  • dict
  • get
  • set
  • unset
  • hasKey
  • pluck
  • dig
  • merge
  • mustMerge
  • mergeOverwrite
  • mustMergeOverwrite
  • keys
  • pick
  • omit
  • values
  • deepCopy
  • mustDeepCopy

Defaults / JSON / Ternary

  • default
  • empty
  • coalesce
  • all
  • any
  • fromJson
  • mustFromJson
  • toJson
  • mustToJson
  • toPrettyJson
  • mustToPrettyJson
  • toRawJson
  • mustToRawJson
  • ternary

Type Conversion

  • atoi
  • float64
  • int
  • int64
  • toDecimal
  • toString
  • toStrings

Encoding

  • b64enc
  • b64dec
  • b32enc
  • b32dec

Paths

  • base
  • dir
  • clean
  • ext
  • isAbs
  • osBase
  • osDir
  • osClean
  • osExt
  • osIsAbs

Math (Integer)

  • add
  • add1
  • sub
  • div
  • mod
  • mul
  • max
  • min
  • floor
  • ceil
  • round
  • randInt

Math (Float)

  • addf
  • add1f
  • subf
  • divf
  • mulf
  • maxf
  • minf

Integer Slices

  • until
  • untilStep
  • seq

Date

  • now
  • ago
  • date
  • dateInZone
  • duration
  • durationRound
  • unixEpoch
  • dateModify
  • mustDateModify

Hinweis: In Sprig-Beispielen taucht teils auch date_modify auf. Falls dateModify nicht funktioniert, probiere date_modify.

Flow Control

  • fail

UUID

  • uuidv4

OS (in SiYuan entfernt)

  • env (entfernt)
  • expandenv (entfernt)

SemVer

  • semver
  • semverCompare

Reflection

  • kindOf
  • kindIs
  • typeOf
  • typeIs
  • typeIsLike
  • deepEqual

Network (in SiYuan entfernt)

  • getHostByName (entfernt)

URL

  • urlParse
  • urlJoin

Crypto

  • sha1sum
  • sha256sum
  • sha512sum
  • adler32sum
  • bcrypt
  • htpasswd
  • randBytes
  • derivePassword
  • genPrivateKey
  • buildCustomCert
  • genCA
  • genCAWithKey
  • genSelfSignedCert
  • genSelfSignedCertWithKey
  • genSignedCert
  • genSignedCertWithKey
  • encryptAES
  • decryptAES

4) Praktische Beispiele (inkl. Bedingungen)

4.1 if / else if / else (Bedingungen)

.action{ $status := index . "Status" }
.action{ if eq $status "Done" }Fertig
.action{ else if eq $status "Doing" }In Arbeit
.action{ else }Offen
.action{ end }

Vergleiche (Go Built-ins): eq, ne, lt, le, gt, ge

.action{ if gt (index . "Amount") 0 }Positiv.action{ end }

Logik (Go Built-ins): and, or, not

.action{ if and (ge (index . "Progress") 0.8) (not (eq (index . "Status") "Done")) }Fast fertig.action{ end }

4.2 "case/switch" nachbauen

Go Templates haben kein echtes switch/case. Uebliche Patterns:

Pattern A: else if Kette (siehe oben).

Pattern B: Mapping via dict + get + default (Sprig):

.action{ $map := dict "Done" "Fertig" "Doing" "In Arbeit" "Open" "Offen" }
.action{ $status := index . "Status" }
.action{ default "Unbekannt" (get $map $status) }

Pattern C: kurze Ja/Nein Logik via ternary (Sprig):

.action{ ternary "Hat Tags" "Keine Tags" (gt (len (default (list) (index . "Tags"))) 0) }

4.3 Umgang mit leeren / fehlenden Werten

Fehlende Keys liefern im Template oft <no value>. Diese Ausgabe wird von SiYuan am Ende zu leerem Text gemacht, aber fuer Bedingungen ist es besser, aktiv zu "normalisieren".

default (Sprig) ist dafuer praktisch:

Name: .action{ default "-" (index . "Name") }

empty (Sprig) prueft "Leerheit" (nil, "", 0, leere Liste, ...):

.action{ if empty (index . "Tags") }Keine Tags.action{ else }Tags: .action{ join ", " (index . "Tags") }.action{ end }

4.4 with (Scope + Null-Check)

with setzt den Dot-Kontext und laeuft nur, wenn der Ausdruck nicht "empty" ist:

.action{ with index . "Due" }Faellig: .action{ date "2006-01-02" . }.action{ else }Keine Deadline.action{ end }

4.5 range (Schleifen)

Ueber eine Multi-Select Liste iterieren:

Tags:
.action{ range $i, $t := index . "Tags" }- .action{ $t }
.action{ else }(keine)
.action{ end }

Ueber SQL-Ergebnis iterieren (siehe querySQL unten):

.action{ range $row := querySQL "select type, count(*) as c from blocks group by type limit 5" }
.action{ index $row "type" }: .action{ index $row "c" }
.action{ end }

Ueber Dict/Map iterieren:

.action{ $m := dict "a" 1 "b" 2 }
.action{ range $k, $v := $m }.action{ $k }=.action{ $v } .action{ end }

Kommentar (Go Template):

.action{/* das wird ignoriert */}

4.6 define/template (wiederverwendbare Snippets)

Du kannst kleine Hilfs-Templates definieren und spaeter wiederverwenden:

.action{ define "tags" }Tags: .action{ join ", " (default (list) (index . "Tags")) }.action{ end }
.action{ template "tags" . }

4.7 Debugging / Guardrails

printf (Go) um Typen/Strukturen zu inspizieren:

.action{ printf "%T" (index . "Tags") }

Weitere Go Built-ins, die manchmal nuetzlich sind:

Query: .action{ urlquery "a b&c" }
Escaped HTML: .action{ html "<b>x</b>" }
Print: .action{ print "A=" (index . "Amount") }

fail (Sprig) um bewusst Fehler zu werfen (z.B. beim Bauen eines Templates):

.action{ if empty (index . "Name") } .action{ fail "Name ist Pflicht" } .action{ end }

4.8 Beispiele fuer haeufige Aufgaben

Multi-Select als Text:

.action{ join ", " (default (list) (index . "Tags")) }

Wenn leer, dann "-":

.action{ ternary (join ", " (default (list) (index . "Tags"))) "-" (gt (len (default (list) (index . "Tags"))) 0) }

Date formatieren:

.action{ with index . "Due" } .action{ date "2006-01-02" . } .action{ end }

Weekday / ISO-Woche (SiYuan-Funktionen):

.action{ with index . "Due" }Wochentag: .action{ Weekday . }, ISO-Woche: .action{ ISOWeek . }.action{ end }

Block-Statistik (SiYuan-Funktion):

.action{ $s := statBlock .id }Words: .action{ $s.WordCount }, Links: .action{ $s.LinkCount }

Markdown in Text umwandeln (SiYuan-Funktion):

.action{ markdown2text (default "" (index . "Notes")) }

SQL: Ein Feld aus dem ersten Ergebnis lesen (Sprig first + index):

.action{ $rows := querySQL "select count(*) as c from blocks" }
.action{ index (first $rows) "c" }

4.9 Bedingungen Cheatsheet (Funktionen)

Vergleich + Logik (Go Built-ins):

.action{ $a := default 0 (index . "A") }
.action{ $b := default 0 (index . "B") }
.action{ if eq $a $b }gleich.action{ end }
.action{ if ne $a $b }ungleich.action{ end }
.action{ if lt $a $b }a<b.action{ end }
.action{ if le $a $b }a<=b.action{ end }
.action{ if gt $a $b }a>b.action{ end }
.action{ if ge $a $b }a>=b.action{ end }

.action{ if and (gt $a 0) (lt $a 10) }1..9.action{ end }
.action{ if or (empty (index . "Due")) (empty (index . "Status")) }unvollstaendig.action{ end }
.action{ if not (empty (index . "Name")) }hat Name.action{ end }

Sprig-Helper, die bei Bedingungen oft helfen:

.action{ default "-" (index . "Name") }
.action{ coalesce (index . "Name") (index . "Title") "-" }
.action{ ternary "Ja" "Nein" (gt (len (default (list) (index . "Tags"))) 0) }

.action{ if has "Urgent" (default (list) (index . "Tags")) }Hat Tag Urgent.action{ end }
.action{ if hasKey . "Status" }Spalte Status existiert.action{ end }
.action{ if contains "TODO" (default "" (index . "Notes")) }enthaelt TODO.action{ end }
.action{ if regexMatch "^https?://" (default "" (index . "URL")) }ist URL.action{ end }