You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@jena.apache.org by "Gert van Valkenhoef (JIRA)" <ji...@apache.org> on 2015/10/13 15:55:05 UTC

[jira] [Commented] (JENA-1031) Aliases for data properties not used

    [ https://issues.apache.org/jira/browse/JENA-1031?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14954953#comment-14954953 ] 

Gert van Valkenhoef commented on JENA-1031:
-------------------------------------------

Hello Andy,

Thanks for having a look at this! I was on holiday so unfortunately I could not respond earlier. You are right that our test is flawed and if the example turtle had been well formatted the models would have been isomorphic. One point remains: aliases are created for the data properties, but those aliases are not used (that is, the properties with literal values are always referred to by their full URI, even if there is an alias for them).

Below I have a new test that will show that this *does* impact how Jena will parse the JSON-LD, and that equivalent JSON may be parsed differently because of this. As a result, JSON LD produced by Jena can not be processed in JavaScript and then given back to Jena in a way that preserves data types.

{code:java|title=test/JenaTest.java}
package test;

import static org.junit.Assert.assertTrue;

import java.io.FileReader;
import java.io.IOException;
import java.io.StringReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

import org.apache.jena.rdf.model.Model;
import org.apache.jena.rdf.model.ModelFactory;
import org.apache.jena.riot.RDFLanguages;
import org.junit.Test;

public class JenaTest {

	private String readJsonThroughJavaScript(String fileName) throws IOException, ScriptException {
		String inputJson = new String(Files.readAllBytes(Paths.get(fileName)), StandardCharsets.UTF_8);
		ScriptEngineManager factory = new ScriptEngineManager();
		ScriptEngine engine = factory.getEngineByName("JavaScript");
		engine.put("inputJson", inputJson);
		engine.eval("var outputJson = JSON.stringify(JSON.parse(inputJson), null, 2)");
		return (String) engine.get("outputJson");
	}
	
	public void testUsingFile(String fileName) throws IOException, ScriptException {
		Model model = ModelFactory.createDefaultModel();
		model.read(new FileReader(fileName), "http://example.com", RDFLanguages.strLangJSONLD);
		
		String outputJsonLd = readJsonThroughJavaScript(fileName);
		System.out.println(outputJsonLd);

		Model model2 = ModelFactory.createDefaultModel();
		model2.read(new StringReader(outputJsonLd), "http://example.com", RDFLanguages.strLangJSONLD);

		System.out.println(model2.getProperty(
				model2.getResource("http://example.com/a"),
				model2.getProperty("http://example.com/ontology#doubleValuedProperty")));

		System.out.println("Isomorphic? " + model.isIsomorphicWith(model2));
		assertTrue(model.isIsomorphicWith(model2));
	}
	
	@Test
	public void testRoundtripNoAlias() throws IOException, ScriptException {
		System.out.println("\n=====================================");
		System.out.println("Example JSON failing to use aliases");
		testUsingFile("test.json");
	}
	
	@Test
	public void testRoundtripAlias() throws IOException, ScriptException {
		System.out.println("\n=====================================");
		System.out.println("Example JSON using aliases");
		testUsingFile("test2.json");
	}
}
{code}

{code:javascript|title=test.json}
{
  "@id" : "http://example.com/a",
  "http://example.com/ontology#doubleValuedProperty" : 30.0,
  "http://www.w3.org/2000/01/rdf-schema#label" : "b",
  "@context" : {
    "doubleValuedProperty" : {
      "@id" : "http://example.com/ontology#doubleValuedProperty",
      "@type" : "http://www.w3.org/2001/XMLSchema#double"
    },
    "label" : {
      "@id" : "http://www.w3.org/2000/01/rdf-schema#label",
      "@type" : "http://www.w3.org/2001/XMLSchema#string"
    }
  }
}
{code}

{code:javascript|title=test2.json}
{
  "@id" : "http://example.com/a",
  "doubleValuedProperty" : 30.0,
  "label" : "b",
  "@context" : {
    "doubleValuedProperty" : {
      "@id" : "http://example.com/ontology#doubleValuedProperty",
      "@type" : "http://www.w3.org/2001/XMLSchema#double"
    },
    "label" : {
      "@id" : "http://www.w3.org/2000/01/rdf-schema#label",
      "@type" : "http://www.w3.org/2001/XMLSchema#string"
    }
  }
}
{code}

Note that the file test.json is exactly what Jena produces given the test.ttl that I supplied earlier. Also note that test2.json is identical, except that the defined aliases for properties are used when giving values to those properties (as I would expect).

This is the output of these two tests:

{code:none}
=====================================
Example JSON failing to use aliases
{
  "@id": "http://example.com/a",
  "http://example.com/ontology#doubleValuedProperty": 30,
  "http://www.w3.org/2000/01/rdf-schema#label": "b",
  "@context": {
    "doubleValuedProperty": {
      "@id": "http://example.com/ontology#doubleValuedProperty",
      "@type": "http://www.w3.org/2001/XMLSchema#double"
    },
    "label": {
      "@id": "http://www.w3.org/2000/01/rdf-schema#label",
      "@type": "http://www.w3.org/2001/XMLSchema#string"
    }
  }
}
[http://example.com/a, http://example.com/ontology#doubleValuedProperty, "30"^^http://www.w3.org/2001/XMLSchema#integer]
Isomorphic? false

=====================================
Example JSON using aliases
{
  "@id": "http://example.com/a",
  "doubleValuedProperty": 30,
  "label": "b",
  "@context": {
    "doubleValuedProperty": {
      "@id": "http://example.com/ontology#doubleValuedProperty",
      "@type": "http://www.w3.org/2001/XMLSchema#double"
    },
    "label": {
      "@id": "http://www.w3.org/2000/01/rdf-schema#label",
      "@type": "http://www.w3.org/2001/XMLSchema#string"
    }
  }
}
[http://example.com/a, http://example.com/ontology#doubleValuedProperty, "3.0E1"^^http://www.w3.org/2001/XMLSchema#double]
Isomorphic? true
{code}

As you can see, doing any kind of JavaScript processing on the JSON-LD is likely to format the number 30.0 differently, as in JavaScript there is no distinction between 30.0 and 30. When aliases are not used, Jena will treat this value as xsd:integer, whereas if the property is referred to by its alias, it will treat the value as xsd:double. Therefore, the JSON LD currently produced by Jena can not safely be processed by JavaScript and then given back to Jena. I suspect this also applies to other rdf/xsd datatypes that have no direct JSON analogue (e.g. xsd:date).

> Aliases for data properties not used
> ------------------------------------
>
>                 Key: JENA-1031
>                 URL: https://issues.apache.org/jira/browse/JENA-1031
>             Project: Apache Jena
>          Issue Type: Bug
>          Components: Jena
>    Affects Versions: Jena 3.0.0
>         Environment: Ubuntu 14.04 64bit, IntelliJ IDEA, JDK 8
>            Reporter: Gert van Valkenhoef
>            Assignee: Andy Seaborne
>            Priority: Minor
>
> When JSON-LD is generated for a graph, the @context will contain property aliases for all properties used in the graph. However, for properties that have a data value (rather than a resource), these aliases are not used, and the properties in the @graph are still their full URIs. This is harmful when the @context also specifies a data type. For example, doubles can be converted to integer by accident. The example turtle below results in JSON-LD that when parsed by Jena is not isomorphic with the graph parsed from turtle (because the doubleValuedProperty will get an integer value):
> {code:title=test.ttl}
> <a> <http://www.w3.org/2000/01/rdf-schema#label> "b".
> <a> <http://example.com/ontology#doubleValuedProperty> 3.0e1 .
> {code}
> The JSON-LD as output by Jena:
> {code:javascript}
> {
>   "@id" : "http://example.com/a",
>   "http://example.com/ontology#doubleValuedProperty" : 30.0,
>   "http://www.w3.org/2000/01/rdf-schema#label" : "b",
>   "@context" : {
>     "doubleValuedProperty" : {
>       "@id" : "http://example.com/ontology#doubleValuedProperty",
>       "@type" : "http://www.w3.org/2001/XMLSchema#double"
>     },
>     "label" : {
>       "@id" : "http://www.w3.org/2000/01/rdf-schema#label",
>       "@type" : "http://www.w3.org/2001/XMLSchema#string"
>     }
>   }
> }
> {code}
> A failing unit test for round-trip through JSON-LD:
> {code:java}
>   @Test
>   public void jenaBugTest() throws IOException {
>     Model model = ModelFactory.createDefaultModel();
>     model.read(new FileReader("test.ttl"), "http://example.com", RDFLanguages.strLangTurtle);
>     StringWriter writer = new StringWriter();
>     RDFDataMgr.write(writer, model, RDFLanguages.JSONLD);
>     writer.close();
>     System.out.println(writer.toString());
>     Model model2 = ModelFactory.createDefaultModel();
>     model2.read(new StringReader(writer.toString()), "http://example.com", RDFLanguages.strLangJSONLD);
>     assertTrue(model.isIsomorphicWith(model2));
>   }
> {code}



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)