158 lines
4.9 KiB
Elixir
158 lines
4.9 KiB
Elixir
defmodule RDF.Literal do
|
|
@moduledoc """
|
|
RDF literals are leaf nodes of a RDF graph containing raw data, like strings and numbers.
|
|
"""
|
|
defstruct [:value, :datatype, :language]
|
|
|
|
@type t :: module
|
|
|
|
# Since the capability of RDF.Vocabulary.Namespaces requires the compilation
|
|
# of the RDF.NTriples.Reader and the RDF.NTriples.Reader depends on RDF.Literals,
|
|
# we can't define the XSD namespace in RDF.NS.
|
|
defmodule NS do
|
|
@moduledoc false
|
|
@vocabdoc false
|
|
use RDF.Vocabulary.Namespace
|
|
defvocab XSD,
|
|
base_uri: "http://www.w3.org/2001/XMLSchema#",
|
|
terms: ~w[
|
|
string
|
|
normalizedString
|
|
token
|
|
language
|
|
Name
|
|
NCName
|
|
ID
|
|
IDREF
|
|
IDREFS
|
|
ENTITY
|
|
ENTITIES
|
|
NMTOKEN
|
|
NMTOKENS
|
|
boolean
|
|
float
|
|
double
|
|
decimal
|
|
integer
|
|
long
|
|
int
|
|
short
|
|
byte
|
|
nonPositiveInteger
|
|
negativeInteger
|
|
nonNegativeInteger
|
|
positiveInteger
|
|
unsignedLong
|
|
unsignedInt
|
|
unsignedShort
|
|
unsignedByte
|
|
duration
|
|
dateTime
|
|
time
|
|
date
|
|
gYearMonth
|
|
gYear
|
|
gMonthDay
|
|
gDay
|
|
gMonth
|
|
base64Binary
|
|
hexBinary
|
|
anyURI
|
|
QName
|
|
NOTATION
|
|
]
|
|
end
|
|
alias NS.XSD
|
|
|
|
|
|
@doc """
|
|
Creates a new `RDF.Literal` of the given value and tries to infer an appropriate XSD datatype.
|
|
|
|
Note: The `RDF.literal` function is a shortcut to this function.
|
|
|
|
The following mapping of Elixir types to XSD datatypes is applied:
|
|
|
|
| Elixir type | XSD datatype |
|
|
| :---------- | :----------- |
|
|
| string | |
|
|
| boolean | `boolean` |
|
|
| integer | `integer` |
|
|
| float | `float` |
|
|
| atom | |
|
|
| ... | |
|
|
|
|
|
|
# Examples
|
|
|
|
iex> RDF.Literal.new(42)
|
|
%RDF.Literal{value: 42, language: nil, datatype: RDF.uri(XSD.integer)}
|
|
|
|
"""
|
|
def new(value)
|
|
|
|
def new(value) when is_binary(value),
|
|
do: %RDF.Literal{value: value, datatype: XSD.string}
|
|
def new(value) when is_boolean(value),
|
|
do: %RDF.Literal{value: value, datatype: XSD.boolean}
|
|
def new(value) when is_integer(value),
|
|
do: %RDF.Literal{value: value, datatype: XSD.integer}
|
|
def new(value) when is_float(value),
|
|
do: %RDF.Literal{value: value, datatype: XSD.float}
|
|
|
|
# def new(value) when is_atom(value), do:
|
|
# def new(value) when is_bitstring(value), do:
|
|
|
|
# def new(value) when is_list(value), do:
|
|
# def new(value) when is_tuple(value), do:
|
|
# def new(value) when is_map(value), do:
|
|
|
|
# def new(value) when is_function(value), do:
|
|
# def new(value) when is_pid(value), do:
|
|
# def new(value) when is_port(value), do:
|
|
# def new(value) when is_reference(value), do:
|
|
|
|
def new(value) do
|
|
raise RDF.InvalidLiteralError, "#{inspect value} not convertible to a RDF.Literal"
|
|
end
|
|
|
|
def new(value, opts) when is_list(opts),
|
|
do: new(value, Map.new(opts))
|
|
|
|
def new(value, %{language: language}) when not is_nil(language) and is_binary(value) do
|
|
%RDF.Literal{value: value, datatype: RDF.langString, language: language}
|
|
end
|
|
|
|
def new(value, %{datatype: %URI{} = datatype}) when is_binary(value) do
|
|
cond do
|
|
datatype == XSD.string -> %RDF.Literal{value: value, datatype: datatype}
|
|
datatype == XSD.integer -> %RDF.Literal{value: String.to_integer(value), datatype: datatype}
|
|
# TODO: datatype == XSD.byte -> nil # %RDF.Literal{value: String.to_integer(value), datatype: datatype}
|
|
# TODO: datatype == RDF.uri(RDFS.XMLLiteral) -> nil # %RDF.Literal{value: String.to_integer(value), datatype: datatype}
|
|
# TODO: Should we support more values, like "1" etc.?
|
|
# TODO: Should we exclude any non-useful value?
|
|
datatype == XSD.boolean -> %RDF.Literal{value: String.downcase(value) == "true", datatype: datatype}
|
|
true -> %RDF.Literal{value: value, datatype: datatype}
|
|
end
|
|
end
|
|
|
|
def new(value, %{datatype: %URI{} = datatype}) when is_integer(value) do
|
|
cond do
|
|
datatype == XSD.string -> %RDF.Literal{value: to_string(value), datatype: datatype}
|
|
datatype == XSD.integer -> %RDF.Literal{value: value, datatype: datatype}
|
|
end
|
|
end
|
|
|
|
def new(value, %{datatype: %URI{} = datatype}) when is_boolean(value) do
|
|
cond do
|
|
datatype == XSD.boolean -> %RDF.Literal{value: value, datatype: datatype}
|
|
# TODO: Should we exclude any non-useful value?
|
|
datatype == XSD.string -> %RDF.Literal{value: to_string(value), datatype: datatype}
|
|
datatype == XSD.integer -> %RDF.Literal{value: (if value, do: 1, else: 0), datatype: datatype}
|
|
end
|
|
end
|
|
|
|
def new(value, %{datatype: datatype}) do
|
|
new(value, datatype: RDF.uri(datatype))
|
|
end
|
|
|
|
end
|