Changelog
View SourceAll notable changes to this project will be documented in this file. This project adheres to Semantic Versioning and Keep a CHANGELOG.
2.1.0 - 2025-04-09
Elixir versions < 1.14 and OTP version < 24 are no longer supported.
Also, compatibility with decimal < v2.0 is dropped.
Added
RDF.JSONdatatypeRDF.IRI.merge!/2which validates that the base and the result of the merge is a valid IRI or fails otherwiseRDF.Test.Assertions.assert_rdf_isomorphic/2ExUnit test helper
Changed
RDF.IRI.valid?/1now performs a proper RFC 3987 conformance validation. Note: This makes various places where the previous very sloppy implementation was used stricter, e.g. the Turtle decoder or~Isigil.- The
RDF.EarlFormattermodule was renamed toRDF.Test.EarlFormatter. - The
RDF.Test.EarlFormatterno longer marks excluded tests asearl:untested, but simply ignores them.
Fixed
- Fixed compilation error when defining
RDF.Vocabulary.Namespaces for large vocabularies (like Schema.org) caused by exceeding implementation limits. - The case violation check during
RDF.Vocabulary.Namespacecreation didn't always recognize properties correctly. - Namespace delegator modules defined with
RDF.Namespace.act_as_namespace/1were not properly recompiled on changes of the underlying vocabulary file.
2.0.1 - 2024-10-07
Fixed
- The Turtle/TriG encoder didn't escape strings properly when using the long literal form, i.e. when the encoded string contains newlines, which could result in invalid output in edge-cases.
2.0.0 - 2024-08-07
Elixir versions < 1.13 and OTP version < 23 are no longer supported
An update to the recent more extensive Turtle test suite revealed that a bug in
Elixir's URI.merge/2 function affects the relative URI handling in the Turtle decoder.
It is therefore strongly recommended to use the Turtle decoder with
Elixir v1.15 or later, where this issue has been resolved.
Added
RDF.TriGwith an implementation of the TriG serialization language.- Several new options on the Turtle/TriG encoders for more customizations and
performance optimizations:
- Capability to add custom content on the Turtle/TriG encoders with the
:contentoption. :line_prefixfor a function defining custom line prefixes:indent_widthto customize the indentation width:pn_local_validationfor controlling IRI validation when encoding prefixed names:rdf_starallowing to skip an RDF-star related preprocessing step
- Capability to add custom content on the Turtle/TriG encoders with the
RDF.Dataset.named_graphs/1to get a list of all named graphs of a dataset.RDF.Dataset.graph_names/1to get a list of all graph names of a dataset.RDF.Dataset.update_all_graphs/2to apply a function on all graphs of a dataset.RDF.Graph.update_all_descriptions/2to apply a function on all descriptions of a graph.RDF.Description.update_all_predicates/2andRDF.Description.update_all_objects/2to apply a function on all predications resp. objects of a description.RDF.Graph.rename_resource/2andRDF.Description.rename_resource/2to replace all occurrences of an id.RDF.turtle_prefixes/1andRDF.sparql_prefixes/1for creating respective prefix headersRDF.Graph.prefixes/2which allows to specify a custom return value when the prefixes are empty.RDF.PrefixMap.empty?/1to check of aRDF.PrefixMapis empty.RDF.PrefixMap.limit/2to limit aRDF.PrefixMapto a subset of some given prefixes.RDF.BlankNode.Generator.UUIDandRDF.BlankNode.Generator.Randomimplementations ofRDF.BlankNode.Generator.Algorithm:bnode_genoption on the Turtle/TriG decoders, allowing customization of blank node generation and aturtle_trig_decoder_bnode_genapplication config for setting the default blank node generator globally.- Performance improvements of N-Triples and N-Quads encoders.
Changed
- Default blank node generation in Turtle decoder now generates UUID blank node
identifiers instead of the previous deterministic incremented identifiers.
This change ensures unique blank nodes across multiple parsing operations.
You can opt back to the previous behaviour with the new
turtle_trig_decoder_bnode_genapplication config using the:incrementvalue. - Aliases defined within
RDF.Graph.buildblocks are no longer supported due to changes
in Elixir 1.17. Aliases from the caller context are still available and automatically
re-aliased in the build block. However, instead of using aliases for vocabulary namespaces, use@prefixdeclarations inside the build block, as it provides additional benefits. Please refer to the user guide for more information. - The
prefixesof anRDF.Graphare now always aRDF.PrefixMapand no longernilinitially, since this had the confusing consequence that anRDF.Graphwhere all prefixes were deleted was not equal to same graph where the deleted were never set, e.g.RDF.graph() |> Graph.add_prefixes(ex: EX) |> Graph.delete_prefixes(:ex) == RDF.graph()did not hold previously. This behaviour was used before to differentiate graphs which should use theRDF.default_prefixes/0(in caseprefixeswasnil) from those which should not use any prefixes (emptyPrefixMap) when serialized to Turtle. You'll now have to add theprefixes: []on Turtle serialization explicitly. The old behaviour of gettingnilon empty prefixes can be achieved with the newRDF.Graph.prefixes/2function. - Update to change in N-Triples and N-Quads specs disallowing colons in bnode labels.
- Rename
:onlyoption ofRDF.Turtle.Encoderto:contentto reflect the enhanced capabilities. - The
RDF.BlankNode.GeneratorandRDF.BlankNode.Generator.Algorithmbehaviour used internally at various places was redesigned. - Deprecated
RDF.Diff.merge/2was removed. UseRDF.Diff.union/2instead. - Replacement of
elixir_uuidwithuniqdependency for UUID generation and make it no longer optional
Fixed
- The
RDF.Turtle.Encoderwas not falling back to usingRDF.default_prefixes/0when the encoded graph had prefixes which were removed afterwards. - Fixed the
RDF.Turtle.Encodervalidation to ensure IRIs with permissible characters, such as hyphens, can be correctly encoded as prefixed names. Previously, the validation was overly strict, preventing some valid IRIs from being encoded as prefixed names. RDF.NTriples.EncoderandRDF.NQuads.Encodercould not stream quoted RDF-star triples could as iodata.
1.2.0 - 2024-03-18
Elixir versions < 1.12 are no longer supported
Added
RDF.Namespace.act_as_namespace/1macro which can be used to let a module act as a specifiedRDF.NamespaceorRDF.Vocabulary.Namespace.canonical_hash/2function onRDF.Dataset,RDF.GraphandRDF.Descriptionwhich computes a hash value for the data based on theRDF.Canonicalizationalgorithmintersection/2function onRDF.Dataset,RDF.GraphandRDF.Descriptionwhich create respective graph data intersections. Since this feature relies onMap.intersect/3that was added in Elixir v1.15, it is only available with a respective Elixir version.RDF.Dataset.put_graph/3adds new graphs overwriting any existing graphsRDF.Dataset.update/4to update graphs in aRDF.DatasetRDF.Graph.delete_predications/3to delete all statements in aRDF.Graphwith the given subjects and predicatesRDF.PrefixMap.to_header/3,RDF.PrefixMap.to_turtle/1andRDF.PrefixMap.to_sparql/1to get header string representations of aRDF.PrefixMapin the respective styleRDF.PrefixMap.to_sorted_list/1which returns the prefix map as keyword list sorted by prefix (this should become useful with OTP 26)RDF.PropertyMap.to_sorted_list/1which returns the property map as keyword list sorted by property- The Turtle encoder now sorts the prefixes (based on
RDF.PrefixMap.to_sorted_list/1), which has become necessary, since OTP 26 maps are now unordered even in smaller cases (previously only larger maps were unordered). - The N-Triples and N-Quads encoders now support a flag option
:sortwhich, when
activated, encodes the statements sorted in Unicode code point order. - The hash algorithm to be used for RDF canonicalization can be configured either
with the
:hash_algorithmkeyword option or the:canon_hash_algorithmapplication runtime configuration. - Add Hash N-Degree Quads algorithm call limit to canonicalization as a countermeasure against poison dataset attacks
- Compile-time application configuration
:optimize_regexesthat allows to switch internal usage to the faster Erlang:re.run/2function for regex pattern matching (@jkrueger) - Some optimizations on
RDF.IRI(@jkrueger) RDF.EarlFormatteras anExUnit.Formatterimplementation that generates EARL reports
Changed
RDF.Canonicalization.canonicalize/2now returns the canonicalized dataset in a tuple along with final state containing the input blank node identifier map and the issued identifiers map as required by the RDF dataset canonicalization specificationRDF.Diff.merge/2was deprecated and will be replaced in future versions with a different merge algorithm. UseRDF.Diff.union/2now for the current algorithm.- Statements as lists (instead of tuples) in the
Collectableimplementations ofRDF.Description,RDF.GraphandRDF.Datasetwere deprecated. Support of those will be removed in RDF.ex v2.0. - The following deprecated types were removed:
RDF.Statement.coercible_t(new type:RDF.Statement.coercible)RDF.Star.Statement.coercible_t(new type:RDF.Star.Statement.coercible)RDF.Triple.t_values(new type:RDF.Triple.mapping_value)RDF.Quad.t_values(new type:RDF.Quad.mapping_value)
Fixed
RDF.Dataset.put/3with aRDF.Datasetinput didn't respect the:graphoption to aggregate everything into single target graph
1.1.1 - 2023-03-31
Added
- a custom option
:content_onlyon theInspectimplementation ofRDF.Graphwhich returns only the (possibly abbreviated) Turtle representation of the graph; this can be used in otherInspectimplementations that want to include thisRDF.Graphrepresentation RDF.prefixes/1as another alias for the creation of aRDF.PrefixMap
Fixed
RDF.Graph.new/2didn't respect the:initopt when the first argument was aRDF.Graph
1.1.0 - 2022-12-19
Added
- implementation of the Standard RDF Dataset Canonicalization Algorithm
which can be used with
RDF.Graph.canonicalize/1andRDF.Dataset.canonicalize/1functions RDF.Graph.isomorphic?/2andRDF.Dataset.isomorphic?/2to compare if two graphs or datasets are the same, regardless of the concrete names of the blank nodes they containRDF.Statement.bnodes/1,RDF.Triple.bnodes/1,RDF.Quad.bnodes/1to get a list of all blank nodes within a statementRDF.Statement.include_value?/2,RDF.Triple.include_value?/2,RDF.Quad.include_value?/2to check whether a given value is a component of a statement- performance improvements of the
RDF.Turtle.Encoder
Changed
RDF.XSD.DoubleandRDF.XSD.Floatliterals created from Elixir floats and integers are now interpreted to be in the canonical lexical formRDF.BlankNode.new/1ignores the prefix"_:"in a given blank node name
Fixed
- the N-Triples, N-Quads and Turtle encoder were creating too many backslashes,
when escaping a backslash in a string;
BEWARE: You'll have to fix the generated Turtle files you've produced with earlier versions! - the N-Triples, N-Quads and Turtle encoder didn't apply proper escaping in typed literals of unknown type in general
- the Turtle encoder didn't encode the descriptions of blank nodes which occurred in
a blank node cycle, e.g. in
_:b1 :p1 _:b2 . _:b2 :p2 _:b1 .neither the description of_:b1nor of_:b2were rendered - the Turtle encoder now preserves the lexical form of a literal instead of always
encoding the canonical form - a regression in
defvocabprevented its use with fully qualified vocabulary namespace module names (i.e. which include a dot) - the
term_to_iri/1macro didn't work properly in all types of pattern matches - the
Inspectprotocol implementation for decimal literals wasn't using the lexical in case of an uncanonical lexical form of a decimal literal
1.0.0 - 2022-11-03
In this version RDF.Namespace and RDF.Vocabulary.Namespace were completely rewritten.
The generated namespaces are much more flexible now and compile faster.
For more details on how to migrate from an earlier version read this wiki page.
Elixir versions < 1.11 are no longer supported
Added
RDF.Vocabulary.Namespace.create/5for dynamic creation ofRDF.Vocabulary.NamespacesRDF.Namespacebuildersdefnamespace/3andcreate/4inside of pattern matchesRDF.Vocabulary.Namespacemodules now have a__file__/0function which returns the path to the vocabulary file they were generated fromRDF.Vocabulary.path/1returning the path to the vocabulary directory of an application andRDF.Vocabulary.path/2returning the path to the files within it- The property functions on the
RDF.NamespaceandRDF.Vocabulary.Namespacemodules now also have a single argument variant, which allows to query the objects for the respective property from aRDF.Description - Aliases on a
RDF.Vocabulary.Namespacecan now be specified directly in the:termslist. - The
:termsoption can now also be used in conjunction with the:fileand:dataoptions to restrict the terms loaded from the vocabulary data with a list of the terms or a restriction function. - The
case_violationsoption ofdefvocabnow supports an:auto_fixoption which adapts the first letter of violating term accordingly. It also supports custom handler functions, either as an inline function or as a function on a separate module. - New option
allow_lowercase_resource_termsoption which can be set totrueto no longer complain about lowercased terms for non-property resources. RDF.Graph.build/2now supports the creation of ad-hoc vocabulary namespaces with a@prefixdeclaration providing the URI of the namespace as a stringRDF.Namespace.IRI.term_to_iri/1macro which allows to resolveRDF.Namespaceterms- a lot of new
RDF.Guards:is_rdf_iri/1,is_rdf_bnode/1,is_rdf_literal/1,is_rdf_literal/2,is_plain_rdf_literal/1,is_typed_rdf_literal/1,is_rdf_resource/1,is_rdf_term/1,is_rdf_triple/1,is_rdf_quad/1andis_rdf_statement/1 - an implementation of
__using__on the top-levelRDFmodule, which allows to add basic imports and aliases with a simpleuse RDF RDF.IRI.starts_with?/2andRDF.IRI.ends_with?/2RDF.Graph.quads/2andRDF.Dataset.quads/2to get all statements of aRDF.GraphandRDF.Datasetas quadsRDF.Dataset.triples/2to get all statements of aRDF.Datasetas triplesRDF.PrefixMap.to_list/1RDF.PropertyMap.to_list/1- support for Elixir 1.14
- support for Decimal v2
Changed
Breaking
- Support for passing multiple objects as separate arguments to the property functions of the description DSL on the vocabulary namespaces was removed to create space for further arguments for other purposes in the future. Multiple objects must be given now in a list instead.
- All errors found during the compilation of
RDF.Vocabulary.Namespaceare now collectively reported under a singleRDF.Vocabulary.Namespace.CompileError. - An
ignoreterm in adefvocabdefinition which actually is not a term of the vocabulary namespace is now considered an error. - When defining an alias for a term of vocabulary which would be invalid as an
Elixir term, the original term is now implicitly ignored and won't any longer
be returned by the
__terms__/0function of aRDF.Vocabulary.Namespace. RDF.Graph.build/2blocks are now wrapped in a function, so the aliases and import no longer affect the caller context.aliases in the caller context are still available in the build block, butimports not and must be reimported in the build block. Variables in the caller context are also no longer available in abuildblock but must be passed explicitly as bindings in a keyword list on the new optional first argument ofRDF.Graph.build/3.RDF.BlankNode.Incrementwas renamed toRDF.BlankNode.Generator.IncrementRDF.XSD.Datatype.Mismatchexception was renamed toRDF.XSD.Datatype.MismatchErrorfor consistency reasons
Non-breaking
- The
defvocabmacro can now be safely used in any module and guarantees cleanliness of the base module. So, a surrounding namespace (likeNS) is no longer necessary. Although still useful for foreign vocabularies, this can be useful eg. to define aMyApplication.Vocabmodule directly under the root module of the application. - The
:base_irispecified indefvocabcan now be given in any form supported byRDF.IRI.new/1. There are also no longer restrictions on the expression of this value. While previously the value had to be provided as a literal value, now any expression returning a value accepted byRDF.IRI.new/1can be given (e.g. function calls, module attributes etc.). The:base_irialso no longer has to end with a/or#. RDF.Data.merge/2andRDF.Data.equal?/2are now commutative, i.e. structs which implement theRDF.Dataprotocol can be given also as the second argument (previously custom structs withRDF.Dataprotocol implementations always had to be given as the first argument).- the
Inspectimplementation for theRDF.Literal,RDF.PrefixMapandRDF.PropertyMapstructs now return a string with a valid Elixir expression that recreates the struct when evaluated - several performance improvements
Fixed
- The RDF vocabulary namespaces used in
@prefixand@basedeclarations in aRDF.Graph.buildblock no longer have to be written out, which had to be done previously even when parts of the module were available as an alias. - No warning on lowercased non-property resources in vocabularies
0.12.0 - 2022-04-11
This version introduces a new graph builder DSL. See the new guide for an introduction.
Added
- a
RDF.Graphbuilder DSL available under theRDF.Graph.build/2function - new
RDF.Sigils~i,~band~las variants of the~I,~Band~Lsigils, which support string interpolation RDF.Graph.new/2andRDF.Graph.add/2support the addition ofRDF.DatasetsRDF.Description.empty?/1,RDF.Graph.empty?/1,RDF.Dataset.empty?/1andRDF.Data.empty?/1which are significantly faster thanEnum.empty?/1- By replacing all
Enum.empty?/1uses over the RDF data structures with these newempty?/1functions throughout the code base, several functions benefit from this performance improvement.
- By replacing all
RDF.Description.first/2now has aRDF.Description.first/3variant which supports a default value- new guards in
RDF.Guards:is_statement/1andis_quad/1 RDF.PropertyMap.terms/1andRDF.PropertyMap.iris/1
Changed
RDF.Graph.description/2is no longer an alias forRDF.Graph.get/2, but has a different behaviour now: it will return an empty description when no description for the requested subject exists in the graph- The inspect string of
RDF.Descriptionnow includes the subject separately, so it can be seen also when the description is empty.
Fixed
- When triples with an empty object list where added to an
RDF.Graph, it included empty descriptions, which lead to inconsistent behaviour (for example it would be counted inRDF.Graph.subject_count/1). - When an
RDF.Graphcontained empty descriptions these were rendered by theRDF.Turtle.Encoderto a subject without predicates and objects, i.e. invalid Turtle. This actually shouldn't happen and is either caused by misuse or a bug. So instead, aRDF.Graph.EmptyDescriptionErrorwith a detailed message will be raised now when this case is detected.
0.11.0 - 2022-03-22
The main feature of this version are the RDF.Resource.Generators.
For an introduction see this guide.
Added
RDF.Resource.Generators which can be used to generate configurable ids:implicit_baseoption on theRDF.Turtle.Encoder:base_descriptionoption on theRDF.Turtle.Encoder- several new types:
RDF.Resource.tfor all node identifiers, i.e.RDF.IRIs andRDF.BlankNodesRDF.Triple.coercible,RDF.Quad.coercible,RDF.Star.Triple.coercibleandRDF.Star.Quad.coerciblefor tuples which can be coerced to the respective statements
Changed
- some types were renamed for consistency reasons; the old types were deprecated
and will be removed
RDF.Statement.coercible_t->RDF.Statement.coercibleRDF.Star.Statement.coercible_t->RDF.Star.Statement.coercibleRDF.Triple.t_values->RDF.Triple.mapping_valueRDF.Quad.t_values->RDF.Quad.mapping_value
Fixed
- the interface of
RDF.BlankNode.Generator.start_link/1was fixed, so that generators can be started supervised
0.10.0 - 2021-12-13
This release adds RDF-star support on the RDF data structures, the N-Triples, N-Quads, Turtle encoders and decoders and the BGP query engine. For an introduction read the new page on the RDF.ex guide. For more details on how to migrate from an earlier version read this wiki page.
Elixir versions < 1.10 are no longer supported
Added
- Support for
RDF.PropertyMaponRDF.Statement.new/2andRDF.Statement.coerce/2. RDF.Dataset.graph_count/1- The
RDF.NQuads.Encodernow supports a:default_graph_nameoption, which allows to specify the graph name to be used as the default for triples from aRDF.GraphorRDF.Description.
Changed
- The
RDF.Turtle.Encoderno longer supports the encoding ofRDF.Datasets.
You'll have to aggregate aRDF.Datasetto aRDF.Graphon your own now. - The
RDF.NQuads.Encodernow uses theRDF.Graph.name/1as the graph name for
the triples of aRDF.Graph. Previously the triples of anRDF.Graphwere always encoded as part of default graph. You can use the new:default_graph_nameoption and set it tonilto get the old behaviour.
0.9.4 - 2021-05-26
Added
RDF.statement/1,RDF.statement/3andRDF.statement/4constructor functions- the
:default_prefixesconfiguration option now allows to set a{mod, fun}tuple, with a function which should be called to determine the default prefixes - the
:default_base_iriconfiguration option now allows to set a{mod, fun}tuple, with a function which should be called to determine the default base IRI - support for Elixir 1.12 and OTP 24
Fixed
- the Turtle encoder was encoding IRIs as prefixed names even when they were resulting in non-conform prefixed names
- the Turtle encoder didn't properly escape special characters in language-tagged literals
- the N-Triples and N-Quads encoders didn't properly escape special characters in both language-tagged and plain literals
- the
Inspectprotocol implementation forRDF.Diffwas causing an error when both graphs had prefixes defined
Note: In the canonical form of -0.0 in XSD doubles and floats the sign is removed in OTP versions < 24 although this is not standard conform. This has the consequence that the sign of -0.0 is also removed when casting these doubles and floats to decimals. These bugs won't be fixed. If you rely on the correct behavior in these cases, you'll have to upgrade to OTP 24 and a respective Elixir version.
0.9.3 - 2021-03-09
Added
:indentoption onRDF.Turtle.Encoder, which allows to specify the number of spaces the output should be indented
Changed
- the performance of the
Enumerableprotocol implementations of the RDF data structures was significantly improved (for graphs almost 10x), which in turn increases the performance of all functions built on top of that, eg. the N-Triples and N-Quads encoders - improvement of the Inspect forms of the RDF data structures: the content is now enclosed in angle brackets and indented
Fixed
- strings of the form
".0"and"0."weren't recognized as valid XSD float
and double literals - the Turtle encoder handles base URIs without a trailing slash or hash properly
(no longer raising a warning and ignoring them)
0.9.2 - 2021-01-06
Added
RDF.XSD.Base64Binarydatatype (@pukkamustard)
Changed
- a new option
:as_valueto enforce interpretation of an input string as a value instead of a lexical, which is needed on datatypes where the lexical space and the value space both consist of strings RDF.XSD.DateandRDF.XSD.Timeboth can now be initialized with tuples of an ElixirDateresp.Timevalue and a timezone string (previously XSD date and time values with time zones could only be created from strings)
0.9.1 - 2020-11-16
Elixir versions < 1.9 are no longer supported
Added
- general serialization functions for reading from and writing to streams and implementations for N-Triples and N-Quads (Turtle still to come)
- a
:gzipoption flag on allread_file/3andwrite_file/3functions allows to read and write all supported serialization formats from and to gzipped files (works also with the new possibility to read and write files via streams) RDF.Dataset.prefixes/1for getting an aggregatedRDF.PrefixMapover all graphsRDF.PrefixMap.put/3for adding a prefix mapping and overwrite an existing oneRDF.BlankNode.value/1for getting the internal string representation of a blank nodeRDF.IRI.in_namespace?/2for determining whether an IRI lies in a namespace
Changed
- all
read_file/3andwrite_file/3functions onRDF.Serializationand the modules of RDF serialization formats can use streaming via the:streamflag option; forread_file/3andwrite_file/3it defaults tofalse, while forread_file!/3andwrite_file!/3it defaults totruewhen the respective format supports streams - the Inspect form of the RDF data structures are now Turtle-based and respect
the usual
:limitbehaviour - more compact Inspect form for
RDF.PrefixMap - the
RDF.Turtle.EncoderacceptsRDF.Vocabulary.Namespacemodules asbase - the performance of the
RDF.Turtle.Encoderwas improved (by using a for most use cases more efficient method for resolving IRIs to prefixed names) RDF.BlankNode.new/0creates integer-based blank nodes, which is much more efficient in terms of performance and memory consumption than the previous ref-based blank nodes
Fixed
RDF.BlankNodes based on refs weren't serializable to TurtleRDF.Vocabulary.Namespaces couldn't contain terms conflicting with functions from Elixirs Kernel module; most of them are supported now, while for the
remaining unsupported ones a proper error message is produced during compilation
0.9.0 - 2020-10-13
The API of the all three RDF datastructures RDF.Dataset, RDF.Graph and
RDF.Description were changed, so that the functions taking input data consist only
of one field in order to open the possibility of introducing options on these
functions. The supported ways with which RDF statements can be passed to the
RDF data structures were extended and unified to be supported across all functions
accepting input data. This includes also the way in which patterns for BGP queries
are specified. Also, the performance for adding data has been improved.
For an introduction on the new data structure API and the commonly supported input formats read the updated page on the RDF data structures in the guide. For more details on how to migrate from an earlier version read this wiki page.
Added
RDF.PropertyMapwhich allow definition of atoms for RDF properties. Such property maps can be provided to all RDF data structure functions accepting input data and BGP query patterns with the:contextopt, allowing the use of the atoms from the property map in the input data.- on
RDF.Description - on
RDF.Graph - on
RDF.Dataset RDF.IRI.append/2
Changed
- the format for the specification of BGP queries with
RDF.Graph.query/2,RDF.Graph.query_stream/2andRDF.Query.bgp/1has been changed to be consistent
with the supported formats for input data in the rest of the library RDF.Description.newnow requires thesubjectto be passed always as first argument; if you want to add some initial data this must be done with the:initoption- The
put/3functions onRDF.GraphandRDF.Datasetnow overwrite all statements with same subject. Previously only statements with the same subject AND predicate were overwritten, which was probably not the expected behaviour, since it's not inline with the commonputsemantics in Elixir. A function with the previous behaviour was added onRDF.GraphandRDF.Datasetwith theput_properties/3function.- CAUTION: This means the
RDF.Graph.put/2andRDF.Dataset.put/2function have become more destructive now when not specified otherwise. - Note: Although one could argue, that following this route
RDF.Dataset.put/3would consequently have to overwrite whole graphs, this was not implemented for practical reasons. It's probably not what's wanted in most cases.
- CAUTION: This means the
- The
Accessprotocol implementation ofget_and_update/3onRDF.GraphandRDF.Datasetpreviously relied on theput/2functions with the old behaviour of overwriting only statements with the same subject and predicate, which was almost never the expected behaviour. This is fixed now by relying on the newput/2behaviour. - the
values/2functions ofRDF.Statement,RDF.Triple,RDF.Quad,RDF.Description,RDF.GraphandRDF.Datasetnow accept on their second argument an optionalRDF.PropertyMapwhich will be used to map predicates accordingly; the variant of thesevalues/2functions to provide a custom mapping function was extracted into a new functionmap/2on all of these modules - for consistency reasons the internal
:idstruct field ofRDF.BlankNodewas renamed to:value - allow the
base_iriofRDF.Vocabulary.Namespaces to end with a.to support vocabularies which use dots in the IRIs for further structuring (e.g. CIM-based formats like CGMES) RDF.Triple.new/1now also accepts four-element tuples and simple ignores fourth elementRDF.Quad.new/1now also accepts three-element tuples and simple assumes the fourth element to benil
Fixed
- the
putfunctions onRDF.Description,RDF.GraphandRDF.Datasetdidn't add all statements properly under certain circumstances RDF.Graph.put/2ignores empty descriptions; this should be the final piece to ensure thatRDF.Graphs never contain empty descriptions, which would distort results of functions likeRDF.Graph.subjects/1,RDF.Graph.subject_count/1,RDF.Graph.descriptions/1
0.8.2 - 2020-09-21
Added
- the Turtle encoder can now produce partial Turtle documents with the
:onlyoption and any combination of the following values::triples,:directives,:base,:prefixes - the style of the Turtle directives produced by the Turtle encoder can be
switched to SPARQL style with the option
:directive_styleand the value:sparql - the most common conflict resolution strategies on
RDF.PrefixMap.merge/3can now be chosen directly with the atoms:ignoreand:overwrite RDF.PrefixMap.prefixed_name/2to convert an IRI to a prefixed nameRDF.PrefixMap.prefixed_name_to_iri/2to convert a prefixed name to an IRI
Changed
- when serializing a
RDF.Datasetwith the Turtle encoder the prefixes of all of its graphs are used now
Fixed
- adding an empty
RDF.Descriptionwith a subject to an emptyRDF.Graphresulted in an invalid non-empty graph (@pukkamustard)
0.8.1 - 2020-06-16
Added
- query functions for basic graph pattern matching (incl. streaming-support)
0.8.0 - 2020-06-01
RDF literals and their datatypes were completely redesigned to support derived XSD datatypes and allow for defining custom datatypes. For an introduction on how literals work now read the updated page on literals in the guide. For more details on how to migrate from an earlier version read this wiki page.
Elixir versions < 1.8 are no longer supported
Added
- a lot of new datatypes like
xsd:float,xsd:byteorxsd:anyURI-- all numeric XSD datatypes are now available; see this page of the API documentation for an up-to-date list of all supported and missing XSD datatypes - an implementation of XSD facet system now makes it easy to define own custom datatypes via restriction of the existing XSD datatypes
RDF.Literal.update/2updates the value of aRDF.Literalwithout changing anything else, eg. the language or datatype
Changed
- the
RDF.Literalstruct now consists entirely of a datatype-specific structs in theliteralfield, which besides being more memory-efficient (since literals no longer consist of all possible fields a literal might have), allows pattern matching now on the datatype of literals. - RDF XSD datatypes are now defined in the
RDF.XSDnamespace - alias constructor functions for the XSD datatypes are now defined on
RDF.XSD matches?,less_than?,greater_thanas higher level functions were removed from theRDF.Literal.Datatypemodulesless_than?,greater_than?now always return a boolean and no longernilwhen incomparable; you can still determine if two terms are comparable by checking ifcompare/2returnsnil- the
languageoption is not supported on theRDF.XSD.String.new/2constructor - the
languageoption onRDF.Literal.new/2is no longer ignored if it's empty (nilor""), so this either produces an invalidRDF.LangStringnow or, if anotherdatatypeis provided will fail with anArgumentError canonicalnow performs implicit coercions when passed plain Elixir values- the inspect format for literals was changed and is now much more informative and uniform, since you now always see the value, the lexical form and if the literal is valid
RDF.Namespace.resolve_term/1now returns ok or error tuples, but a new functionRDF.Namespace.resolve_term!/1with the old behaviour was added
Fixed
- numeric operations on invalid numeric literals no longer fail, but return
nilinstead - Datetimes preserve the original lexical form of the timezone when casting from a date
- BEAM error warnings when trying to use top-level modules as vocabulary terms
0.7.1 - 2020-03-11
Added
- proper typespecs so that Dialyzer passes without warnings (@rustra)
Fixed
RDF.XSD.Timedidn't handle 24h overflows with an offset correctly
0.7.0 - 2019-11-22
Added
RDF.Diffdata structure for diffs between RDF graphs and descriptionsRDF.Description.update/4updates the objects of a predicate in a description with a custom update functionRDF.Graph.update/4updates the descriptions of a subject in a graph with a custom update functionRDF.Description.take/2creates a description from another one by limiting its statements to a set of predicatesRDF.Graph.take/3creates a graph from another one by limiting its statements to a set of subjects and optionally also a set of predicatesRDF.Graph.clear/1removes the triples from a graph- Mix formatter configuration for using
defvocabwithout parens
Changed
RDF.Serialization.Writer.write_file/4which is the basis used by all thewrite_file/3andwrite_file!/3functions of all serialization format modules likeRDF.NTriples,RDF.Turtle,JSON.LDetc. now opens file in a different mode: it no longer opens them with the:utf8option. First, this by default slowed down the writing, but more importantly could lead to unexpected encoding issues. This is a breaking change: If your code relied on this file mode, you can get the old behaviour, by specifying thefile_modeon these functions accordingly as[:utf8, :write, :exclusive]. For example, to write a Turtle file with the old behaviour, you can do it like this:
RDF.Turtle.write_file!(some_data, some_path, file_mode: ~w[utf8 write exclusive]a)0.6.2 - 2019-09-08
Added
- field
base_irionRDF.Graphstructure which can be set via newbase_irioption onRDF.Graph.newor the new functionsRDF.Graph.set_base_iri/2andRDF.Graph.clear_base_iri/1 RDF.Graph.clear_metadata/1which clears the base IRI and the prefixesRDF.IRI.coerce_base/1which coerces base IRIs; as opposed toRDF.IRI.new/1it also accepts bareRDF.Vocabulary.Namespacemodules
Changed
RDF.Turtle.Decodersaves the base IRI in theRDF.GraphnowRDF.Turtle.Encodernow takes the base IRI to be used during serialization in
the following order of precedence:- from the
baseoption or its new aliasbase_iri - from the
base_irifield of the given graph - from the
RDF.default_base_irireturning the one from the application configuration
- from the
RDF.PrefixMap.newandRDF.PrefixMap.addnow also accepts terms fromRDF.Vocabulary.Namespaces as namespaces
Fixed
- Vocabulary namespace modules weren't always detected properly
0.6.1 - 2019-07-15
Added
RDF.IRI.to_string/1returns the string representation of anRDF.IRI
(implicitly resolving vocabulary namespace terms)RDF.Literal.matches?/3for XQuery regex pattern matchingRDF.Decimal.digit_count/1andRDF.Decimal.fraction_digit_count/1for
determining the number of digits of decimal literals
Fixed
- language literals were not properly unescaped during Turtle parsing
RDF.Literal.new/1can take decimals and infers the datatypexsd:decimalcorrectlytrueandfalsewith capital letters are no longer validRDF.Booleans following the XSD specification; the same applies for booleans in Turtle+INFis no longer a validRDF.Double(positive infinity doesn't expect a sign)- slightly improve output of errors during parsing of Turtle, N-Triples and N-Quads
0.6.0 - 2019-04-06
see here for upgrading notes to RDF.ex 0.6
Added
RDF.PrefixMap- prefix management of
RDF.Graphs:- the structure now has a
prefixesfield with an optionalRDF.PrefixMap - new functions
add_prefixes/2,delete_prefixes/2andclear_prefixes/1
- the structure now has a
- configurable
RDF.default_prefixes RDF.Description.equal?/2,RDF.Graph.equal?/2,RDF.Dataset.equal?/2andRDF.Data.equal?/2
Changed
- the constructor functions for
RDF.Graphs andRDF.Datasets now take the graph name resp. dataset name through anameoption, instead of the first argument RDF.Graph.newsupports an additionalprefixesargument to initialize theprefixesfield- when
RDF.Graph.addandRDF.Graph.putare called with another graph, its prefixes are merged RDF.Turtle.Decodersaves the prefixes nowRDF.Turtle.Encodernow takes the prefixes to be serialized in the following order of precedence:- from the
prefixesoption (as before) - from the
prefixesfield of the given graph - from the
RDF.default_prefixes
- from the
- drop support for OTP < 20, since prefixes can consist of UTF characters which are not supported in atoms on these versions
0.5.4 - 2019-01-17
Fixed
- issue with Elixir 1.8
RDF.write_fileandRDF.write_file!delegators had wrong signatures
0.5.3 - 2018-11-11
Added
RDF.Triple.valid?/1,RDF.Quad.valid?/1andRDF.Statement.valid?/1, which validate if a tuple is a valid RDF triple or RDF quad
0.5.2 - 2018-11-04
Added
RDF.Term.value/1returning the native Elixir value of a RDF termRDF.Statement.values/1,RDF.Triple.values/1andRDF.Quad.values/1returning a tuple ofRDF.Term.value/1converted native Elixir values from a tuple of RDF termsRDF.Description.values/1,RDF.Graph.values/1,RDF.Dataset.values/1andRDF.Data.values/1returning a map ofRDF.Term.value/1converted native Elixir values from the respective structure of RDF terms- for all of aforementioned
values/1functions a variantvalues/2which allows to specify custom mapping function to be applied when creating the resp. structure RDF.Literal.compare/2,RDF.Literal.less_than?/2andRDF.Literal.greater_than?/2
forRDF.Datatypeaware comparisons ofRDF.Literals
Fixed
RDF.DateTime.equal_value?/2andRDF.Date.equal_value?/2did not handle timezones correctly-00:00is a valid timezone offset onRDF.DateTime
0.5.1 - 2018-09-17
Fixed
- generated Erlang output files of Leex and Yecc are excluded from Hex package
0.5.0 - 2018-09-17
Elixir versions < 1.6 are no longer supported
Added
- Possibility to execute simple SPARQL queries against
RDF.Graphs with SPARQL 0.2 - New
RDF.Termprotocol implemented for all structs representing RDF nodes and
all native Elixir datatypes which are coercible to those modules. For now, it
mainly offers, besides the coercion, just the functionRDF.Term.equal?/2andRDF.Term.equal_value?/2for term- and value comparisons. - New
RDF.Decimaldatatype forxsd:decimalliterals and support for decimal literals in Turtle encoder RDF.Numericmodule with a list of all numeric datatypes and shared functions for all numeric literals, e.g. arithmetic functions- Various new
RDF.DatatypefunctionRDF.Datatype.cast/1for casting betweenRDF.Literals as specified in the XSD spec on allRDF.Datatypes- logical operators and the Effective Boolean Value (EBV) coercion algorithm
from the XPath and SPARQL specs on
RDF.Boolean - various functions on the
RDF.DateTimeandRDF.Timedatatypes RDF.LangString.match_language?/2
- Many new convenience functions on the top-level
RDFmodule- constructors for all the supported
RDF.Datatypes - constant functions
RDF.trueandRDF.falsefor the two booleanRDF.Literalvalues
- constructors for all the supported
RDF.Literal.Guardswhich allow pattern matching of common literal datatypesRDF.BlankNode.Generator- Possibility to configure an application-specific default base IRI; for now it
is used only on reading of RDF serializations (when no
basespecified)
Changed
RDF.String.new/2andRDF.String.new!/2produce ardf:langStringwhen given a language tag- Some of the defined structs now enforce keys at compile-time (via Elixirs
@enforce_keysfeature) when not setting the corresponding fields would lead to invalid structs, namely the following fields:RDF.IRI.valueRDF.BlankNode.idRDF.Description.subjectRDF.List.head
Fixed
RDF.resource?/1does not fail anymore when called with unresolvable atoms but returnsfalseinsteadRDF.IRI.absolute/2does not fail with aFunctionClauseErrorwhen the given base is not absolute, but returnsnilinsteadRDF.DateTimeandRDF.Timestore microsecondsRDF.DateTime: '24:00:00' is a valid time in a xsd:dateTime; the dateTime value so represented is the first instant of the following dayRDF.LangString: non-strings or the empty string as language produce invalid literals
0.4.1 - 2018-03-19
Added
RDF.Literal.new!/2which fails when creating an invalid literal
Changed
RDF.Literal.new/2can createrdf:langStringliterals without failing, they
are simply invalid; if you want to fail without a language tag use the newRDF.Literal.new!/2function
0.4.0 - 2018-03-10
Changed
- renamed
RDF.Serializationbehaviour toRDF.Serialization.Format; the newRDF.Serializationmodule contains just simple RDF serialization related functions - renamed
RDF.Serialization.Formatfunctioncontent_type/0tomedia_type/0 - moved
RDF.ReaderandRDF.WriterintoRDF.Serializationmodule - removed the limitation to serialization formats defined in the core RDF.ex package
for use as a source of
RDF.Vocabulary.Namespaces; so you can now also define vocabulary namespaces from JSON-LD files for example, provided that the corresponding Hex package is defined as a dependency
Added
RDF.Serialization.Formats define anameatom- all
RDF.Serialization.ReaderandRDF.Serialization.Writerfunctions are now available on theRDF.Serializationmodule (or aliased on the top-levelRDFmodule) and the format can be specified instead of aRDF.Serialization.Formatargument, via theformatormedia_typeoption or in case of*_filefunctions, without explicit specification of the format, but inferred from file name extension instead; see the updated README section about RDF serializations - the following functions to access available
RDF.Serialization.Formats:
0.3.1 - 2018-01-19
Added
Collectableimplementations for allRDF.Datastructures, so they can be used as destinations ofEnum.intoandforcomprehensionsRDF.Quadcan be created from triple andRDF.Triplecan be created from quadRDF.Statement.map/2which creates a statement with mapped nodes from another statementRDF.Statementfunctions to get the coerced components of a statement
Fixed
- Fix
unescape_mapinparse_helperfor Elixir 1.6 (@ajkeys)
0.3.0 - 2017-08-24
Added
RDF.IRIas a more suitable URI/IRI representation for RDF, bringing enormous performance and memory consumption benefits (see here for the details about the improvements)
Changed
- use
RDF.IRIinstead of ElixirsURIeverywhere - use the term iri instead of uri consistently, leading to the following
function renamings:
base_iriinstead ofbase_urifor the definition ofRDF.Vocabulary.Namespaces__base_iri__instead of__base_uri__in allRDF.Vocabulary.Namespaces__iris__instead of__uris__in allRDF.Vocabulary.NamespacesRDF.IRI.InvalidErrorinstead ofRDF.InvalidURIErrorRDF.Literal.InvalidErrorinstead ofRDF.InvalidLiteralErrorRDF.Namespace.InvalidVocabBaseIRIErrorinstead ofRDF.Namespace.InvalidVocabBaseURIError
- show compilation message of vocabulary namespaces always to be able to relate resp. errors and warnings
Fixed
- when trying to resolve a term from an undefined module a
RDF.Namespace.UndefinedTermErrorexception
0.2.0 - 2017-08-12
Elixir versions < 1.4 are no longer supported
Added
- full Turtle support
RDF.Liststructure for the representation of RDF listsdescribes?/1onRDF.Dataprotocol and all RDF data structures which checks
if statements about a given resource existRDF.Data.descriptions/1which returns all descriptions within an RDF data structureRDF.Description.first/2which returns a single object to a predicate of aRDF.DescriptionRDF.Description.objects/2now supports a custom filter functionRDF.bnode?/1which checks if the given value is a blank node
Changed
- Rename
RDF.Statement.convert*functions toRDF.Statement.coerce*
Fixed
RDF.uri/1and URI parsing of N-Triples and N-Quads decoders preserve empty fragments- booleans weren't recognized as coercible literals on object positions
- N-Triples and N-Quads decoder didn't handle escaping properly
0.1.1 - 2017-06-25
Fixed
- Add
srcdirectory to package files.
0.1.0 - 2017-06-25
Initial release
Note: This version is not usable, since the src directory is not part of the
package, which has been immediately fixed on version 0.1.1.