# `Dmn.Reader`
[🔗](https://github.com/FeeJai/BDM/blob/dmn-v0.1.0/apps/dmn/lib/dmn/reader.ex#L1)

Reads a DMN model from the element tree of `Dmn.XML` into `Dmn.Model` structs.

The reader knows the schema (DMN 1.6, clause 13, and the schemas of 1.1 to 1.5, which are the same elements in other
namespaces) and checks what a schema would: the document is a `definitions` in a namespace of DMN, the elements it needs are
there, an attribute that has a fixed set of values has one of them. It stops at the first element that breaks the schema
and returns an error that names it, with its `id` and its line (`Dmn.Error`, kind `:model`). What it does not do is anything
that needs more than one element: it follows no reference, resolves no name, and reads no FEEL.

It reads only what is in the namespace of the document's `definitions`. Elements of other vocabularies (the `extensionElements`,
the diagram interchange `DMNDI`) are not read, and an attribute of another namespace is not either.

## Type references

A `typeRef` is a string, and a string can have a prefix that the document declares: `feel:string`, `tns:tPerson`. The
reader resolves it where the prefixes are in scope, to the name that FEEL and the compiler use:

  * a name of the FEEL namespace is the built-in type, `feel:string` is `string`;
  * a name of the namespace of the document is the item definition, `tns:tPerson` is `tPerson`;
  * a name of the namespace of an import is `Import.tPerson` (just `tPerson` when the import has no name);
  * a name with no prefix, or with one that is not declared, is as it is written.

## Expression languages

`expression_language` of a literal expression or of unary tests is `nil` for the language of the model, which is FEEL unless
the `definitions` say otherwise. `Dmn.Compiler` decides what it can compile.

# `feel_language?`

```elixir
@spec feel_language?(String.t()) :: boolean()
```

Whether a URI names FEEL (or S-FEEL, which has the same one), as the `expressionLanguage` of the model or of an expression:
the URI of the FEEL of a version of DMN (`.../DMN/20240513/FEEL/`), or the one of DMN 1.1 (`.../FEEL/20140401`).

    iex> Dmn.Reader.feel_language?("https://www.omg.org/spec/DMN/20240513/FEEL/")
    true
    iex> Dmn.Reader.feel_language?("http://www.omg.org/spec/FEEL/20140401")
    true
    iex> Dmn.Reader.feel_language?("http://www.omg.org/spec/DMN/uninterpreted/20140801")
    false

# `read`

```elixir
@spec read(Dmn.XML.Element.t()) :: {:ok, Dmn.Model.t()} | {:error, Dmn.Error.t()}
```

Reads the root element of a document as a model.

    iex> {:ok, root} = Dmn.XML.parse(~s(<definitions xmlns="https://www.omg.org/spec/DMN/20240513/MODEL/" name="m" namespace="urn:m"/>))
    iex> {:ok, model} = Dmn.Reader.read(root)
    iex> {model.name, model.namespace, model.version}
    {"m", "urn:m", :dmn_1_6}

# `version`

```elixir
@spec version(String.t() | nil) :: Dmn.Model.version() | nil
```

The version of DMN that a namespace of the model belongs to, or `nil` for a namespace that is not one.

    iex> Dmn.Reader.version("https://www.omg.org/spec/DMN/20230324/MODEL/")
    :dmn_1_5
    iex> Dmn.Reader.version("http://www.omg.org/spec/DMN/20151101/dmn.xsd")
    :dmn_1_1
    iex> Dmn.Reader.version("urn:other")
    nil

---

*Consult [api-reference.md](api-reference.md) for complete listing*
