{"id":1675,"date":"2019-03-26T14:24:19","date_gmt":"2019-03-26T19:24:19","guid":{"rendered":"http:\/\/inova8.com\/bg_inova8.com\/?p=1675"},"modified":"2019-04-23T02:29:13","modified_gmt":"2019-04-23T07:29:13","slug":"shaping-rdf-graph-data-with-shacl-via-odata2sparql","status":"publish","type":"post","link":"https:\/\/inova8.com\/bg_inova8.com\/shaping-rdf-graph-data-with-shacl-via-odata2sparql\/","title":{"rendered":"Shaping RDF-Graph Data with SHACL via OData2SPARQL"},"content":{"rendered":"<div class=\"boldgrid-section\">\n<div class=\"container-fluid\">\n<p class=\"\"><a href=\"http:\/\/inova8.com\/bg_inova8.com\/offerings\/odata2sparql\/\">OData2SPARQL<\/a> V4 endpoint now publishes any <a href=\"https:\/\/www.w3.org\/TR\/shacl\/\">SHACL<\/a> nodeShapes defined in the model mapping them to OData complexTypes, along with existing capability of publishing RDFS and OWL classes, and SPIN queries.<\/p>\n<p>RDF graphs provide the best (IMHO) way to store and retrieve information. However creating user applications is complicated by the lack of a standard RESTful access to the graph, certainly not one that is supported by mainstream UI frameworks. OData2SPARQL solves that by providing a model-driven RESTful API that can be deployed against any RDF graph.<\/p>\n<p class=\"\">The addition of support for <a href=\"https:\/\/www.w3.org\/TR\/shacl\/\">SHACL<\/a> allows the RESTful services published by <a href=\"http:\/\/inova8.com\/bg_inova8.com\/offerings\/odata2sparql\/\">OData2SPARQL<\/a> to not only reflect the underlying model structure, but also match the business requirements as defined by different information shapes.<\/p>\n<p class=\"\">Since <a href=\"https:\/\/www.odata.org\/\">OData<\/a> is used by many applications and UI\/UX frameworks as the 21<sup>st<\/sup> century replacement to ODBC\/JDBC, the addition of SHACL support means that user interfaces can be automatically generated that match with the SHACL shapes metadata published by OData2SPARQL.<\/p>\n<p class=\"\"><img loading=\"lazy\" class=\"aligncenter wp-image-1682 size-full\" src=\"http:\/\/inova8.com\/bg_inova8.com\/wp-content\/uploads\/2019\/03\/MasterDetail.png\" alt=\"\" width=\"1302\" height=\"573\" srcset=\"https:\/\/inova8.com\/bg_inova8.com\/wp-content\/uploads\/2019\/03\/MasterDetail.png 1302w, https:\/\/inova8.com\/bg_inova8.com\/wp-content\/uploads\/2019\/03\/MasterDetail-300x132.png 300w, https:\/\/inova8.com\/bg_inova8.com\/wp-content\/uploads\/2019\/03\/MasterDetail-768x338.png 768w, https:\/\/inova8.com\/bg_inova8.com\/wp-content\/uploads\/2019\/03\/MasterDetail-1024x451.png 1024w\" sizes=\"(max-width: 1302px) 100vw, 1302px\" \/><\/p>\n<h2 class=\"\">SHACL Northwind Model Example<\/h2>\n<p class=\"\">The ubiquitous <a href=\"https:\/\/github.com\/peterjohnlawrence\/com.inova8.northwind\">Northwind model<\/a> contains sample data of employees, customers, products, orders, order-details, and other related information. This was originally a sample SQL database, but is also available in many other formats including RDF.<\/p>\n<h3 class=\"\">OData2SPARQL using RDFS+ model<\/h3>\n<p class=\"\">Using OData2SPARQL to map the Northwind RDF-graph will create entity-sets of Employees, Customers, Orders, OrderDetails, and so on.<\/p>\n<table style=\"height: 173px; margin-top: 28px; margin-right: 34px;\" width=\"642\">\n<tbody>\n<tr>\n<td>\n<blockquote><p><em>OData4SPARQL maps RDFS+<\/em><\/p>\n<ul>\n<li><em>Any rdfs:Class\/owl:Class to an OData EntityType and EntitySet<\/em><\/li>\n<li><em>Any OWL DatatypeProperty to a property of an OData EntityType<\/em><\/li>\n<li><em>Any OWL ObjectProperty to an OData navigationProperty<\/em><\/li>\n<\/ul>\n<\/blockquote>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p class=\"\">Within RDF it is possible to create an Order-type of thing, without that order having a customer, or any order-details. Note that this is not a disadvantage of RDF; in fact it is one of the many advantages of RDF as it allows an order to be registered before all of its other details are available.<\/p>\n<p class=\"\">However, when querying an RDF-graph we are likely to ask what orders exist for a customer made by an employee, and with at least one order line-item (order-detail) that includes the product, quantity and discount. We could say that this is a qualified-order.<\/p>\n<p>If we were to request the description of a particular order using OData2SPARQL:<\/p>\n<pre>OData2SPARQL Request:\r\n \u2026\/odata2sparql\/northwind\/Order('NWD~Order-10248')?format=json<\/pre>\n<pre>OData2SPARQL Response:\r\n{\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @odata.context: \"http:\/\/localhost:8080\/odata2sparql\/northwind\/$metadata#Order\/$entity\",\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; customerId: \"NWD~Customer-VINET\",\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; employeeId: \"NWD~Employee-5\",\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; freight: \"32.380001\",\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; label: \"Order-10248\",\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lat: 49.2559582,\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; long: 4.1547448,\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; orderDate: \"2016-07-03T23:00:00Z\",\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \u2026\r\n}<\/pre>\n<p class=\"\">Now the above response includes every OData property (aka RDF datatypeProperty) we know about Order(&#8216;NWD~Order-10248&#8217;). Not all are shown above for brevity.<\/p>\n<p class=\"\">However we might want to include related information, that which is connected via an OData navigation property (aka RDF objectproperty). To include this related information we simple augment the request with select=* and expand=* as follows:<\/p>\n<pre>OData2SPARQL Request:&nbsp;\r\n\u2026\/odata2sparql\/northwind\/Order('NWD~Order-10248')?$select=*&amp;$expand=*&amp;$format=json<\/pre>\n<pre>OData2SPARQL Response:&nbsp;\r\n{\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @odata.context: \"http:\/\/localhost:8080\/odata2sparql\/northwind\/$metadata#Order(*)\/$entity\",\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; freight: \"32.380001\",\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lat: 49.2559582,\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; long: 4.1547448,\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; orderDate: \"2016-07-03T23:00:00Z\",\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; subjectId: \"NWD~OrderDetail-10248\u201d,\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \u2026\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; employee: {\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; birthDate: \"1975-03-04\",\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; employeeAddress: \"14 Garrett Hill\",\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; employeeCity: \"London\",\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; employeeCountry: \"UK\",\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; subjectId: \"NWD~Employee-5\",\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \u2026\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; },\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; orderRegion: null,\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; shipVia: {\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; shipperCompanyName: \"Federal Shipping\",\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; shipperPhone: \"(503) 555-9931\",\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; subjectId: \"NWD~Shipper-3\"\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; },\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; customer: {\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; customerAddress: \"59 rue de l'Abbaye\",\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; subjectId: \"NWD~Customer-VINET\",\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \u2026\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; },\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hasOrderDetail: [{\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; discount: 0,\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; orderDetailUnitPrice: 14,\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; orderId: \"NWD~Order-10248\",\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; productId: \"NWD~Product-11\",\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; quantity: 12,\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; subjectId: \"NWD~OrderDetail-10248-11\",\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \u2026\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; },\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; discount: 0,\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; orderDetailUnitPrice: 9.8,\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; orderId: \"NWD~Order-10248\",\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; productId: \"NWD~Product-42\",\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; quantity: 10,\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; subjectId: \"NWD~OrderDetail-10248-42\",\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \u2026\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; },\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; discount: 0,\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; orderDetailUnitPrice: 34.8,\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; orderId: \"NWD~Order-10248\",\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; productId: \"NWD~Product-72\",\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; quantity: 5,\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; subjectId: \"NWD~OrderDetail-10248-72\",\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \u2026\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }],\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \u2026\r\n}<\/pre>\n<h3 class=\"\">OData2SPARQL with SHACL Shapes<\/h3>\n<p class=\"\">Well we got what we asked for: everything (a lot of the information returned has been hidden in the above for clarity). However this might be a little overwhelming as the actual question we wanted answered was:<\/p>\n<table width=\"100%\">\n<tbody>\n<tr>\n<td>\n<blockquote><p><em>Give me any qualified orders that have salesperson and customer with a least one line-item that has product, quantity, and discount defined.<\/em><\/p><\/blockquote>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p class=\"\">The beauty of RDF is that it is based on an open-world assumption: anything can be said. Unfortunately the information-transaction world is steeped in referential integrity, so they see the looseness of RDF as anarchical. SHACL bridges that gap by defining patterns to which the RDF-graphs should adhere if they want to be classified as that particular shape. However SHACL still allows the open-world to co-exist.<\/p>\n<table width=\"100%\">\n<tbody>\n<tr>\n<td>\n<blockquote><p><em>Closed or Open World? We can have the best of both worlds:<\/em><\/p>\n<ul>\n<li><em>The open-world assumption behind RDF-graphs in which anyone can say anything about anything, combined with<\/em><\/li>\n<li><em>The close world assumption behind referential integrity that limits information to predefined patterns<\/em><\/li>\n<\/ul>\n<\/blockquote>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p class=\"\">Let\u2019s shape what is a qualified order using <a href=\"https:\/\/www.w3.org\/TR\/shacl\/\">SHACL<\/a>. Using this shapes constraint language we can say that:<\/p>\n<table width=\"100%\">\n<tbody>\n<tr>\n<td>\n<blockquote>\n<ul>\n<li><em>A QualifiedOrder comprises of<\/em>\n<ul>\n<li><em>An Order, with<\/em>\n<ul>\n<li><em>One and only one Customer<\/em><\/li>\n<li><em>One and only one Employee (salesperson)<\/em><\/li>\n<li><em>At least one OrderDetail, each with<\/em>\n<ul>\n<li><em>Optionally one discount<\/em><\/li>\n<li><em>One and only one product<\/em><\/li>\n<li><em>One and only one quantity<\/em><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/blockquote>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p class=\"\">OK, this is not overly complex but the intention is not to befuddle with complexity, but illustrate with a simple yet meaningful example.<\/p>\n<p class=\"\">The above \u2018word-model\u2019 can be expressed using the SHACL vocabulary as the following, which can be included with any existing schema\/model of the information:<\/p>\n<pre>shapes:QualifiedOrder\r\n&nbsp; rdf:type sh:NodeShape ;\r\n&nbsp; sh:name \"QualifiedOrder\" ;\r\n&nbsp; sh:targetClass model:Order ;\r\n&nbsp; sh:property [\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rdf:type sh:PropertyShape ;\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; skos:prefLabel \"\" ;\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sh:maxCount 1 ;\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sh:minCount 1 ;\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sh:name \"mustHaveCustomer\" ;\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sh:path model:customer ;\r\n&nbsp;&nbsp;&nbsp; ] ;\r\n&nbsp; sh:property [\r\n&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;rdf:type sh:PropertyShape ;\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sh:maxCount 1 ;\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sh:minCount 1 ;\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sh:name \"mustHaveSalesperson\" ;\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sh:path model:employee ;\r\n&nbsp;&nbsp;&nbsp; ] ;\r\n&nbsp; sh:property [\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rdf:type sh:PropertyShape ;\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sh:inversePath model:order ;\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sh:minCount 1 ;\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sh:name \"mustHaveOrderDetails\" ;\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sh:node [\r\n&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rdf:type sh:NodeShape ;\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sh:name \"QualifiedOrderDetail\" ;\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sh:property [\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rdf:type sh:PropertyShape ;\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sh:maxCount 1 ;\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sh:minCount 0 ;\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sh:name \"mayHaveOrderDetailDiscount\" ;\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sh:path model:discount ;\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ] ;\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sh:property [\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rdf:type sh:PropertyShape ;\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sh:maxCount 1 ;\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sh:minCount 1 ;\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sh:name \"mustHaveOrderDetailProduct\" ;\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sh:path model:product ;\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ] ;\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sh:property [\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rdf:type sh:PropertyShape ;\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sh:maxCount 1 ;\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sh:minCount 1 ;\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sh:name \"mustHaveOrderDetailQuantity\" ;\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sh:path model:quantity ;\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ] ;\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sh:targetClass model:OrderDetail ;\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ] ;\r\n&nbsp;&nbsp;&nbsp; ] ;\r\n.<\/pre>\n<p class=\"\">OData2SPARQL has been extended to extract both the RDFS+ model, any SPIN operations, with now any SHACL shapes. These SHACL shapes are mapped as follows:<\/p>\n<table width=\"100%\">\n<tbody>\n<tr>\n<td>\n<blockquote><p><em>OData4SPARQL maps SHACL<\/em><\/p>\n<ul>\n<li><em>any SHACL nodeShape to an OData ComplexType and a OData EntityType and EntitySet<\/em><\/li>\n<li><em>any propertyShape to an OData property with the same restrictions<\/em><\/li>\n<\/ul>\n<\/blockquote>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p class=\"\">An OData2SPARQL request for an EntityType derived from a SHACL shape will construct the SPARQL query adhering to the shapes restrictions as shown in the example request below:<\/p>\n<pre>OData2SPARQL Request:&nbsp;\r\n\r\n\u2026\/odata2sparql\/northwind\/shapes_QualifiedOrder('NWD~Order-10248')?$select=*&amp;$expand=*&amp;$format=json<\/pre>\n<pre>OData2SPARQL Response:&nbsp;\r\n\r\n{\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; @odata.context: \"http:\/\/localhost:8080\/odata2sparql\/northwind\/$metadata#shapes_QualifiedOrder(*)\/$entity\",\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; QualifiedOrder: {\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hasOrderDetail: [{\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; discount: 0,\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; quantity: 12,\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; product: {\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; subjectId: \"NWD~Product-11\",\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \u2026\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; },\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; discount: 0,\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; quantity: 10,\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; product: {\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; subjectId: \"NWD~Product-42\",\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \u2026\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; },\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; discount: 0,\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; quantity: 5,\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; product: {\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; subjectId: \"NWD~Product-72\",\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \u2026\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }],\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; customer: {\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; subjectId: \"NWD~Customer-VINET\"\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; },\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; employee: {\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; subjectId: \"NWD~Employee-5\",\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; },\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; subjectId: \"NWD~Order-10248\",\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; \u2026\r\n}<\/pre>\n<p class=\"\">In OData2SPARQL terms this means the following request:<\/p>\n<pre>OData2SPARQL Request:&nbsp;\r\n\r\n\u2026\/odata2sparql\/northwind\/shapes_QualifiedOrder?$format=json<\/pre>\n<pre>OData2SPARQL Response:&nbsp;\r\n\r\n(Returns all orders that match the shape)<\/pre>\n<table width=\"100%\">\n<tbody>\n<tr>\n<td>\n<blockquote><p><em>The shape is not implying that all orders have to follow the same shape rules. There could still be orders without, for example, any line-items. These are still valid, but they simply do not match this shape restriction. <\/em><\/p><\/blockquote>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h3 class=\"\">Extending a SHACL shape<\/h3>\n<p class=\"\">SHACL allows shapes to be derived from other shapes. For example we might further qualify an order with those that have a shipper specified: a ShippingOrder<\/p>\n<p>&nbsp;This can be expressed in SHACL as follows:<\/p>\n<pre>shapes:ShippingOrder\r\n&nbsp; rdf:type sh:NodeShape ;\r\n&nbsp; sh:name \"ShippingOrder\" ;\r\n&nbsp; sh:node shapes:QualifiedOrder ;\r\n&nbsp; sh:property [\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rdf:type sh:PropertyShape ;\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sh:maxCount 1 ;\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sh:minCount 1 ;\r\n&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sh:path model:shipVia ;\r\n&nbsp;&nbsp;&nbsp; ];\r\n.<\/pre>\n<pre>OData2SPARQL Request:&nbsp;\r\n\r\n\u2026\/odata2sparql\/northwind\/shapes_QShippingOrder('NWD~Order-10248')?$select=*&amp;$expand=*&amp;$format=json<\/pre>\n<pre>OData2SPARQL Response:\r\n\r\n(This is the same structure as the QualifiedOrder with the addition of the Shipper details.)<\/pre>\n<h2 class=\"\">SHACL Northwind User Interface Example<\/h2>\n<p class=\"\">One of the motivations for the use of OData2SPARQL to publish RDF is that it brings together the strength of a ubiquitous RESTful interface standard (OData) with the flexibility, federation ability of RDF\/SPARQL. This opens up many popular user-interface development frameworks and tools such as OpenUI5 and SAP WebIDE. This greatly simplifies the creation of user interface applications.<\/p>\n<p class=\"\">Already OpenUI5 makes it very easy to create a user interface of say Orders. OpenUI5 uses the metadata published by OData (and hence RDF schema published by OData2SPARQL, as illustrated in <a href=\"http:\/\/inova8.com\/bg_inova8.com\/really-rapid-rdf-graph-application-development\/\">Really Rapid RDF Graph Application Development<\/a>)<\/p>\n<p class=\"\">With the addition of SHACL shapes to OData2SPARQL, it allows us to create a UI\/UX derived from the OData metadata, including these SHACL shapes. For example the QualifiedOrders shapes is what we would expect of a typical master-detail UI: the Order is the \u2018master\u2019 and the line-items of the order the \u2018detail\u2019. With OpenUI5 it is as simple to publish a SHACL shape as it is to publish any OData EntitySet based on an rdfs:Class.<\/p>\n<p class=\"\">Requesting all QualifiedOrders will show a list of any (not all) orders that satisfy the restrictions in the SHACL nodeShape. Odata2SPARQL does this by constructing a SPARQL query aligned with the nodeShape and containing the same restrictions.<\/p>\n<p class=\"\"><img loading=\"lazy\" class=\"alignnone size-full wp-image-1683\" src=\"http:\/\/inova8.com\/bg_inova8.com\/wp-content\/uploads\/2019\/03\/Grid.png\" alt=\"\" width=\"1898\" height=\"907\" srcset=\"https:\/\/inova8.com\/bg_inova8.com\/wp-content\/uploads\/2019\/03\/Grid.png 1898w, https:\/\/inova8.com\/bg_inova8.com\/wp-content\/uploads\/2019\/03\/Grid-300x143.png 300w, https:\/\/inova8.com\/bg_inova8.com\/wp-content\/uploads\/2019\/03\/Grid-768x367.png 768w, https:\/\/inova8.com\/bg_inova8.com\/wp-content\/uploads\/2019\/03\/Grid-1024x489.png 1024w\" sizes=\"(max-width: 1898px) 100vw, 1898px\" \/><\/p>\n<p class=\"\" style=\"text-align: center;\">Figure 1: A Grid displaying all QualifiedOrders derived directly from the shape definition<\/p>\n<p class=\"\">Similarly requesting everything about a particular QualifiedOrder will show a master-detail.<\/p>\n<ul class=\"\">\n<li>The master displays required salesperson and customer<\/li>\n<li>The detail contains all line items of the order (the shape specifies at least one)<\/li>\n<li>Each line item displays product, quantity, and discount<\/li>\n<\/ul>\n<p class=\"\"><img loading=\"lazy\" class=\"alignnone size-full wp-image-1682\" src=\"http:\/\/inova8.com\/bg_inova8.com\/wp-content\/uploads\/2019\/03\/MasterDetail.png\" alt=\"\" width=\"1302\" height=\"573\" srcset=\"https:\/\/inova8.com\/bg_inova8.com\/wp-content\/uploads\/2019\/03\/MasterDetail.png 1302w, https:\/\/inova8.com\/bg_inova8.com\/wp-content\/uploads\/2019\/03\/MasterDetail-300x132.png 300w, https:\/\/inova8.com\/bg_inova8.com\/wp-content\/uploads\/2019\/03\/MasterDetail-768x338.png 768w, https:\/\/inova8.com\/bg_inova8.com\/wp-content\/uploads\/2019\/03\/MasterDetail-1024x451.png 1024w\" sizes=\"(max-width: 1302px) 100vw, 1302px\" \/><\/p>\n<p class=\"\" style=\"text-align: center;\">Figure 2: A Master-Detail Derived Directly from the QualifiedOrder Shape<\/p>\n<h2 class=\"\">The benefits of OData2SPARQL+SHACL<\/h2>\n<p class=\"\">The addition of SHACL support to OData2SPARQL enables the model-centric approach of RDF-graphs to drive both a model-centric RESTful interface and model-centric user-interface.<\/p>\n<\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>OData2SPARQL V4 endpoint now publishes any SHACL nodeShapes defined in the model mapping them to OData complexTypes, along with existing capability of publishing RDFS and OWL classes, and SPIN queries. RDF graphs provide the best (IMHO) way to store and retrieve information. However creating user applications is complicated by the lack of a standard RESTful [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"bgseo_title":"","bgseo_description":"","bgseo_robots_index":"index","bgseo_robots_follow":"follow","_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0},"categories":[28],"tags":[48,43,41,40,49,35,44,38,42,36,37,39,45,34,47,46],"_links":{"self":[{"href":"https:\/\/inova8.com\/bg_inova8.com\/wp-json\/wp\/v2\/posts\/1675"}],"collection":[{"href":"https:\/\/inova8.com\/bg_inova8.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/inova8.com\/bg_inova8.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/inova8.com\/bg_inova8.com\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/inova8.com\/bg_inova8.com\/wp-json\/wp\/v2\/comments?post=1675"}],"version-history":[{"count":21,"href":"https:\/\/inova8.com\/bg_inova8.com\/wp-json\/wp\/v2\/posts\/1675\/revisions"}],"predecessor-version":[{"id":1719,"href":"https:\/\/inova8.com\/bg_inova8.com\/wp-json\/wp\/v2\/posts\/1675\/revisions\/1719"}],"wp:attachment":[{"href":"https:\/\/inova8.com\/bg_inova8.com\/wp-json\/wp\/v2\/media?parent=1675"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/inova8.com\/bg_inova8.com\/wp-json\/wp\/v2\/categories?post=1675"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/inova8.com\/bg_inova8.com\/wp-json\/wp\/v2\/tags?post=1675"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}