JavaScriptを有効にしてください

【Elixir】XMLを簡単に Map にしてくれる XmlToMap を使う

 ·  ☕ 2 分で読めます

【Elixir】XMLを簡単に Map にしてくれる XmlToMap を使う

Elixir で標準で用意されてるXMLの読み込みのクセが強いので簡単に Map にしてくれる XmlToMap を使ってみました。

環境

  • Elixir 1.14.2

XMLを普通に読み込んで見る

比較するためにいったん普通にXMLを読み込んでみます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
# XML文字列
xml_str = """
<todos>
  <todo id="1">
    <body>This is the body of to-do item #1</body>
    <priority>3</priority>
  </todo>
  <todo id="2">
    <body>This is the body of to-do item #2</body>
    <priority>1</priority>
  </todo>
  <todo id="3">
    <body>This is the body of to-do item #3</body>
    <priority>3</priority>
  </todo>
</todos>
"""

# XML を読み込む
{doc, []} = xml_str |> to_charlist() |> :xmerl_scan.string()

IO.inspect(doc)

出力結果がこちらになります。
中々に扱いづらい状態…

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
{:xmlElement, :todos, :todos, [], {:xmlNamespace, [], []}, [], 1, [],
 [
   {:xmlText, [todos: 1], 1, [], '\n  ', :text},
   {:xmlElement, :todo, :todo, [], {:xmlNamespace, [], []}, [todos: 1], 2,
    [{:xmlAttribute, :id, [], [], [], [todo: 2, todos: 1], 1, [], '1', false}],
    [
      {:xmlText, [todo: 2, todos: 1], 1, [], '\n    ', :text},
      {:xmlElement, :body, :body, [], {:xmlNamespace, [], []},
       [todo: 2, todos: 1], 2, [],
       [
         {:xmlText, [body: 2, todo: 2, todos: 1], 1, [],
          'This is the body of to-do item #1', :text}
       ], [], '/workspace', :undeclared},
      {:xmlText, [todo: 2, todos: 1], 3, [], '\n    ', :text},
      {:xmlElement, :priority, :priority, [], {:xmlNamespace, [], []},
       [todo: 2, todos: 1], 4, [],
       [{:xmlText, [priority: 4, todo: 2, todos: 1], 1, [], '3', :text}], [],
       '/workspace', :undeclared},
      {:xmlText, [todo: 2, todos: 1], 5, [], '\n  ', :text}
    ], [], '/workspace', :undeclared},
   {:xmlText, [todos: 1], 3, [], '\n  ', :text},
   {:xmlElement, :todo, :todo, [], {:xmlNamespace, [], []}, [todos: 1], 4,
    [{:xmlAttribute, :id, [], [], [], [todo: 4, todos: 1], 1, [], '2', false}],
    [
      {:xmlText, [todo: 4, todos: 1], 1, [], '\n    ', :text},
      {:xmlElement, :body, :body, [], {:xmlNamespace, [], []},
       [todo: 4, todos: 1], 2, [],
       [
         {:xmlText, [body: 2, todo: 4, todos: 1], 1, [],
          'This is the body of to-do item #2', :text}
       ], [], '/workspace', :undeclared},
      {:xmlText, [todo: 4, todos: 1], 3, [], '\n    ', :text},
      {:xmlElement, :priority, :priority, [], {:xmlNamespace, [], []},
       [todo: 4, todos: 1], 4, [],
       [{:xmlText, [priority: 4, todo: 4, todos: 1], 1, [], '1', :text}], [],
       '/workspace', :undeclared},
      {:xmlText, [todo: 4, todos: 1], 5, [], '\n  ', :text}
    ], [], '/workspace', :undeclared},
   {:xmlText, [todos: 1], 5, [], '\n  ', :text},
   {:xmlElement, :todo, :todo, [], {:xmlNamespace, [], []}, [todos: 1], 6,
    [{:xmlAttribute, :id, [], [], [], [todo: 6, todos: 1], 1, [], '3', false}],
    [
      {:xmlText, [todo: 6, todos: 1], 1, [], '\n    ', :text},
      {:xmlElement, :body, :body, [], {:xmlNamespace, [], []},
       [todo: 6, todos: 1], 2, [],
       [
         {:xmlText, [body: 2, todo: 6, todos: 1], 1, [],
          'This is the body of to-do item #3', :text}
       ], [], '/workspace', :undeclared},
      {:xmlText, [todo: 6, todos: 1], 3, [], '\n    ', :text},
      {:xmlElement, :priority, :priority, [], {:xmlNamespace, [], []},
       [todo: 6, todos: 1], 4, [],
       [{:xmlText, [priority: 4, todo: 6, todos: 1], 1, [], '3', :text}], [],
       '/workspace', :undeclared},
      {:xmlText, [todo: 6, todos: 1], 5, [], '\n  ', :text}
    ], [], '/workspace', :undeclared},
   {:xmlText, [todos: 1], 7, [], '\n', :text}
 ], [], '/workspace', :undeclared}

XmlToMap を使ってみる

XMLを簡単にMapにしてくれるXmlToMapを使ってみます。

導入

mix.exselixir_xml_to_map を追加します。

1
2
3
4
5
  defp deps do
    [
      {:elixir_xml_to_map, "~> 2.0"} # Add elixir_xml_to_map
    ]
  end

mix deps.get を実行してインストールします。

実装

実際に使ってみます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
xml_str = """
<todos>
  <todo id="1">
    <body>This is the body of to-do item #1</body>
    <priority>3</priority>
  </todo>
  <todo id="2">
    <body>This is the body of to-do item #2</body>
    <priority>1</priority>
  </todo>
  <todo id="3">
    <body>This is the body of to-do item #3</body>
    <priority>3</priority>
  </todo>
</todos>
"""

xml_map = XmlToMap.naive_map(xml_str)
IO.inspect(xml_map)

Mapになってこれで扱いやすい形になりました。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
%{
  "todos" => %{
    "todo" => [
      %{
        "#content" => %{
          "body" => "This is the body of to-do item #1",
          "priority" => "3"
        },
        "-id" => "1"
      },
      %{
        "#content" => %{
          "body" => "This is the body of to-do item #2",
          "priority" => "1"
        },
        "-id" => "2"
      },
      %{
        "#content" => %{
          "body" => "This is the body of to-do item #3",
          "priority" => "3"
        },
        "-id" => "3"
      }
    ]
  }
}

参考

共有

こぴぺたん
著者
こぴぺたん
Copy & Paste Engineer