diff --git a/README.md b/README.md index accea51..cc261bc 100644 --- a/README.md +++ b/README.md @@ -105,6 +105,10 @@ goblin.enemyOf.println('Enemies of the Green Goblin: '); If there are predicates with the same local name but different namespace URIs in the graph formed by all the loaded documents in a model, a warning will be issued. In this case, you should be using a prefix to avoid the ambiguity. +### Values of predicates + +The values in `resource.p` will be either other resources, or the values of the associated literals (without filtering by language tags). + It is possible to mention a language suffix, to limit the results to literals with that language. For instance: @@ -112,3 +116,19 @@ For instance: var spider = Model.getElementById('http://example.org/#spiderman'); spider.`name@ru`.println('Name of Spiderman in Russian: '); ``` + +### Accessing literal objects + +If you would like to access the `RDFLiteral` objects rather than just their values, use a `_literal` suffix as part of the local name (before any language tags). +For instance, we could change the above example to: + +``` +var spider = Model.getElementById('http://example.org/#spiderman'); +spider.`name_literal@ru`.println('Name literal of Spiderman in Russian: '); +``` + +`RDFLiteral` objects have several properties: + +* `value`: the raw value of the literal (usually a String, but it can be different for typed literals - see [Apache Jena typed literals](https://jena.apache.org/documentation/notes/typed-literals.html)). +* `language`: the language tag for the literal (if any). +* `datatypeURI`: the datatype URI for the literal. \ No newline at end of file diff --git a/bundles/org.eclipse.epsilon.emc.rdf/src/org/eclipse/epsilon/emc/rdf/RDFQualifiedName.java b/bundles/org.eclipse.epsilon.emc.rdf/src/org/eclipse/epsilon/emc/rdf/RDFQualifiedName.java index d870a4d..d27bb30 100644 --- a/bundles/org.eclipse.epsilon.emc.rdf/src/org/eclipse/epsilon/emc/rdf/RDFQualifiedName.java +++ b/bundles/org.eclipse.epsilon.emc.rdf/src/org/eclipse/epsilon/emc/rdf/RDFQualifiedName.java @@ -58,4 +58,15 @@ public static RDFQualifiedName from(String property, Function pr return new RDFQualifiedName(prefix, nsURI, property, languageTag); } + + public RDFQualifiedName withLocalName(String newLocalName) { + return new RDFQualifiedName(prefix, namespaceURI, newLocalName, languageTag); + } + + @Override + public String toString() { + return "RDFQualifiedName [prefix=" + prefix + ", namespaceURI=" + namespaceURI + ", localName=" + localName + + ", languageTag=" + languageTag + "]"; + } + } \ No newline at end of file diff --git a/bundles/org.eclipse.epsilon.emc.rdf/src/org/eclipse/epsilon/emc/rdf/RDFResource.java b/bundles/org.eclipse.epsilon.emc.rdf/src/org/eclipse/epsilon/emc/rdf/RDFResource.java index 272a72b..2c65b38 100644 --- a/bundles/org.eclipse.epsilon.emc.rdf/src/org/eclipse/epsilon/emc/rdf/RDFResource.java +++ b/bundles/org.eclipse.epsilon.emc.rdf/src/org/eclipse/epsilon/emc/rdf/RDFResource.java @@ -33,6 +33,12 @@ public class RDFResource extends RDFModelElement { + protected static final String LITERAL_SUFFIX = "_literal"; + + enum LiteralMode { + RAW, VALUES_ONLY + } + private Resource resource; public RDFResource(Resource resource, RDFModel rdfModel) { @@ -47,6 +53,17 @@ public Resource getResource() { public Collection getProperty(String property, IEolContext context) { final RDFQualifiedName pName = RDFQualifiedName.from(property, this.owningModel::getNamespaceURI); + Collection value = getProperty(pName, context, LiteralMode.VALUES_ONLY); + if (value.isEmpty() && pName.localName.endsWith(LITERAL_SUFFIX)) { + final String localNameWithoutSuffix = pName.localName.substring(0, pName.localName.length() - LITERAL_SUFFIX.length()); + RDFQualifiedName withoutLiteral = pName.withLocalName(localNameWithoutSuffix); + return getProperty(withoutLiteral, context, LiteralMode.RAW); + } + + return value; + } + + public Collection getProperty(RDFQualifiedName pName, IEolContext context, LiteralMode literalMode) { // Filter statements by prefix and local name ExtendedIterator itStatements = null; if (pName.prefix == null) { @@ -74,14 +91,15 @@ public Collection getProperty(String property, IEolContext context) { ListMultimap values = MultimapBuilder.hashKeys().arrayListValues().build(); while (itStatements.hasNext()) { Statement stmt = itStatements.next(); - values.put(stmt.getPredicate().getURI(), convertToModelObject(stmt.getObject())); + values.put(stmt.getPredicate().getURI(), + convertToModelObject(stmt.getObject(), literalMode)); } final Set distinctKeys = values.keySet(); if (distinctKeys.size() > 1) { context.getWarningStream().println(String.format( "Ambiguous access to property '%s': multiple prefixes found (%s)", - property, + pName, String.join(", ", distinctKeys) )); } @@ -92,7 +110,7 @@ public Collection getProperty(String property, IEolContext context) { final List values = new ArrayList<>(); while (itStatements.hasNext()) { Statement stmt = itStatements.next(); - values.add(convertToModelObject(stmt.getObject())); + values.add(convertToModelObject(stmt.getObject(), literalMode)); } return values; } @@ -111,9 +129,14 @@ public String getUri() { return resource.getURI(); } - protected RDFModelElement convertToModelObject(RDFNode node) { + protected Object convertToModelObject(RDFNode node, LiteralMode lMode) { if (node instanceof Literal) { - return new RDFLiteral((Literal) node, this.owningModel); + switch (lMode) { + case RAW: + return new RDFLiteral((Literal) node, this.owningModel); + case VALUES_ONLY: + return ((Literal) node).getValue(); + } } else if (node instanceof Resource) { return new RDFResource((Resource) node, this.owningModel); } diff --git a/tests/org.eclipse.epsilon.emc.rdf.tests/src/org/eclipse/epsilon/emc/rdf/RDFModelTest.java b/tests/org.eclipse.epsilon.emc.rdf.tests/src/org/eclipse/epsilon/emc/rdf/RDFModelTest.java index d8c9eea..eaf970d 100644 --- a/tests/org.eclipse.epsilon.emc.rdf.tests/src/org/eclipse/epsilon/emc/rdf/RDFModelTest.java +++ b/tests/org.eclipse.epsilon.emc.rdf.tests/src/org/eclipse/epsilon/emc/rdf/RDFModelTest.java @@ -76,19 +76,24 @@ public void listAll() throws EolModelLoadingException { public void getNamesWithoutPrefix() throws Exception { Set names = new HashSet<>(); for (RDFModelElement o : model.allContents()) { - for (RDFLiteral l : (Collection) pGetter.invoke(o, "name", context)) { - names.add((String) pGetter.invoke(l, "value", context)); - } + names.addAll((Collection) pGetter.invoke(o, "name", context)); } assertEquals(ALL_NAMES, names); } @Test public void getNamesWithPrefix() throws Exception { + RDFResource res = (RDFResource) model.getElementById(SPIDERMAN_URI); + Set names = new HashSet<>((Collection) pGetter.invoke(res, "foaf:name", context)); + assertEquals(SPIDERMAN_NAMES, names); + } + + @Test + public void getNameLiteralsWithPrefix() throws Exception { RDFResource res = (RDFResource) model.getElementById(SPIDERMAN_URI); Set names = new HashSet<>(); - for (RDFLiteral l : (Collection) pGetter.invoke(res, "foaf:name", context)) { - names.add((String) pGetter.invoke(l, "value", context)); + for (RDFLiteral l : (Collection) pGetter.invoke(res, "foaf:name_literal", context)) { + names.add((String) l.getValue()); } assertEquals(SPIDERMAN_NAMES, names); } @@ -96,20 +101,14 @@ public void getNamesWithPrefix() throws Exception { @Test public void getNamesWithoutPrefixWithLanguageTag() throws Exception { RDFResource res = (RDFResource) model.getElementById(SPIDERMAN_URI); - Set names = new HashSet<>(); - for (RDFLiteral l : (Collection) pGetter.invoke(res, "name@ru", context)) { - names.add((String) pGetter.invoke(l, "value", context)); - } + Set names = new HashSet<>((Collection) pGetter.invoke(res, "name@ru", context)); assertEquals(Collections.singleton(SPIDERMAN_NAME_RU), names); } @Test public void getNamesWithPrefixAndLanguageTag() throws Exception { RDFResource res = (RDFResource) model.getElementById(SPIDERMAN_URI); - Set names = new HashSet<>(); - for (RDFLiteral l : (Collection) pGetter.invoke(res, "foaf:name@ru", context)) { - names.add((String) pGetter.invoke(l, "value", context)); - } + Set names = new HashSet<>((Collection) pGetter.invoke(res, "foaf:name@ru", context)); assertEquals(Collections.singleton(SPIDERMAN_NAME_RU), names); }