◀ 6.

Struts「TLD によると、タグ form の属性 id は無効です」原因と対処

この記事の要点
  • Struts JSP で <html:form id="..."> を書くと「TLD によると、タグ form の属性 id は無効です」
  • 原因: Struts の HTML タグライブラリは標準 HTML 属性をそのまま受け付けない
  • 対処: id → styleId、class → styleClass に書き換える
  • styleId / styleClassは生成HTMLのid / classになる。属性エラーが消えてもAction設定やフォーム処理は別に確認
  • Struts 2 では話が変わる — id 属性はサポートされる

エラー内容

Struts 1.x の JSP で以下のように書くとコンパイル時に怒られます:

<%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %>

<!-- ❌ NG: TLD によると、タグ form の属性 id は無効です -->
<html:form action="/login" id="loginForm" class="form-horizontal">
    <html:text property="username" id="usernameInput" />
</html:form>
TLDによると、タグ form の属性 id は無効です
According to TLD, attribute id is not valid for tag form.

これはJSPタグの属性宣言に関するエラーです。Struts 1の保守向けに、タグの属性と生成HTMLを分けて確認します。Struts 1は保守終了しており、新規導入は勧めません。

原因

Struts 1.x の HTML タグライブラリ(<html:form>、<html:text> 等)は標準 HTML 属性をそのまま受け取れない仕様になっています。JSPカスタムタグの属性は、そのタグを定義するTLDで決まります。Struts 1.3.10のhtml:formにはidとclassが宣言されず、styleIdとstyleClassが宣言されています。標準HTMLのformと、JSPで実行されるhtml:formは別のものとして確認してください。

主に名前がぶつかる属性は以下で、それぞれ別名が用意されています:

標準 HTML 属性Struts での書き方出力される HTML 属性
idstyleIdid
classstyleClassclass
stylestyle (そのまま)style
name(通常の非indexed入力項目名)property(html:text等)name。JSPタグのname属性はBean参照名であり別の用途
valuevalue または ActionForm の値value

対処: styleId / styleClass に書き換える

<!-- ✅ OK -->
<html:form action="/login" styleId="loginForm" styleClass="form-horizontal">
    <html:text property="username" styleId="usernameInput" styleClass="form-control" />
    <html:password property="password" styleId="passwordInput" styleClass="form-control" />
    <html:submit styleClass="btn btn-primary">ログイン</html:submit>
</html:form>

出力される HTML は通常通りで、ブラウザ側は id="loginForm" として認識します:

<form action="/login.do" name="loginForm" method="post"
      id="loginForm" class="form-horizontal">
    <input type="text" name="username" value=""
           id="usernameInput" class="form-control">
    <input type="password" name="password" value=""
           id="passwordInput" class="form-control">
    <input type="submit" value="ログイン" class="btn btn-primary">
</form>

CSS / JavaScript からの参照

生成されたidとclassの値を維持するなら、対応するCSSセレクタやdocument.getElementById()、jQueryセレクタ$('#loginForm')は同じ値を参照できます。ただし、ページ内のid重複、JavaScriptの実行タイミング、生成HTMLを確認してください。属性名の訂正だけで、入力検証や送信処理まで正しく動くとは限りません。

// styleId を使っても JS からは id として参照可能
$('#loginForm').on('submit', function(e) {
    if ($('#usernameInput').val() === '') {
        alert('ユーザー名を入力してください');
        e.preventDefault();
    }
});

その他の Struts 1 タグでも同じパターン

同じ属性名のリネームは、<html:text> / <html:select> / <html:checkbox> / <html:radio> などでもstyleId/styleClassを使います。ただし、すべてのタグが同じ属性一覧を持つわけではありません。対象タグのTLDを確認します:

<html:select property="category" styleId="categorySelect" styleClass="form-select">
    <html:option value="1">食品</html:option>
    <html:option value="2">飲料</html:option>
</html:select>

<html:checkbox property="agree" styleId="agreeCheck" styleClass="form-check-input" />

Struts 2 の場合は異なる

Struts 2 では設計が刷新されており、id / cssClass という属性名になっています:

<!-- Struts 2 -->
<%@ taglib prefix="s" uri="/struts-tags" %>

<s:form action="login" id="loginForm" cssClass="form-horizontal">
    <s:textfield name="username" id="usernameInput" cssClass="form-control" />
</s:form>
Struts 1Struts 2
idstyleIdid(そのまま)
classstyleClasscssClass
stylestylecssStyle

関連エラー

  • 「タグ form の属性 class は無効です」 — 同じパターン。styleClass に変更
  • 「タグ ... の属性 name は無効です」 — タグ名を確認します。1.3.10のhtml:formはnameもpropertyも宣言せず、html:textは両方を宣言します。nameを一律にpropertyへ置換しないでください。
  • 「タグ ... の属性 onclick は無効です」 — 別名へ推測で変更せず、対象タグの宣言を確認します。1.3.10のhtml:textはonclickを宣言しますが、html:formはonclickを宣言せずonsubmit/onresetを宣言します。必要なイベントと付ける要素が正しいか確認してください。

まとめ

Struts 1 のタグライブラリは標準 HTML とは別の独自仕様。以下を覚えておけば大体の TLD エラーは解決:

  1. id → styleId
  2. class → styleClass
  3. 入力部品のpropertyはフォームプロパティ、nameは読込み用Bean参照名。タグ別の意味と許可属性を確認する
  4. その他は Struts HTML Tag Library Reference を確認

修正しても同じTLDエラーが出るとき

  1. スタックトレースのJSP名・タグ名・属性名を確認します。formの訂正後にtextのidが別途指摘される場合もあります。
  2. taglibディレクティブのprefixとuri、web.xmlのタグライブラリ設定、配備したJAR内のMETA-INF/tldを照合します。prefixがhtmlという名前でも、読み込むタグライブラリが必ずStrutsとは限りません。
  3. 実際に配備した版のTLDで、そのタグのattribute/nameを確認します。IDEに登録された別の版の定義だけを見て判断しません。
  4. JSPと配備物の反映を確認し、生成HTMLでid/classが期待値になっているか調べます。生成idが重複しないことも確認します。Tomcatのwork削除やライブラリの一括交換を初手にしません。

掲載の生成HTMLは例示

上の/login.doという出力は、アプリのコンテキストやサーブレットのマッピングなどが対応している場合の説明例です。実際のAction URL、formのname、入力値は設定や状態に依存します。styleIdを付けるだけでそのHTML全文が必ず生成されるという意味ではありません。

Struts 1とStruts 2を混ぜない

Struts 2のform/textfield公式資料ではid、cssClass、cssStyleが確認できます。ただし既存のStruts 1 JSPで属性名やtaglibだけをStruts 2へ変更しても移行は完了しません。Action、フォームのモデル、設定、検証、ビュー、認証を含む移行設計が必要です。旧ActionFormのnameとStruts 2の入力nameも同じ仕様と扱いません。

確認した範囲と一次資料

Struts 1.3.10の配布JAR内TLDを解析し、formのstyleId/styleClassとid/class/name/propertyの非宣言、textのname/property/onclick、optionのvalueとpropertyの非宣言を単体検証しました。JSPコンパイラやTomcatでのページ生成全体、すべてのStruts版・タグの動作保証ではありません。

一次資料(2026年10月確認):Struts 1.3.10公式ソースとTLD(sources JAR)、Struts 2 formタグ、Struts 2 textfieldタグ。

子ページ

子ページはありません

同階層のページ
  1. createActionFormにてNullPointerException
  2. java.lang.NullPointerException: Module 'null' not found
  3. javax.servlet.jsp.JspException: Cannot find bean org.apache.struts.taglib.html.BEAN in any scope
  4. Description Resource Path Location Type cvc-complex-type.2.4.a: Invalid content was found starting with element 'X'
  5. パス ... に対するアクションのインスタンスがありません
  6. TLDによると、タグ form の属性 id は無効です