Erweiterungen der Jelly-Syntax

  • Freigeben Version: Yokohama
  • Aktualisiert 30. Januar 2025
  • 9 Minuten Lesedauer
  • Die Jelly-Syntax von Apache wird zum Rendern von Formularen, Listen, UI-Seiten und vielen anderen Elementen in ServiceNow verwendet.

    Mit Jelly lässt sich Logik in statische Inhalte einbetten. Auch das Einfügen berechneter Werte in statische Inhalte ist möglich.

    Wichtig:
    Diese Funktionalität erfordert Kenntnisse in Apache Jelly (Java- und XML-basierte Engine für Skripterstellung und Verarbeitung, mit der sich XML in ausführbaren Code umwandeln lässt).

    Eine Übersicht über die standardmäßigen Jelly-Tags finden Sie auf der Apache-Seite http://commons.apache.org/jelly/tags.html.

    Namespaces

    Jelly schließt beim Aufrufen von Tags oft mehrere Namespaces ein.

    Die Namespaces des Typs „j“ sind standardmäßige Jelly-Namespaces, während die Namespaces des Typs „g“ ausschließlich Skripts von ServiceNow vorbehalten sind. Das Tag „<g:evaluate>“ beispielsweise wird von ServiceNow bereitgestellt, damit Werte mit JavaScript berechnet werden können. Das standardmäßige Jelly-Tag „<j:test>“ wird zur Auswertung von Bedingungen verwendet.

    Phasen

    In der Regel gibt es zwei Phasen, die jeweils durch die Namespaces „<j>“ und „<j2>“ bzw. „<g>“ und „<g2>“ gekennzeichnet werden.

    Die Namespaces ohne „2“ finden in der ersten Verarbeitungsphase statt und werden zwischengespeichert, sofern sie nicht auf einer UI-Seite verwendet werden. Die Namespaces mit „2“ werden niemals zwischengespeichert. Um Effizienz und korrekte Ergebnisse zu gewährleisten, muss bei der Entscheidung zwischen Phase 1 und Phase 2 mit Bedacht vorgegangen werden.

    Neben den Namespaces unterscheidet sich auch die zum Einfügen von Werten in statische Inhalte verwendete Syntax je nach der Phase, die den Wert liefern soll. Ein Dollarzeichen mit einem in geschweifte Klammern gesetzten Wert fügt den Wert in Phase 1 ein. Beispiel: ${jvar_ref} fügt den Wert jvar_ref während Phase 1 des Jelly-Prozesses ein. Ein Dollarzeichen mit einem in eckige Klammern gesetzten Wert fügt den Wert in Phase 2 ein. Beispiel: $[jvar_ref] fügt den Wert jvar_ref während Phase 2 ein. In Anführungszeichen gesetzte Werte werden als Zeichenfolgen behandelt. Beispielsweise fügt '[jvar_ref]' den Wert jvar_ref als Zeichenfolge während Phase 2 ein.

     <script>
    if (confirm("$[gs.getMessage('home.delete.confirm') ]"))
       ...
    </script>
    <input type="hidden" id="${jvar_name}" name="${jvar_name}" value="${jvar_value}" class="${jvar_class}" />

    „if“-Prüfungen

    Sie können „if“-Anweisungen in Jelly-Skripts verwenden.

    Sie können wie folgt prüfen, ob eine Bedingung wahr ist oder nicht:

    <j:if test="${jvar_something}">...do something...</j:if>
    <j:if test="${!jvar_something}">...do something...</j:if>
    Diese Anweisung funktioniert, weil in Jelly ein Begriff wie „jvar_something“ in einem „if“-Tag wahr ist, wenn:
    1. er ein boolean Wert ist und wahr ist
    2. er eine Zeichenfolge ist und „true“, „yes“, „on“ oder „1“ gesetzt ist

    Prüfen, ob etwas existiert, können Sie wie folgt:

    <j:if test="${empty(jvar_something)}">...do something...</j:if>
    Diese Anweisung funktioniert, weil die leere JEXL-Funktion „true“ zurückgibt, wenn ihr Argument Folgendes ist:
    1. „null“
    2. Eine leere Zeichenfolge
    3. Eine Sammlung mit Länge Null
    4. Eine Karte ohne Schlüssel
    5. Ein leeres Array
    Hinweis:
    Variablen des Typs „javascript“ und des Typs „jvar“ dürfen nicht in ein und demselben JEXL-Ausdruck verwendet werden. Sie müssen auf separate Ausdrücke verteilt werden.

    Set_If

    Setzt für eine Variable einen von zwei unterschiedlichen Werten, je nachdem, ob eine Prüfung „true“ oder „false“ zurückgibt.

    <g2:set_if var="jvar_style" test="$[gs.getPreference('table.compact') != 'false']" 
       true="margin-top:0px; margin-bottom:0px;" 
       false="margin-top:2px; margin-bottom:2px;" />

    Unterschiede zwischen „<g:insert>“, „<g:inline>“ und „<g:call>“

    Nachfolgend finden Sie eine vergleichende Erläuterung der drei Tags „<g:insert>“, „<g:inline>“ und „<g:call>“.

    <g:insert>

    Das Tag „<g:insert>“ fügt eine Jelly-Datei in einem neuen Kontext in Ihren Jelly-Code ein. Das bedeutet, dass Sie nicht auf zuvor in Ihrem Jelly-Code definierte Variablen zugreifen können.

    <g:insert template="get_target_form_function.xml" />

    <g:inline>

    Das Tag „<g:inline>“ fügt eine Jelly-Datei im selben Kontext in Ihren Jelly-Code ein. Das bedeutet, dass der eingefügte Jelly-Code auf zuvor definierte Variablen zugreifen und die Werte dieser Variablen ändern kann.

    <g:inline template="element_default.xml" />

    <g:call>

    Mit dem Tag „<g:call>“ können Sie die Kapselung verbessern. Ihre Funktion hat dann nur Zugriff auf die an sie übergebenen Werte. Der Jelly-Kontext sieht nach dem Aufruf noch genauso aus wie vor dem Aufruf. Das bedeutet: Sie können hier keine globalen Variablen setzen und diese erst später lesen. Es bedeutet außerdem, dass Sie nicht versehentlich eine globale Variable mit dem Namen „jvar_temp“ festlegen und damit eine Variable überschreiben können, von der das Skript eines anderen Benutzers abhängt.

    Das Übergeben von Werten erfolgt bei Bedarf explizit, indem der Name des Parameters in die Zeile „<g:call>“ eingefügt wird, gefolgt von einem Gleichheitszeichen und dem Wert in Anführungszeichen:

    <g:call function="collapsing_image.xml" id="${jvar_section_id}" image="$[jvar_cimg]" 
       first_section_id="${jvar_first_section_id}" image_alt="${jvar_cimg_alt}"/>

    Wenn Werte übergeben werden und Sie Standardwerte oder erforderliche Parameter verwenden möchten, muss der in der Funktion referenzierte Jelly-Code eine Zeile enthalten, die deklariert, ob die Parameter erforderlich sind oder einen Standardwert aufweisen:

    <g:function id="REQUIRED" image="REQUIRED" image_prefix="" image_alt="REQUIRED"/>

    Im obigen Beispiel sind drei der Parameter erforderlich, und ein Parameter ist optional. Letzterer wird als Standardwert leer gelassen. Wenn Sie keine Werte übergeben oder Standardwerte oder erforderliche Werte setzen möchten, können Sie die Zeile „<g:function>“ auch ganz weglassen. Im Allgemeinen sollten Sie jedoch eine Zeile „<g:function>“ einfügen.

    Der Wert kann dann in Ihrer Vorlage referenziert werden, indem Sie dem Namen des Parameters das Präfix „jvar_“ voranstellen:

    <img id="img.${jvar_id}" src="images/${jvar_image}" alt="${jvar_image_alt}"     onclick="toggleSectionDisplay('${jvar_id}', '${jvar_image_prefix}','${jvar_first_section_id}');"/>

    Im Falle von „<g:call>“ können Parameter auch implizit als Liste benannter Variablen in einem Parameter „arguments“ übergeben werden:

     <g:call function="item_link_default.xml" arguments="sysparm_view,ref_parent,jvar_target_text"/>

    Als Alternative zur Übergabe von Variablen an die Funktion über separate Tag-Argumente ist es möglich, eine Liste von Variablen in einem einzelnen Argument „arguments“ zu übergeben. Alle Variablen, die durch ihren Namen (kommagetrennt) im Parameter argument identifiziert werden, werden innerhalb der Funktion unter genau demselben Namen wieder eingeführt (z. B. stünden uns in der Funktionsvorlage die Variablen „sysparm_view“, „ref_parent“ und „jvar_target_text“ zur Verfügung).

    Die Funktionsvorlage kann über das Attribut return= einen Wert an die aufrufende Vorlage zurückgeben. Innerhalb der Funktion legt die Variable jvar_answer den Rückgabewert fest.

    <g:call function="item_body_cell_calc_style.xml" arguments="jvar_type" return="jvar_style"/>

    <g:evaluate>

    Das Tag „<g:evaluate>“ wird verwendet, um in Rhino JavaScript geschriebene Ausdrücke auszuwerten. Manchmal wird es auch genutzt, um Variablen auf den Wert des Ausdrucks zu setzen.

    Die letzte Anweisung im Ausdruck ist der Wert, den die Variable enthalten wird.

    <g2:evaluate var="jvar_page" jelly="true">
         var page = "";
         var pageTitle = "";
         var pageGR = new GlideRecord("cmn_schedule_page");
         pageGR.addQuery("type", jelly.jvar_type");
         pageGR.query();
         if (pageGR.next()) {
            page = pageGR.getValue("sys_id");
            pageTitle = pageGR.getDisplayValue();
         }
         page;
    </g2:evaluate>
    <g2:evaluate var="not_important" expression="sc_req_item.popCurrent()"/>

    object="true"

    Soll die Auswertung ein Objekt zurückgeben (z. B. ein Array), müssen Sie das Argument „object="true"“ verwenden.

    <g2:evaluate object="true" var="jvar_items" expression="SncRelationships.getCMDBViews()" />

    jelly="true"

    Möchten Sie innerhalb eines „evaluate“-Tag auf Jelly-Variablen zugreifen, fügen Sie „jelly="true"“ in das „evaluate“-Tag ein und setzen „jelly“ als Namen der Jelly-Variablen. Beispielsweise könnten Sie wie folgt auf „GlideJellyContext“ zugreifen:

    <g2:evaluate var="jvar_row_no" jelly="true">
       var gf = jelly.context.getGlideForm();
       var row = gf.getRowNumber();
       row;
    </g2:evaluate>

    Nachfolgend sehen Sie ein weiteres Beispiel für den Zugriff auf eine „jvar“-Variable über den Parameter „jelly="true"“. Der Wert von jvar_h wurde bereits zuvor gesetzt und kann innerhalb von evaluate abgerufen werden:

    $[NLBR:jvar_h.getHTMLValue('newvalue')]
    <g2:evaluate var="jvar_fix_escaping" jelly="true">
        var auditValue = jelly.jvar_h.getHTMLValue('newvalue');
        gs.log("************ " + auditValue);
    </g2:evaluate>

    copyToPhase2="true"

    Wenn Sie die Ergebnisse einer in Phase 1 durchgeführten Auswertung in Phase 2 übertragen möchten, verwenden Sie „copyToPhase2="true"“. Diese Verwendung schließt einen gewissen Escaping-Schutz ein. Beispiel:

    <g:evaluate var="jvar_has_special_inc" copyToPhase2="true">
       var specialInc = gs.tableExists("special_incident");
       specialInc;
    </g:evaluate>
    $[jvar_has_special_inc]

    Muss etwas nicht ausgewertet werden, ist eine direktere Herangehensweise möglich. Achten Sie hier auf Escaping-Probleme (doppelte Anführungszeichen in „jvar_rows“ würden in diesem Beispiel ein Problem verursachen):

    <j2:set var="jvar_rows" value="${jvar_rows}"/>

    <g:breakpoint/>

    Mit diesem Tag können Sie alle aktuellen Jelly-Variablen samt ihren Werten im Protokoll hinterlegen.

    Entfernen Sie dieses Tag, bevor Sie den Code für die Produktion freigeben.

    <g:ui_form/>

    Dieses Tag definiert ein Formular auf einer UI-Seite.

    Wenn Ihr Formular beispielsweise das Feld application_sys_id enthält, kann g:ui_form von einem Verarbeitungsskript profitieren.

    <g:ui_form>
        <p>Click OK to run the processing script.</p>
        <g:dialog_buttons_ok_cancel ok="return true" />
        <input type="hidden" name="application_sys_id" value="499836460a0a0b1700003e7ad950b5da"/>
     </g:ui_form>

    Weitere Informationen finden Sie unter UI-Makros.

    <g:ui_input_field />

    Dieses Tag fügt eine Referenz zu einem UI-Makro hinzu, das auf einer Seite ein Eingabefeld für Benutzereingaben erstellt. ui_input_field übergibt eine Bezeichnung, einen Namen, einen Wert und eine Größe an das UI-Makro.

    Hier ein Beispiel auf einer UI-Seite:
    <g:ui_input_field label="sys_id" name="sysid" value="9d385017c611228701d22104cc95c371" size="50"/>

    Weitere Informationen finden Sie unter UI-Makros.

    <g:ui_checkbox/>

    Dieses Tag platziert ein vom Benutzer bearbeitbares Häkchen auf der Seite. Name und Wert werden an das UI-Makro übergeben.

    Hier ein Beispiel aus einer Tabelle auf einer UI-Seite:

    <table>
        <tr>
          <td nowrap="true">
              <label>Time Card Active:</label>
          </td>
          <td>
              <g:ui_checkbox name="timecard_active" value="${sysparm_timecard_active}"/>
          </td>
       </tr>
    </table>

    Weitere Informationen finden Sie unter UI-Makros.

    <g:dialog_buttons_ok_cancel/>

    Dieses Tag fügt Schaltflächen auf der UI-Seite ein, die das angegebene Verarbeitungsskript ausführen, wenn das Tag „true“ zurückgibt.

    Wenn die UI-Seite ein Formular enthält (also das Tag „<g:form>“ verwendet), wird das Verarbeitungsskript ausgeführt, sobald das Formular abgesendet wird. Das Verarbeitungsskript kann naturgemäß auf Felder im Formular zugreifen. Beispiel: Ihr Formular enthält das Feld „application_sys_id“:

    <g:ui_form>
        <p>Click OK to run the processing script.</p>
        <g:dialog_buttons_ok_cancel ok="return true" />
        <input type="hidden" name="application_sys_id" value="499836460a0a0b1700003e7ad950b5da"/>
     </g:ui_form>

    <g:ui_reference/>

    Dieses Tag fügt ein Referenz auf eine Seite hinzu, die von einem Verarbeitungsskript referenziert werden kann.

    Im folgenden Beispiel wird eine Referenz erstellt, die durch den Namen, die ID und die Tabellenparameter im -Tag definiert wird:

    <g:ui_reference name="QUERY:active=true^roles=itil" id="assigned_to" table="sys_user" />

    Im Verarbeitungsskript wird das Feld „name“ dann wie folgt referenziert:

    newTask.assigned_to = request.getParameter("QUERY:active=true^roles=itil");
    Sie können einen Referenzqualifizierer angeben, damit das Attribut „name֧“ eindeutig ist. Im folgenden Beispiel wird eine Referenz erstellt, die durch den Namen, die ID und die Tabellenparameter im -Tag definiert wird.
    Hinweis:
    Das Attribut „Spalten“ gilt nur für den Autovervollständiger.
    <g:ui_reference name="parent_id" id="parent_id" table="pm_project" query="active=true" completer="AJAXTableCompleter" 
    columns="project_manager;short_description"/>

    Kaufmännisches Und-Zeichen

    Kaufmännische Und-Zeichen können in Jelly zu Problemen führen, da Jelly XML-basiert ist.

    Verwenden Sie ${AMP}, um in Jelly ein kaufmännisches Und-Zeichen einzufügen. Wenn Sie JavaScript-Code schreiben, der im HTML-Teil einer UI-Seite oder in einem UI-Makro zur Ausführung im Browser angezeigt wird, sollten Sie ihn besser in das Feld „Client-Skript“ einfügen. So vermeiden Sie Escaping-Probleme. Muss er in das Feld „HTML“ eingefügt werden, müssen Sie ähnlich wie hier vorgehen:

    ta = ta[1].split('$[AMP]');

    Und

    Verwenden Sie ${AND} um ein JavaScript-Und in Jelly einzufügen.

    Beispiel:

    if (d ${AND} e)
       var color = d.value;

    In einer Jelly-Prüfung können Sie alternativ &amp&amp verwenden. Beispiel:

    <j:if test="${jvar_form_name == 'sys_form_template' && !RP.isDialog()}">

    Weniger als

    Ähnlich wie kaufmännische Und-Zeichen können auch Kleiner-als-Zeichen („<“) Probleme verursachen, weil Jelly XML-basiert ist. Sie können dies beheben, indem Sie die Prüfung entweder so modifizieren, dass das Zeichen nicht mehr benötigt wird, oder indem Sie ${AMP}lt; anstelle des Kleiner-als-Zeichens verwenden.

    <g2:evaluate var="jvar_text">
         var days = "";
         var selectedDays = '$[${ref}]';
         for (var i = 1; i ${AMP}lt;= 7; i++) {
            if (selectedDays.indexOf(i.toString()) >= 0) {
               days += gs.getMessage("dow" + i);
               days += " ";
            }
         }
         days;
     </g2:evaluate>

    Oft können Sie den Kleiner-als-Operator ganz vermeiden, indem Sie einfach das Ist-ungleich-Zeichen verwenden. Dieses Zeichen verursacht keine Escaping-Probleme. Beispiel:

    for (var i=0; i != ta.length; i++) {
    }

    Leerzeichen

    Normalerweise werden Leerräume von Jelly entfernt. Sollen sie beibehalten werden, müssen Sie festlegen, dass sie nicht weggekürzt werden sollen.

    Folgender Code legt beispielsweise fest, dass das Leerzeichen nach dem Doppelpunkt beibehalten wird:

    <j2:whitespace trim="false">${gs.getMessage('Did you mean')}: </j2:whitespace>

    Flächen

    Geschützte Leerzeichen (°) können Sie mithilfe von $[SP] setzen.

    Beispiel:

    <span id="gsft_domain" style="display: inline">
        ${gs.getMessage('Domain')}:$[SP]
        <span id="domainDD" class="drop_down_element" style="text-decoration: none; color: white">
            ${gs.getMessage("Loading...")}
       </span>
    </span>

    Jelly nachverfolgen

    ServiceNow bietet ein Feature, mit dem Jelly-Auswertungen nachverfolgt werden können.

    Die Ablaufverfolgung (Trace) wird an das Protokoll gesendet. Dieses Feature sollte nur während des Debugging aktiviert werden, da es viele Protokolleinträge generiert. Zur Aktivierung der Ablaufverfolgung setzen Sie die Eigenschaft „glide.ui.template.trace“ auf „true“. Um dies zu erreichen, können Sie beispielsweise das folgende Skript ausführen:

    GlideProperties.set ( 'glide.ui.template.trace' , true ) ;

    Wenn Sie Ihre Protokolleinträge in Ihrem Webbrowser unten auf jeder Seite anzeigen möchten, navigieren Sie zu Systemdiagnostik > Protokoll debuggen.