1
2

More than 3 years have passed since last update.

SwiftでHTML/XMLジェネレータを作成する(dynamicMemberLookup)

Posted at

概要

@dynamicMemberLookup を使ってSwiftでHTML/XMLを生成するDSLを作ります。(作りました)

SwiftPM

SwiftPMの形で配布しています。

コード例

HTML

以下のような形でSwiftを記述します。

MarkUp()
    .html[MarkUp()
            .body[MarkUp()
                    .table[MarkUp()
                            .tr[MarkUp()
                                    .td[character: "one"]
                                    .td[character: "two"]
                            ]
                    ]
            ]
    ].generate()

上記のような構造でSwiftのコードを書くと、以下のような形でHTMLなテキストを生成します。

<html>
<body>
  <table>
    <tr>
      <td>one</td>
      <td>two</td>
    </tr>
  </table>
</body>
</html>

XML

同様にXMLも生成できます。
レシピ手順 をドットアクセスでつないでいきます。

MarkUp(doctype: #"<?xml version="1.0" encoding="UTF-8"?>"#)
    .レシピ[MarkUp()
                .手順[character: "全ての材料を一緒にして混ぜます。"]
                .手順[character: "オーブンに入れて温度を180℃にして30分間焼きます。"]
    ]
    .generate()

こうすると以下のような形でXMLを生成します。

<?xml version="1.0" encoding="UTF-8"?>
<レシピ>
    <手順>全ての材料を一緒にして混ぜます。</手順>
    <手順>オーブンに入れて温度を180℃にして30分間焼きます。</手順>
</レシピ>

仕組み

これらのタグの生成には、 @dynamicMemberLookupを使っています。

dynamicMemberLookup

dynamicMemberLookupは、Swift 4.2より追加された機能です。
@dynamicMemberLookupが付与されると、まるでプロパディが実装されているかのようにドットでアクセスできて、内部ではsubscript(dynamicMember:)の部分でドットアクセスに対する処理を書いていきます。

上記コードの場合、.html.body.レシピ などのアクセスで subscript(dynamicMember:) が動き、タグを生成する処理を行っています。

    public subscript(dynamicMember member: String) -> MarkUp {
        tagName(member)
    }

    public func tagName(_ tagName: String) -> MarkUp {
        queue.append(self)
        return MarkUp(tag: tagName,queue: queue)
    }
1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2