【Godot】XMLParserの使い方

今回は Godot Engine で XMLファイルを読み込むための XMLParser の使い方について紹介します。

XML Parser の使い方

XMLとは

XMLとは以下のように <タグ名> で構成されるデータ構造のファイルです。

<player>
    <param name="勇者" class="hero">
        <hp>123</hp>
        <mp>10</mp>
    </param>
</player>

JSONやConfigFileと比べるとやや冗長な記述で、最近はあまり使われなくなったデータ構造です。通常、Godot で複雑なデータ構造を扱うのであれば JSON や ConfigFile がおすすめです。

読み込み方法は以下の記事に書きました。

XMLファイルの読み込みサンプルコード

とはいえ、XMLを扱いたい場合のために、Godot Engine は XMLParser という読み込みモジュールを用意しています。

以下、"test.xml" を読み込むサンプルコードです。

extends Node2D

func _ready():
    # XMLパーサーを生成.
    var parser = XMLParser.new()
    # test.xml を読み込む.
    var error = parser.open("test.xml")
    if error != OK:
        # 読み込み失敗.
        push_error(str("Error opening XML file:", error))
        return

    # ここから解析開始.
    var cnt = 0 # 読み込みをした回数.
    var tab = "" # インデント.
    while true:
        # 次を読み込む.
        if parser.read() != OK:
            return # 読み込み終了.
        cnt += 1
        
        var type = parser.get_node_type() # ノード種別.
        var name = parser.get_node_name() # ノード名.
        
        #print(type, name)
        match type:
            parser.NODE_ELEMENT: # 開始タグ
                # 属性の数を取得.
                var attr = ""
                var count = parser.get_attribute_count()
                for i in range(count):
                    # 属性名を取得.
                    var attr_name = parser.get_attribute_name(i)
                    # 属性の値を取得.
                    var attr_value = parser.get_named_attribute_value_safe(attr_name)
                    attr += " %s=%s"%[attr_name, attr_value]
                print("%2d:"%cnt, tab, "<%s%s>"%[name, attr])
                tab += " " # インデント
                
            parser.NODE_ELEMENT_END: # 閉じタグ
                tab.erase(tab.length()-1, ord(' ')) # インデント削除.
                print("%2d:"%cnt, tab, "</%s>"%name)
                
            parser.NODE_TEXT: # 値
                var value = parser.get_node_data().strip_edges() # 空白文字を消す.
                if value != "": # 空文字の TEXT の可能性がある…?
                    print("%2d:"%cnt, tab, value)

"test.xml" は以下のファイルとします。

<player>
    <param name="勇者" class="hero">
        <hp>123</hp>
        <mp>10</mp>
    </param>
</player>

この場合に実行結果は以下のとおりです。

実行結果
 1:<player>
 3: <param name=勇者 class=hero>
 5:  <hp>
 6:   123
 7:  </hp>
 9:  <mp>
10:   10
11:  </mp>
13: </param>
14:</player>

行頭の数字は read() を呼び出した回数で、XMLParserの挙動としては改行やスペースなど空白が見つかると、値(XMLParser.NODE_TEXT) と評価されてしまうような印象です。

open ( String file ): XMLファイルを開く

open() はXMLファイルを開きます。ファイルが読み込めなかったりするとエラーが返却されます。

read (): 次のノードを読み込む

Godot の場合は一般的なXMLパーサーと異なり、read() で次のノードに移動するような実装となっています。なので、read()を呼ぶたびにノードの階層を下ったり上に登ったりするような挙動です。

get_node_type (): 現在のノードが示しているタイプを返す

XMLParserはノードのカーソルを移動するタイプなので、この関数で処理を分岐していきます。この関数が返すノードタイプは以下のとおりです。

  • NODE_NONE = 0 --- 無効なノード (ファイルが存在しない or バッファを開いていない)
  • NODE_ELEMENT = 1 --- 要素 (タグ)
  • NODE_ELEMENT_END = 2 --- タグの終了
  • NODE_TEXT = 3 --- テキストノード
  • NODE_COMMENT = 4 --- コメントノード
  • NODE_CDATA = 5 --- CDATAコンテント
  • NODE_UNKNOWN = 6 --- 不明なノード

get_node_name (): ノード名を取得する

現在のノード名を取得します。ノードタイプが "NODE_ELEMENT" (タグ) の場合のみ取得できそうな印象です。

get_node_data (): ノードの値を取得する

現在のノードの値を取得します。ノードタイプが "NODE_TEXT" (テキストノード) の場合のみ取得できそうな印象です。それとノードの値には無駄な空白文字が含まれていることが多いので、String.strip_edges() で削除したほうが良いのかなと思います。

get_named_attribute_value_safe ( String name ): 属性の値を取得する

ノードタイプが "NODE_ELEMENT" (タグ) の場合に、属性の名前を指定して値を取得します。

その他の注意点

XMLParserはノードの階層構造を管理する機能が用意されていないので、タグ名のスタックを作るなど階層構造の管理を自作する必要があります。

プロジェクトファイル

今回作成したプロジェクトファイルを添付します。

参考