{"id":13514588,"url":"https://github.com/ruby-rdf/json-ld","last_synced_at":"2026-04-07T17:31:37.072Z","repository":{"id":1474748,"uuid":"1717192","full_name":"ruby-rdf/json-ld","owner":"ruby-rdf","description":"Ruby JSON-LD reader/writer for RDF.rb","archived":false,"fork":false,"pushed_at":"2025-05-19T16:33:07.000Z","size":9202,"stargazers_count":243,"open_issues_count":2,"forks_count":27,"subscribers_count":25,"default_branch":"develop","last_synced_at":"2026-03-15T14:03:52.489Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"unlicense","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ruby-rdf.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":"AUTHORS","dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2011-05-07T23:52:16.000Z","updated_at":"2025-10-18T08:26:22.000Z","dependencies_parsed_at":"2024-06-18T13:45:53.910Z","dependency_job_id":"5913a206-9c43-44a3-8804-a0d6e19cded5","html_url":"https://github.com/ruby-rdf/json-ld","commit_stats":{"total_commits":1082,"total_committers":10,"mean_commits":108.2,"dds":0.4861367837338263,"last_synced_commit":"32d4deb5743ea5126f3e52d15d8d3e0d3d754d1d"},"previous_names":[],"tags_count":78,"template":false,"template_full_name":null,"purl":"pkg:github/ruby-rdf/json-ld","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ruby-rdf%2Fjson-ld","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ruby-rdf%2Fjson-ld/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ruby-rdf%2Fjson-ld/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ruby-rdf%2Fjson-ld/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ruby-rdf","download_url":"https://codeload.github.com/ruby-rdf/json-ld/tar.gz/refs/heads/develop","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ruby-rdf%2Fjson-ld/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31522235,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-07T16:28:08.000Z","status":"ssl_error","status_checked_at":"2026-04-07T16:28:06.951Z","response_time":105,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T05:00:58.144Z","updated_at":"2026-04-07T17:31:37.042Z","avatar_url":"https://github.com/ruby-rdf.png","language":"HTML","funding_links":[],"categories":["HTML"],"sub_categories":[],"readme":"# JSON-LD reader/writer\n\n[JSON-LD][] reader/writer for [RDF.rb][RDF.rb] and fully conforming [JSON-LD API][] processor. Additionally this gem implements [JSON-LD Framing][].\n\n[![Gem Version](https://badge.fury.io/rb/json-ld.svg)](https://rubygems.org/gems/json-ld)\n[![Build Status](https://github.com/ruby-rdf/json-ld/actions/workflows/ci.yml/badge.svg)](https://github.com/ruby-rdf/json-ld/actions?query=workflow%3ACI)\n[![Coverage Status](https://coveralls.io/repos/ruby-rdf/json-ld/badge.svg?branch=develop)](https://coveralls.io/github/ruby-rdf/json-ld?branch=develop)\n[![Gitter chat](https://badges.gitter.im/ruby-rdf.png)](https://gitter.im/gitterHQ/gitter)\n\n## Features\n\nJSON::LD parses and serializes [JSON-LD][] into [RDF][] and implements expansion, compaction and framing API interfaces. It also extracts JSON-LD from HTML.\n\nJSON::LD can now be used to create a _context_ from an RDFS/OWL definition, and optionally include a JSON-LD representation of the ontology itself. This is currently accessed through the `script/gen_context` script.\n\n* If the [jsonlint][] gem is installed, it will be used when validating an input document.\n* If available, uses [Nokogiri][] for parsing HTML, falls back to REXML otherwise.\n* Provisional support for [JSON-LD-star][JSON-LD-star].\n\n[Implementation Report](https://ruby-rdf.github.io/json-ld/etc/earl.html)\n\nInstall with `gem install json-ld`\n\n### JSON-LD Streaming Profile\nThis gem implements an optimized streaming reader used for generating RDF from large dataset dumps formatted as JSON-LD. Such documents must correspond to the [JSON-LD Streaming Profile](https://w3c.github.io/json-ld-streaming/):\n\n* Keys in JSON objects must be ordered with any of `@context`, and/or `@type` coming before any other keys, in that order. This includes aliases of those keys. It is strongly encouraged that `@id` be present, and come immediately after.\n* JSON-LD documents can be signaled or requested in [streaming document form](https://w3c.github.io/json-ld-streaming/#dfn-streaming-document-form). The profile URI identifying the [streaming document form](https://w3c.github.io/json-ld-streaming/#dfn-streaming-document-form) is `http://www.w3.org/ns/json-ld#streaming`.\n\nThis gem also implements an optimized streaming writer used for generating JSON-LD from large repositories. Such documents result in the JSON-LD Streaming Profile:\n\n* Each statement written as a separate node in expanded/flattened form.\n* `RDF List`s are written as separate nodes using `rdf:first` and `rdf:rest` properties.\n\nThe order of triples retrieved from the `RDF::Enumerable` dataset determines the way that JSON-LD node objects are written; for best results, statements should be ordered by _graph name_, _subject_, _predicate_ and _object_.\n\n### MultiJson parser\nThe [MultiJson](https://rubygems.org/gems/multi_json) gem is used for parsing and serializing JSON; this defaults to the native JSON parser/serializer, but will use a more performant parser if one is available. A specific parser can be specified by adding the `:adapter` option to any API call. Additionally, a custom serialilzer may be specified by passing the `:serializer` option to {JSON::LD::Writer} or methods of {JSON::LD::API}. See [MultiJson](https://rubygems.org/gems/multi_json) for more information.\n\n### JSON-LD-star (RDFStar)\n\nThe {JSON::LD::API.expand}, {JSON::LD::API.compact}, {JSON::LD::API.toRdf}, and {JSON::LD::API.fromRdf} API methods, along with the {JSON::LD::Reader} and {JSON::LD::Writer}, include provisional support for [JSON-LD-star][JSON-LD-star].\n\nInternally, an `RDF::Statement` is treated as another resource, along with `RDF::URI` and `RDF::Node`, which allows an `RDF::Statement` to have a `#subject` or `#object` which is also an `RDF::Statement`.\n\nIn JSON-LD, with the `rdfstar` option set, the value of `@id`, in addition to an IRI or Blank Node Identifier, can be a JSON-LD node object having exactly one property with an optional `@id`, which may also be an embedded object. (It may also have `@context` and `@index` values).\n\n    {\n      \"@id\": {\n        \"@context\": {\"foaf\": \"http://xmlns.com/foaf/0.1/\"},\n        \"@index\": \"ignored\",\n        \"@id\": \"bob\",\n        \"foaf:age\" 23\n      },\n      \"ex:certainty\": 0.9\n    }\n\nAdditionally, the `@annotation` property (or alias) may be used on a node object or value object to annotate the statement for which the associated node is the object of a triple.\n\n    {\n      \"@context\": {\"foaf\": \"http://xmlns.com/foaf/0.1/\"},\n      \"@id\": \"bob\",\n      \"foaf:age\" 23,\n      \"@annotation\": {\n        \"ex:certainty\": 0.9\n      }\n    }\n\nIn the first case, the embedded node is not asserted, and only appears as the subject of a triple. In the second case, the triple is asserted and used as the subject in another statement which annotates it.\n\n**Note: This feature is subject to change or elimination as the standards process progresses.**\n\n#### Serializing a Graph containing embedded statements\n\n    require 'json/ld'\n    statement = RDF::Statement(RDF::URI('bob'), RDF::Vocab::FOAF.age, RDF::Literal(23))\n    graph = RDF::Graph.new \u003c\u003c [statement, RDF::URI(\"ex:certainty\"), RDF::Literal(0.9)]\n    graph.dump(:jsonld, validate: false, standard_prefixes: true)\n    # =\u003e {\"@id\": {\"@id\": \"bob\", \"foaf:age\" 23}, \"ex:certainty\": 0.9}\n\nAlternatively, using the {JSON::LD::API.fromRdf} method:\n\n    JSON::LD::API::fromRdf(graph)\n    # =\u003e {\"@id\": {\"@id\": \"bob\", \"foaf:age\" 23}, \"ex:certainty\": 0.9}\n\n#### Reading a Graph containing embedded statements\n\nBy default, {JSON::LD::API.toRdf} (and {JSON::LD::Reader}) will reject a document containing a subject resource.\n\n    jsonld = %({\n      \"@id\": {\n        \"@id\": \"bob\", \"foaf:age\" 23\n      },\n      \"ex:certainty\": 0.9\n    })\n    graph = RDF::Graph.new \u003c\u003c JSON::LD::API.toRdf(input)\n    # =\u003e JSON::LD::JsonLdError::InvalidIdValue\n\n{JSON::LD::API.toRdf} (and {JSON::LD::Reader}) support a boolean valued `rdfstar` option; only one statement is asserted, although the reified statement is contained within the graph.\n\n    graph = RDF::Graph.new do |graph|\n      JSON::LD::Reader.new(jsonld, rdfstar: true) {|reader| graph \u003c\u003c reader}\n    end\n    graph.count #=\u003e 1\n\n## Examples\n\n```ruby\nrequire 'rubygems'\nrequire 'json/ld'\n ```\n\n### Expand a Document\n\n```ruby\n   input = JSON.parse %({\n      \"@context\": {\n        \"name\": \"http://xmlns.com/foaf/0.1/name\",\n        \"homepage\": \"http://xmlns.com/foaf/0.1/homepage\",\n        \"avatar\": \"http://xmlns.com/foaf/0.1/avatar\"\n      },\n      \"name\": \"Manu Sporny\",\n      \"homepage\": \"http://manu.sporny.org/\",\n      \"avatar\": \"http://twitter.com/account/profile_image/manusporny\"\n    })\n    JSON::LD::API.expand(input) =\u003e\n    \n    [{\n        \"http://xmlns.com/foaf/0.1/name\": [{\"@value\"=\u003e\"Manu Sporny\"}],\n        \"http://xmlns.com/foaf/0.1/homepage\": [{\"@value\"=\u003e\"https://manu.sporny.org/\"}], \n        \"http://xmlns.com/foaf/0.1/avatar\": [{\"@value\": \"https://twitter.com/account/profile_image/manusporny\"}]\n    }]\n```\n\n### Compact a Document\n\n    input = JSON.parse %([{\n        \"http://xmlns.com/foaf/0.1/name\": [\"Manu Sporny\"],\n        \"http://xmlns.com/foaf/0.1/homepage\": [{\"@id\": \"https://manu.sporny.org/\"}],\n        \"http://xmlns.com/foaf/0.1/avatar\": [{\"@id\": \"https://twitter.com/account/profile_image/manusporny\"}]\n    }])\n    \n    context = JSON.parse(%({\n      \"@context\": {\n        \"name\": \"http://xmlns.com/foaf/0.1/name\",\n        \"homepage\": {\"@id\": \"http://xmlns.com/foaf/0.1/homepage\", \"@type\": \"@id\"},\n        \"avatar\": {\"@id\": \"http://xmlns.com/foaf/0.1/avatar\", \"@type\": \"@id\"}\n      }\n    }))['@context']\n    \n    JSON::LD::API.compact(input, context) =\u003e\n    {\n        \"@context\": {\n          \"name\": \"http://xmlns.com/foaf/0.1/name\",\n          \"homepage\": {\"@id\": \"http://xmlns.com/foaf/0.1/homepage\", \"@type\": \"@id\"},\n          \"avatar\": {\"@id\": \"http://xmlns.com/foaf/0.1/avatar\", \"@type\": \"@id\"}\n        },\n        \"avatar\": \"https://twitter.com/account/profile_image/manusporny\",\n        \"homepage\": \"https://manu.sporny.org/\",\n        \"name\": \"Manu Sporny\"\n    }\n\n### Frame a Document\n\n    input = JSON.parse %({\n      \"@context\": {\n        \"Book\":         \"http://example.org/vocab#Book\",\n        \"Chapter\":      \"http://example.org/vocab#Chapter\",\n        \"contains\":     {\"@id\": \"http://example.org/vocab#contains\", \"@type\": \"@id\"},\n        \"creator\":      \"http://purl.org/dc/terms/creator\",\n        \"description\":  \"http://purl.org/dc/terms/description\",\n        \"Library\":      \"http://example.org/vocab#Library\",\n        \"title\":        \"http://purl.org/dc/terms/title\"\n      },\n      \"@graph\":\n      [{\n        \"@id\": \"http://example.com/library\",\n        \"@type\": \"Library\",\n        \"contains\": \"http://example.org/library/the-republic\"\n      },\n      {\n        \"@id\": \"http://example.org/library/the-republic\",\n        \"@type\": \"Book\",\n        \"creator\": \"Plato\",\n        \"title\": \"The Republic\",\n        \"contains\": \"http://example.org/library/the-republic#introduction\"\n      },\n      {\n        \"@id\": \"http://example.org/library/the-republic#introduction\",\n        \"@type\": \"Chapter\",\n        \"description\": \"An introductory chapter on The Republic.\",\n        \"title\": \"The Introduction\"\n      }]\n    })\n    \n    frame = JSON.parse %({\n      \"@context\": {\n        \"Book\":         \"http://example.org/vocab#Book\",\n        \"Chapter\":      \"http://example.org/vocab#Chapter\",\n        \"contains\":     \"http://example.org/vocab#contains\",\n        \"creator\":      \"http://purl.org/dc/terms/creator\",\n        \"description\":  \"http://purl.org/dc/terms/description\",\n        \"Library\":      \"http://example.org/vocab#Library\",\n        \"title\":        \"http://purl.org/dc/terms/title\"\n      },\n      \"@type\": \"Library\",\n      \"contains\": {\n        \"@type\": \"Book\",\n        \"contains\": {\n          \"@type\": \"Chapter\"\n        }\n      }\n    })\n\n    JSON::LD::API.frame(input, frame) =\u003e\n    {\n      \"@context\": {\n        \"Book\": \"http://example.org/vocab#Book\",\n        \"Chapter\": \"http://example.org/vocab#Chapter\",\n        \"contains\": \"http://example.org/vocab#contains\",\n        \"creator\": \"http://purl.org/dc/terms/creator\",\n        \"description\": \"http://purl.org/dc/terms/description\",\n        \"Library\": \"http://example.org/vocab#Library\",\n        \"title\": \"http://purl.org/dc/terms/title\"\n      },\n      \"@graph\": [\n        {\n          \"@id\": \"http://example.com/library\",\n          \"@type\": \"Library\",\n          \"contains\": {\n            \"@id\": \"http://example.org/library/the-republic\",\n            \"@type\": \"Book\",\n            \"contains\": {\n              \"@id\": \"http://example.org/library/the-republic#introduction\",\n              \"@type\": \"Chapter\",\n              \"description\": \"An introductory chapter on The Republic.\",\n              \"title\": \"The Introduction\"\n            },\n            \"creator\": \"Plato\",\n            \"title\": \"The Republic\"\n          }\n        }\n      ]\n    }\n\n### Turn JSON-LD into RDF (Turtle)\n\n    input = JSON.parse %({\n      \"@context\": {\n        \"\":       \"https://manu.sporny.org/\",\n        \"foaf\":   \"http://xmlns.com/foaf/0.1/\"\n      },\n      \"@id\":       \"http://example.org/people#joebob\",\n      \"@type\":          \"foaf:Person\",\n      \"foaf:name\":      \"Joe Bob\",\n      \"foaf:nick\":      { \"@list\": [ \"joe\", \"bob\", \"jaybe\" ] }\n    })\n    \n    graph = RDF::Graph.new \u003c\u003c JSON::LD::API.toRdf(input)\n\n    require 'rdf/turtle'\n    graph.dump(:ttl, prefixes: {foaf: \"http://xmlns.com/foaf/0.1/\"})\n    @prefix foaf: \u003chttp://xmlns.com/foaf/0.1/\u003e .\n\n    \u003chttp://example.org/people#joebob\u003e a foaf:Person;\n       foaf:name \"Joe Bob\";\n       foaf:nick (\"joe\" \"bob\" \"jaybe\") .\n\n### Turn RDF into JSON-LD\n\n    require 'rdf/turtle'\n    input = RDF::Graph.new \u003c\u003c RDF::Turtle::Reader.new(%(\n      @prefix foaf: \u003chttp://xmlns.com/foaf/0.1/\u003e .\n\n      \u003chttps://manu.sporny.org/#me\u003e a foaf:Person;\n         foaf:knows [ a foaf:Person;\n           foaf:name \"Gregg Kellogg\"];\n         foaf:name \"Manu Sporny\" .\n    ))\n    \n    context = JSON.parse %({\n      \"@context\": {\n        \"\":       \"https://manu.sporny.org/\",\n        \"foaf\":   \"http://xmlns.com/foaf/0.1/\"\n      }\n    })\n\n    compacted = nil\n    JSON::LD::API::fromRdf(input) do |expanded|\n      compacted = JSON::LD::API.compact(expanded, context['@context'])\n    end\n    compacted =\u003e\n      [\n        {\n          \"@id\": \"_:g70265766605380\",\n          \"@type\": [\"http://xmlns.com/foaf/0.1/Person\"],\n          \"http://xmlns.com/foaf/0.1/name\": [{\"@value\": \"Gregg Kellogg\"}]\n        },\n        {\n          \"@id\": \"https://manu.sporny.org/#me\",\n          \"@type\": [\"http://xmlns.com/foaf/0.1/Person\"],\n          \"http://xmlns.com/foaf/0.1/knows\": [{\"@id\": \"_:g70265766605380\"}],\n          \"http://xmlns.com/foaf/0.1/name\": [{\"@value\": \"Manu Sporny\"}]\n        }\n      ]\n\n## Use a custom Document Loader\nIn some cases, the built-in document loader {JSON::LD::API.documentLoader} is inadequate; for example, when using `http://schema.org` as a remote context, it will be re-loaded every time (however, see [json-ld-preloaded](https://rubygems.org/gems/json-ld-preloaded)).\n\nAll entries into the {JSON::LD::API} accept a `:documentLoader` option, which can be used to provide an alternative method to use when loading remote documents. For example:\n\n```ruby\nload_document_local = Proc.new do |url, **options, \u0026block|\n  if RDF::URI(url, canonicalize: true) == RDF::URI('http://schema.org/')\n    remote_document = JSON::LD::API::RemoteDocument.new(url, File.read(\"etc/schema.org.jsonld\"))\n    return block_given? ? yield(remote_document) : remote_document\n  else\n    JSON::LD::API.documentLoader(url, options, \u0026block)\n  end\nend\n\n```\nThen, when performing something like expansion:\n\n```ruby\nJSON::LD::API.expand(input, documentLoader: load_document_local)\n```\n\n## Preloading contexts\nIn many cases, for small documents, processing time can be dominated by loading and parsing remote contexts. In particular, a small schema.org example may need to download a large context and turn it into an internal representation, before the actual document can be expanded for processing. Using {JSON::LD::Context.add_preloaded}, an implementation can perform this loading up-front, and make it available to the processor.\n\n```ruby\n    ctx = JSON::LD::Context.new().parse('http://schema.org/')\n    JSON::LD::Context.add_preloaded('http://schema.org/', ctx)\n ```\n\nOn lookup, URIs with an `https` prefix are normalized to `http`.\n\nA context may be serialized to Ruby to speed this process using `Context#to_rb`. When loaded, this generated file will add entries to the {JSON::LD::Context::PRELOADED}.\n\n## RDF Reader and Writer\n{JSON::LD} also acts as a normal RDF reader and writer, using the standard RDF.rb reader/writer interfaces:\n\n```ruby\n    graph = RDF::Graph.load(\"etc/doap.jsonld\", format: :jsonld)\n    graph.dump(:jsonld, standard_prefixes: true)\n```\n\n`RDF::GRAPH#dump` can also take a `:context` option to use a separately defined context\n\nAs JSON-LD may come from many different sources, included as an embedded script tag within an HTML document, the RDF Reader will strip input before the leading `{` or `[` and after the trailing `}` or `]`.\n\n## Extensions from JSON-LD 1.0\nThis implementation is being used as a test-bed for features planned for an upcoming JSON-LD 1.1 Community release.\n\n### Scoped Contexts\nA term definition can include `@context`, which is applied to values of that object. This is also used when compacting. Taken together, this allows framing to effectively include context definitions more deeply within the framed structure.\n\n    {\n      \"@context\": {\n        \"ex\": \"http://example.com/\",\n        \"foo\": {\n          \"@id\": \"ex:foo\",\n          \"@type\": \"@vocab\"\n          \"@context\": {\n            \"Bar\": \"ex:Bar\",\n            \"Baz\": \"ex:Baz\"\n          }\n        }\n      },\n      \"foo\": \"Bar\"\n    }\n\n### @id and @type maps\nThe value of `@container` in a term definition can include `@id` or `@type`, in addition to `@set`, `@list`, `@language`, and `@index`. This allows value indexing based on either the `@id` or `@type` of associated objects.\n\n    {\n      \"@context\": {\n        \"@vocab\": \"http://example/\",\n        \"idmap\": {\"@container\": \"@id\"}\n      },\n      \"idmap\": {\n        \"http://example.org/foo\": {\"label\": \"Object with @id \u003cfoo\u003e\"},\n        \"_:bar\": {\"label\": \"Object with @id _:bar\"}\n      }\n    }\n\n### @graph containers and maps\nA term can have `@container` set to include `@graph` optionally including `@id` or `@index` and `@set`. In the first form, with `@container` set to `@graph`, the value of a property is treated as a _simple graph object_, meaning that values treated as if they were contained in an object with `@graph`, creating _named graph_ with an anonymous name.\n\n    {\n      \"@context\": {\n        \"@vocab\": \"http://example.org/\",\n        \"input\": {\"@container\": \"@graph\"}\n      },\n      \"input\": {\n        \"value\": \"x\"\n      }\n    }\n\nwhich expands to the following:\n\n    [{\n      \"http://example.org/input\": [{\n        \"@graph\": [{\n          \"http://example.org/value\": [{\"@value\": \"x\"}]\n        }]\n      }]\n    }]\n\nCompaction reverses this process, optionally ensuring that a single value is contained within an array of `@container` also includes `@set`:\n\n    {\n      \"@context\": {\n        \"@vocab\": \"http://example.org/\",\n        \"input\": {\"@container\": [\"@graph\", \"@set\"]}\n      }\n    }\n\nA graph map uses the map form already existing for `@index`, `@language`, `@type`, and `@id` where the index is either an index value or an id.\n\n    {\n      \"@context\": {\n        \"@vocab\": \"http://example.org/\",\n        \"input\": {\"@container\": [\"@graph\", \"@index\"]}\n      },\n      \"input\": {\n        \"g1\": {\"value\": \"x\"}\n      }\n    }\n\ntreats \"g1\" as an index, and expands to the following:\n\n    [{\n      \"http://example.org/input\": [{\n        \"@index\": \"g1\",\n        \"@graph\": [{\n          \"http://example.org/value\": [{\"@value\": \"x\"}]\n        }]\n      }]\n    }])\n\nThis can also include `@set` to ensure that, when compacting, a single value of an index will be in array form.\n\nThe _id_ version is similar:\n\n    {\n      \"@context\": {\n        \"@vocab\": \"http://example.org/\",\n        \"input\": {\"@container\": [\"@graph\", \"@id\"]}\n      },\n      \"input\": {\n        \"http://example.com/g1\": {\"value\": \"x\"}\n      }\n    }\n\nwhich expands to:\n\n    [{\n      \"http://example.org/input\": [{\n        \"@id\": \"http://example.com/g1\",\n        \"@graph\": [{\n          \"http://example.org/value\": [{\"@value\": \"x\"}]\n        }]\n      }]\n    }])\n\n### Transparent Nesting\nMany JSON APIs separate properties from their entities using an intermediate object. For example, a set of possible labels may be grouped under a common property:\n\n    {\n      \"@context\": {\n        \"skos\": \"http://www.w3.org/2004/02/skos/core#\",\n        \"labels\": \"@nest\",\n        \"main_label\": {\"@id\": \"skos:prefLabel\"},\n        \"other_label\": {\"@id\": \"skos:altLabel\"},\n        \"homepage\": {\"@id\":\"http://schema.org/description\", \"@type\":\"@id\"}\n      },\n      \"@id\":\"http://example.org/myresource\",\n      \"homepage\": \"http://example.org\",\n      \"labels\": {\n         \"main_label\": \"This is the main label for my resource\",\n         \"other_label\": \"This is the other label\"\n      }\n    }\n \n In this case, the `labels` property is semantically meaningless. Defining it as equivalent to `@nest` causes it to be ignored when expanding, making it equivalent to the following:\n\n    {\n      \"@context\": {\n        \"skos\": \"http://www.w3.org/2004/02/skos/core#\",\n        \"labels\": \"@nest\",\n        \"main_label\": {\"@id\": \"skos:prefLabel\"},\n        \"other_label\": {\"@id\": \"skos:altLabel\"},\n        \"homepage\": {\"@id\":\"http://schema.org/description\", \"@type\":\"@id\"}\n      },\n      \"@id\":\"http://example.org/myresource\",\n      \"homepage\": \"http://example.org\",\n      \"main_label\": \"This is the main label for my resource\",\n      \"other_label\": \"This is the other label\"\n    }\n \n Similarly, properties may be marked with \"@nest\": \"nest-term\", to cause them to be nested. Note that the `@nest` keyword can also be aliased in the context.\n\n     {\n       \"@context\": {\n         \"skos\": \"http://www.w3.org/2004/02/skos/core#\",\n         \"labels\": \"@nest\",\n         \"main_label\": {\"@id\": \"skos:prefLabel\", \"@nest\": \"labels\"},\n         \"other_label\": {\"@id\": \"skos:altLabel\", \"@nest\": \"labels\"},\n         \"homepage\": {\"@id\":\"http://schema.org/description\", \"@type\":\"@id\"}\n       },\n       \"@id\":\"http://example.org/myresource\",\n       \"homepage\": \"http://example.org\",\n       \"labels\": {\n          \"main_label\": \"This is the main label for my resource\",\n          \"other_label\": \"This is the other label\"\n       }\n     }\n\nIn this way, nesting survives round-tripping through expansion, and framed output can include nested properties.\n\n## Sinatra/Rack support\nJSON-LD 1.1 describes support for the _profile_ parameter to a media type in an HTTP ACCEPT header. This allows an HTTP request to specify the format (expanded/compacted/flattened/framed) along with a reference to a context or frame to use to format the returned document.\n\nAn HTTP header may be constructed as follows:\n\n    GET /ordinary-json-document.json HTTP/1.1\n    Host: example.com\n    Accept: application/ld+json;profile=\"http://www.w3.org/ns/json-ld#compacted http://conneg.example.com/context\", application/ld+json\n\nThis tells a server that the top priority is to return JSON-LD compacted using a context at `http://conneg.example.com/context`, and if not available, to just return any form of JSON-LD.\n\nThe {JSON::LD::ContentNegotiation} class provides a [Rack][Rack] `call` method, and [Sinatra][Sinatra] `registered` class method to allow content-negotiation using such profile parameters. For example:\n\n    #!/usr/bin/env rackup\n    require 'sinatra/base'\n    require 'json/ld'\n    \n    module My\n      class Application \u003c Sinatra::Base\n        register JSON::LD::ContentNegotiation\n    \n        get '/hello' do\n          [{\n            \"http://example.org/input\": [{\n              \"@id\": \"http://example.com/g1\",\n              \"@graph\": [{\n                \"http://example.org/value\": [{\"@value\": \"x\"}]\n              }]\n            }]\n          }])\n        end\n      end\n    end\n    \n    run My::Application\n\nThe {JSON::LD::ContentNegotiation#call} method looks for a result which includes an object, with an acceptable `Accept` header and formats the result as JSON-LD, considering the profile parameters. This can be tested using something like the following:\n\n    $ rackup config.ru\n    \n    $ curl -iH 'Accept: application/ld+json;profile=\"http://www.w3.org/ns/json-ld#compacted http://conneg.example.com/context\"' http://localhost:9292/hello\n\nSee [Rack::LinkedData][] to do the same thing with an RDF Graph or Dataset as the source, rather than Ruby objects.\n\n## Documentation\nFull documentation available on [RubyDoc](https://ruby-rdf.github.io/json-ld/file/README.md)\n\n## Differences from [JSON-LD API][]\nThe specified JSON-LD API is based on a WebIDL definition implementing [Promises][] intended for use within a browser.\nThis version implements a more Ruby-like variation of this API without the use\nof promises or callback arguments, preferring Ruby blocks. All API methods\nexecute synchronously, so that the return from a method can typically be used as well as a block.\n\nNote, the API method signatures differed in versions before 1.0, in that they also had a callback parameter. And 1.0.6 has some other minor method signature differences than previous versions. This should be the only exception to the use of semantic versioning.\n\n### Principal Classes\n* {JSON::LD}\n  * {JSON::LD::API}\n  * {JSON::LD::Compact}\n  * {JSON::LD::Context}\n  * {JSON::LD::Format}\n  * {JSON::LD::Frame}\n  * {JSON::LD::FromRDF}\n  * {JSON::LD::Reader}\n  * {JSON::LD::ToRDF}\n  * {JSON::LD::Writer}\n\n## Dependencies\n* [Ruby](https://ruby-lang.org/) (\u003e= 3.0)\n* [RDF.rb](https://rubygems.org/gems/rdf) (~\u003e 3.3)\n* [JSON](https://rubygems.org/gems/json) (\u003e= 2.6)\n\n## Installation\nThe recommended installation method is via [RubyGems](https://rubygems.org/).\nTo install the latest official release of the `JSON-LD` gem, do:\n\n    % [sudo] gem install json-ld\n\n## Download\nTo get a local working copy of the development repository, do:\n\n    % git clone git://github.com/ruby-rdf/json-ld.git\n\n## Change Log\n\nSee [Release Notes on GitHub](https://github.com/ruby-rdf/json-ld/releases)\n\n## Mailing List\n* \u003chttps://lists.w3.org/Archives/Public/public-rdf-ruby/\u003e\n\n## Author\n* [Gregg Kellogg](https://github.com/gkellogg) - \u003chttps://greggkellogg.net/\u003e\n\n## Contributing\n* Do your best to adhere to the existing coding conventions and idioms.\n* Don't use hard tabs, and don't leave trailing whitespace on any line.\n* Do document every method you add using [YARD][] annotations. Read the\n  [tutorial][YARD-GS] or just look at the existing code for examples.\n* Don't touch the `json-ld.gemspec`, `VERSION` or `AUTHORS` files. If you need to\n  change them, do so on your private branch only.\n* Do feel free to add yourself to the `CREDITS` file and the corresponding\n  list in the the `README`. Alphabetical order applies.\n* Do note that in order for us to merge any non-trivial changes (as a rule\n  of thumb, additions larger than about 15 lines of code), we need an\n  explicit [public domain dedication][PDD] on record from you,\n  which you will be asked to agree to on the first commit to a repo within the organization.\n  Note that the agreement applies to all repos in the [Ruby RDF](https://github.com/ruby-rdf/) organization.\n\n## License\n\nThis is free and unencumbered public domain software. For more information,\nsee \u003chttps://unlicense.org/\u003e or the accompanying {file:UNLICENSE} file.\n\n[Ruby]:             https://ruby-lang.org/\n[RDF]:              https://www.w3.org/RDF/\n[YARD]:             https://yardoc.org/\n[YARD-GS]:          https://rubydoc.info/docs/yard/file/docs/GettingStarted.md\n[PDD]:              https://unlicense.org/#unlicensing-contributions\n[RDF.rb]:           https://rubygems.org/gems/rdf\n[JSON-LD-star]:             https://json-ld.github.io/json-ld-star/\n[Rack::LinkedData]: https://rubygems.org/gems/rack-linkeddata\n[Backports]:        https://rubygems.org/gems/backports\n[JSON-LD]:          https://www.w3.org/TR/json-ld11/ \"JSON-LD 1.1\"\n[JSON-LD API]:      https://www.w3.org/TR/json-ld11-api/ \"JSON-LD 1.1 Processing Algorithms and API\"\n[JSON-LD Framing]:  https://www.w3.org/TR/json-ld11-framing/ \"JSON-LD 1.1 Framing\"\n[Promises]:         https://dom.spec.whatwg.org/#promises\n[jsonlint]:         https://rubygems.org/gems/jsonlint\n[Sinatra]:          https://www.sinatrarb.com/\n[Rack]:             https://rack.github.com/\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fruby-rdf%2Fjson-ld","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fruby-rdf%2Fjson-ld","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fruby-rdf%2Fjson-ld/lists"}