CodamAIDocs
Themafertig

Die Vorlagensprache

FreeMarker in einer Sandbox: wie eine Vorlage auf die Payload zugreift, wie Zahlen und Daten formatiert werden, wie Assets und SVG-Grafiken hineinkommen und was gesperrt ist.

Ausprägungen
DOCUMENT (XHTML)WORD (Flat OPC)TABLE (CRMS-Tabellendokument)asset:<name>crms.svg

Worum es geht

Der Quelltext einer Vorlage ist FreeMarker. FreeMarker ist eine Vorlagensprache für Java: normaler Text mit Platzhaltern wie ${title} und Anweisungen wie <#if> und <#list>. CRMS führt sie in einer Sandbox aus. Das ist eine abgeschottete Umgebung, in der eine Vorlage nur die Daten sieht, die du ihr gibst, und sonst nichts erreicht.

Was die Vorlage schreibt

Was eine Vorlage ausgibt, hängt von ihrer Ausgabeart ab. Danach richtet sich auch das automatische Escaping.

AusgabeartDie Vorlage schreibtEscapingFormate
DOCUMENTXHTML, also HTML als sauberes XMLXHTMLHTML, PDF
WORDdas ganze Word-Paket als ein XML-Dokument (Flat OPC)XMLDOCX
TABLEdas CRMS-Tabellendokument (<workbook>, <sheet>, <row>, <cell>)XMLXLSX, CSV, ODS

Escaping heißt: Zeichen wie < und & in einem Wert werden so umgeschrieben, dass sie als Text erscheinen und kein Markup werden. Steht in der Payload <script>alert(1)</script>, schreibt <p>${title}</p> daraus <p>&lt;script&gt;alert(1)&lt;/script&gt;</p>. Die Einzelheiten zu jedem Format stehen unter Ausgabearten und Formate.

Auf die Payload zugreifen

Die Payload ist die oberste Ebene der Vorlage. Ihre Felder sind direkt da.

<#-- Payload: { "title": "Audit Halle 3", "customer": { "name": "ACME" },
                "items": [ { "label": "HACCP", "amount": 480 } ] } -->
<h1>${title}</h1>
<p>Kunde: ${customer.name}</p>
<table>
  <#list items as item>
    <tr><td>${item.label}</td><td>${item.amount}</td></tr>
  </#list>
</table>
<p>Prüfer: ${(inspector)!"–"}</p>
<#if remarks?has_content><p>${remarks}</p></#if>
  • ${…} gibt einen Wert aus, escaped.
  • <#list> läuft über eine Liste, <#if> prüft eine Bedingung.
  • ! setzt einen Ersatzwert, wenn ein Feld fehlt. ?? fragt, ob es da ist.
  • <#assign>, <#macro> und <#function> bauen Hilfen innerhalb desselben Quelltexts. Die Hub-Vorlagen machen davon reichlich Gebrauch, etwa für Überschriften und das Inhaltsverzeichnis.

Die Payload hat höchstens zwei Ebenen: title, customer.name, items[].amount. Tiefer geht es nicht. Was CRMS an der Payload prüft, steht unter Die Payload-Prüfung.

Zahlen, Daten, Wahrheitswerte

CRMS setzt für jede Ausgabe die Sprache und die Zeitzone des Dokuments. Danach formatiert FreeMarker:

AusdruckWertAusgabe bei de
${amount}1234.51.234,5
${amount?string("0.00")}1234.51234,50
${due?string("dd.MM.yyyy")}"2026-10-17", als DATE deklariert17.10.2026
${done}truetrue

Ein Feld, das die Revision als DATE oder DATETIME deklariert, wird zu einem echten Datum, auch wenn es als ISO-Text kommt. So kommt es aus JSON. Ein DATE ist Mitternacht in der Zeitzone des Dokuments, nie in der des Servers. Ohne Deklaration bleibt ein ISO-Text ein Text. Woher Sprache und Zeitzone kommen, steht unter Sprache und Zeitzone.

Assets

Ein Asset der Revision nennst du mit asset:<name>. Was CRMS daraus macht, hängt vom Format ab:

FormatWo asset: stehtWas passiert
HTMLsrc, href, CSS url()wird zu einer data:-Adresse, die Seite ist danach in sich vollständig
PDFBilder, Schriften (@font-face { src: url('asset:own.ttf') }), Stylesheetswird aus dem Speicher geladen. Jede andere Adresse wird abgewiesen
DOCX<pkg:binaryData>asset:logo.png</pkg:binaryData>wird mit dem Inhalt des Assets gefüllt
<img src="asset:logo.png" alt="Logo"/>

Nennt die Vorlage ein Asset, das die Revision nicht hat, schlägt das Rendern fehl, bei HTML mit render-asset-unknown.

Bilder, die zur Anfrage gehören, etwa eine Unterschrift oder Fotos einer Begehung, sind keine Assets. Die Vorlage nennt sie attachment:<name>. Mehr unter Bilder und SVG.

SVG aus der Payload: crms.svg

Eine Grafik, die der Aufrufer selbst zeichnet, zum Beispiel ein Diagramm, kommt als SVG-Text in der Payload. Ausgeben würde sie das Escaping nur als Text. Dafür gibt es die Funktion crms.svg:

<div class="figure">${crms.svg(diagramSvg)}</div>

CRMS prüft das SVG gegen eine Liste erlaubter Elemente und Attribute und setzt es dann ein. crms gehört CRMS: Ein Payload-Feld namens crms ersetzt die Funktion nicht.

Ausgabeartcrms.svg schreibt
DOCUMENTdas SVG direkt ins XHTML. HTML zeigt es, PDF zeichnet es als Vektorgrafik
WORDeinen Platzhalter innerhalb von <w:p>. Daraus wird ein eingebettetes Bild
TABLEnichts: 422 template-svg-not-for-output-type|table

Was erlaubt ist und was abgewiesen wird, steht unter Bilder und SVG.

Was gesperrt ist

Erlaubt und gesperrt
Erlaubt
die Sprache selbst
  • ${…}, <#if>, <#list>, <#assign>
  • <#macro>, <#function> im selben Quelltext
  • Built-ins wie ?string, ?has_content, ?size, ?filter
  • Ersatzwerte mit !, Abfragen mit ??
  • crms.svg(…)
Gesperrt
alles, was aus der Vorlage hinausführt
  • ?new: keine Klasse lässt sich erzeugen
  • ?api: keine Methode hinter einem Wert
  • <#include>, <#import>: es gibt keine andere Datei und keine andere Vorlage
  • Methodenaufrufe an Objekten: die Payload enthält nur Text, Zahlen, Wahrheitswerte, Daten, Listen und Maps

Dazu kommen Grenzen beim Rendern: Die Ausgabe hat eine Höchstgröße, und eine Vorlage, die nicht endet, wird nach der Zeitgrenze abgebrochen. Siehe Ausführung und Grenzen.

Fehler in der Vorlage

Fehler kommen als Schlüssel mit Zeile und Spalte im Quelltext. Den Text von FreeMarker bekommt der Client nicht.

SchlüsselWann
template-syntax-error|<zeile>|<spalte>der Quelltext lässt sich nicht parsen
template-render-failed|<zeile>|<spalte>beim Rendern ging etwas schief, etwa ein fehlender Wert oder ein gesperrtes ?new
render-output-too-largedas Dokument wurde größer als erlaubt

Einen Syntaxfehler findet CRMS schon beim Einreichen. Der Renderer parst den Entwurf, und eine Revision, die sich nicht parsen lässt, entsteht gar nicht: 422 template-source-rejected mit violations: [{"field": "source", "rule": "template-syntax-error|1|7"}].

Fallen

Weiter

Suchen