### Update RDF.Graph Constructor with Name Option (Elixir) Source: https://github.com/rdf-elixir/rdf-ex/wiki/Upgrading-to-RDF.ex-0.6 Demonstrates the change in the RDF.Graph constructor signature. It now requires the graph name to be passed as a 'name' option, facilitating the addition of new features like prefix management. ```elixir RDF.Graph.new(EX.GraphName, data) # now has to be written like this RDF.Graph.new(data, name: EX.GraphName) ``` -------------------------------- ### Update RDF.Dataset Constructor with Name Option (Elixir) Source: https://github.com/rdf-elixir/rdf-ex/wiki/Upgrading-to-RDF.ex-0.6 Illustrates the updated RDF.Dataset constructor, which now accepts the dataset name via the 'name' option. This change is essential for supporting new functionalities such as prefix management. ```elixir RDF.Dataset.new(EX.DatasetName, data) # now has to be written like this RDF.Dataset.new(data, name: EX.DatasetName) ``` -------------------------------- ### Compare Graph Equality with RDF.Graph.equal?/2 (Elixir) Source: https://github.com/rdf-elixir/rdf-ex/wiki/Upgrading-to-RDF.ex-0.6 Introduces the `RDF.Graph.equal?/2` function for accurate equality checks between graphs. This function is necessary because the `==` operator no longer provides reliable comparisons when graphs have different prefixes. ```elixir RDF.Graph.equal?(graph1, graph2) ``` -------------------------------- ### Compare Dataset Equality with RDF.Dataset.equal?/2 (Elixir) Source: https://github.com/rdf-elixir/rdf-ex/wiki/Upgrading-to-RDF.ex-0.6 Presents the `RDF.Dataset.equal?/2` function for robust equality comparisons of datasets. This function should be used instead of `==` to ensure correct results, especially when dealing with datasets that may have differing prefix definitions. ```elixir RDF.Dataset.equal?(dataset1, dataset2) ``` -------------------------------- ### Diff and Merge Operations on RDF Graphs in Elixir Source: https://context7.com/rdf-elixir/rdf-ex/llms.txt Provides examples of performing diff and merge operations on RDF graphs using RDF.ex. It demonstrates how to compute differences between graphs, access additions and deletions, and merge graphs to create a union. ```elixir import RDF.Sigils # Create two graphs graph1 = RDF.Graph.new([ {~I, ~I, "value1"}, {~I, ~I, "value2"} ]) graph2 = RDF.Graph.new([ {~I, ~I, "value2"}, {~I, ~I, "value3"} ]) # Compute the difference between graphs diff = RDF.Diff.diff(graph1, graph2) # => %RDF.Diff{ # additions: RDF.Graph with {s, p3, "value3"}, # deletions: RDF.Graph with {s, p1, "value1"} # } # Access additions and deletions diff.additions # Statements in graph2 but not in graph1 diff.deletions # Statements in graph1 but not in graph2 # Apply a diff to transform one graph into another transformed = RDF.Data.merge(graph1, diff.additions) |> RDF.Graph.delete(diff.deletions) # Merge graphs (union) merged = RDF.Data.merge(graph1, graph2) # Contains all statements from both graphs # Graph intersection (Elixir 1.15+) intersection = RDF.Graph.intersection(graph1, graph2) # Contains only statements present in both graphs ``` -------------------------------- ### Use Expressions in `defvocab` Definitions Source: https://github.com/rdf-elixir/rdf-ex/wiki/Upgrading-to-RDF.ex-1.0 Shows how to use expressions, not just plain literals, within `defvocab` definitions. This allows for more dynamic vocabulary namespace configurations, such as concatenating base IRIs with other values. ```elixir defmodule YourApp.NS do use RDF.Vocabulary.Namespace defvocab EX, base_iri: M.ns() <> "/foo", terms: [:bar] end ``` -------------------------------- ### Define Vocabulary Namespace Terms with Aliases Directly Source: https://github.com/rdf-elixir/rdf-ex/wiki/Upgrading-to-RDF.ex-1.0 Illustrates a new best practice for defining vocabulary namespaces. Aliases for terms can now be provided directly within the list of terms, simplifying the `alias` definition. This reduces redundancy when defining terms and their corresponding aliases. ```elixir defmodule YourApp.NS do use RDF.Vocabulary.Namespace defvocab EX, base_iri: "http://www.example.com/ns/", terms: ["Foo-bar", "Baz"], alias: [FooBar: "Foo-bar"] end ``` ```elixir defmodule YourApp.NS do use RDF.Vocabulary.Namespace defvocab EX, base_iri: "http://www.example.com/ns/", terms: [ :Baz, FooBar: "Foo-bar" ] end ``` -------------------------------- ### Update Vocabulary Namespace Property Function Arguments Source: https://github.com/rdf-elixir/rdf-ex/wiki/Upgrading-to-RDF.ex-1.0 Demonstrates how to update property function calls in vocabulary namespaces. Previously, multiple objects were passed as separate arguments; now they must be provided within a list. This change accommodates future argument additions. ```elixir EX.S |> EX.p(1, 2, 3) ``` ```elixir EX.S |> EX.p([1, 2, 3]) ``` -------------------------------- ### Read RDF Serializations from String Source: https://context7.com/rdf-elixir/rdf-ex/llms.txt Shows how to read RDF data from a string using the `RDF.read_string` function. It supports various formats, with an example using Turtle format. The function returns `{:ok, graph}` on success or raises an error with the bang version. ```elixir # Read Turtle from a string turtle_string = """ @prefix foaf: . @prefix ex: . ex:john foaf:name "John Doe" ; foaf:knows ex:jane . """ {:ok, graph} = RDF.read_string(turtle_string, format: :turtle) # => {:ok, %RDF.Graph{...}} # Read with bang version (raises on error) graph = RDF.read_string!(turtle_string, format: :turtle) ``` -------------------------------- ### Update RDF Graph Builder Usage with Bindings Source: https://github.com/rdf-elixir/rdf-ex/wiki/Upgrading-to-RDF.ex-1.0 Details changes in `RDF.Graph.build/2`. Blocks are now wrapped in functions, requiring explicit passing of caller context variables as bindings in a keyword list to the new optional first argument of `RDF.Graph.build/3`. Imports also need to be re-declared within the build block. ```elixir use RDF alias EX import Something var = "foo" # we need to pass var as binding to be able to use it in the build block RDF.Graph.build var: var do # Something is not imported here and needs to be re-imported again to be available import Something # EX is available {EX.S, something(), var} end ``` -------------------------------- ### XSD Datatypes and Operations in Elixir Source: https://context7.com/rdf-elixir/rdf-ex/llms.txt Illustrates the usage of XML Schema (XSD) datatypes within RDF.ex. It covers various numeric, date/time, string, and boolean types, along with examples of numeric operations and literal comparisons. This functionality is crucial for representing and manipulating typed data in RDF. ```elixir # Numeric types RDF.XSD.integer(42) RDF.XSD.decimal("3.14159") RDF.XSD.double(2.718281828) RDF.XSD.float(1.5) RDF.XSD.non_negative_integer(100) RDF.XSD.positive_integer(1) # Date and time types RDF.XSD.date(~D[2024-01-15]) RDF.XSD.time(~T[14:30:00]) RDF.XSD.dateTime(~U[2024-01-15 14:30:00Z]) RDF.XSD.dateTime(~N[2024-01-15 14:30:00]) # String types RDF.XSD.string("plain string") RDF.XSD.any_uri("http://example.com") RDF.XSD.base64_binary(<<1, 2, 3>>) # Boolean RDF.XSD.boolean(true) RDF.XSD.false() RDF.XSD.true() # Numeric operations a = RDF.XSD.integer(10) b = RDF.XSD.integer(3) RDF.XSD.Numeric.add(a, b) # => RDF.XSD.integer(13) RDF.XSD.Numeric.subtract(a, b) # => RDF.XSD.integer(7) RDF.XSD.Numeric.multiply(a, b) # => RDF.XSD.integer(30) RDF.XSD.Numeric.divide(a, b) # => RDF.XSD.decimal("3.333...") # Literal comparison RDF.Literal.compare(RDF.XSD.integer(1), RDF.XSD.integer(2)) # => :lt RDF.Literal.less_than?(RDF.XSD.integer(1), RDF.XSD.integer(2)) # => true # Type checking lit = RDF.XSD.integer(42) RDF.Literal.is_a?(lit, RDF.XSD.Integer) # => true RDF.Literal.is_a?(lit, RDF.XSD.Numeric) # => true RDF.Literal.is_a?(lit, RDF.XSD.String) # => false ``` -------------------------------- ### Initialize RDF.Description with :init option Source: https://github.com/rdf-elixir/rdf-ex/wiki/Upgrading-to-RDF.ex-0.9 Illustrates the updated initialization process for RDF.Description. Initial statements are now passed using the `:init` option, and a subject must always be provided explicitly. This replaces the previous method of passing initial statements directly, which could lead to unpredictable results. ```elixir RDF.Description.new({EX.S, EX.p, EX.o}) ``` ```elixir RDF.Description.new(EX.S, init: {EX.p, EX.o}) ``` ```elixir EX.S |> EX.p(EX.O) ``` -------------------------------- ### Create and Manipulate RDF Graphs Source: https://context7.com/rdf-elixir/rdf-ex/llms.txt Illustrates creating RDF graphs, both empty and with initial data. Shows how to add triples, create named graphs with prefixes, retrieve descriptions, delete triples, query graph statistics, check for triple inclusion, and convert graphs to native Elixir values. ```elixir import RDF.Sigils # Create an empty graph graph = RDF.Graph.new() # Create a graph with initial data graph = RDF.Graph.new([ {~I, ~I, "John Doe"}, {~I, ~I, ~I}, {~I, ~I, "Jane Smith"} ]) # Create a named graph with prefixes graph = RDF.Graph.new([{~I, ~I, "John"}], name: ~I, prefixes: [ ex: "http://example.com/", foaf: "http://xmlns.com/foaf/0.1/" ]) # Add triples to a graph graph = RDF.Graph.new() |> RDF.Graph.add({~I, ~I, "object"}) |> RDF.Graph.add([ {~I, ~I, "value1"}, {~I, ~I, "value2"} ]) # Get description for a subject desc = RDF.Graph.get(graph, ~I) # => %RDF.Description{...} # Delete triples graph = RDF.Graph.delete(graph, {~I, ~I, "object"}) # Query graph statistics RDF.Graph.statement_count(graph) # => 3 RDF.Graph.subject_count(graph) # => 2 RDF.Graph.subjects(graph) # => MapSet of subject IRIs # Check if graph contains a triple RDF.Graph.include?(graph, {~I, ~I, "John Doe"}) # => true # Convert to native Elixir values RDF.Graph.values(graph) # => %{"http://example.com/john" => %{"http://xmlns.com/foaf/0.1/name" => ["John Doe"], ...}, ...} ``` -------------------------------- ### Create RDF Descriptions with RDF.ex Source: https://context7.com/rdf-elixir/rdf-ex/llms.txt Illustrates how to create an `RDF.Description`, which groups multiple predicate-object pairs for the same subject resource. Shows defining a vocabulary namespace for cleaner code and initializing a description with initial data. ```elixir # Define a vocabulary namespace for cleaner code defmodule EX do use RDF.Vocabulary.Namespace defvocab EX, base_iri: "http://example.com/", terms: [], strict: false end import RDF.Sigils # Create a new description with initial data description = RDF.Description.new(~I, init: { ~I, "John Doe" }) ``` -------------------------------- ### Build Graphs using DSL Source: https://context7.com/rdf-elixir/rdf-ex/llms.txt Demonstrates using the `RDF.Graph.build` macro to declaratively construct graphs with a Turtle-like syntax. This includes defining vocabulary namespaces and using prefixes for concise triple creation. ```elixir defmodule MyApp.GraphBuilder do use RDF defmodule NS do use RDF.Vocabulary.Namespace defvocab EX, base_iri: "http://example.com/", terms: [], strict: false end def build_person_graph(name, age) do alias NS.EX RDF.Graph.build do @prefix ex: EX @prefix foaf: ~I EX.john |> foaf.name(name) |> foaf.age(age) |> foaf.knows(EX.jane) EX.jane |> foaf.name("Jane Smith") end end end # Usage graph = MyApp.GraphBuilder.build_person_graph("John Doe", 30) # Returns an RDF.Graph with the specified triples and prefixes ``` -------------------------------- ### Working with RDF Datasets in Elixir Source: https://context7.com/rdf-elixir/rdf-ex/llms.txt Explains how to create, manipulate, and serialize RDF datasets, which are collections of graphs. It covers creating default and named graphs, combining them into datasets, and serializing datasets to formats like N-Quads and TriG. ```elixir import RDF.Sigils # Create graphs default_graph = RDF.Graph.new([ {~I, ~I, "default"} ]) named_graph1 = RDF.Graph.new([ {~I, ~I, "graph1"} ], name: ~I) named_graph2 = RDF.Graph.new([ {~I, ~I, "graph2"} ], name: ~I) # Create a dataset from graphs dataset = RDF.Dataset.new([default_graph, named_graph1, named_graph2]) # Create dataset with a name dataset = RDF.Dataset.new(default_graph, name: ~I) # Add graphs to a dataset dataset = RDF.Dataset.new() |> RDF.Dataset.add(default_graph) |> RDF.Dataset.add(named_graph1) # Get the default graph default = RDF.Dataset.default_graph(dataset) # => %RDF.Graph{name: nil, ...} # Get a named graph graph = RDF.Dataset.graph(dataset, ~I) # => %RDF.Graph{name: ~I, ...} # List all graph names RDF.Dataset.graph_names(dataset) # => [nil, ~I, ~I] # Get all statements as quads RDF.Dataset.quads(dataset) # => [{subject, predicate, object, graph_name}, ...] # Serialize to N-Quads {:ok, nquads} = RDF.write_string(dataset, format: :nquads) # Serialize to TriG {:ok, trig} = RDF.write_string(dataset, format: :trig) ``` -------------------------------- ### Using Vocabulary Namespaces in Elixir Source: https://context7.com/rdf-elixir/rdf-ex/llms.txt Demonstrates how to use predefined and custom vocabulary namespaces to construct IRIs and build RDF graphs. It shows how to alias namespaces for cleaner code and how to represent vocabulary terms as IRIs within graph structures. ```elixir defmodule MyApp.RDFBuilder do alias MyApp.NS.{EX, Custom} alias RDF.NS.{RDFS, XSD} # Built-in vocabularies def example do import RDF.Sigils # Use vocabulary terms as IRIs Custom.Person # => ~I Custom.name # => ~I # Non-strict vocabularies accept any term EX.anything_goes # => ~I # Build graphs with vocabulary namespaces RDF.Graph.new([ {EX.john, RDF.type(), Custom.Person}, {EX.john, Custom.name, "John Doe"}, {EX.john, RDFS.label, "John"} ]) end end ``` -------------------------------- ### Create and Manipulate RDF Descriptions Source: https://context7.com/rdf-elixir/rdf-ex/llms.txt Demonstrates creating RDF descriptions, adding multiple statements, handling multiple objects for a predicate, retrieving objects, deleting statements, and converting descriptions to triples or native Elixir values. ```elixir description = RDF.Description.new(~I) |> RDF.Description.add({~I, "John Doe"}) |> RDF.Description.add({~I, 30}) |> RDF.Description.add({~I, ~I}) description = RDF.Description.new(~I, init: [ {~I, "John Doe"}, {~I, ["Johnny", "JD"]} ]) RDF.Description.get(description, ~I) # => [%RDF.Literal{literal: %RDF.XSD.String{value: "John Doe"}}] RDF.Description.first(description, ~I) # => %RDF.Literal{literal: %RDF.XSD.String{value: "John Doe"}} description = RDF.Description.delete(description, {~I, "JD"}) RDF.Description.triples(description) # => [{~I, ~I, ~L"John Doe"}, ...] RDF.Description.values(description) # => %{"http://xmlns.com/foaf/0.1/name" => ["John Doe"], ...} ``` -------------------------------- ### Prefix Map Management in Elixir Source: https://context7.com/rdf-elixir/rdf-ex/llms.txt Details how to manage namespace prefix bindings using RDF.ex's PrefixMap module. This includes creating, adding, resolving, merging, and serializing prefix maps for use in RDF serialization formats like Turtle and SPARQL. It also shows how to access default prefixes. ```elixir import RDF.Sigils # Create a prefix map prefixes = RDF.PrefixMap.new( ex: "http://example.com/", foaf: "http://xmlns.com/foaf/0.1/", xsd: "http://www.w3.org/2001/XMLSchema#" ) # Add prefixes prefixes = RDF.PrefixMap.new() |> RDF.PrefixMap.add(:ex, "http://example.com/") |> RDF.PrefixMap.add(:foaf, ~I) # Resolve prefixed name to IRI RDF.PrefixMap.prefixed_name_to_iri(prefixes, "ex:person") # => {:ok, ~I} # Convert IRI to prefixed name RDF.PrefixMap.prefixed_name(prefixes, ~I) # => {:ok, "ex:john"} # Merge prefix maps other_prefixes = RDF.PrefixMap.new(rdfs: "http://www.w3.org/2000/01/rdf-schema#") merged = RDF.PrefixMap.merge(prefixes, other_prefixes) # Generate Turtle prefix declarations RDF.PrefixMap.to_turtle(prefixes) # => "@prefix ex: .\n@prefix foaf: ..." # Generate SPARQL prefix declarations RDF.PrefixMap.to_sparql(prefixes) # => "PREFIX ex: \nPREFIX foaf: ..." # Default prefixes (configurable via application config) RDF.default_prefixes() # => %RDF.PrefixMap{xsd: ..., rdf: ..., rdfs: ...} ``` -------------------------------- ### Create Blank Nodes with RDF.ex Sigils and Functions Source: https://context7.com/rdf-elixir/rdf-ex/llms.txt Explains how to create blank nodes, which represent anonymous resources, using the `~B` sigil for convenience and the `RDF.bnode` function for programmatic creation. Supports both identified and anonymous blank nodes. ```elixir import RDF.Sigils # Create blank node using sigil bnode = ~B # Create blank node programmatically with an identifier bnode = RDF.bnode("my_blank_node") # => %RDF.BlankNode{value: "my_blank_node"} # Create anonymous blank node (auto-generated identifier) bnode = RDF.bnode() # => %RDF.BlankNode{value: "b0"} # or similar auto-generated id # Check if a value is a blank node RDF.bnode?(~B) # => true RDF.bnode?(~I) # => false ``` -------------------------------- ### Move Datatype Constructors to RDF.XSD Namespace Source: https://github.com/rdf-elixir/rdf-ex/wiki/Upgrading-to-RDF.ex-0.8 Demonstrates how to update code that previously used top-level datatype constructors (e.g., RDF.Decimal.new) to the new RDF.XSD namespace. This change affects how you access and construct literals for various XSD datatypes. ```elixir alias RDF.XSD XSD.Decimal.new(3.14) XSD.decimal(3.14) ``` -------------------------------- ### Create IRIs with RDF.ex Sigils and Functions Source: https://context7.com/rdf-elixir/rdf-ex/llms.txt Demonstrates creating Internationalized Resource Identifiers (IRIs) using the `~I` sigil for compile-time validation and the `RDF.IRI` module for programmatic creation and manipulation. Supports validation, parsing URI components, and merging relative IRIs. ```elixir import RDF.Sigils # Create IRIs using the sigil subject = ~I predicate = ~I # Create IRI programmatically iri = RDF.IRI.new("http://example.com/resource") # => %RDF.IRI{value: "http://example.com/resource"} # Create IRI with validation (raises on invalid IRI) iri = RDF.IRI.new!("http://example.com/valid") # Check if a value is a valid IRI RDF.IRI.valid?("http://example.com/resource") # => true RDF.IRI.valid?("not a valid iri") # => false # Parse IRI components uri_struct = RDF.IRI.parse(~I) # => %URI{scheme: "http", host: "example.com", path: "/path", ...} # Merge IRIs (resolve relative against base) RDF.IRI.merge(~I, "relative/path") # => %RDF.IRI{value: "http://example.com/base/relative/path"} ``` -------------------------------- ### Read RDF Data from Files, Strings, and Streams Source: https://context7.com/rdf-elixir/rdf-ex/llms.txt Demonstrates how to read RDF data from gzipped files, N-Triples formatted strings, and Turtle formatted streams using RDF.ex. It covers the `RDF.read_file`, `RDF.read_string`, and `RDF.read_stream` functions. ```elixir ```elixir # Read gzipped file {:ok, graph} = RDF.read_file("data.ttl.gz", gzip: true) # Read N-Triples ntriples = """ "John Doe" . "30"^^ . """ {:ok, graph} = RDF.read_string(ntriples, format: :ntriples) # Read from a stream stream = File.stream!("large_data.ttl") {:ok, graph} = RDF.read_stream(stream, format: :turtle) ``` ``` -------------------------------- ### Query RDF Graphs using Basic Graph Patterns (BGP) Source: https://context7.com/rdf-elixir/rdf-ex/llms.txt Explains how to perform queries on RDF graphs using Basic Graph Patterns (BGP) in RDF.ex. It covers simple variable matching, multi-pattern queries for implicit joins, and streaming results for large datasets. ```elixir ```elixir import RDF.Sigils # Create a sample graph graph = RDF.Graph.new([ {~I, ~I, "John Doe"}, {~I, ~I, ~I}, {~I, ~I, "Jane Smith"}, {~I, ~I, RDF.XSD.integer(25)} ]) # Simple query: find all names {:ok, results} = RDF.Query.execute( {:_, ~I, :name?}, graph ) # => {:ok, [%{name: ~L"John Doe"}, %{name: ~L"Jane Smith"}]} # Query with multiple patterns (implicit join) {:ok, results} = RDF.Query.execute([ {:person?, ~I, :name?}, {:person?, ~I, :friend?} ], graph) # => {:ok, [%{person: ~I, name: ~L"John Doe", friend: ~I}]} # Bang version returns results directly results = RDF.Query.execute!({:_, ~I, :name?}, graph) # Streaming query results for large graphs {:ok, stream} = RDF.Query.stream({:_, ~I, :name?}, graph) Enum.each(stream, fn %{name: name} -> IO.puts("Found: #{RDF.Literal.value(name)}") end) # Path query: follow a chain of predicates {:ok, results} = RDF.Query.path([ ~I, ~I, ~I, :friend_name? ]) |> RDF.Query.execute(graph) # => {:ok, [%{friend_name: ~L"Jane Smith"}]} # Using Graph.query as pipeline-friendly alternative results = graph |> RDF.Graph.query({:_, ~I, :name?}) # => [%{name: ~L"John Doe"}, %{name: ~L"Jane Smith"}] ``` ``` -------------------------------- ### Write RDF Data to Various Formats Source: https://context7.com/rdf-elixir/rdf-ex/llms.txt Shows how to serialize RDF graphs into different formats like Turtle, N-Triples, and N-Quads, both to strings and files. It highlights automatic prefix handling, explicit format specification, and gzipped output. ```elixir ```elixir import RDF.Sigils # Create a graph to serialize graph = RDF.Graph.new([ {~I, ~I, "John Doe"}, {~I, ~I, RDF.XSD.integer(30)} ], prefixes: [ ex: "http://example.com/", foaf: "http://xmlns.com/foaf/0.1/", xsd: "http://www.w3.org/2001/XMLSchema#" ]) # Write to Turtle string {:ok, turtle} = RDF.write_string(graph, format: :turtle) # => {:ok, "@prefix ex: .\n@prefix foaf: ..."} # Write with bang version turtle = RDF.write_string!(graph, format: :turtle) # Write to file (format auto-detected from extension) :ok = RDF.write_file(graph, "output.ttl") # Write to file with explicit format and options :ok = RDF.write_file(graph, "output.rdf", format: :turtle, force: true) # Write gzipped file :ok = RDF.write_file(graph, "output.ttl.gz", gzip: true) # Write N-Triples (no prefix support) {:ok, ntriples} = RDF.write_string(graph, format: :ntriples) # => {:ok, " \"John Doe\" .\n..."} # Write N-Quads (for datasets) dataset = RDF.Dataset.new(graph) {:ok, nquads} = RDF.write_string(dataset, format: :nquads) # Stream output for large graphs stream = RDF.write_stream(graph, format: :ntriples) Enum.each(stream, &IO.write/1) ``` ``` -------------------------------- ### Define and Use Vocabulary Namespaces Source: https://context7.com/rdf-elixir/rdf-ex/llms.txt Illustrates how to define custom vocabulary namespaces using `RDF.Vocabulary.Namespace`. This allows for compile-time checked access to RDF vocabulary terms as Elixir atoms, with automatic IRI resolution. ```elixir ```elixir # Define a custom vocabulary namespace defmodule MyApp.NS do use RDF.Vocabulary.Namespace # Strict vocabulary from a file defvocab Schema, base_iri: "http://schema.org/", file: "priv/vocabs/schema.ttl" # Non-strict vocabulary allows any term defvocab EX, base_iri: "http://example.com/", terms: [], strict: false # Vocabulary with explicit terms defvocab Custom, base_iri: "http://custom.example/", terms: [:Person, :name, :email, :knows] end ``` ``` -------------------------------- ### Create Literals with RDF.ex Sigils and Functions Source: https://context7.com/rdf-elixir/rdf-ex/llms.txt Details the creation of RDF literals, representing data values like strings, numbers, and dates. Covers using the `~L` sigil, automatic XSD datatype inference from Elixir types, and programmatic creation with explicit datatypes or language tags. Includes accessing literal properties. ```elixir import RDF.Sigils # Create plain string literals using sigil lit = ~L"Hello World" # => %RDF.Literal{literal: %RDF.XSD.String{value: "Hello World"}} # Create language-tagged literals lit_en = ~L"Hello"en lit_de = ~L"Hallo"de # Create literals programmatically with automatic type inference RDF.literal("string value") # => xsd:string RDF.literal(42) # => xsd:integer RDF.literal(3.14) # => xsd:double RDF.literal(true) # => xsd:boolean RDF.literal(~D[2024-01-15]) # => xsd:date RDF.literal(~T[14:30:00]) # => xsd:time # Create literal with explicit datatype RDF.literal("42", datatype: RDF.NS.XSD.integer) # => %RDF.Literal{literal: %RDF.XSD.Integer{value: 42}} # Create language-tagged literal RDF.literal("Hello", language: "en") # => %RDF.Literal{literal: %RDF.LangString{value: "Hello", language: "en"}} # Access literal properties lit = RDF.XSD.integer(42) RDF.Literal.value(lit) # => 42 RDF.Literal.lexical(lit) # => "42" RDF.Literal.datatype_id(lit) # => ~I RDF.Literal.valid?(lit) # => true ``` -------------------------------- ### Graph Canonicalization in Elixir Source: https://context7.com/rdf-elixir/rdf-ex/llms.txt Details how to use RDF.ex for graph canonicalization, a process essential for comparing graphs with blank nodes and generating consistent hashes. It covers checking graph isomorphism and generating canonical representations. ```elixir import RDF.Sigils # Create graphs with blank nodes graph1 = RDF.Graph.new([ {~B, ~I, ~B}, {~B, ~I, 42} ]) graph2 = RDF.Graph.new([ {~B, ~I, ~B}, {~B, ~I, 42} ]) # Check if graphs are isomorphic (structurally equivalent) RDF.Graph.isomorphic?(graph1, graph2) # => true (same structure, different blank node names) # Canonicalize a graph (rename blank nodes consistently) canonical = RDF.Graph.canonicalize(graph1) # Blank nodes are renamed to c14n0, c14n1, etc. # => RDF.Graph.new([{~B, ~I, ~B}, ...]) # Generate a canonical hash for comparison hash1 = RDF.Graph.canonical_hash(graph1) hash2 = RDF.Graph.canonical_hash(graph2) hash1 == hash2 # => true (isomorphic graphs have the same canonical hash) # Canonicalize entire datasets dataset = RDF.Dataset.new(graph1) {canonicalized_dataset, state} = RDF.Canonicalization.canonicalize(dataset) # state contains the blank node identifier mappings ``` -------------------------------- ### RDF-star Support in Elixir Source: https://context7.com/rdf-elixir/rdf-ex/llms.txt Demonstrates how to create and manipulate RDF-star graphs in Elixir. RDF-star allows statements to be made about other statements, enabling annotations and provenance tracking. This includes creating base triples, annotating them, retrieving annotations, and serializing to Turtle-star format. ```elixir import RDF.Sigils # Create a base triple base_triple = {~I, ~I, ~I} # Create a graph with RDF-star annotations graph = RDF.Graph.new([ base_triple, # Annotate the triple itself (triple as subject) {base_triple, ~I, "social_network"}, {base_triple, ~I, RDF.XSD.decimal("0.95")} ]) # Add annotations using helper functions graph = RDF.Graph.new(base_triple) |> RDF.Graph.add_annotations(base_triple, { ~I, ~I }) # Get annotations for statements annotations = RDF.Graph.annotations(graph) # Returns a graph containing only annotation triples # Get graph without annotations base_graph = RDF.Graph.without_annotations(graph) # Serialize RDF-star to Turtle-star {:ok, turtle_star} = RDF.write_string(graph, format: :turtle) # Produces: <> foaf:knows > ex:source "social_network" . ``` -------------------------------- ### Read RDF Serializations from File Source: https://context7.com/rdf-elixir/rdf-ex/llms.txt Demonstrates reading RDF data from files using `RDF.read_file`. The function can auto-detect the format from the file extension or accept an explicit format. It returns `{:ok, graph}` on success. ```elixir # Read from file (format auto-detected from extension) {:ok, graph} = RDF.read_file("data.ttl") # Read from file with explicit format {:ok, graph} = RDF.read_file("data.rdf", format: :turtle) ``` -------------------------------- ### Pattern Matching on RDF.Literal Datatypes Source: https://github.com/rdf-elixir/rdf-ex/wiki/Upgrading-to-RDF.ex-0.8 Shows how the updated `RDF.Literal` structure allows for direct pattern matching on the datatype. This enables more idiomatic Elixir code by replacing conditional checks with dedicated function clauses for different literal types. ```elixir def fun(%RDF.Literal{literal: %XSD.Integer{}} = literal) do # ... end ``` -------------------------------- ### Migrate Triple Elements to Tuple for RDF.Graph.add Source: https://github.com/rdf-elixir/rdf-ex/wiki/Upgrading-to-RDF.ex-0.9 Demonstrates how to adapt calls to RDF.Graph.add when providing triple elements. Previously, elements could be passed as separate arguments; now they must be wrapped in a tuple. This change affects `new`, `add`, `put`, `delete`, and `include?` functions across `RDF.Description`, `RDF.Graph`, and `RDF.Dataset`. ```elixir RDF.Graph.add(graph, EX.S, EX.p, EX.o) ``` ```elixir RDF.Graph.add(graph, {EX.S, EX.p, EX.o}) ``` -------------------------------- ### Handling Language Tag for String Literals Source: https://github.com/rdf-elixir/rdf-ex/wiki/Upgrading-to-RDF.ex-0.8 Details the changes to the `language` option for string literals. The `String.new/2` constructor no longer supports the `language` option directly. Use `RDF.LangString.new/2` or `RDF.Literal.new/2` instead. Additionally, `RDF.Literal.new/2` now enforces valid language tags, preventing empty or `nil` values. ```elixir # Old way (no longer supported) # RDF.String.new("hello", language: "en") # New way RDF.LangString.new("hello", "en") # or RDF.Literal.new("hello", datatype: RDF.LangString, language: "en") ``` -------------------------------- ### Aggregate RDF.Dataset to RDF.Graph for Turtle Encoding (Elixir) Source: https://github.com/rdf-elixir/rdf-ex/wiki/Upgrading-to-RDF.ex-0.10 Demonstrates the updated method for encoding an RDF.Dataset to Turtle format. Previously, RDF.Turtle.Encoder directly supported datasets. Now, datasets must be aggregated into an RDF.Graph before encoding. This involves extracting graphs from the dataset and reducing them into a new graph. ```elixir dataset |> RDF.Dataset.graphs() |> Enum.reduce(RDF.graph(), &RDF.Graph.add(&2, &1)) |> RDF.Turtle.to_string() ``` -------------------------------- ### Migrate Query Pattern Format for RDF.Graph.query Source: https://github.com/rdf-elixir/rdf-ex/wiki/Upgrading-to-RDF.ex-0.9 Shows the revised format for Basic Graph Pattern (BGP) query patterns in `RDF.Graph.query`. Multiple objects must now be in a list, and multiple predicate-object pairs for the same subject should be represented as a list of tuples or maps. This change aligns query patterns with RDF statement input formats. ```elixir RDF.Graph.query(graph, [ {:s?, [EX.p2, :o?], [EX.p3, 42, 3.14, true] }, {:o?, EX.p, "foo", "bar"}, ]) ``` ```elixir RDF.Graph.query(graph, [ {:s?, [ {EX.p2, :o?}, {EX.p3, [42, 3.14, true]} ]}, {:o?, EX.p, ["foo", "bar"]}, ]) ``` ```elixir property_map = %{p1: EX.p1(), p2: EX.p2(), p3: EX.p3()} RDF.Graph.query(graph, %{ s?: %{ p2: :o?, p3: [42, 3.14, true] }, o?: %{p: ["foo", "bar"]}, }, context: property_map ) ``` -------------------------------- ### Centralized Higher-Level Literal Functions in RDF.Literal Source: https://github.com/rdf-elixir/rdf-ex/wiki/Upgrading-to-RDF.ex-0.8 Explains that higher-level functions like `matches?`, `less_than?`, and `greater_than?` have been moved from datatype-specific modules (e.g., `RDF.String`) to the general `RDF.Literal` module. This change consolidates common literal operations. ```elixir RDF.Literal.matches?(literal, pattern) ```