Rustam A. Gasanov

$ echo "Inspired developer's blog" > /dev/null

Parse XML With Elixir and Xmerl Example

| Comments

Here I want to share a little snippet which explains how to use Xmerl library to parse XML in Elixir project.

simple.xml
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
<?xml version="1.0" encoding="UTF-8"?>
<breakfast_menu>
        <food>
                <name>Belgian Waffles</name>
                <price>$5.95</price>
                <description>Two of our famous Belgian Waffles with plenty of real maple syrup</description>
                <calories>650</calories>
        </food>
        <food>
                <name>Strawberry Belgian Waffles</name>
                <price>$7.95</price>
                <description>Light Belgian waffles covered with strawberries and whipped cream</description>
                <calories>900</calories>
        </food>
        <food>
                <name>Berry-Berry Belgian Waffles</name>
                <price>$8.95</price>
                <description>Light Belgian waffles covered with an assortment of fresh berries and whipped cream</description>
                <calories>900</calories>
        </food>
        <food>
                <name>French Toast</name>
                <price>$4.50</price>
                <description>Thick slices made from our homemade sourdough bread</description>
                <calories>600</calories>
        </food>
        <food>
                <name>Homestyle Breakfast</name>
                <price>$6.95</price>
                <description>Two eggs, bacon or sausage, toast, and our ever-popular hash browns</description>
                <calories>950</calories>
        </food>
</breakfast_menu>
xml_parser.exs
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
defmodule XMLParser do
  require Record
  Record.defrecord :xmlElement, Record.extract(:xmlElement, from_lib: "xmerl/include/xmerl.hrl")
  Record.defrecord :xmlText,    Record.extract(:xmlText,    from_lib: "xmerl/include/xmerl.hrl")

  def parse(file) do
    File.read!(file)
      |> scan_text
      |> parse_xml
  end

  def scan_text(text) do
    :xmerl_scan.string(String.to_char_list(text))
  end

  def parse_xml({ xml, _ }) do
    # single element
    [element]  = :xmerl_xpath.string('/breakfast_menu/food[1]/description', xml)
    [text]     = xmlElement(element, :content)
    value      = xmlText(text, :value)
    IO.inspect to_string(value)
    # => "Two of our famous Belgian Waffles with plenty of real maple syrup"

    # multiple elements
    elements   = :xmerl_xpath.string('/breakfast_menu//food/name', xml)
    Enum.each(
      elements,
      fn(element) ->
        [text]     = xmlElement(element, :content)
        value      = xmlText(text, :value)
        IO.inspect to_string(value)
      end
    )
    # => "Belgian Waffles"
    # => "Strawberry Belgian Waffles"
    # => "Berry-Berry Belgian Waffles"
    # => "French Toast"
    # => "Homestyle Breakfast"
  end
end

Record is required to interface with Erlang records.
Two kinds of records are used: xmlElement and xmlText.
:xmerl_scan.string - Parses string containing an XML document.
:xmerl_xpath.string - Extracts the nodes from the parsed XML tree according to XPath.

Comments