Thymeleaf version 2.1.5 で独自のダイアレクトを実装する

# 概要

Thymeleafで独自のダイアレクトを実装する方法のまとめです。
ダイアレクトでどのようなことが出来るのかを中心にしているので、サンプルコードに実用性はあまりありません。
また、このサンプルコードで説明するダイアレクトのprefixは`my`としています。

ダイアレクトとプロセッサについては公式サイトのチュートリアルの説明が詳しかったので下記にその一部を引用します。
引用部分に書かれているとおり、基本的にはスタンダードダイアレクトだけで十分間に合うことが多いのですが、同じロジックを多くのテンプレートに記述しなければいけないなどの場合は、独自プロセッサに任せることでテンプレート上から冗長性を排除することができます。

> ### 1.3 ダイアレクト: スタンダードダイアレクト
> http://www.thymeleaf.org/doc/tutorials/2.1/usingthymeleaf_ja.html#ダイアレクト-スタンダードダイアレクト
> 
> DOMノードにロジックを適用するものを「プロセッサ」と呼びます。そして、プロセッサ一式 — と、いくつかの特別な生成物 — のことをダイアレクトと呼びます。Thymeleafでは「スタンダードダイアレクト」というそのまますぐに使えるコアライブラリを提供していて、大半のユーザーにとってはこれで十分です。
> 
> もちろん、ライブラリの拡張機能を利用して独自の処理ロジックを定義したい、など(スタンダードダイアレクトを拡張することも含めて)独自のダイアレクトを作りたい場合があるかもしれません。テンプレートエンジンは複数のダイアレクトを同時に使用できます。

**環境**

* Windows10 Professional
* Java 1.8.0_101
* Spring Boot 1.4.1
 * thymeleaf 2.1.5

**参考**

* [Tutorial: Using Thymeleaf (ja)] (http://www.thymeleaf.org/doc/tutorials/2.1/usingthymeleaf_ja.html)
* [thymeleaf 2.1.5.RELEASE API] (http://www.thymeleaf.org/apidocs/thymeleaf/2.1.5.RELEASE/index.html)
* [thymeleaf-spring4 2.1.5.RELEASE API] (http://www.thymeleaf.org/apidocs/thymeleaf-spring4/2.1.5.RELEASE/index.html)


## 実装方法

独自のダイアレクトの実装は、大きく分けると以下の3つの実装が必要です。

1. プロセッサの実装
2. ダイアレクトの実装
3. 設定の実装


### 検証用のコントローラーとモデル

サンプルコードの検証に使用するモデルとコントローラーです。

#### モデル

```java:UserModel
public class UserModel implements Serializable {
  private static final long serialVersionUID = 1595768734175347794L;

  public UserModel() {
  }

  public UserModel(Long id, String name) {
    this.id = id;
    this.name = name;
  }

  private Long id;
  private String name;

  ...getter/setterは省略...

  @Override
  public String toString() {
    return "User [id=" + id + ", name=" + name + "]";
  }

}
```

```java:ItemModel
public class ItemModel implements Serializable {
  private static final long serialVersionUID = 4429386992827915231L;

  public ItemModel() {
  }

  public ItemModel(Long id, String name, Integer price, Integer remaining, String imageUrl) {
    this.id = id;
    this.name = name;
    this.price = price;
    this.remaining = remaining;
    this.imageUrl = imageUrl;
  }

  private Long id;
  private String name;
  private Integer price;
  private Integer remaining;
  private String imageUrl;

  // ...getter/setterは省略...

  @Override
  public String toString() {
    return "ItemModel [id=" + id + ", name=" + name + ", price=" + price + ", remaining=" + remaining
      + ", imageUrl=" + imageUrl + "]";
  }

}
```

#### コントローラー

```java:MyController
@Controller
public class MyController {

  private static final Map<Long, ItemModel> LIST;
  static {
    Map<Long, ItemModel> tmp = new HashMap<Long, ItemModel>();
    tmp.put(1L, new ItemModel(1L, "うまい棒", 10, 50, "/path/to/image/umaibou.png"));
    tmp.put(2L, new ItemModel(2L, "チョコバット", 20, 20, "/path/to/image/chocobat.png"));
    tmp.put(3L, new ItemModel(3L, "ベビースター", 30, 5, null));
    LIST = Collections.unmodifiableMap(tmp);
  }

  @RequestMapping(value = "/my/{id}", method = RequestMethod.GET)
  public String my(@PathVariable(name = "id", required = true) Long id, HttpServletRequest request, Model model) {

    UserModel user = new UserModel(100L, "rubytomato");
    HttpSession session = request.getSession();
    session.setAttribute("user", user);

    ItemModel item = LIST.get(id);
    model.addAttribute("item", item);

    return "my/my";
  }

}
```


### 1. プロセッサの実装

プロセッサではHTMLの要素や属性を操作する処理を実装します。基本的な機能はThymeleafのスタンダードダイアレクトで使われている抽象クラスで実装されているので、これらを継承して必要なプロセッサを開発します。また、必要があればプロセッサ内からリクエストやセッションスコープのオブジェクトへのアクセス、ThymeleafをSpringと併用する場合にはSpringが管理するBeanを使用することもできます。

プロセッサには、属性プロセッサと要素プロセッサがあります。version 2.1.5ではほとんどが属性プロセッサで、要素プロセッサは1つしかありません。


**属性プロセッサ**

DOMの属性として使う、例えば下記のような`th:if`などです。

```html
<div th:if="${price} gt 10000" th:remove="tag">
  ...何かの処理...
</div>
```

**要素プロセッサ**

それ自体をDOMの要素として扱います。いまのところ`th:block`しかありません。

```html
<th:block th:if="${price} gt 10000">
  ...何かの処理...
</th:block>
```


#### 属性プロセッサの実装例

##### AbstractConditionalVisibilityAttrProcessor

AbstractConditionalVisibilityAttrProcessorを継承すると`th:if`と同じような機能を持つ属性プロセッサを実装することができます。
オーバーライドするメソッドで重要なのは`isVisible`です。isVisibleメソッドの戻り値で要素の表示を制御します。trueを返せば自身の要素と子要素を表示し、falseを返せば表示しません。

###### サンプルコード

```java:MyIfAttrProcessor
public class MyIfAttrProcessor extends AbstractConditionalVisibilityAttrProcessor {
  private static final String ATTR_NAME = "if";
  private static final int ATTR_PRECEDENCE = 1000;

  public MyIfAttrProcessor() {
    super(ATTR_NAME);
  }

  @Override
  public int getPrecedence() {
    return ATTR_PRECEDENCE;
  }

  @Override
  protected boolean isVisible(Arguments arguments, Element element, String attributeName) {
    // ...オーバーライドします...
  }

}
```


**式を評価する**

属性に指定された式を評価します。
式はプロセッサ内から文字列として取得できるので、それをパーサーで評価します。

```html:テンプレート
<div my:if="${item.remaining gt 10}">
  <p>trueなら表示される</p>
</div>
```

```java
@Override
protected boolean isVisible(Arguments arguments, Element element, String attributeName) {

  final String attributeValue = element.getAttributeValue(attributeName);
  System.out.println(attributeValue);
  // → ${item.remaining gt 10}

  final Configuration configuration = arguments.getConfiguration();
  final IStandardExpressionParser parser = StandardExpressions.getExpressionParser(configuration);
  final IStandardExpression expression = parser.parseExpression(configuration, arguments, attributeValue);

  final Boolean result = (Boolean) expression.execute(configuration, arguments);
  System.out.println(result);
  // → true

  return result;
}
```

```html:レンダリング
<div>
  <p>trueなら表示される</p>
</div>
```


**オブジェクトを扱う**

属性にオブジェクトが指定された場合でも、パーサーで評価すればそのオブジェクトを取得することができます。

```html:テンプレート
<div my:if="${item}">
  <p>trueなら表示される</p>
</div>
```

```java
@Override
protected boolean isVisible(Arguments arguments, Element element, String attributeName) {

  final String attributeValue = element.getAttributeValue(attributeName);
  System.out.println(attributeValue);
  // → ${item}

  // ...省略...

  final ItemModel item = (ItemModel) expression.execute(configuration, arguments);
  System.out.println(item.toString());
  // → ItemModel [id=1, name=うまい棒, price=10, remaining=50, imageUrl=/path/to/image/umaibou.png]

  return item.getRemaining() > 10;
}
```

```html:レンダリング
<div>
  <p>trueなら表示される</p>
</div>
```


**HttpServletRequest、HttpServletResponse、HttpSessionを扱う**

プロセッサ内から`HttpServletRequest`、`HttpServletResponse`、`HttpSession `を扱うことができます。

```java
@Override
protected boolean isVisible(Arguments arguments, Element element, String attributeName) {
  // ...省略...

  final IContext context = arguments.getContext();

  final SpringWebContext springWebContext = (SpringWebContext) context;
  final HttpServletRequest request = springWebContext.getHttpServletRequest();
  final HttpServletResponse response = springWebContext.getHttpServletResponse();

  final HttpSession session = springWebContext.getHttpSession();
  UserModel user = (UserModel) session.getAttribute("user");
  System.out.println(user.toString());
  // → User [id=100, name=rubytomato]

  // ...省略...
}
```

ThymeleafをSpringと併用しない場合は下記のコードになります。

```java
Springと併用していない場合はこちら
final IWebContext webContext = (IWebContext) context;
final HttpServletRequest request = webContext.getHttpServletRequest();
final HttpServletResponse response = webContext.getHttpServletResponse();
```

**SpringのApplicationContextを参照する**

ThymeleafをSpringと併用している場合は、Springの`ApplicationContext`のインスタンスを参照することができます。

```java
@Override
protected boolean isVisible(Arguments arguments, Element element, String attributeName) {
  // ...省略...

  final IContext context = arguments.getContext();

  final SpringWebContext springWebContext = (SpringWebContext) context;
  final ApplicationContext applicationContext = springWebContext.getApplicationContext();

  // ...省略...
}
```

**他の属性値を取得する**

同じ要素の他の属性の値も取得できます。

```html
<div my:if="${item.remaining gt 10}" data-hoge="fuga">
 <p>trueなら表示される</p>
</div>
```

```java
final String hoge = element.getAttributeValue("data-hoge");
System.out.println("hoge:" + hoge);
// → fuga
```


##### AbstractSingleAttributeModifierAttrProcessor

AbstractSingleAttributeModifierAttrProcessorを継承すると`th:src`と同じような機能を持つ属性プロセッサを実装することができます。
オーバーライドするメソッドで重要なのは`getTargetAttributeName`と`getTargetAttributeValue`です。
getTargetAttributeNameメソッドの戻り値で値を設定する属性を指定します。
getTargetAttributeValueメソッドの戻り値が指定した属性へセットする値になります。

###### サンプルコード

```java:MySrcAttrProcessor
public class MySrcAttrProcessor extends AbstractSingleAttributeModifierAttrProcessor {
  private static final String ATTR_NAME = "src";
  private static final int ATTR_PRECEDENCE = 1000;

  public MySrcAttrProcessor() {
    super(ATTR_NAME);
  }

  @Override
  public int getPrecedence() {
    return ATTR_PRECEDENCE;
  }

  @Override
  protected String getTargetAttributeName(Arguments arguments, Element element, String attributeName) {
    // 通常はプロセッサの属性名と同じにします。
    return ATTR_NAME;
  }

  @Override
  protected String getTargetAttributeValue(Arguments arguments, Element element, String attributeName) {
    // ...オーバーライドします...
  }

  @Override
  protected ModificationType getModificationType(Arguments arguments, Element element, String attributeName, String newAttributeName) {
    // 属性値の設定方法を指定します。
    return ModificationType.SUBSTITUTION;
  }

  @Override
  protected boolean removeAttributeIfEmpty(Arguments arguments, Element element, String attributeName, String newAttributeName) {
    // 属性にセットする値が空の場合に属性を削除するか
    return true;
  }

  @Override
  protected boolean recomputeProcessorsAfterExecution(Arguments arguments, Element element, String attributeName) {
    // 用途不明です。
    return false;
  }

}
```

**オブジェクトを扱う**

プロセッサでできることは上記の`my:if`と同じです。
この例では、属性に指定したItemModelのインスタンスのimageUrlフィールドがnullの場合に代替URLを、nullでない場合にimageUrlの値を返します。

```html:テンプレート
<img my:src="${item}" />
```

```java
@Override
protected String getTargetAttributeValue(Arguments arguments, Element element, String attributeName) {

  final String attributeValue = element.getAttributeValue(attributeName);
  System.out.println("attribute:" + attributeValue);
  // → ${item}

  final Configuration configuration = arguments.getConfiguration();
  final IStandardExpressionParser parser = StandardExpressions.getExpressionParser(configuration);

  final IStandardExpression expression = parser.parseExpression(configuration, arguments, attributeValue);
  final ItemModel item = (ItemModel) expression.execute(configuration, arguments);
  System.out.println("request item:" + item.toString());
  // → ItemModel [id=1, name=うまい棒, price=10, remaining=50, imageUrl=/path/to/image/umaibou.png]

  return StringUtils.isEmpty(item.getImageUrl()) ? "/path/to/image/noimage.png" : item.getImageUrl();
}
```

```html:レンダリング
<img src="/path/to/image/umaibou.png">
```


**属性値の設定方法を指定する**

getModificationTypeメソッドの戻り値で、属性値の設定方法を選択します。返せる値はModificationTypeというEnumで定義されています。

|VALUE              |実行内容                            |
|:------------------|:----------------------------------|
|SUBSTITUTION       |指定する属性の値を置き換える         |
|APPEND             |指定する属性の値の末尾に加える       |
|APPEND_WITH_SPACE  |APPENDを空白区切りで行う            |
|PREPEND            |指定する属性の値の先頭に加える        |
|PREPEND_WITH_SPACE |PREPENDを空白区切りで行う            |



#### 要素プロセッサの実装例

できることは属性プロセッサと変わりませんが、属性プロセッサと違って属性を必要としませんのでいく分かテンプレート上はすっきりします。

##### AbstractConditionalVisibilityElementProcessor

AbstractConditionalVisibilityElementProcessorを継承すると`th:if`と同じように条件によって内部の要素を表示するか制御することができます。
オーバーライドするメソッドで重要なのは属性プロセッサと同じで`isVisible`です。

###### サンプルコード

```java:MyIfElementProcessor
public class MyIfElementProcessor extends AbstractConditionalVisibilityElementProcessor {
  private static final String ELEMENT_NAME = "if";
  private static final int PRECEDENCE = 1000;

  public MyIfElementProcessor() {
    super(ELEMENT_NAME);
  }

  @Override
  public int getPrecedence() {
    return PRECEDENCE;
  }

  @Override
  protected boolean isVisible(Arguments arguments, Element element) {
    // ...オーバーライドします...
  }

  @Override
  protected boolean removeHostElementIfVisible(Arguments arguments, Element element) {
    // 通常は独自の要素を削除するのでtrueを返します
    return true;
  }

}
```

**オブジェクトを扱う**

属性プロセッサで説明した`my:if`を要素プロセッサで書き換える例です。

```html:テンプレート
<my:if>
<div>
 <p>trueなら表示される</p>
</div>
</my:if>
```

```java
@Override
protected boolean isVisible(Arguments arguments, Element element) {
  final IContext context = arguments.getContext();

  final SpringWebContext springWebContext = (SpringWebContext) context;

  final HttpServletRequest request = springWebContext.getHttpServletRequest();
  final ItemModel item = (ItemModel) request.getAttribute("item");
  System.out.println(item.toString());
  // → ItemModel [id=1, name=うまい棒, price=10, remaining=50, imageUrl=/path/to/image/umaibou.png]

  return item.getRemaining() > 10;
}
```

```html:レンダリング
<div>
 <p>trueなら表示される</p>
</div>
```


**要素を出力する**

プロセッサで任意の要素を出力させることができます。（属性プロセッサでは触れていませんが属性プロセッサでもできます。）
（多用するとThymeleafの良さを削ぐことになるので使いどころをよく検討する必要があると思います。）

```html:テンプレート
<my:if />
```

```java
@Override
protected boolean isVisible(Arguments arguments, Element element) {
  final IContext context = arguments.getContext();

  final SpringWebContext springWebContext = (SpringWebContext) context;

  final HttpServletRequest request = springWebContext.getHttpServletRequest();
  final ItemModel item = (ItemModel) request.getAttribute("item");
  System.out.println(item.toString());
  // → ItemModel [id=1, name=うまい棒, price=10, remaining=50, imageUrl=/path/to/image/umaibou.png]

  boolean isVisible = item.getRemaining() > 10;

  if (isVisible) {
    Element pEle = new Element("p");
    pEle.addChild(new Text("trueなら表示される"));
    Element divEle = new Element("div");
    divEle.addChild(pEle);
    element.getParent().insertBefore(element, divEle);
  }

  return isVisible;
}
```

```html:レンダリング
<div><p>trueなら表示される</p></div>
```


### 2. ダイアレクトの実装

用意されている抽象クラスAbstractDialectを継承して独自のダイアレクトを実装します。
ダイアレクトで行うことは、実装したプロセッサのインスタンスを生成することと、このダイアレクトのprefixの指定です。
prefixはプロセッサのネームスペースの役割を果たします。ちなみにスタンダードダイアレクトのprefixは"th"です。

```java
public class MyDialect extends AbstractDialect {
  private static final String PREFIX = "my";
  private static final Set<IProcessor> PROCESSORS;

  static {
    Set<IProcessor> tmp = new HashSet<>();
    tmp.add(new MyIfAttrProcessor());
    tmp.add(new MySrcAttrProcessor());
    tmp.add(new MyIfElementProcessor());
    PROCESSORS = Collections.unmodifiableSet(tmp);
  }

  @Override
  public String getPrefix() {
    return PREFIX;
  }

  @Override
  public boolean isLenient() {
    return false;
  }

  @Override
  public Set<IProcessor> getProcessors() {
    return PROCESSORS;
  }

}
```


### 3. 設定の実装

実装したダイアレクトを有効にするために下記のコードで有効化します。

```java
@Configuration
public class MyDialaectConfigurer {

  // 独自ダイアレクト
  @Bean
  MyDialect myDialect() {
    return new MyDialect();
  }

}
```

若しくは

```java
@SpringBootApplication
public class App {

  public static void main( String[] args ) {
    SpringApplication.run(App.class, args);
  }

  // 独自ダイアレクト
  @Bean
  MyDialect myDialect() {
    return new MyDialect();
  }

}
```

以上で独自のダイアレクトとプロセッサの実装方法の説明は終了です。


## 独自のユーティリティオブジェクトを実装する

おまけです。
実装方法は、[カスタム Utility Object を追加する ー Thymeleaf] (http://dev.classmethod.jp/client-side/thymeleaf/custome-utility-objects/)という記事の通りです。

### 実装方法

1. ユーティリティオブジェクトの実装
2. ダイアレクトの実装

#### ユーティリティオブジェクトの実装

```java:ViewHelper
public interface ViewHelper {
  public String hello(String message);
}
```

```java:ViewHelperImpl
@Component
public class ViewHelperImpl implements ViewHelper {

  @Autowired
  MessageSource messageSource;

  @Override
  public String hello(String message) {
    return messageSource.getMessage("message.text1", new Object[]{message}, Locale.getDefault());
  }

}
```

#### ダイアレクトの実装

独自のダイアレクトクラスにIExpressionEnhancingDialectインターフェースを実装します。

```java
public class MyDialect extends AbstractDialect implements IExpressionEnhancingDialect {

  // ...省略...

  @Override
  public Map<String, Object> getAdditionalExpressionObjects(IProcessingContext processingContext) {
    final SpringWebContext springWebContext = (SpringWebContext) processingContext.getContext();
    final ApplicationContext applicationContext = springWebContext.getApplicationContext();
    
    ViewHelper viewHelper = applicationContext.getBean(ViewHelper.class);

    Map<String, Object> tmp = new HashMap<>();
    tmp.put("vh", viewHelper);

    return Collections.unmodifiableMap(tmp);
  }

}
```

#### メッセージリソースファイル

```properties:message_ja.properties
message.text1 = こんにちは {0}.
```

```properties:message.properties
message.text1 = hello {0}.
```

#### テンプレート

```html:テンプレート
<p th:text="${#vh.hello(user.name)}"></p>
```

```html:レンダリング
<p>こんにちは rubytomato.</p>
```



## 補足資料

### thymeleaf 2.1.5.RELEASE

#### Dialect

* [Class StandardDialect] (http://www.thymeleaf.org/apidocs/thymeleaf/2.1.5.RELEASE/org/thymeleaf/standard/StandardDialect.html)
* [Standard-Dialect.xml] (https://github.com/thymeleaf/thymeleaf/blob/thymeleaf-2.1.5.RELEASE/src/main/resources/org/thymeleaf/xml/thymeleaf/Standard-Dialect.xml)

|PREFIX       |Class |
|:------------|:-----|
|th           |AbstractDialect <br>&nbsp;&nbsp;└ AbstractXHTMLEnabledDialect <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└ StandardDialect |


#### Processor

* [org.thymeleaf.processor.attr] (https://github.com/thymeleaf/thymeleaf/tree/thymeleaf-2.1.5.RELEASE/src/main/java/org/thymeleaf/processor/attr)
* [org.thymeleaf.processor.element] (https://github.com/thymeleaf/thymeleaf/tree/thymeleaf-2.1.5.RELEASE/src/main/java/org/thymeleaf/processor/element)
* [org.thymeleaf.processor.text] (https://github.com/thymeleaf/thymeleaf/tree/thymeleaf-2.1.5.RELEASE/src/main/java/org/thymeleaf/processor/text)

##### Attribute一覧

|ATTR<br>NAME |ATTR<br>PRECEDENCE|Class |
|:------------|:--------------|:-----|
|assert       |1550           |AbstractAssertionAttrProcessor <br>&nbsp;&nbsp;└ AbstractStandardAssertionAttrProcessor <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└ StandardAssertAttrProcessor |
|inline       |1000           |AbstractAttrProcessor <br>&nbsp;&nbsp;└ AbstractStandardTextInlinerAttrProcessor <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└ StandardInlineAttrProcessor |
|attr         |700            |AbstractAttributeModifierAttrProcessor <br>&nbsp;&nbsp;└ AbstractStandardAttributeModifierAttrProcessor <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└ StandardAttrAttrProcessor |
|attrappend   |900            |AbstractAttributeModifierAttrProcessor <br>&nbsp;&nbsp;└ AbstractStandardAttributeModifierAttrProcessor <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└ StandardAttrappendAttrProcessor |
|attrprepend  |800            |AbstractAttributeModifierAttrProcessor <br>&nbsp;&nbsp;└ AbstractStandardAttributeModifierAttrProcessor <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└ StandardAttrprependAttrProcessor |
|alt-title    |990            |AbstractAttributeModifierAttrProcessor <br>&nbsp;&nbsp;└ AbstractStandardSingleValueMultipleAttributeModifierAttrProcessor <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└ StandardAltTitleAttrProcessor |
|lang-xmllang |990            |AbstractAttributeModifierAttrProcessor <br>&nbsp;&nbsp;└ AbstractStandardSingleValueMultipleAttributeModifierAttrProcessor <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└ StandardLangXmlLangAttrProcessor |
|async...     |1000           |AbstractConditionalFixedValueAttrProcessor <br>&nbsp;&nbsp;└ AbstractStandardConditionalFixedValueAttrProcessor <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└ StandardConditionalFixedValueAttrProcessor |
|case         |275            |AbstractConditionalVisibilityAttrProcessor <br>&nbsp;&nbsp;└ AbstractStandardCaseAttrProcessor <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└ StandardCaseAttrProcessor |
|if           |300            |AbstractConditionalVisibilityAttrProcessor <br>&nbsp;&nbsp;└ AbstractStandardConditionalVisibilityAttrProcessor <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└ StandardIfAttrProcessor|
|unless       |400            |AbstractConditionalVisibilityAttrProcessor <br>&nbsp;&nbsp;└ AbstractStandardConditionalVisibilityAttrProcessor <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└ StandardUnlessAttrProcessor |
|include      |100            |AbstractFragmentHandlingAttrProcessor <br>&nbsp;&nbsp;└ AbstractStandardFragmentHandlingAttrProcessor <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└ StandardIncludeFragmentAttrProcessor |
|replace      |100            |AbstractFragmentHandlingAttrProcessor <br>&nbsp;&nbsp;└ AbstractStandardFragmentHandlingAttrProcessor <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└ StandardReplaceFragmentAttrProcessor |
|substituteby |100            |AbstractFragmentHandlingAttrProcessor <br>&nbsp;&nbsp;└ AbstractStandardFragmentHandlingAttrProcessor <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└ StandardSubstituteByFragmentAttrProcessor |
|each         |200            |AbstractIterationAttrProcessor <br>&nbsp;&nbsp;└ AbstractStandardIterationAttrProcessor <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└ StandardEachAttrProcessor |
|with         |600            |AbstractLocalVariableDefinitionAttrProcessor <br>&nbsp;&nbsp;└ AbstractStandardLocalVariableDefinitionAttrProcessor <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└ StandardWithAttrProcessor|
|switch       |250            |AbstractLocalVariableDefinitionAttrProcessor <br>&nbsp;&nbsp;└ AbstractStandardSwitchStructureAttrProcessor <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└ StandardSwitchAttrProcessor |
|remove       |1600           |AbstractMarkupRemovalAttrProcessor <br>&nbsp;&nbsp;└ StandardRemoveAttrProcessor |
|fragment     |1500           |AbstractNoOpAttrProcessor <br>&nbsp;&nbsp;└ StandardFragmentAttrProcessor |
|object       |500            |AbstractSelectionTargetAttrProcessor <br>&nbsp;&nbsp;└ AbstractStandardSelectionAttrProcessor <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└ StandardObjectAttrProcessor |
|action       |1000           |AbstractSingleAttributeModifierAttrProcessor <br>&nbsp;&nbsp;└ AbstractStandardSingleAttributeModifierAttrProcessor <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└ StandardActionAttrProcessor |
|classappend  |1100           |AbstractSingleAttributeModifierAttrProcessor <br>&nbsp;&nbsp;└ AbstractStandardSingleAttributeModifierAttrProcessor <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└ StandardClassappendAttrProcessor |
|onabort...   |1000           |AbstractSingleAttributeModifierAttrProcessor <br>&nbsp;&nbsp;└ AbstractStandardSingleAttributeModifierAttrProcessor <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└ StandardDOMEventAttributeModifierAttrProcessor |
|href         |1000           |AbstractSingleAttributeModifierAttrProcessor <br>&nbsp;&nbsp;└ AbstractStandardSingleAttributeModifierAttrProcessor <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└ StandardHrefAttrProcessor |
|method       |990            |AbstractSingleAttributeModifierAttrProcessor <br>&nbsp;&nbsp;└ AbstractStandardSingleAttributeModifierAttrProcessor <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└ StandardMethodAttrProcessor |
|name...      |1000           |AbstractSingleAttributeModifierAttrProcessor <br>&nbsp;&nbsp;└ AbstractStandardSingleAttributeModifierAttrProcessor <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└ StandardSingleNonRemovableAttributeModifierAttrProcessor |
|abbr...      |1000           |AbstractSingleAttributeModifierAttrProcessor <br>&nbsp;&nbsp;└ AbstractStandardSingleAttributeModifierAttrProcessor <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└ StandardSingleRemovableAttributeModifierAttrProcessor |
|src          |1000           |AbstractSingleAttributeModifierAttrProcessor <br>&nbsp;&nbsp;└ AbstractStandardSingleAttributeModifierAttrProcessor <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└ StandardSrcAttrProcessor |
|styleappend  |1100           |AbstractSingleAttributeModifierAttrProcessor <br>&nbsp;&nbsp;└ AbstractStandardSingleAttributeModifierAttrProcessor <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└ StandardStyleappendAttrProcessor |
|value        |1010           |AbstractSingleAttributeModifierAttrProcessor <br>&nbsp;&nbsp;└ AbstractStandardSingleAttributeModifierAttrProcessor <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└ StandardValueAttrProcessor |
|xmlbase      |1000           |AbstractSingleAttributeModifierAttrProcessor <br>&nbsp;&nbsp;└ AbstractStandardSingleAttributeModifierAttrProcessor <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└ StandardXmlBaseAttrProcessor |
|xmllang      |1000           |AbstractSingleAttributeModifierAttrProcessor <br>&nbsp;&nbsp;└ AbstractStandardSingleAttributeModifierAttrProcessor <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└ StandardXmlLangAttrProcessor |
|xmlspace     |1000           |AbstractSingleAttributeModifierAttrProcessor <br>&nbsp;&nbsp;└ AbstractStandardSingleAttributeModifierAttrProcessor <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└ StandardXmlSpaceAttrProcessor |
|text         |1300           |AbstractTextChildModifierAttrProcessor <br>&nbsp;&nbsp;└ AbstractStandardTextChildModifierAttrProcessor <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└ StandardTextAttrProcessor |
|utext        |1400           |AbstractUnescapedTextChildModifierAttrProcessor <br>&nbsp;&nbsp;└ AbstractStandardUnescapedTextChildModifierAttrProcessor <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└ StandardUtextAttrProcessor|
|block        |100000         |AbstractNoOpElementProcessor <br>&nbsp;&nbsp;└ StandardBlockElementProcessor  |
|             |100            |AbstractTextNodeProcessor <br>&nbsp;&nbsp;└ StandardTextInliningTextProcessor |


### thymeleaf-spring4 2.1.5.RELEASE

#### Dialect

* [Class SpringStandardDialect] (http://www.thymeleaf.org/apidocs/thymeleaf-spring4/2.1.5.RELEASE/org/thymeleaf/spring4/dialect/SpringStandardDialect.html)
* [pring-Standard-Dialect.xml] (https://github.com/thymeleaf/thymeleaf-spring/blob/thymeleaf-spring4-2.1.5.RELEASE/thymeleaf-spring4/src/main/resources/org/thymeleaf/xml/thymeleaf-spring4/Spring-Standard-Dialect.xml)

|PREFIX       |Class |
|:------------|:-----|
|th           |AbstractDialect <br>&nbsp;&nbsp;└ AbstractXHTMLEnabledDialect <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└ StandardDialect <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└ SpringStandardDialect |

#### Processor

* [org.thymeleaf.spring4.processor.attr] (https://github.com/thymeleaf/thymeleaf-spring/tree/thymeleaf-spring4-2.1.5.RELEASE/thymeleaf-spring4/src/main/java/org/thymeleaf/spring4/processor/attr)

##### Attribute一覧

|ATTR<br>NAME |ATTR<br>PRECEDENCE|Class |
|:------------|:-----------------|:-----|
|field        |1200              |AbstractAttrProcessor <br>&nbsp;&nbsp;└ AbstractSpringFieldAttrProcessor |
|checkbox     |1200              |AbstractAttrProcessor <br>&nbsp;&nbsp;└ AbstractSpringFieldAttrProcessor <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└ SpringInputCheckboxFieldAttrProcessor |
|file         |1200              |AbstractAttrProcessor <br>&nbsp;&nbsp;└ AbstractSpringFieldAttrProcessor <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└ SpringInputFileFieldAttrProcessor |
|text...      |1200              |AbstractAttrProcessor <br>&nbsp;&nbsp;└ AbstractSpringFieldAttrProcessor <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└ SpringInputGeneralFieldAttrProcessor |
|password     |1200              |AbstractAttrProcessor <br>&nbsp;&nbsp;└ AbstractSpringFieldAttrProcessor <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└ SpringInputPasswordFieldAttrProcessor |
|radio        |1200              |AbstractAttrProcessor <br>&nbsp;&nbsp;└ AbstractSpringFieldAttrProcessor <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└ SpringInputRadioFieldAttrProcessor |
|option       |1200              |AbstractAttrProcessor <br>&nbsp;&nbsp;└ AbstractSpringFieldAttrProcessor <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└ SpringOptionFieldAttrProcessor |
|select       |1200              |AbstractAttrProcessor <br>&nbsp;&nbsp;└ AbstractSpringFieldAttrProcessor <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└ SpringSelectFieldAttrProcessor |
|textarea     |1200              |AbstractAttrProcessor <br>&nbsp;&nbsp;└ AbstractSpringFieldAttrProcessor <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└ SpringTextareaFieldAttrProcessor |
|action       |1000              |AbstractSingleAttributeModifierAttrProcessor <br>&nbsp;&nbsp;└ AbstractStandardSingleAttributeModifierAttrProcessor <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└ SpringActionAttrProcessor |
|errorclass   |1500              |AbstractSingleAttributeModifierAttrProcessor <br>&nbsp;&nbsp;└ AbstractStandardSingleAttributeModifierAttrProcessor <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└ SpringErrorClassAttrProcessor |
|method       |990               |AbstractSingleAttributeModifierAttrProcessor <br>&nbsp;&nbsp;└ AbstractStandardSingleAttributeModifierAttrProcessor <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└ SpringMethodAttrProcessor |
|src          |1000              |AbstractSingleAttributeModifierAttrProcessor <br>&nbsp;&nbsp;└ AbstractStandardSingleAttributeModifierAttrProcessor <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└ SpringSrcAttrProcessor |
|value        |1010              |AbstractSingleAttributeModifierAttrProcessor <br>&nbsp;&nbsp;└ AbstractStandardSingleAttributeModifierAttrProcessor <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└ SpringValueAttrProcessor |
|errors       |1200              |AbstractAttrProcessor <br>&nbsp;&nbsp;└ AbstractStandardTextInlinerAttrProcessor <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└ SpringErrorsAttrProcessor |
|object       |500               |AbstractSelectionTargetAttrProcessor <br>&nbsp;&nbsp;└ AbstractStandardSelectionAttrProcessor <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;└ SpringObjectAttrProcessor |