mcpField
B
boxlang-templating

boxlang-templating

github.com/ortus-boxlang開発045 回インストール1 週間前に更新
リポジトリ

boxlang-templating について

boxlang-templatingは、BoxLangでサーバー描画ページを作る開発者向けのスキルです。`.bxm`でHTMLと動的コードを組み合わせる方法や、テンプレートの再利用、制御フロー、出力エンコードを解説します。

主な機能

  1. 01`.bxm`ファイルでHTMLとBoxLangを記述
  2. 02式の埋め込み出力
  3. 03条件分岐と反復処理
  4. 04パーシャルとレイアウトの再利用
  5. 05テンプレート内のスクリプトブロック
  6. 06HTML出力エンコードの指針

活用シーン

  1. 01動的なBoxLang Webページの構築
  2. 02共通レイアウトによるビュー構成
  3. 03ユーザー入力の安全な表示

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/ortus-boxlang/skills --skill boxlang-templating

インストール後、Claude Code で/boxlang-templatingを入力して読み込まれたか確認します。

詳細

BoxLang テンプレート言語

BoxLang は、開発者と AI エージェントが協力してアプリケーションを構築、モダナイズ、実行するための、AI ネイティブなソフトウェア生産性プラットフォームです。

概要

BoxLang のテンプレート言語では、.bxm ファイル(BoxLang Markup)を使用して、HTML と動的なサーバーサイドコードを組み合わせます。.bxm ファイルのデフォルトモードは HTML 出力です。<bx:*> タグを使って BoxLang のロジックを埋め込み、#expression# で式を出力します。


ファイルの種類のおさらい

拡張子デフォルトモード主な用途
.bxスクリプトクラス、サービス、モデル
.bxsスクリプトスタンドアロンスクリプト、CLI ツール
.bxmタグ/マークアップテンプレート、ビュー、HTML ページ

出力式の構文

値を補間するには #expression# を使います。式は評価され、<bx:output> 内では HTML エスケープされて自動的に出力されます。

<bx:output>
    <h1>Hello, #user.name#!</h1>
    <p>Today is #dateFormat( now(), "long" )#</p>
    <p>Items: #order.items.len()#</p>
</bx:output>

出力は必ず <bx:output> で囲んでください。これがないと、#variable# はリテラル文字列として扱われ、評価されません。


<p>#name#</p>


<bx:output><p>#name#</p></bx:output>

再利用可能な部分テンプレート(app/views/partials/*.bxm)では、ブロック内に補間がある場合、レンダリングする HTML ブロック全体を <bx:output> で囲んでください。bx:param と bx:set の宣言は出力ブロックの外に置きます。


テンプレートの主要コンポーネント

<bx:output> — 動的コンテンツのレンダリング
<bx:output>
    <p>User: #user.firstName# #user.lastName#</p>
    <p>Email: #encodeForHTML( user.email )#</p>
</bx:output>

オプション:

  • encodeFor="html" — すべての式を自動エンコードします(信頼できないデータに推奨)

<bx:output encodeFor="html">
    <p>#userSuppliedContent#</p>
</bx:output>
<bx:set> — 変数の宣言
<bx:set var="greeting" value="Hello, #user.name#!">
<bx:set var="items" value="#productService.getFeatured()#">
<bx:set var="count" value="#items.len()#">
<bx:if> / <bx:elseif> / <bx:else> — 条件分岐
<bx:if condition="#user.isLoggedIn#">
    <p>Welcome back, #encodeForHTML( user.name )#!</p>
<bx:elseif condition="#session.hasGuideToken#">
    <p>Continue as guest</p>
<bx:else>
    <a href="/login">Please log in</a>
</bx:if>
<bx:loop> — 繰り返し処理

配列のループ:

<bx:loop array="#products#" item="product">
    <div class="product">
        <h3><bx:output>#encodeForHTML( product.name )#</bx:output></h3>
        <p><bx:output>$#numberFormat( product.price, "0.00" )#</bx:output></p>
    </div>
</bx:loop>

構造体のループ:

<bx:loop struct="#config#" item="value" key="key">
    <bx:output><p>#key#: #value#</p></bx:output>
</bx:loop>

クエリのループ:

<bx:loop query="#users#">
    <bx:output>
        <tr>
            <td>#users.id#</td>
            <td>#encodeForHTML( users.name )#</td>
            <td>#encodeForHTML( users.email )#</td>
        </tr>
    </bx:output>
</bx:loop>

インデックス/カウントのループ:

<bx:loop from="1" to="#items.len()#" index="i">
    <bx:output><li>#i#. #items[ i ].name#</li></bx:output>
</bx:loop>
<bx:include> — 部分テンプレートのインクルード

<bx:include template="/includes/header.bxm">

<main>
    
</main>

<bx:include template="/includes/footer.bxm">

インクルード先のテンプレートには、現在のスコープを通じて変数を渡します(インクルードでは、デフォルトで変数が継承されます)。

<bx:script> — インラインスクリプトブロック

テンプレート内でスクリプトモードに切り替えます。

<bx:script>
    var products  = productService.getFeatured( limit=6 )
    var totalPages = ceiling( products.recordCount / 10 )
</bx:script>

<bx:loop array="#products#" item="p">
    <bx:output><div>#p.name#</div></bx:output>
</bx:loop>
<bx:switch> / <bx:case> — Switch 文
<bx:switch expression="#user.role#">
    <bx:case value="admin">
        <bx:include template="/views/admin-dashboard.bxm">
    </bx:case>
    <bx:case value="editor">
        <bx:include template="/views/editor-dashboard.bxm">
    </bx:case>
    <bx:defaultcase>
        <bx:include template="/views/user-dashboard.bxm">
    </bx:defaultcase>
</bx:switch>
<bx:try> / <bx:catch> — テンプレート内のエラー処理
<bx:try>
    <bx:set var="data" value="#remoteService.getData()#">
    <bx:output><p>#data.message#</p></bx:output>
<bx:catch type="any" variable="e">
    <p class="error">Could not load data: <bx:output>#encodeForHTML( e.message )#</bx:output></p>
</bx:catch>
</bx:try>

スクリプト構文とタグ構文の併用

.bxm ファイルでは、スクリプトブロックとタグコンポーネントを自由に組み合わせられます。

<bx:script>
    // Load data using script syntax
    var pageTitle    = "Product Catalog"
    var categories   = categoryService.getAll()
    var featuredIds  = url.keyExists( "cat" ) ? [ url.cat ] : []
</bx:script>

<!DOCTYPE html>
<html lang="en">
<head>
    <bx:output><title>#encodeForHTML( pageTitle )#</title></bx:output>
</head>
<body>
    <nav>
        <bx:loop array="#categories#" item="cat">
            <bx:output>
                <a href="/catalog?cat=#encodeForURL( cat.slug )#"
                   class="#featuredIds.contains( cat.id ) ? 'active' : ''#">
                    #encodeForHTML( cat.name )#
                </a>
            </bx:output>
        </bx:loop>
    </nav>
</body>
</html>

レイアウト/ビューのパターン

ネストしたインクルード(レイアウトパターン)

<!DOCTYPE html>
<html lang="en">
<head>
    <bx:output><title>#pageTitle ?: "My App"#</title></bx:output>
    <link rel="stylesheet" href="/css/app.css">
</head>
<body>
    <bx:include template="/views/partials/nav.bxm">
    <main>
        <bx:include template="#contentTemplate#">
    </main>
    <bx:include template="/views/partials/footer.bxm">
</body>
</html>

<bx:set var="pageTitle" value="Dashboard">
<bx:set var="contentTemplate" value="/views/dashboard-content.bxm">
<bx:include template="/views/layout.bxm">

HTML 出力エンコーディングのリファレンス

ユーザーが入力したデータは、レンダリング前に必ずエンコードしてください。

<bx:output>
    
    <p>#encodeForHTML( userBio )#</p>

    
    <input value="#encodeForHTMLAttribute( formValue )#">

    
    <a href="/profile?u=#encodeForURL( username )#">View Profile</a>

    
    <script>
        const name = "#encodeForJavaScript( displayName )#";
    </script>
</bx:output>

テンプレート内のクエリ・オブ・クエリーズ

テンプレート内で直接データベースクエリを実行するには、<bx:query> を使います(シンプルなテンプレートでは問題ありませんが、複雑なロジックにはサービスレイヤーを使用してください)。

<bx:script>
    var users = queryExecute(
        "SELECT id, name, email FROM users WHERE active = :active ORDER BY name",
        { active: { value: true, cfsqltype: "cf_sql_bit" } }
    )
</bx:script>

<table>
    <thead><tr><th>Name</th><th>Email</th></tr></thead>
    <tbody>
        <bx:loop query="#users#">
            <bx:output>
                <tr>
                    <td>#encodeForHTML( users.name )#</td>
                    <td>#encodeForHTML( users.email )#</td>
                </tr>
            </bx:output>
        </bx:loop>
    </tbody>
</table>

避けるべきよくある間違い

間違い修正方法
<bx:output> の外での #var#<bx:output> で囲む
出力内の未加工のユーザーデータencodeForHTML() または encodeFor="html" を使用する
ロジックが複雑すぎるテンプレートロジックをサービスレイヤーに移し、テンプレートは表示に専念させる
閉じタグがない<bx:if> には </bx:if>、<bx:loop> には </bx:loop> が必要
スコープ指定のない変数<bx:set> または <bx:script> の var 文で宣言する
絶対 OS パスでのインクルードWeb ルート相対パス(/views/...)を使用する

コメント