# `RDF.Canonicalization`
[🔗](https://github.com/rdf-elixir/rdf-ex/blob/v3.0.1/lib/rdf/canonicalization/canonicalization.ex#L1)

An implementation of the standard RDF Dataset Canonicalization Algorithm.

See <https://www.w3.org/TR/rdf-canon/>.

## Options

All functions in this module support the following options:

- `:hash_algorithm`: Allows to set the hash algorithm to be used. Any of the `:crypto.hash_algorithm()`
  values of Erlang's `:crypto` module are allowed.
  Defaults to the runtime configured `:canon_hash_algorithm` of the `:rdf` application
  or `:sha256` if not configured otherwise.

      config :rdf,
        canon_hash_algorithm: :sha512

- `:hndq_call_limit`: This algorithm has to go through complex cycles that may in extreme situations
  result in an unreasonably long canonicalization process. Although this never occurs in practice,
  attackers may use some "poison graphs" to create such situations
  (see the [security consideration section](https://www.w3.org/TR/rdf-canon/#security-considerations) in the specification).
  This implementation sets a maximum call limit for the Hash N-Degree Quads algorithm
  which can be configured with this value. Note, that actual limit is the product
  of the multiplication of the given value with the number of blank nodes in the input graph.
  Defaults to the runtime configured `:hndq_call_limit` of the `:rdf` application
  or `50` if not configured otherwise.

      config :rdf,
        hndq_call_limit: 10

# `canonicalize`

```elixir
@spec canonicalize(
  RDF.Graph.t() | RDF.Dataset.t(),
  keyword()
) :: {RDF.Dataset.t(), RDF.Canonicalization.State.t()}
```

Canonicalizes the blank nodes of a graph or dataset according to the RDF Dataset Canonicalization spec.

This function always returns an `RDF.Dataset` and wraps it in a tuple with the
resulting internal state from which the blank node mapping can be retrieved.
If you want to get just a `RDF.Dataset` back, use `RDF.Dataset.canonicalize/2`.
If you want to canonicalize just a `RDF.Graph` and get a `RDF.Graph` back,
use `RDF.Graph.canonicalize/2`.

See module documentation on the available options.

# `isomorphic?`

```elixir
@spec isomorphic?(
  RDF.Graph.t() | RDF.Dataset.t(),
  RDF.Graph.t() | RDF.Dataset.t(),
  keyword()
) ::
  boolean()
```

Checks whether two graphs or datasets are equal, regardless of the concrete names of the blank nodes they contain.

See module documentation on the available options.

## Examples

    iex> RDF.Graph.new([{~B<foo>, EX.p(), ~B<bar>}, {~B<bar>, EX.p(), 42}])
    ...> |> RDF.Canonicalization.isomorphic?(
    ...>      RDF.Graph.new([{~B<b1>, EX.p(), ~B<b2>}, {~B<b2>, EX.p(), 42}]))
    true

    iex> RDF.Graph.new([{~B<foo>, EX.p(), ~B<bar>}, {~B<bar>, EX.p(), 42}])
    ...> |> RDF.Canonicalization.isomorphic?(
    ...>      RDF.Graph.new([{~B<b1>, EX.p(), ~B<b2>}, {~B<b3>, EX.p(), 42}]))
    false

---

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