CINXE.COM

Clean JSON(-LD) from RDF using Framing - Sparna Blog

<!DOCTYPE html> <html lang="fr-FR" prefix="og: http://ogp.me/ns#"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Clean JSON(-LD) from RDF using Framing - Sparna Blog</title> <link rel="pingback" href="https://blog.sparna.fr/xmlrpc.php"> <!--[if lt IE 9]> <script src="https://blog.sparna.fr/wp-content/themes/wpex-luxmag/js/plugins/html5.js"></script> <![endif]--> <!-- This site is optimized with the Yoast WordPress SEO plugin v2.2.1 - https://yoast.com/wordpress/plugins/seo/ --> <meta name="robots" content="noindex,follow"/> <link rel="canonical" href="https://blog.sparna.fr/2022/07/20/clean-json-ld-from-rdf-using-framing/" /> <meta property="og:locale" content="fr_FR" /> <meta property="og:type" content="article" /> <meta property="og:title" content="Clean JSON(-LD) from RDF using Framing - Sparna Blog" /> <meta property="og:description" content="Say you have a nice RDF knowledge graph based on an ontology, or maybe reusing ontologies, and maybe you have specified the structure of the knowledge graph with SHACL. And now you would like to expose your RDF in JSON in an API, for the average developer (or maybe you would like to produce a&hellip;" /> <meta property="og:url" content="https://blog.sparna.fr/2022/07/20/clean-json-ld-from-rdf-using-framing/" /> <meta property="og:site_name" content="Sparna Blog" /> <meta property="article:tag" content="Framing" /> <meta property="article:tag" content="json-ld" /> <meta property="article:tag" content="RDF" /> <meta property="article:section" content="Linked Data" /> <meta property="article:published_time" content="2022-07-20T07:56:36+00:00" /> <meta property="og:image" content="https://blog.sparna.fr/wp-content/uploads/2022/07/Encadrement_ornemental_1er_état___...Mignon_Jean_btv1b53230250h_1.jpg" /> <meta name="twitter:card" content="summary"/> <meta name="twitter:description" content="Say you have a nice RDF knowledge graph based on an ontology, or maybe reusing ontologies, and maybe you have specified the structure of the knowledge graph with SHACL. And now you would like to expose your RDF in JSON in an API, for the average developer (or maybe you would like to produce a&hellip;"/> <meta name="twitter:title" content="Clean JSON(-LD) from RDF using Framing - Sparna Blog"/> <meta name="twitter:domain" content="Sparna Blog"/> <meta name="twitter:image:src" content="https://blog.sparna.fr/wp-content/uploads/2022/07/Encadrement_ornemental_1er_état___...Mignon_Jean_btv1b53230250h_1.jpg"/> <!-- / Yoast WordPress SEO plugin. --> <link rel="alternate" type="application/rss+xml" title="Sparna Blog &raquo; Flux" href="https://blog.sparna.fr/feed/" /> <link rel="alternate" type="application/rss+xml" title="Sparna Blog &raquo; Flux des commentaires" href="https://blog.sparna.fr/comments/feed/" /> <link rel="alternate" type="application/rss+xml" title="Sparna Blog &raquo; Clean JSON(-LD) from RDF using Framing Flux des commentaires" href="https://blog.sparna.fr/2022/07/20/clean-json-ld-from-rdf-using-framing/feed/" /> <script type="text/javascript"> window._wpemojiSettings = {"baseUrl":"https:\/\/s.w.org\/images\/core\/emoji\/72x72\/","ext":".png","source":{"concatemoji":"https:\/\/blog.sparna.fr\/wp-includes\/js\/wp-emoji-release.min.js?ver=4.2.38"}}; !function(e,n,t){var a;function o(e){var t=n.createElement("canvas"),a=t.getContext&&t.getContext("2d");return!(!a||!a.fillText)&&(a.textBaseline="top",a.font="600 32px Arial","flag"===e?(a.fillText(String.fromCharCode(55356,56812,55356,56807),0,0),3e3<t.toDataURL().length):(a.fillText(String.fromCharCode(55357,56835),0,0),0!==a.getImageData(16,16,1,1).data[0]))}function i(e){var t=n.createElement("script");t.src=e,t.type="text/javascript",n.getElementsByTagName("head")[0].appendChild(t)}t.supports={simple:o("simple"),flag:o("flag")},t.DOMReady=!1,t.readyCallback=function(){t.DOMReady=!0},t.supports.simple&&t.supports.flag||(a=function(){t.readyCallback()},n.addEventListener?(n.addEventListener("DOMContentLoaded",a,!1),e.addEventListener("load",a,!1)):(e.attachEvent("onload",a),n.attachEvent("onreadystatechange",function(){"complete"===n.readyState&&t.readyCallback()})),(a=t.source||{}).concatemoji?i(a.concatemoji):a.wpemoji&&a.twemoji&&(i(a.twemoji),i(a.wpemoji)))}(window,document,window._wpemojiSettings); </script> <style type="text/css"> img.wp-smiley, img.emoji { display: inline !important; border: none !important; box-shadow: none !important; height: 1em !important; width: 1em !important; margin: 0 .07em !important; vertical-align: -0.1em !important; background: none !important; padding: 0 !important; } </style> <link rel='stylesheet' id='symple_shortcode_styles-css' href='https://blog.sparna.fr/wp-content/plugins/symple-shortcodes/shortcodes/css/symple_shortcodes_styles.css?ver=4.2.38' type='text/css' media='all' /> <link rel='stylesheet' id='wpex-style-css' href='https://blog.sparna.fr/wp-content/themes/wpex-luxmag/style.css?ver=4.2.38' type='text/css' media='all' /> <link rel='stylesheet' id='wpex-google-font-source-sans-pro-css' href='http://fonts.googleapis.com/css?family=Source+Sans+Pro%3A300%2C400%2C600%2C700&#038;subset=latin%2Cvietnamese%2Clatin-ext&#038;ver=4.2.38' type='text/css' media='all' /> <link rel='stylesheet' id='jetpack_social_media_icons_widget-css' href='https://blog.sparna.fr/wp-content/plugins/jetpack/modules/widgets/social-media-icons/style.css?ver=20150602' type='text/css' media='all' /> <link rel='stylesheet' id='genericons-css' href='https://blog.sparna.fr/wp-content/plugins/jetpack/_inc/genericons/genericons/genericons.css?ver=3.1' type='text/css' media='all' /> <link rel='stylesheet' id='jetpack_css-css' href='https://blog.sparna.fr/wp-content/plugins/jetpack/css/jetpack.css?ver=3.6.4' type='text/css' media='all' /> <script type='text/javascript' src='https://blog.sparna.fr/wp-includes/js/jquery/jquery.js?ver=1.11.2'></script> <script type='text/javascript' src='https://blog.sparna.fr/wp-includes/js/jquery/jquery-migrate.min.js?ver=1.2.1'></script> <link rel="EditURI" type="application/rsd+xml" title="RSD" href="https://blog.sparna.fr/xmlrpc.php?rsd" /> <link rel="wlwmanifest" type="application/wlwmanifest+xml" href="https://blog.sparna.fr/wp-includes/wlwmanifest.xml" /> <link rel='shortlink' href='https://wp.me/p55RD1-nA' /> <meta name='robots' content='noindex,follow' /> <style type='text/css'>img#wpstats{display:none}</style><!-- Theme Customizer Styling Options --> <style type="text/css"> #header-wrap{ padding-top:0 !important; }#header-wrap{ padding-bottom:0 !important; }.author-badge{ color:#ffffff !important; } </style><style type="text/css" id="custom-background-css"> body.custom-background { background-color: #f9f9f9; } </style> <style id="custom-css-css">body{font-size:16px}</style> </head> <body class="single single-post postid-1462 single-format-standard custom-background symple-shortcodes symple-shortcodes-responsive wpex-theme responsive default-skin right-sidebar entry-columns-3 with-sidebar"> <div id="wrap" class="clr"> <div id="header-wrap" class="clr"> <header id="header" class="site-header clr container" role="banner"> <div class="site-branding clr"> <div id="logo" class="clr"> <a href="https://blog.sparna.fr" title="Sparna Blog" rel="home"><img src="http://blog.sparna.fr/wp-content/uploads/2015/04/header2.jpg" alt="Sparna Blog" /></a> </div><!-- #logo --> <div id="blog-description" class="clr"> Web de données | Architecture de l&#039;information | Accès aux connaissances </div><!-- #blog-description --> </div><!-- .site-branding --> <div class="site-social clr"><a href="https://fr.linkedin.com/in/thomasfrancart" title="LinkedIn" target="_blank"><i class="fa fa-linkedin"></i></a><a href="http://blog.sparna.fr/feed" title="RSS" target="_blank"><i class="fa fa-rss"></i></a></div> </header><!-- #header --> </div><!-- #header-wrap --> <div id="site-navigation-wrap" class="clr "> <div id="site-navigation-inner" class="clr"> <nav id="site-navigation" class="navigation main-navigation clr container" role="navigation"> <a href="#mobile-nav" class="navigation-toggle"><span class="fa fa-bars navigation-toggle-icon"></span><span class="navigation-toggle-text">Click here to navigate</span></a> <div class="menu-menu-container"><ul id="menu-menu" class="main-nav dropdown-menu sf-menu"><li id="menu-item-1009" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-1009"><a href="http://blog.sparna.fr">Accueil</a></li> <li id="menu-item-1008" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-has-children dropdown menu-item-1008"><a href="#">Thèmes</a> <ul class="sub-menu"> <li id="menu-item-1002" class="menu-item menu-item-type-taxonomy menu-item-object-category current-post-ancestor current-menu-parent current-post-parent menu-item-1002"><a href="https://blog.sparna.fr/category/theme/linked-data/">Linked Data</a></li> <li id="menu-item-1004" class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-1004"><a href="https://blog.sparna.fr/category/theme/opendata/">Open Data</a></li> <li id="menu-item-1003" class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-1003"><a href="https://blog.sparna.fr/category/theme/ontologies-theme/">Ontologies</a></li> <li id="menu-item-1005" class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-1005"><a href="https://blog.sparna.fr/category/theme/recherche-informations/">Recherche d&rsquo;informations</a></li> <li id="menu-item-1006" class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-1006"><a href="https://blog.sparna.fr/category/theme/thesaurus-theme/">Thesaurus</a></li> <li id="menu-item-1007" class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-1007"><a href="https://blog.sparna.fr/category/theme/visualisation-de-donnees/">Visualisation de données</a></li> </ul> </li> <li id="menu-item-1019" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-has-children dropdown menu-item-1019"><a href="#">Outils</a> <ul class="sub-menu"> <li id="menu-item-1013" class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-1013"><a href="https://blog.sparna.fr/category/outils/triplestores/">Triplestores</a></li> <li id="menu-item-1010" class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-1010"><a href="https://blog.sparna.fr/category/outils/editeurs/">Editeurs</a></li> <li id="menu-item-1011" class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-1011"><a href="https://blog.sparna.fr/category/outils/moteurs-de-recherche/">Moteurs de recherche</a></li> <li id="menu-item-1012" class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-1012"><a href="https://blog.sparna.fr/category/outils/skos-play-outils/">SKOS Play</a></li> </ul> </li> <li id="menu-item-1020" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-has-children dropdown menu-item-1020"><a href="#">Technologies</a> <ul class="sub-menu"> <li id="menu-item-1015" class="menu-item menu-item-type-taxonomy menu-item-object-category current-post-ancestor current-menu-parent current-post-parent menu-item-1015"><a href="https://blog.sparna.fr/category/technologie/rdf/">RDF</a></li> <li id="menu-item-1018" class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-1018"><a href="https://blog.sparna.fr/category/technologie/sparql-technologies/">SPARQL</a></li> <li id="menu-item-1014" class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-1014"><a href="https://blog.sparna.fr/category/technologie/owl/">OWL</a></li> <li id="menu-item-1017" class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-1017"><a href="https://blog.sparna.fr/category/technologie/skos-technologies/">SKOS</a></li> <li id="menu-item-1016" class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-1016"><a href="https://blog.sparna.fr/category/technologie/schema-org-technologies/">Schema.org</a></li> </ul> </li> <li id="menu-item-1024" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-has-children dropdown menu-item-1024"><a href="#">Autres</a> <ul class="sub-menu"> <li id="menu-item-1023" class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-1023"><a href="https://blog.sparna.fr/category/projets/">Projets</a></li> <li id="menu-item-1022" class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-1022"><a href="https://blog.sparna.fr/category/evenements/">Evénements</a></li> <li id="menu-item-1021" class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-1021"><a href="https://blog.sparna.fr/category/et/">Et&#8230;</a></li> </ul> </li> <li id="menu-item-1025" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-1025"><a href="http://sparna.fr">sparna.fr</a></li> </ul></div> <a href="#" class="header-search-icon" title="Search"> <span class="fa fa-search"></span> </a><!-- .header-search-icon --> </nav><!-- #site-navigation --> </div><!-- #site-navigation-inner --> </div><!-- #site-navigation-wrap --> <div class="site-main-wrap clr"> <div id="main" class="site-main clr container"> <div class="search-overlay clr"> <form method="get" id="searchform" class="overlay-searchform" action="https://blog.sparna.fr/" role="search"> <input type="search" class="field" name="s" id="s" value="To search type and hit enter" onfocus="if(this.value==this.defaultValue)this.value='';" onblur="if(this.value=='')this.value=this.defaultValue;" autocomplete="off" /> </form> </div><!-- .search-overlay --> <div id="primary" class="content-area clr"> <div id="content" class="site-content left-content boxed-content clr" role="main"> <article class="single-post-article clr"> <div class="single-post-media clr"> <div class="post-thumbnail"> <img src="https://blog.sparna.fr/wp-content/uploads/2022/07/Encadrement_ornemental_1er_état___...Mignon_Jean_btv1b53230250h_1-650x450.jpg" alt="Clean JSON(-LD) from RDF using Framing" width="650" height="450" /> </div><!-- .post-thumbnail --> </div><!-- .single-post-media --> <header class="post-header clr"> <div class="post-meta clr"> <div class="post-meta-date"> <span class="fa fa-clock-o"></span>20 juillet 2022 </div> <div class="post-meta-author"> <span class="fa fa-user"></span><a href="https://blog.sparna.fr/author/thomas/" title="Articles par Thomas Francart" rel="author">Thomas Francart</a> </div> <div class="post-meta-category"> <span class="fa fa-folder"></span><a href="https://blog.sparna.fr/category/theme/linked-data/">Linked Data</a>, <a href="https://blog.sparna.fr/category/technologie/rdf/">RDF</a>, <a href="https://blog.sparna.fr/category/outils/shacl-play/">SHACL Play</a> </div> <div class="post-meta-comments"> <span class="fa fa-comments"></span><a href="https://blog.sparna.fr/2022/07/20/clean-json-ld-from-rdf-using-framing/#comments">7 commentaires <span class="screen-reader-text"> sur Clean JSON(-LD) from RDF using Framing</span></a> </div> </div><!-- .post-meta --> <h1 class="post-header-title">Clean JSON(-LD) from RDF using Framing</h1> </header><!-- .page-header --> <div class="entry clr"> <p>Say you have a nice RDF knowledge graph based on an ontology, or maybe reusing ontologies, and maybe you have specified the structure of the knowledge graph with SHACL. And now you would like to <strong>expose your RDF in JSON</strong> in an API, for the average developer (or maybe you would like to produce a clean JSON to be indexed by Elastic). And the average developer (or Elastic) does not care about RDF and does not care about the “-LD” in “JSON-LD”, he just cares about JSON; and he is right ! we are here to care about the “-LD” part for him.</p> <p>So what you need is to produce a clean JSON structure from your raw RDF triples. And when I mean “clean”, I mean :</p> <ul> <li><strong>no URIs</strong>. Nowhere. No URIs in JSON keys, No URIs in types of entities, no URIs in the value of properties controlled by a closed list; the only places where it is acceptable to see a URI are : to give the id of the entities, and when making a reference to such an id of entity within the graph; even in these cases the URIs can be shortened.</li> <li><strong>no fancy JSON-LD keys</strong> like @type, @value, @datatype, @id, etc.</li> <li><strong>indented</strong>.</li> </ul> <p>You have 2 possibilities to do that :</p> <ol> <li>You develop a custom script, to either generate a JSON export of your data, or to implement the API that will query the knowledge graph, parse the triples, and generate that clean JSON output.</li> <li>You use <strong><a href="https://www.w3.org/TR/json-ld11-framing/">JSON-LD framing</a> to automate the production of a clean JSON(-LD) from RDF</strong>.</li> </ol> <p>There are 2 nice things about the solution with JSON-LD framing :</p> <ol> <li>it can be automated</li> <li>you automatically retain the RDF compatibility &#8211; because your JSON will necessarily be JSON-LD. This means you can import your nice JSON directly in a triplestore.</li> </ol> <p>The principle of JSON-LD framing is that you provide a <a href="https://www.w3.org/TR/json-ld/#the-context">JSON-LD @context </a>with an additionnal <a href="https://www.w3.org/TR/json-ld11-framing/#framing">frame specification</a> that defines how the JSON should be structured (indented), which entity to include at each level (entities can be filtered based on some criteria), and also which properties to include in each entity.</p> <p>To start with JSON-LD framing, what you need is JSON-LD. Any JSON-LD. Typically the raw JSON-LD serialization that any RDF library or triplestore will produce; that kind of ugly, messy, full-of-URIs-and-@language kind of JSON. So something like:</p> <p><a href="http://blog.sparna.fr/wp-content/uploads/2022/07/Capture-d’écran-du-2022-07-19-17-30-45.png"><img class="aligncenter size-large wp-image-1465" src="http://blog.sparna.fr/wp-content/uploads/2022/07/Capture-d’écran-du-2022-07-19-17-30-45-1024x658.png" alt="Capture d’écran du 2022-07-19 17-30-45" width="650" height="418" /></a></p> <p><em>(Brrr, scary, no ?)</em></p> <p>And then what you need is the <a href="https://json-ld.org/playground/">JSON-LD playground</a> with the “Framed” tab. This will allow you to test your context and frame specification.</p> <p>And when deployed in production, what you will need is a JSON-LD library that is capable of implementing the JSON-LD framing algorithm. Implementations are listed <a href="https://json-ld.org/#developers">here</a>, and you need an implementation compatible with JSON-LD 1.1.</p> <h2>Example files</h2> <p>As an example, I use a JSON-LD file from the French National Library, the one from Les Misérables here : <a href="https://data.bnf.fr/fr/13516296/victor_hugo_les_miserables/">https://data.bnf.fr/fr/13516296/victor_hugo_les_miserables/</a> (download link at the bottom of the page).</p> <p><strong>You can download <a href="http://blog.sparna.fr/wp-content/uploads/2022/07/les_miserables_jsonld_framing_example.zip">the initial JSON example, the frame specification, and the result in a zip</a>.</strong> The zip also contains intermediate frame specifications.</p> <h2>The @context</h2> <p>We&rsquo;ll start by specifying the JSON-LD context part.</p> <h3><b>Map @type to type and @id to id</b></h3> <p>Average developer will wonder what are those @type and @id keys. Re-map them straight away to type and id:</p> <blockquote><p><code>"type" : "@type",<br /> "id" : "@id",<br /> </code></p></blockquote> <p>Schema.org and lot of other specifications do that.</p> <h3><b>What about @graph ?<br /> </b></h3> <p>If you have a named graph at the top, introduced by @graph, my suggestion would be to simply remap it to a fixed key, like &laquo;&nbsp;data&nbsp;&raquo;, or &laquo;&nbsp;entities&nbsp;&raquo; :</p> <blockquote><p><code>"data" : "@graph",<br /> </code></p></blockquote> <h3><b>Map RDF properties URIs to JSON keys</b></h3> <p>Get rid of any trace of URI or short URIs in JSON keys. Declare a term for every property in your graph. The simplest way to do this is to use the local part of the URI (after last “#” or “/”) as the term. Order the context by the alphabetical order of the terms. Terms for properties will usually start with a lowercase letter.</p> <p>In corner cases you may end up with the same term (such as in the example bnf-onto:subject and dcterms:subject), so in that case you need a different key, I chose “bnf-subject” here for bnf-onto:subject and kept “subject” for dcterms:subject.</p> <blockquote><p><code>"creator" : "dcterms:creator",<br /> "date" : "dcterms:date",<br /> "dateOfWork" : "rdagroup1elements:dateOfWork",<br /> "depiction" : "foaf:depiction",<br /> "description" : "dcterms:description",<br /> </code></p></blockquote> <h3><b>Map classes URIs to JSON terms</b></h3> <p>Now you want to do the same thing to get rid of any trace of URIs in the “type” of entities. Declare a term for every class in your ontology/application profile. List the classes in a different section than the properties. Terms for classes will usually start with an uppercase.</p> <blockquote><p><code>"Concept" : "skos:Concept",<br /> "Document" : "foaf:Document",<br /> "ExpositionVirtuelle" : "bnf-onto:ExpositionVirtuelle",<br /> </code></p></blockquote> <h3> <b>Declare object properties with “@type”: “@id”</b></h3> <p>Now you want to get rid of all those ugly “id”, we are only interested in listing the values. To do that, modify the mapping of the property (here “depiction”) to state its values are URIs. You need to change the mapping from</p> <blockquote><p><code>"depiction" : "foaf:depiction",</code></p></blockquote> <p>to</p> <blockquote><p><code>"depiction" : { "@value" : "foaf:depiction", "@type":"@id" },</code></p></blockquote> <p>And so parts like this :</p> <blockquote><p><code>"depiction": [<br /> {<br /> "id": "https://gallica.bnf.fr/ark:/12148/btv1b8438568p.thumbnail"<br /> },<br /> {<br /> "id": "https://gallica.bnf.fr/ark:/12148/btv1b9004781d.thumbnail"<br /> },<br /> {<br /> "id": "https://gallica.bnf.fr/ark:/12148/bpt6k5545348q.thumbnail"<br /> }<br /> ]</code></p></blockquote> <p>Will be turned into</p> <blockquote><p><code> "depiction": [<br /> "https://gallica.bnf.fr/ark:/12148/btv1b8438568p.thumbnail",<br /> "https://gallica.bnf.fr/ark:/12148/btv1b9004781d.thumbnail",<br /> "https://gallica.bnf.fr/ark:/12148/bpt6k5545348q.thumbnail",<br /> "https://gallica.bnf.fr/ark:/12148/btv1b8438570r.thumbnail"<br /> ]</code></p></blockquote> <h3><b>Map datatypes</b></h3> <p>Now you want to get rid of the @datatype information for literals. If the value of a property always uses the same datatype, which is the case 99,9% of the time, then you can change the mapping from</p> <blockquote><p><code>"property" : "http://myproperty",</code></p></blockquote> <p>to</p> <blockquote><p><code>"property" : { “@id”: "http://myproperty", “@type”:”xsd:date” }</code></p></blockquote> <p>(The example used does not have datatype properties.)</p> <h3><b>Map languages, with fixed language or when multilingual</b></h3> <p>Now let’s get rid of the @language. For this you have 2 choices : when the language is always the same for the value, you can indicate it in the context, the same way that you would do for the datatype but with the @language key. So you change from</p> <blockquote><p><code>"description" : "dcterms:description",</code></p></blockquote> <p>to</p> <blockquote><p><code>"description" : { “@id” : "dcterms:description", “@language” : “fr” }</code></p></blockquote> <p>You could even have different terms for different languages, such as :</p> <blockquote><p><code>"title_fr" : { "@id" : "dcterms:title", "@language" : "fr" },<br /> "title_en" : { "@id" : "dcterms:title", "@language" : "en" },<br /> "title" : { "@id" : "dcterms:title" },</code></p></blockquote> <p>or when you have multilingual multiple values, you can make the property a language map by declaring it this way:</p> <blockquote><p><code>"editorialNote" : { "@id" : "skos:editorialNote", "@container" : "@language" },</code></p></blockquote> <p>Which will turn the language code as a key in the JSON output:</p> <blockquote><p><code>"editorialNote": {<br /> "fr": [<br /> "BN Cat. gén. (sous : Hugo, comte Victor-Marie) : Les misérables. - . - BN Cat. gén. 1960-1969 (sous : Hugo, Victor) : idem. - . -",<br /> "Laffont-Bompiani, Oeuvres, 1994. - . - GDEL. - . -"<br /> ] },</code></p></blockquote> <p>In that case, watch out for cases where there is a value without language, it will generate a @none key.</p> <h3><b>Map controlled list values to JSON terms</b></h3> <p>By now you already get a much cleaner JSON and almost all “unnecessary” URIs have disappeared. But we still have some URI references that we can clean up : the ones that are references to controlled lists with a finite number of values.</p> <p>We can declare term mappings for those values just like we did to map properties and classes. BUT &#8211; and this is the trick, <strong>we need to change the property declaration from “@id” to “@vocab” for the replacement to happen</strong>. This is documented in the <a href="https://www.w3.org/TR/json-ld/#type-coercion">&laquo;&nbsp;Type coercion&nbsp;&raquo; section of the spec</a>.</p> <p>In our example, the mapping to languages and subjects are good candidates to be mapped to JSON terms. So we change</p> <blockquote><p><code>"language" : { "@id" : "dcterms:language", "@type":"@id" },<br /> "subject" : { "@id" : "dcterms:subject", "@type":"@id" },<br /> </code></p></blockquote> <p>to</p> <blockquote><p><code>"language" : { "@id" : "dcterms:language", "@type":"@vocab" },<br /> "subject" : { "@id" : "dcterms:subject", "@type":"@vocab" },<br /> “fre” : “http://id.loc.gov/vocabulary/iso639-2/fre”,<br /> “eng” : “http://id.loc.gov/vocabulary/iso639-2/eng”,</code></p></blockquote> <h3><b>Shorten remaining URI references<br /> </b></h3> <p>Now the only URIs left are the ids of the main entities in our graph, and references to those ids. Reference to controlled vocabularies with a limited number of values have been mapped to JSON terms. Although we cannot turn all the remaining URIs to JSON terms (because we can&rsquo;t declare all possible entity URIs in the context), we can shorten them by adding a prefix mapping in the context, in our case:</p> <blockquote><p><code>"ark-https": "https://data.bnf.fr/ark:/12148/",<br /> </code></p></blockquote> <p>(I note that there are http:// and https:// URIs in the data, I don&rsquo;t know why)</p> <p>&nbsp;</p> <h2>The frame specification</h2> <p>So now we have clean values, no URIs, no fancy JSON-LD keys. But we still don’t have a structure indented the way the average developer would expect it; and this is where the frame specification comes into play.</p> <h3><b>Define indentation and filters (and reverse properties if needed)<br /> </b></h3> <p>The frame specification acts as both a filter/selection mechanism and as a structure definition. At each level you indicate the criterias for the object to be included. In our example we have a skos:Concept (the entry in the library catalog) that is foaf:focus a Work (the Book &laquo;&nbsp;in the real world&nbsp;&raquo;), and that skos:Concept is the subject of many virtual exhibits. We want to have the Concept and the Work at first level, and under the concept the exhibits. But there is a trick : it is the virtual exhibits that points to the concept with a dcterms:subject, and we want it the other direction : Concept is_subject_of Exhibit, so we need a @reverse property.</p> <p>To do that, add the following reverse mapping declaration: (don&rsquo;t modify the existing one):</p> <blockquote><p><code>"subject_of" : { "@reverse" : "dcterms:subject" },</code></p></blockquote> <p>Note the use of &laquo;&nbsp;@reverse&nbsp;&raquo; to indicate that JSON key is to be interpreted from object to subject when turned into triples.</p> <p>With that in place, we can write our frame specification, which goes right after the @context we have designed before:</p> <blockquote><p><code>"type" : ["Concept", "Work"],<br /> "subject_of" : {<br /> "type" : "ExpositionVirtuelle"<br /> }</code></p></blockquote> <p>Note how we use the terms defined in the context previously. This is to be understood the following way : <em>&laquo;&nbsp;at the first level, take any entity with a type of either Concept or Work, then insert a subject_of key and put inside any value that has a type ExpositionVirtuelle&nbsp;&raquo;</em>. This garantees the virtual exhibits objects will go under the Concept, and not above or at the same level. But this is not sufficient, as you will notice if you apply that framing that the Work is <strong>repeated</strong> under the &laquo;&nbsp;focus&nbsp;&raquo; property of the Concept, and at the root level. This is because of the default behavior of the JSON-LD playground regarding <a href="https://www.w3.org/TR/json-ld11-framing/#object-embed-flag">object embedding</a> (objects are always embeded when they are referenced)</p> <h3><b>Avoid embedding</b></h3> <p>To avoid embedding when it is undesired, we can set the &laquo;&nbsp;@embed&nbsp;&raquo; option to &laquo;&nbsp;@never&nbsp;&raquo; on the &laquo;&nbsp;focus&nbsp;&raquo; property, like so :</p> <blockquote><p><code>"type" : ["Concept", "Work"],<br /> "subject_of" : {<br /> "type" : "ExpositionVirtuelle"<br /> },<br /> "focus" : {<br /> "@embed" : "@never",<br /> "@omitDefault": true<br /> }<br /> </code></p></blockquote> <p>This tells the framing algorithm to never embed the complete entity inside the focus property, just reference the URI instead.</p> <p>Also, you will notice the use of &laquo;&nbsp;@omitDefault&nbsp;&raquo; to true; this tells the framing algorithm to omit the focus property when it has no value. Otherwise, since the Work does not have a foaf:focus property (only the Concept), then it will get a &laquo;&nbsp;focus&nbsp;&raquo; key set to null.</p> <h3><b>What about order of keys in the JSON ?</b></h3> <p>Well, I am sure this can be controlled, either by specifying explicitely all the keys you want, in the order you want them, in the frame specification, or by using an &laquo;&nbsp;ordered&nbsp;&raquo; parameter to the JSON-LD API, but that is not available in the playground.</p> <p>If you list all keys explicitely in the frame specification, don&rsquo;t forget to use wildcards so that any value will match; wildcards are empty objects with &laquo;&nbsp;{}&nbsp;&raquo;:</p> <blockquote><p><code>"myProperty" : {}</code></p></blockquote> <h2>The result</h2> <p><a href="http://blog.sparna.fr/wp-content/uploads/2022/07/Capture-d’écran-du-2022-07-20-08-01-19.png"><img class="aligncenter size-full wp-image-1475" src="http://blog.sparna.fr/wp-content/uploads/2022/07/Capture-d’écran-du-2022-07-20-08-01-19.png" alt="Capture d’écran du 2022-07-20 08-01-19" width="806" height="360" /></a></p> <p>Much nicer no ? This is something you can put into the hand of an average developer.</p> <h2>Automate context generation from SHACL</h2> <p>Do you have a SHACL specification of the structure of your graph ? wouldn&rsquo;t it be nice to automate the generation of the JSON-LD context from SHACL ? Maybe we could do that in <a href="https://shacl-play.sparna.fr/play/">SHACL-Play</a> ? stay tuned !</p> <p>Probably what we can automate is the context part, which can be global and unique for all your graph, but the framing specification should probably be different for each different API you need; each framing specification will then reference the same context by its URL.</p> <p><em>Image : <a href="https://gallica.bnf.fr/ark:/12148/btv1b53230250h/f1.item.r=encadrement.zoom#"><span class="title">[Encadrement ornemental] ([1er état]) / .Io. MIGon 1544. [Jean Mignon] ; [d&rsquo;après Le Primatice]</span></a> <a href="https://gallica.bnf.fr/ark:/12148/btv1b53230250h">https://gallica.bnf.fr/ark:/12148/btv1b53230250h</a></em></p> <div class="sharedaddy sd-sharing-enabled"><div class="robots-nocontent sd-block sd-social sd-social-icon sd-sharing"><h3 class="sd-title">Partager :</h3><div class="sd-content"><ul><li class="share-linkedin"><a rel="nofollow" data-shared="sharing-linkedin-1462" class="share-linkedin sd-button share-icon no-text" href="https://blog.sparna.fr/2022/07/20/clean-json-ld-from-rdf-using-framing/?share=linkedin" target="_blank" title="Cliquez pour partager sur LinkedIn"><span></span><span class="sharing-screen-reader-text">Cliquez pour partager sur LinkedIn(ouvre dans une nouvelle fenêtre)</span></a></li><li class="share-twitter"><a rel="nofollow" data-shared="sharing-twitter-1462" class="share-twitter sd-button share-icon no-text" href="https://blog.sparna.fr/2022/07/20/clean-json-ld-from-rdf-using-framing/?share=twitter" target="_blank" title="Partager sur Twitter"><span></span><span class="sharing-screen-reader-text">Partager sur Twitter(ouvre dans une nouvelle fenêtre)</span></a></li><li class="share-facebook"><a rel="nofollow" data-shared="sharing-facebook-1462" class="share-facebook sd-button share-icon no-text" href="https://blog.sparna.fr/2022/07/20/clean-json-ld-from-rdf-using-framing/?share=facebook" target="_blank" title="Partager sur Facebook"><span></span><span class="sharing-screen-reader-text">Partager sur Facebook(ouvre dans une nouvelle fenêtre)</span></a></li><li class="share-google-plus-1"><a rel="nofollow" data-shared="sharing-google-1462" class="share-google-plus-1 sd-button share-icon no-text" href="https://blog.sparna.fr/2022/07/20/clean-json-ld-from-rdf-using-framing/?share=google-plus-1" target="_blank" title="Cliquez pour partager sur Google+"><span></span><span class="sharing-screen-reader-text">Cliquez pour partager sur Google+(ouvre dans une nouvelle fenêtre)</span></a></li><li class="share-end"></li></ul></div></div></div> <div class="post-tags"><span class="strong">Post Tagged:</span> <a href="https://blog.sparna.fr/tag/framing/" rel="tag">Framing</a>, <a href="https://blog.sparna.fr/tag/json-ld/" rel="tag">json-ld</a>, <a href="https://blog.sparna.fr/tag/rdf/" rel="tag">RDF</a></div> <div class="single-post-pagination clr"> <div class="post-next"><strong>Next Post:</strong> <a href="https://blog.sparna.fr/2022/05/24/evenement-sparnatural-demonstrateurs-archives-nationales-bnf/" rel="prev">Evènement : Sparnatural et les démonstrateurs Archives Nationales + BNF</a></div> <div class="post-prev"><strong>Previous Post:</strong> <a href="https://blog.sparna.fr/2022/10/18/dashboards-from-sparql-knowledge-graphs-using-looker-studio-google-data-studio/" rel="next">Dashboards from SPARQL knowledge graphs using Looker Studio (Google Data Studio)</a></div> </div><!-- .post-post-pagination --> </div><!-- .entry --> </article> <section class="related-posts clr"> <div class="related-posts-title"><span class="fa fa-pencil"></span>Related Posts</div> <article class="related-entry"> <div class="related-entry-media clr"> <div class="related-entry-thumbnail"> <a href="https://blog.sparna.fr/2015/05/31/eli-european-legislation-identifier-web-de-donnees-legislatif-europeen/" title="ELI &#8211; European Legislation Identifier : une voie pour le web de données législatif européen"> <img src="https://blog.sparna.fr/wp-content/uploads/2015/05/Iustitia_van_Heemskerck-e1431439733333-563x450.png" alt="ELI &#8211; European Legislation Identifier : une voie pour le web de données législatif européen" width="563" height="450" /> <span class="overlay"></span> </a> </div><!-- .related-entry-thumbnail --> </div><!-- .related-entry-media --> <div class="related-entry-content clr"> <div class="related-entry-title"><a href="https://blog.sparna.fr/2015/05/31/eli-european-legislation-identifier-web-de-donnees-legislatif-europeen/" title="ELI &#8211; European Legislation Identifier : une voie pour le web de données législatif européen">ELI &#8211; European Legislation Identifier : une voie pour le web de données législatif européen</a></div> <div class="related-entry-excerpt entry clr"> Identifier, décrire et relier les lois sur le web ELI&hellip; </div><!-- .related-entry-excerpt --> </div><!-- .related-entry-content --> </article><!-- .related-entry --> <article class="related-entry"> <div class="related-entry-media clr"> <div class="related-entry-thumbnail"> <a href="https://blog.sparna.fr/2012/05/18/data-is-king/" title="Data Is King !"> <img src="https://blog.sparna.fr/wp-content/uploads/2012/05/DataIsKing_small.jpg" alt="Data Is King !" width="183" height="109" /> <span class="overlay"></span> </a> </div><!-- .related-entry-thumbnail --> </div><!-- .related-entry-media --> <div class="related-entry-content clr"> <div class="related-entry-title"><a href="https://blog.sparna.fr/2012/05/18/data-is-king/" title="Data Is King !">Data Is King !</a></div> <div class="related-entry-excerpt entry clr"> "Data Is King" est un principe qui sous-tend plusieurs buzzwords&hellip; </div><!-- .related-entry-excerpt --> </div><!-- .related-entry-content --> </article><!-- .related-entry --> <article class="related-entry"> <div class="related-entry-media clr"> <div class="related-entry-thumbnail"> <a href="https://blog.sparna.fr/2014/12/12/data-bnf-fr-enrichir-portail-documentaire-crdp-canope-poitou-charentes/" title="data.bnf.fr pour enrichir un portail de recherche documentaire : le cas de Canopé Académie de Poitiers"> <img src="https://blog.sparna.fr/wp-content/uploads/2014/12/BNF-site_Richelieu-salle_ovale-650x450.jpg" alt="data.bnf.fr pour enrichir un portail de recherche documentaire : le cas de Canopé Académie de Poitiers" width="650" height="450" /> <span class="overlay"></span> </a> </div><!-- .related-entry-thumbnail --> </div><!-- .related-entry-media --> <div class="related-entry-content clr"> <div class="related-entry-title"><a href="https://blog.sparna.fr/2014/12/12/data-bnf-fr-enrichir-portail-documentaire-crdp-canope-poitou-charentes/" title="data.bnf.fr pour enrichir un portail de recherche documentaire : le cas de Canopé Académie de Poitiers">data.bnf.fr pour enrichir un portail de recherche documentaire : le cas de Canopé Académie de Poitiers</a></div> <div class="related-entry-excerpt entry clr"> Je teste actuellement avec le Canopé Académie de Poitiers (Anciennement&hellip; </div><!-- .related-entry-excerpt --> </div><!-- .related-entry-content --> </article><!-- .related-entry --> </section> <div id="comments" class="comments-area clr"> <div class="comments-title"> <span class="fa fa-comments"></span> There are 7 comments for this article </div> <div class="comments-inner clr"> <ol class="commentlist"> <li id="li-comment-31752"> <article id="comment-31752" class="comment even thread-even depth-1 clr"> <div class="comment-author vcard"> <img alt='' src='https://1.gravatar.com/avatar/71cdd3918b895cf7aa9dc4ba282218b1?s=45&#038;d=identicon&#038;r=g' srcset='https://1.gravatar.com/avatar/71cdd3918b895cf7aa9dc4ba282218b1?s=90&amp;d=identicon&amp;r=g 2x' class='avatar avatar-45 photo' height='45' width='45' /> </div><!-- .comment-author --> <div class="comment-details clr"> <header class="comment-meta"> <cite class="fn"> <a href='http://linked.art' rel='external nofollow' class='url'>Rob Sanderson</a> </cite> <span class="comment-date"> <a href="https://blog.sparna.fr/2022/07/20/clean-json-ld-from-rdf-using-framing/#comment-31752"><time datetime="2022-07-21T14:08:15+00:00">21 juillet 2022</time></a> at 14 h 08 min </span><!-- .comment-date --> </header><!-- .comment-meta --> <div class="comment-content entry clr"> <p>Salut!</p> <p>To put forward an alternative view for &laquo;&nbsp;No URIs&nbsp;&raquo; &#8230; if you never expect a consuming application to retrieve the information at the URI, then sure, it can just be an enumerated string value. But if there&rsquo;s no reason to retrieve the information, does it even need to be a URI ever, or have a URI rather than being a blank node? Is there nothing else about the resource that isn&rsquo;t in the current document?</p> <p>Conversely if there&rsquo;s ever a need to retrieve the representation from the URI, then the consuming application needs to know how to reverse the process to get from the shortened form back to the expanded form. That&rsquo;s not hard &#8230; if you have a JSON-LD aware client, as it could expand the framed, compacted json out into the full form&#8230; and then (hopefully) find the URI. Otherwise it would need some understanding of the context document for the expansion. If that uses nested contexts from 1.1, it will be very painful for the consumer.</p> <p>Three examples:<br /> 1. IIIF uses context controlled json terms for vocabulary URIs. The vocabulary is tied explicitly to the JSON-LD in the specification. There&rsquo;s very little need to ever extend the vocabulary set, and there&rsquo;s very few occurrences of it as a pattern: <a href="https://iiif.io/api/presentation/3.0/#behavior" rel="nofollow">https://iiif.io/api/presentation/3.0/#behavior</a><br /> 2. The web annotation data model uses it for motivations: <a href="https://www.w3.org/TR/annotation-model/#motivation-and-purpose" rel="nofollow">https://www.w3.org/TR/annotation-model/#motivation-and-purpose</a> but otherwise leaves in URIs for targets, sources, and so on as clients definitely need to retrieve them<br /> 3. Linked Art never uses it for vocabulary, as the vocabulary entries are very likely to have useful information when you retrieve them. e.g. <a href="https://linked.art/model/base/#types-and-classifications" rel="nofollow">https://linked.art/model/base/#types-and-classifications</a> </p> <p>Hope that&rsquo;s useful to someone <img src="https://blog.sparna.fr/wp-includes/images/smilies/simple-smile.png" alt=":)" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p> </div><!-- .comment-content --> <div class="reply comment-reply-link"> <a class='comment-reply-link' href='/2022/07/20/clean-json-ld-from-rdf-using-framing/?replytocom=31752#respond' onclick='return addComment.moveForm( "comment-31752", "31752", "respond", "1462" )' aria-label='Répondre à Rob Sanderson'>Reply to this message</a> </div><!-- .reply --> </div><!-- .comment-details --> </article><!-- #comment-## --> <ul class="children"> <li id="li-comment-31799"> <article id="comment-31799" class="comment byuser comment-author-thomas bypostauthor odd alt depth-2 clr"> <div class="comment-author vcard"> <img alt='' src='https://1.gravatar.com/avatar/1950cc2227b99d9f090a5b98b01dd418?s=45&#038;d=identicon&#038;r=g' srcset='https://1.gravatar.com/avatar/1950cc2227b99d9f090a5b98b01dd418?s=90&amp;d=identicon&amp;r=g 2x' class='avatar avatar-45 photo' height='45' width='45' /> </div><!-- .comment-author --> <div class="comment-details clr"> <header class="comment-meta"> <cite class="fn"> Thomas Francart <span class="author-badge">Author</span> </cite> <span class="comment-date"> <a href="https://blog.sparna.fr/2022/07/20/clean-json-ld-from-rdf-using-framing/#comment-31799"><time datetime="2022-07-25T12:08:18+00:00">25 juillet 2022</time></a> at 12 h 08 min </span><!-- .comment-date --> </header><!-- .comment-meta --> <div class="comment-content entry clr"> <p>Hi Rob, Thanks for the pointers !<br /> I didn&rsquo;t mean to replace URIs by strings **in the RDF data**; I meant **presenting** the URIs as strings for the clients. If there is a URI then it is for a reason and we must of course keep it.<br /> What I get from your comment is : if we &laquo;&nbsp;hide&nbsp;&raquo; URIs behind JSON strings, then a non-JSONLD-aware client can have a hard time knowing it is a URI if it needs to access it; indeed, this could be a reason to leave them as URIs in the JSON.</p> </div><!-- .comment-content --> <div class="reply comment-reply-link"> <a class='comment-reply-link' href='/2022/07/20/clean-json-ld-from-rdf-using-framing/?replytocom=31799#respond' onclick='return addComment.moveForm( "comment-31799", "31799", "respond", "1462" )' aria-label='Répondre à Thomas Francart'>Reply to this message</a> </div><!-- .reply --> </div><!-- .comment-details --> </article><!-- #comment-## --> </li><!-- #comment-## --> </ul><!-- .children --> </li><!-- #comment-## --> <li id="li-comment-33459"> <article id="comment-33459" class="comment even thread-odd thread-alt depth-1 clr"> <div class="comment-author vcard"> <img alt='' src='https://1.gravatar.com/avatar/1370b226caf1badc9bb4d50ca4f6b1c8?s=45&#038;d=identicon&#038;r=g' srcset='https://1.gravatar.com/avatar/1370b226caf1badc9bb4d50ca4f6b1c8?s=90&amp;d=identicon&amp;r=g 2x' class='avatar avatar-45 photo' height='45' width='45' /> </div><!-- .comment-author --> <div class="comment-details clr"> <header class="comment-meta"> <cite class="fn"> Christian </cite> <span class="comment-date"> <a href="https://blog.sparna.fr/2022/07/20/clean-json-ld-from-rdf-using-framing/#comment-33459"><time datetime="2023-01-20T20:27:46+00:00">20 janvier 2023</time></a> at 20 h 27 min </span><!-- .comment-date --> </header><!-- .comment-meta --> <div class="comment-content entry clr"> <p>Does it make sense to create the JSON-LD context from the ontology triples via JSON-LD framing? Without knowing exactly, I‘d assume that the default RDF to JSON-LD generates some generic constructs which could be framed in a common manner.</p> </div><!-- .comment-content --> <div class="reply comment-reply-link"> <a class='comment-reply-link' href='/2022/07/20/clean-json-ld-from-rdf-using-framing/?replytocom=33459#respond' onclick='return addComment.moveForm( "comment-33459", "33459", "respond", "1462" )' aria-label='Répondre à Christian'>Reply to this message</a> </div><!-- .reply --> </div><!-- .comment-details --> </article><!-- #comment-## --> <ul class="children"> <li id="li-comment-33476"> <article id="comment-33476" class="comment byuser comment-author-thomas bypostauthor odd alt depth-2 clr"> <div class="comment-author vcard"> <img alt='' src='https://1.gravatar.com/avatar/1950cc2227b99d9f090a5b98b01dd418?s=45&#038;d=identicon&#038;r=g' srcset='https://1.gravatar.com/avatar/1950cc2227b99d9f090a5b98b01dd418?s=90&amp;d=identicon&amp;r=g 2x' class='avatar avatar-45 photo' height='45' width='45' /> </div><!-- .comment-author --> <div class="comment-details clr"> <header class="comment-meta"> <cite class="fn"> Thomas Francart <span class="author-badge">Author</span> </cite> <span class="comment-date"> <a href="https://blog.sparna.fr/2022/07/20/clean-json-ld-from-rdf-using-framing/#comment-33476"><time datetime="2023-01-23T09:21:50+00:00">23 janvier 2023</time></a> at 9 h 21 min </span><!-- .comment-date --> </header><!-- .comment-meta --> <div class="comment-content entry clr"> <p>I had never thought about creating the JSON-LD **context** itself via framing. For the moment I would use a dedicated script that interpret SHACL constraints (rather than OWL ontology) and generates the context. If you happen to do something relating to automated generation of JSON-LD context from OWL or SHACL, let me know !</p> </div><!-- .comment-content --> <div class="reply comment-reply-link"> <a class='comment-reply-link' href='/2022/07/20/clean-json-ld-from-rdf-using-framing/?replytocom=33476#respond' onclick='return addComment.moveForm( "comment-33476", "33476", "respond", "1462" )' aria-label='Répondre à Thomas Francart'>Reply to this message</a> </div><!-- .reply --> </div><!-- .comment-details --> </article><!-- #comment-## --> </li><!-- #comment-## --> </ul><!-- .children --> </li><!-- #comment-## --> <li id="li-comment-33761"> <article id="comment-33761" class="comment even thread-even depth-1 clr"> <div class="comment-author vcard"> <img alt='' src='https://1.gravatar.com/avatar/1ff7d7f658b5be1ad51127c61e302da2?s=45&#038;d=identicon&#038;r=g' srcset='https://1.gravatar.com/avatar/1ff7d7f658b5be1ad51127c61e302da2?s=90&amp;d=identicon&amp;r=g 2x' class='avatar avatar-45 photo' height='45' width='45' /> </div><!-- .comment-author --> <div class="comment-details clr"> <header class="comment-meta"> <cite class="fn"> <a href='http://culturecreates.com' rel='external nofollow' class='url'>Gregory Saumier-Finch</a> </cite> <span class="comment-date"> <a href="https://blog.sparna.fr/2022/07/20/clean-json-ld-from-rdf-using-framing/#comment-33761"><time datetime="2023-02-17T22:53:22+00:00">17 février 2023</time></a> at 22 h 53 min </span><!-- .comment-date --> </header><!-- .comment-meta --> <div class="comment-content entry clr"> <p>Very cool. I am also taking a similar approach to create JSON that developers love from RDF. Last week I made a presentation including these ideas, and now I stumbled across your post. Glad to see this approach gaining momentum. If you are interested I can share the video of my presentation.</p> </div><!-- .comment-content --> <div class="reply comment-reply-link"> <a class='comment-reply-link' href='/2022/07/20/clean-json-ld-from-rdf-using-framing/?replytocom=33761#respond' onclick='return addComment.moveForm( "comment-33761", "33761", "respond", "1462" )' aria-label='Répondre à Gregory Saumier-Finch'>Reply to this message</a> </div><!-- .reply --> </div><!-- .comment-details --> </article><!-- #comment-## --> <ul class="children"> <li id="li-comment-33794"> <article id="comment-33794" class="comment byuser comment-author-thomas bypostauthor odd alt depth-2 clr"> <div class="comment-author vcard"> <img alt='' src='https://1.gravatar.com/avatar/1950cc2227b99d9f090a5b98b01dd418?s=45&#038;d=identicon&#038;r=g' srcset='https://1.gravatar.com/avatar/1950cc2227b99d9f090a5b98b01dd418?s=90&amp;d=identicon&amp;r=g 2x' class='avatar avatar-45 photo' height='45' width='45' /> </div><!-- .comment-author --> <div class="comment-details clr"> <header class="comment-meta"> <cite class="fn"> Thomas Francart <span class="author-badge">Author</span> </cite> <span class="comment-date"> <a href="https://blog.sparna.fr/2022/07/20/clean-json-ld-from-rdf-using-framing/#comment-33794"><time datetime="2023-02-20T09:26:54+00:00">20 février 2023</time></a> at 9 h 26 min </span><!-- .comment-date --> </header><!-- .comment-meta --> <div class="comment-content entry clr"> <p>Please do share !<br /> I recently learned a lot more about the possibilities of JSON-LD, including &laquo;&nbsp;@included&nbsp;&raquo; flag and language-based or property-based indexes, which really can hide a lot of the RDF complexity from the average JSON developper.</p> </div><!-- .comment-content --> <div class="reply comment-reply-link"> <a class='comment-reply-link' href='/2022/07/20/clean-json-ld-from-rdf-using-framing/?replytocom=33794#respond' onclick='return addComment.moveForm( "comment-33794", "33794", "respond", "1462" )' aria-label='Répondre à Thomas Francart'>Reply to this message</a> </div><!-- .reply --> </div><!-- .comment-details --> </article><!-- #comment-## --> </li><!-- #comment-## --> </ul><!-- .children --> </li><!-- #comment-## --> <li id="li-comment-33795"> <article id="comment-33795" class="comment even thread-odd thread-alt depth-1 clr"> <div class="comment-author vcard"> <img alt='' src='https://1.gravatar.com/avatar/1370b226caf1badc9bb4d50ca4f6b1c8?s=45&#038;d=identicon&#038;r=g' srcset='https://1.gravatar.com/avatar/1370b226caf1badc9bb4d50ca4f6b1c8?s=90&amp;d=identicon&amp;r=g 2x' class='avatar avatar-45 photo' height='45' width='45' /> </div><!-- .comment-author --> <div class="comment-details clr"> <header class="comment-meta"> <cite class="fn"> Christian </cite> <span class="comment-date"> <a href="https://blog.sparna.fr/2022/07/20/clean-json-ld-from-rdf-using-framing/#comment-33795"><time datetime="2023-02-20T10:29:21+00:00">20 février 2023</time></a> at 10 h 29 min </span><!-- .comment-date --> </header><!-- .comment-meta --> <div class="comment-content entry clr"> <p>Yes, please share!</p> </div><!-- .comment-content --> <div class="reply comment-reply-link"> <a class='comment-reply-link' href='/2022/07/20/clean-json-ld-from-rdf-using-framing/?replytocom=33795#respond' onclick='return addComment.moveForm( "comment-33795", "33795", "respond", "1462" )' aria-label='Répondre à Christian'>Reply to this message</a> </div><!-- .reply --> </div><!-- .comment-details --> </article><!-- #comment-## --> </li><!-- #comment-## --> </ol><!-- .commentlist --> <div id="respond" class="comment-respond"> <h3 id="reply-title" class="comment-reply-title">Répondre à <a href="#comment-31752">Rob Sanderson</a> <small><a rel="nofollow" id="cancel-comment-reply-link" href="/2022/07/20/clean-json-ld-from-rdf-using-framing/#respond"><i class="fa fa-times"></i>Cancel comment reply</a></small></h3> <form action="https://blog.sparna.fr/wp-comments-post.php" method="post" id="commentform" class="comment-form"> <p class="comment-notes"><span id="email-notes">Votre adresse de messagerie ne sera pas publiée.</span> Les champs obligatoires sont indiqués avec <span class="required">*</span></p> <div class="col span_1_of_3 col-1"><input id="author" name="author" type="text" placeholder="Name*" value="" size="30" aria-required='true' /></div> <div class="col span_1_of_3"><input id="email" name="email" type="text" placeholder="Email*" value="" size="30" aria-required='true' /></div> <div class="col span_1_of_3"><input id="url" name="url" type="text" placeholder="Website" value="" size="30" /></div> <p class="comment-form-comment"><label for="comment">Commentaire</label> <textarea id="comment" name="comment" cols="45" rows="8" aria-describedby="form-allowed-tags" aria-required="true" required="required"></textarea></p> <p class="form-allowed-tags" id="form-allowed-tags">Vous pouvez utiliser ces balises et attributs <abbr title="HyperText Markup Language">HTML</abbr>&nbsp;: <code>&lt;a href=&quot;&quot; title=&quot;&quot;&gt; &lt;abbr title=&quot;&quot;&gt; &lt;acronym title=&quot;&quot;&gt; &lt;b&gt; &lt;blockquote cite=&quot;&quot;&gt; &lt;cite&gt; &lt;code&gt; &lt;del datetime=&quot;&quot;&gt; &lt;em&gt; &lt;i&gt; &lt;q cite=&quot;&quot;&gt; &lt;s&gt; &lt;strike&gt; &lt;strong&gt; </code></p> <p class="form-submit"><input name="submit" type="submit" id="submit" class="submit" value="Laisser un commentaire" /> <input type='hidden' name='comment_post_ID' value='1462' id='comment_post_ID' /> <input type='hidden' name='comment_parent' id='comment_parent' value='31752' /> </p><p style="display: none;"><input type="hidden" id="akismet_comment_nonce" name="akismet_comment_nonce" value="756d6bc615" /></p><p class="comment-subscription-form"><input type="checkbox" name="subscribe_comments" id="subscribe_comments" value="subscribe" style="width: auto; -moz-appearance: checkbox; -webkit-appearance: checkbox;" /> <label class="subscribe-label" id="subscribe-label" for="subscribe_comments">Prévenez-moi de tous les nouveaux commentaires par e-mail.</label></p><p class="comment-subscription-form"><input type="checkbox" name="subscribe_blog" id="subscribe_blog" value="subscribe" style="width: auto; -moz-appearance: checkbox; -webkit-appearance: checkbox;" /> <label class="subscribe-label" id="subscribe-blog-label" for="subscribe_blog">Prévenez-moi de tous les nouveaux articles par email.</label></p><p style="display: none;"><input type="hidden" id="ak_js" name="ak_js" value="212"/></p> </form> </div><!-- #respond --> </div><!-- .comments-inner --> </div><!-- #comments --> </div><!-- #content --> <aside id="secondary" class="sidebar-container" role="complementary"> <div class="sidebar-inner"> <div class="widget-area"> <div class="sidebar-widget widget_wpex_recent_posts_thumb clr"><span class="widget-title">Derniers articles</span> <ul class="wpex-widget-recent-posts clr"> <li class="clr wpex-widget-recent-posts-li left-thumbnail format- count-3" > <a href="https://blog.sparna.fr/2024/10/15/sparnatural-say-it-with-shacl/" title="Sparnatural : say it with SHACL !" class="wpex-widget-recent-posts-thumbnail clr"> <img src="https://blog.sparna.fr/wp-content/uploads/2024/10/navigate-55x55.png" alt="Sparnatural : say it with SHACL !" width="55" height="55" /> </a> <div class="clr"></div> <a href="https://blog.sparna.fr/2024/10/15/sparnatural-say-it-with-shacl/" title="Sparnatural : say it with SHACL !" class="wpex-widget-recent-posts-title">Sparnatural : say it with SHACL !</a> </li> <li class="clr wpex-widget-recent-posts-li left-thumbnail format- count-3" > <a href="https://blog.sparna.fr/2024/01/15/cordis-a-sparql-endpoint-is-born/" title="CORDIS : a SPARQL endpoint is born !" class="wpex-widget-recent-posts-thumbnail clr"> <img src="https://blog.sparna.fr/wp-content/uploads/2024/01/person-holding-bengal-light-hand_23-2147955677-55x55.jpg" alt="CORDIS : a SPARQL endpoint is born !" width="55" height="55" /> </a> <div class="clr"></div> <a href="https://blog.sparna.fr/2024/01/15/cordis-a-sparql-endpoint-is-born/" title="CORDIS : a SPARQL endpoint is born !" class="wpex-widget-recent-posts-title">CORDIS : a SPARQL endpoint is born !</a> </li> <li class="clr wpex-widget-recent-posts-li left-thumbnail format- count-3" > <a href="https://blog.sparna.fr/2023/03/13/2013-2023-tis-skosplays-birthday/" title="2013-2023 : ‘Tis SKOSPlay!’s Birthday !" class="wpex-widget-recent-posts-thumbnail clr"> <img src="https://blog.sparna.fr/wp-content/uploads/2023/03/SKOSPlayBDay-55x55.jpg" alt="2013-2023 : ‘Tis SKOSPlay!’s Birthday !" width="55" height="55" /> </a> <div class="clr"></div> <a href="https://blog.sparna.fr/2023/03/13/2013-2023-tis-skosplays-birthday/" title="2013-2023 : ‘Tis SKOSPlay!’s Birthday !" class="wpex-widget-recent-posts-title">2013-2023 : ‘Tis SKOSPlay!’s Birthday !</a> </li> </ul> </div><div class="sidebar-widget widget_wpex_recent_comments_avatars_widget clr"><span class="widget-title">Derniers commentaires</span> <ul class="wpex-recent-comments-widget clr"> <li class="clr"> <a href="https://blog.sparna.fr/2013/12/07/ontologie-thesaurus-taxonomie-web-de-donnees/#comment-44170" title="Clean JSON(-LD) from RDF using Framing" class="clr"> <img alt='' src='https://1.gravatar.com/avatar/d34d02d390b703a3345c70b3d4d97910?s=55&#038;d=identicon&#038;r=g' srcset='https://1.gravatar.com/avatar/d34d02d390b703a3345c70b3d4d97910?s=110&amp;d=identicon&amp;r=g 2x' class='avatar avatar-55 photo' height='55' width='55' /> <span class="title strong">Nicolas:</span> bonjour Rachid, je vous invite à lire "La survie des&hellip;... </a> </li> <li class="clr"> <a href="https://blog.sparna.fr/2013/12/07/ontologie-thesaurus-taxonomie-web-de-donnees/#comment-44169" title="Clean JSON(-LD) from RDF using Framing" class="clr"> <img alt='' src='https://1.gravatar.com/avatar/d34d02d390b703a3345c70b3d4d97910?s=55&#038;d=identicon&#038;r=g' srcset='https://1.gravatar.com/avatar/d34d02d390b703a3345c70b3d4d97910?s=110&amp;d=identicon&amp;r=g 2x' class='avatar avatar-55 photo' height='55' width='55' /> <span class="title strong">Nicolas:</span> Votre article est éclairant. merci!! Mais encore... "La Taxonomie n'est&hellip;... </a> </li> <li class="clr"> <a href="https://blog.sparna.fr/2024/01/15/cordis-a-sparql-endpoint-is-born/#comment-38753" title="Clean JSON(-LD) from RDF using Framing" class="clr"> <img alt='' src='https://2.gravatar.com/avatar/8adc53424babfab9191c11759c20c30e?s=55&#038;d=identicon&#038;r=g' srcset='https://2.gravatar.com/avatar/8adc53424babfab9191c11759c20c30e?s=110&amp;d=identicon&amp;r=g 2x' class='avatar avatar-55 photo' height='55' width='55' /> <span class="title strong">Marie Muller:</span> Thank you Vladimir for your comment ! I've seen there&hellip;... </a> </li> </ul> </div><div class="sidebar-widget jetpack_subscription_widget clr"><span class="widget-title">Abonnez-vous à ce blog par e-mail.</span> <form action="#" method="post" accept-charset="utf-8" id="subscribe-blog-blog_subscription-2"> <div id="subscribe-text"><p>Saisissez votre adresse e-mail pour vous abonner à ce blog et recevoir une notification de chaque nouvel article par email.</p> </div> <p id="subscribe-email"> <label id="jetpack-subscribe-label" for="subscribe-field"> Adresse e-mail </label> <input type="email" name="email" required="required" class="required" value="" id="subscribe-field-blog_subscription-2" placeholder="Adresse e-mail" /> </p> <p id="subscribe-submit"> <input type="hidden" name="action" value="subscribe" /> <input type="hidden" name="source" value="https://blog.sparna.fr/2022/07/20/clean-json-ld-from-rdf-using-framing/?replytocom=31752" /> <input type="hidden" name="sub-type" value="widget" /> <input type="hidden" name="redirect_fragment" value="blog_subscription-2" /> <input type="submit" value="S&#039;abonner" name="jetpack_subscriptions_widget" /> </p> </form> <script> /* Custom functionality for safari and IE */ (function( d ) { // Creates placeholders for IE if ( ( 'placeholder' in d.createElement( 'input' ) ) ) { var label = d.getElementById( 'jetpack-subscribe-label' ); label.style.clip = 'rect(1px, 1px, 1px, 1px)'; label.style.position = 'absolute'; label.style.height = '1px'; label.style.width = '1px'; label.style.overflow = 'hidden'; } // Make sure the email value is filled in before allowing submit var form = d.getElementById('subscribe-blog-blog_subscription-2'), input = d.getElementById('subscribe-field-blog_subscription-2'), handler = function( event ) { if ( '' === input.value ) { input.focus(); if ( event.preventDefault ){ event.preventDefault(); } return false; } }; if ( window.addEventListener ) { form.addEventListener( 'submit', handler, false ); } else { form.attachEvent( 'onsubmit', handler ); } })( document ); </script> </div><div class="sidebar-widget widget_wpcom_social_media_icons_widget clr"><ul><li><a title="Voir le profil de thomasfrancart sur LinkedIn" href="https://www.linkedin.com/in/thomasfrancart/" class="genericon genericon-linkedin-alt" target="_blank"><span class="screen-reader-text">Voir le profil de thomasfrancart sur LinkedIn</span></a></li><li><a title="Voir le profil de tfrancart sur GitHub" href="https://github.com/tfrancart/" class="genericon genericon-github" target="_blank"><span class="screen-reader-text">Voir le profil de tfrancart sur GitHub</span></a></li></ul></div> </div> </div> </aside><!-- #secondary --> </div><!-- #primary --> </div><!--.site-main --> </div><!-- .site-main-wrap --> </div><!-- #wrap --> <footer id="footer-wrap" class="site-footer clr"> <div id="footer-bottom" class="clr"> <div class="container clr"> <div id="copyright" class="clr" role="contentinfo"> Copyright 2014 Your Company LLC </div><!-- #copyright --> </div><!-- .container --> </div><!-- #footer-bottom --> </footer><!-- #footer-wrap --> <div style="display:none"> <div class="grofile-hash-map-71cdd3918b895cf7aa9dc4ba282218b1"> </div> <div class="grofile-hash-map-1950cc2227b99d9f090a5b98b01dd418"> </div> <div class="grofile-hash-map-1370b226caf1badc9bb4d50ca4f6b1c8"> </div> <div class="grofile-hash-map-1ff7d7f658b5be1ad51127c61e302da2"> </div> <div class="grofile-hash-map-d34d02d390b703a3345c70b3d4d97910"> </div> <div class="grofile-hash-map-8adc53424babfab9191c11759c20c30e"> </div> </div> <div id="mobile-search"> <form method="get" action="https://blog.sparna.fr/" role="search" id="mobile-search-form"> <input type="search" class="field" name="s" value="" placeholder="To search type and hit enter" /> </form> </div> <a href="#" class="site-scroll-top"><span class="fa fa-arrow-up"></span></a> <script type="text/javascript"> window.WPCOM_sharing_counts = {"https:\/\/blog.sparna.fr\/2022\/07\/20\/clean-json-ld-from-rdf-using-framing\/":1462}; window.WPCOM_jetpack = true; window.WPCOM_site_ID = 75279471; </script> <script type="text/javascript"> var windowOpen; jQuery(document).on( 'ready post-load', function(){ jQuery( 'a.share-linkedin' ).on( 'click', function() { if ( 'undefined' !== typeof windowOpen ){ // If there's another sharing window open, close it. windowOpen.close(); } windowOpen = window.open( jQuery(this).attr( 'href' ), 'wpcomlinkedin', 'menubar=1,resizable=1,width=580,height=450' ); return false; }); }); </script> <script type="text/javascript"> var windowOpen; jQuery(document).on( 'ready post-load', function(){ jQuery( 'a.share-twitter' ).on( 'click', function() { if ( 'undefined' !== typeof windowOpen ){ // If there's another sharing window open, close it. windowOpen.close(); } windowOpen = window.open( jQuery(this).attr( 'href' ), 'wpcomtwitter', 'menubar=1,resizable=1,width=600,height=350' ); return false; }); }); </script> <script type="text/javascript"> var windowOpen; jQuery(document).on( 'ready post-load', function(){ jQuery( 'a.share-facebook' ).on( 'click', function() { if ( 'undefined' !== typeof windowOpen ){ // If there's another sharing window open, close it. windowOpen.close(); } windowOpen = window.open( jQuery(this).attr( 'href' ), 'wpcomfacebook', 'menubar=1,resizable=1,width=600,height=400' ); return false; }); }); </script> <script type="text/javascript"> var windowOpen; jQuery(document).on( 'ready post-load', function(){ jQuery( 'a.share-google-plus-1' ).on( 'click', function() { if ( 'undefined' !== typeof windowOpen ){ // If there's another sharing window open, close it. windowOpen.close(); } windowOpen = window.open( jQuery(this).attr( 'href' ), 'wpcomgoogle-plus-1', 'menubar=1,resizable=1,width=480,height=550' ); return false; }); }); </script> <script type='text/javascript' src='https://blog.sparna.fr/wp-content/plugins/akismet/_inc/form.js?ver=3.1.5'></script> <script type='text/javascript' src='https://blog.sparna.fr/wp-content/plugins/contact-form-7/includes/js/jquery.form.min.js?ver=3.51.0-2014.06.20'></script> <script type='text/javascript'> /* <![CDATA[ */ var _wpcf7 = {"loaderUrl":"https:\/\/blog.sparna.fr\/wp-content\/plugins\/contact-form-7\/images\/ajax-loader.gif","sending":"Envoi en cours ..."}; /* ]]> */ </script> <script type='text/javascript' src='https://blog.sparna.fr/wp-content/plugins/contact-form-7/includes/js/scripts.js?ver=4.2.1'></script> <script type='text/javascript' src='https://s0.wp.com/wp-content/js/devicepx-jetpack.js?ver=202447'></script> <script type='text/javascript' src='https://secure.gravatar.com/js/gprofiles.js?ver=2024Novaa'></script> <script type='text/javascript'> /* <![CDATA[ */ var WPGroHo = {"my_hash":""}; /* ]]> */ </script> <script type='text/javascript' src='https://blog.sparna.fr/wp-content/plugins/jetpack/modules/wpgroho.js?ver=4.2.38'></script> <script type='text/javascript' src='https://blog.sparna.fr/wp-includes/js/comment-reply.min.js?ver=4.2.38'></script> <script type='text/javascript'> /* <![CDATA[ */ var wpexLocalize = {"mobileMenuOpen":"Click here to navigate","mobileMenuClosed":"Close navigation","flexSlideshow":"true","flexSlideshowSpeed":"7000"}; /* ]]> */ </script> <script type='text/javascript' src='https://blog.sparna.fr/wp-content/themes/wpex-luxmag/js/global-min.js?ver=1.0'></script> <script type='text/javascript'> /* <![CDATA[ */ var sharing_js_options = {"lang":"en","counts":"1"}; /* ]]> */ </script> <script type='text/javascript' src='https://blog.sparna.fr/wp-content/plugins/jetpack/modules/sharedaddy/sharing.js?ver=3.6.4'></script> <script type='text/javascript' src='https://stats.wp.com/e-202447.js' async defer></script> <script type='text/javascript'> _stq = window._stq || []; _stq.push([ 'view', {v:'ext',j:'1:3.6.4',blog:'75279471',post:'1462',tz:'1',srv:'blog.sparna.fr'} ]); _stq.push([ 'clickTrackerInit', '75279471', '1462' ]); </script> </body> </html>

Pages: 1 2 3 4 5 6 7 8 9 10