View Source XmlSchema (XmlSchema v1.3.0)

Adds XML parsing and generation to modules via use XmlSchema.

Define Xml structures with:

Options to use: tag: <string> string to use as xml tag name for this element. This allows a tag name not derived from the module name.

print: <boolean> will print the macro generated code, e.g:

`print: Mix.env() in [:test, :dev]`

Generated functions

An XmlSchema will provide the generated functions:

  • parse_xml/1 - accepts an xml string to parse
  • xml_tag/0 - returns the tag used when generating xml from this node
  • xml_tag_list - order list of tags in this schema
  • transform/1 - overridable function that can be used to transform tag names during parsing

Example

defmodule Simple do
  use XmlSchema, xml_name: "a"
  xml do
    xml_tag :x, :string
    xml_tag :y, :boolean
    xml_one :z, Z do
      xml_tag :a, :string
      xml_tag :b, :string
    end
    xml_many :j, J do
      xml_tag :q, :string
    end
    xml_tag :g, {:array, :string}
  end
end

Will parse

<?xml encoding="utf-8" ?>
<a someattr="blue" otherattr="red">
  <x>hill</x>
  <y>false</y>
  <z>
    <a>tree</a>
    <b>bush</b>
  </z>
  <j>
    <q>cat</q>
  </j>
  <j>
    <q>dog</q>
  </j>
  <g>hippo</g>
  <g>elephant</g>
  <g>rhino</g>
</a>

Into:

%Simple{
  _attributes: %{"otherattr" => "red", "someattr" => "blue"},
  x: "hill",
  y: false,
  z: %Simple.Z{_attributes: nil, a: "tree", b: "bush"},
  j: [
    %Simple.J{_attributes: nil, q: "cat"},
    %Simple.J{_attributes: nil, q: "dog"}
  ],
  g: ["hippo", "elephant", "rhino"]
}

Attributes

Parsed attibutes are stored in a map, this precludes multiple same named attribute in a single tag. It also does not preserve attribute ordering.

Terminal nodes defined with xml_tag provide bare values. If you wish to capture attributes the type argument takes the form of {:param, type} which will result in not bare values but a tuple of {value, %{attribute map}}.

An example:

defmodule Example.Attribute do
  use XmlSchema, tag: "a"

  xml do
    xml_tag :k, :string
    xml_tag :j, {:param, :string}
    xml_tag :manyj, {:array, {:param, :string}}
  end

  def doc do
    """
      <a first="lemon" second="lime">
        <k third="peach">one</k>
        <j fourth="orange">tree</j>
        <manyj five="cherry">shrub</manyj>
        <manyj six="berry">flower</manyj>
      </a>
    """
  end

  def expect do
    %Example.Attribute{
      _attributes: %{"first" => "lemon", "second" => "lime"},
      k: "one",
      j: {"tree", %{"fourth" => "orange"}},
      manyj: [
        {"shrub", %{"five" => "cherry"}},
        {"flower", %{"six" => "berry"}}
      ]
    }
  end

  def expect_xml do
    """
    <?xml version="1.0" encoding="UTF-8"?>
    <a first="lemon" second="lime">
      <k>one</k>
      <j fourth="orange">tree</j>
      <manyj five="cherry">shrub</manyj>
      <manyj six="berry">flower</manyj>
    </a>
    """
    |> String.trim_trailing()
  end
end

For more examples, see test/support.

Summary

Functions

Generate xml document from xml schema

Generate xml document from xml schema with name top tag

Parse an xml string based on the structure of module, which must be an XmlSchema. This function is added to any module that uses XmlSchema and is simplest to call the function there instead of this one.

Start definition of xml document structure.

Similar to xml_one/3 except the tag can occur 0 or more times. Values will be presented in a list. Unlike xml_one if the tag is not present an empty list will result.

Declare a tag that occurs once with XML tag name as either a block or a declared module. Modules generated by blocks automatically use XmlSchema. nil value is used if a tag is not present.

Declare an XML tag with a scalar value with type conversion. Any type accepted by Ecto.Schema can be used. Custom types can be defined in the same manner. An xml_tag is terminal, for tags containing substructure use xml_one or xml_many. See attributes section above for details on how to capture tag attributes.

Functions

Generate xml document from xml schema

Link to this function

generate_xml(schema, name)

View Source

Generate xml document from xml schema with name top tag

Link to this function

parse_xml(xml_string, module)

View Source

Parse an xml string based on the structure of module, which must be an XmlSchema. This function is added to any module that uses XmlSchema and is simplest to call the function there instead of this one.

Start definition of xml document structure.

Link to this macro

xml_many(name, schema, opts \\ [])

View Source (macro)

Similar to xml_one/3 except the tag can occur 0 or more times. Values will be presented in a list. Unlike xml_one if the tag is not present an empty list will result.

In this example (from test/support/example/many.ex), doc is an xml sample that will result in the expect struct.

defmodule Example.Many do
  use XmlSchema, tag: "a"

  xml do
    xml_many :j, Example.Tag
    xml_many :s, Example.Tag
  end

  def doc do
    """
      <a>
        <j>
          <k>one</k>
        </j>
        <j>
          <k>two</k>
        </j>
      </a>
    """
  end

  def expect do
    %Example.Many{
      _attributes: nil,
      j: [
        %Example.Tag{_attributes: nil, k: "one"},
        %Example.Tag{_attributes: nil, k: "two"}
      ],
      s: []
    }
  end
  def expect_xml do
    """
    <?xml version="1.0" encoding="UTF-8"?>
    <a>
      <j>
        <k>one</k>
      </j>
      <j>
        <k>two</k>
      </j>
    </a>
    """
    |> String.trim_trailing()
  end
end
Link to this macro

xml_one(name, schema, opts \\ [])

View Source (macro)

Declare a tag that occurs once with XML tag name as either a block or a declared module. Modules generated by blocks automatically use XmlSchema. nil value is used if a tag is not present.

Block form example:

defmodule Example.OneBlock do
  use XmlSchema, tag: "a"

  xml do
    xml_one :j, Tag do
      xml_tag :k, :string
    end
  end

  def doc do
    """
    <a>
      <j>
        <k>one</k>
      </j>
    </a>
    """
  end

  def expect do
    %Example.OneBlock{
      _attributes: nil,
      j: %Example.OneBlock.Tag{_attributes: nil, k: "one"}
    }
  end

  def expect_xml do
    """
    <?xml version="1.0" encoding="UTF-8"?>
    <a>
      <j>
        <k>one</k>
      </j>
    </a>
    """
    |> String.trim_trailing()
  end
end

In this example (from test/support/example/one.ex) doc is an xml sample that will result in the expect struct.

Defined module form:

defmodule Example.One do
  use XmlSchema, tag: "a"

  xml do
    xml_one :j, Example.Tag
    xml_one :s, Example.Tag
  end

  def doc do
    """
    <a>
      <j>
        <k>one</k>
      </j>
    </a>
    """
  end

  def expect do
    %Example.One{
      _attributes: nil,
      j: %Example.Tag{_attributes: nil, k: "one"},
      s: nil
    }
  end

  def expect_xml do
    """
    <?xml version="1.0" encoding="UTF-8"?>
    <a>
      <j>
        <k>one</k>
      </j>
    </a>
    """
    |> String.trim_trailing()
  end
end

Depends on the definition of module Example.Tag.

Link to this macro

xml_tag(name, type, opts \\ [])

View Source (macro)

Declare an XML tag with a scalar value with type conversion. Any type accepted by Ecto.Schema can be used. Custom types can be defined in the same manner. An xml_tag is terminal, for tags containing substructure use xml_one or xml_many. See attributes section above for details on how to capture tag attributes.

defmodule Example.Tag do
  use XmlSchema, tag: "a"

  xml do
    xml_tag :k, :string
  end

  def doc do
    """
      <a>
        <k>one</k>
      </a>
    """
  end

  def expect do
    %Example.Tag{_attributes: nil, k: "one"}
  end

  def expect_xml do
    """
    <?xml version="1.0" encoding="UTF-8"?>
    <a>
      <k>one</k>
    </a>
    """
    |> String.trim_trailing()
  end

end