Skip to content

Commit

Permalink
Return values by default, use _literal suffix to access full RDFLiter…
Browse files Browse the repository at this point in the history
…al objects
  • Loading branch information
agarciadom committed Nov 14, 2024
1 parent 057a225 commit 5d5c4d4
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 18 deletions.
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,30 @@ 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:

```
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.
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,15 @@ public static RDFQualifiedName from(String property, Function<String, String> 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 + "]";
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -47,6 +53,17 @@ public Resource getResource() {
public Collection<Object> getProperty(String property, IEolContext context) {
final RDFQualifiedName pName = RDFQualifiedName.from(property, this.owningModel::getNamespaceURI);

Collection<Object> 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<Object> getProperty(RDFQualifiedName pName, IEolContext context, LiteralMode literalMode) {
// Filter statements by prefix and local name
ExtendedIterator<Statement> itStatements = null;
if (pName.prefix == null) {
Expand Down Expand Up @@ -74,14 +91,15 @@ public Collection<Object> getProperty(String property, IEolContext context) {
ListMultimap<String, Object> 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<String> 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)
));
}
Expand All @@ -92,7 +110,7 @@ public Collection<Object> getProperty(String property, IEolContext context) {
final List<Object> values = new ArrayList<>();
while (itStatements.hasNext()) {
Statement stmt = itStatements.next();
values.add(convertToModelObject(stmt.getObject()));
values.add(convertToModelObject(stmt.getObject(), literalMode));
}
return values;
}
Expand All @@ -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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,40 +76,39 @@ public void listAll() throws EolModelLoadingException {
public void getNamesWithoutPrefix() throws Exception {
Set<String> names = new HashSet<>();
for (RDFModelElement o : model.allContents()) {
for (RDFLiteral l : (Collection<RDFLiteral>) pGetter.invoke(o, "name", context)) {
names.add((String) pGetter.invoke(l, "value", context));
}
names.addAll((Collection<String>) pGetter.invoke(o, "name", context));
}
assertEquals(ALL_NAMES, names);
}

@Test
public void getNamesWithPrefix() throws Exception {
RDFResource res = (RDFResource) model.getElementById(SPIDERMAN_URI);
Set<String> names = new HashSet<>((Collection<String>) pGetter.invoke(res, "foaf:name", context));
assertEquals(SPIDERMAN_NAMES, names);
}

@Test
public void getNameLiteralsWithPrefix() throws Exception {
RDFResource res = (RDFResource) model.getElementById(SPIDERMAN_URI);
Set<String> names = new HashSet<>();
for (RDFLiteral l : (Collection<RDFLiteral>) pGetter.invoke(res, "foaf:name", context)) {
names.add((String) pGetter.invoke(l, "value", context));
for (RDFLiteral l : (Collection<RDFLiteral>) pGetter.invoke(res, "foaf:name_literal", context)) {
names.add((String) l.getValue());
}
assertEquals(SPIDERMAN_NAMES, names);
}

@Test
public void getNamesWithoutPrefixWithLanguageTag() throws Exception {
RDFResource res = (RDFResource) model.getElementById(SPIDERMAN_URI);
Set<String> names = new HashSet<>();
for (RDFLiteral l : (Collection<RDFLiteral>) pGetter.invoke(res, "name@ru", context)) {
names.add((String) pGetter.invoke(l, "value", context));
}
Set<String> names = new HashSet<>((Collection<String>) 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<String> names = new HashSet<>();
for (RDFLiteral l : (Collection<RDFLiteral>) pGetter.invoke(res, "foaf:name@ru", context)) {
names.add((String) pGetter.invoke(l, "value", context));
}
Set<String> names = new HashSet<>((Collection<String>) pGetter.invoke(res, "foaf:name@ru", context));
assertEquals(Collections.singleton(SPIDERMAN_NAME_RU), names);
}

Expand Down

0 comments on commit 5d5c4d4

Please sign in to comment.