Skip to content

Commit

Permalink
Rework pref. language logic to act as a filter
Browse files Browse the repository at this point in the history
  • Loading branch information
agarciadom committed Dec 18, 2024
1 parent 1d512dd commit c7ae549
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import org.apache.jena.rdf.model.Literal;
import org.apache.jena.rdf.model.Property;
Expand All @@ -28,12 +29,16 @@
import org.apache.jena.vocabulary.RDF;
import org.eclipse.epsilon.eol.execute.context.IEolContext;

import com.google.common.collect.HashMultimap;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.MultimapBuilder;

public class RDFResource extends RDFModelElement {
protected static final String LITERAL_SUFFIX = "_literal";
protected static List<String> preferredLanguageTagList;

// TODO should be moved to the model, and parsed only once when the model loads
protected List<String> preferredLanguageTagList;

enum LiteralMode {
RAW, VALUES_ONLY
Expand All @@ -51,45 +56,82 @@ public RDFResource(Resource resource, RDFModel rdfModel) {
public Resource getResource() {
return resource;
}


private Collection<Object> getPropertyPreferredLanguage(RDFQualifiedName pName, IEolContext context, LiteralMode literalMode) {
Collection<Object> value = null ;
for (String lTag : preferredLanguageTagList) {
RDFQualifiedName withLanguageTag = pName.withLanguageTag(lTag);
value = getProperty(withLanguageTag, context, literalMode);
if (!value.isEmpty()) {
break;
}
}
return value;
}

public Collection<Object> getProperty(String property, IEolContext context) {
final RDFQualifiedName pName = RDFQualifiedName.from(property, this.owningModel::getNamespaceURI);
Collection<Object> value = null ;

if ((pName.languageTag != null) && (pName.languageTag.equals(""))) { // Try preferred language tags
value = getPropertyPreferredLanguage(pName, context, LiteralMode.VALUES_ONLY);
} else { // A language tag was provided
value = getProperty(pName, context, LiteralMode.VALUES_ONLY);

Collection<Object> value = getProperty(pName, context, LiteralMode.RAW);
if (!value.isEmpty() && !value.stream().anyMatch(p -> p instanceof RDFResource)) {
value = filterByPreferredLanguage(value, LiteralMode.VALUES_ONLY);
if (!value.isEmpty()) {
return value;
}
}

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);

if ((pName.languageTag != null) && (pName.languageTag.equals(""))) { // Try preferred language tags
return getPropertyPreferredLanguage(withoutLiteral, context, LiteralMode.RAW);
} else { // A tag was provided
return getProperty(withoutLiteral, context, LiteralMode.RAW);
value = getProperty(withoutLiteral, context, LiteralMode.RAW);
if (!value.isEmpty() && !value.stream().anyMatch(p -> p instanceof RDFResource)) {
value = filterByPreferredLanguage(value, LiteralMode.RAW);
}
}

return value;
}

private Collection<Object> filterByPreferredLanguage(Collection<Object> value, LiteralMode literalMode) {
// If no preferred languages are specified, don't do any filtering
if (preferredLanguageTagList.isEmpty()) {
switch (literalMode) {
case RAW:
return value;
case VALUES_ONLY:
return value.stream().map(e -> e instanceof RDFLiteral
? ((RDFLiteral) e).getValue() : e).collect(Collectors.toList());
default:
throw new IllegalArgumentException("Unknown literal mode " + literalMode);
}
}

// Otherwise, group literals by language tag
Multimap<String, RDFLiteral> literalsByTag = HashMultimap.create();
for (Object element : value) {
if (element instanceof RDFLiteral) {
RDFLiteral literal = (RDFLiteral) element;
literalsByTag.put(literal.getLanguage() == null ? "" : literal.getLanguage(), literal);
} else {
// TODO see if we run into this scenario, print some warning, return value as is as fallback
throw new IllegalArgumentException("Expected RDFLiteral while filtering based on preferred languages, but got " + element);
}
}

for (String tag : preferredLanguageTagList) {
if (literalsByTag.containsKey(tag)) {
switch (literalMode) {
case RAW:
return new ArrayList<>(literalsByTag.get(tag));
case VALUES_ONLY:
return literalsByTag.get(tag).stream().map(l ->
l.getValue()).collect(Collectors.toList());
}
}
}

// If we don't find any matches in the preferred languages,
// fall back to the untagged literals (if any).
Collection<RDFLiteral> rawFromUntagged = literalsByTag.get("");
switch (literalMode) {
case RAW:
return new ArrayList<>(rawFromUntagged);
case VALUES_ONLY:
return rawFromUntagged.stream().map(l -> l.getValue())
.collect(Collectors.toList());
default:
throw new IllegalArgumentException("Unknown literal mode " + literalMode);
}
}

public Collection<Object> getProperty(RDFQualifiedName pName, IEolContext context, LiteralMode literalMode) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ goblin.enemyOf.println('Enemies of Green Goblin (without prefix): ');
//
// Q. Do we want some setting of "preferred language" for the RDF driver, instead of showing values for all languages?

goblin.enemyOf.name.flatten.println('All names of the enemies of the Green Goblin: ');
goblin.enemyOf.`name@`.flatten.println('All names in the default language of the enemies of the Green Goblin: ');
goblin.enemyOf.name.flatten.println('All names of the enemies of the Green Goblin (using language preferences, if any): ');
goblin.enemyOf.`name@`.flatten.println('All names without a language tag of the enemies of the Green Goblin: ');
goblin.enemyOf.`name@ru`.flatten.println('All Russian names of the enemies of the Green Goblin: ');
goblin.enemyOf.name_literal.flatten.println('All name literals of the enemies of the Green Goblin: ');
goblin.enemyOf.`name_literal@`.flatten.println('All name literals in the default language of the enemies of the Green Goblin: ');
Expand Down

0 comments on commit c7ae549

Please sign in to comment.