Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce https://enola.dev/labelProperty #875

Merged
merged 1 commit into from
Sep 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions docs/concepts/metadata.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ This is read from a number of "typical" properties; in order of priority:

If the thing itself doesn't have any of these, it will check if its [RDFS range](../models/www.w3.org/2000/01/rdf-schema/range.md) has any.

Alternatively, the (RDFS) `Class` of a Thing's (RDF) `type` can specify an [https://enola.dev/labelProperty](../models/enola.dev/labelProperty.md)
to specify the IRI of a "custom" property to use a label, if present; see `test/metadata-label-property.ttl` for an example illustrating how to use this.

This is always available; if a Thing has none of the above, then it will fallback to the CURIE, or else just the last part of its IRI.

## Description
Expand Down
1 change: 1 addition & 0 deletions java/dev/enola/thing/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ junit_tests(
":thing_java",
":thing_java_proto",
"//java/dev/enola/common/context",
"//java/dev/enola/common/context/testlib",
"//java/dev/enola/common/convert",
"//java/dev/enola/common/function",
"//java/dev/enola/common/io",
Expand Down
1 change: 1 addition & 0 deletions java/dev/enola/thing/KIRI.java
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ public static final class E {

public static final String IRI_TEMPLATE_PROPERTY = NS + "iriTemplate";
public static final String IRI_TEMPLATE_DATATYPE = NS + "IRITemplate";
public static final String LABEL_PROPERTY = NS + "labelProperty";
}

/** Schema.org Properties. */
Expand Down
25 changes: 18 additions & 7 deletions java/dev/enola/thing/metadata/ThingMetadataProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@

/**
* {@link MetadataProvider} implementation based on looking at {@link Things}s obtained via {@link
* ThingProvider}.
* ThingProvider}; see also related <a href="https://docs.enola.dev/concepts/metadata/>end-user
* documentation</a>.
*
* <p>Logs errors, but does not propagate exceptions from the <tt>ThingProvider</tt>, because we do
* not want to fail operations "just" because Metadata could not be obtained; all the methods have
Expand Down Expand Up @@ -101,10 +102,13 @@ public Metadata get(@Nullable Thing thing, String fallbackIRI) {
* as-is.
*/
private String getLabel(@Nullable Thing thing, String curie, String fallbackIRI) {
var label = getLabel_(thing);
var label = getAlternative(thing, KIRI.RDF.TYPE, type -> getLabelViaProperty(thing, type));
if (label != null) return label;

label = getAlternative(thing, KIRI.RDFS.RANGE, thingX -> getLabel_(thingX));
label = getLabel_(thing);
if (label != null) return label;

label = getAlternative(thing, KIRI.RDFS.RANGE, range -> getLabel_(range));
if (label != null) return label;

if (!curie.equals(fallbackIRI)) return curie;
Expand All @@ -123,6 +127,13 @@ private String getLabel(@Nullable Thing thing, String curie, String fallbackIRI)
}
}

private @Nullable String getLabelViaProperty(@Nullable Thing thing, Thing type) {
if (thing == null) return null;
var typesLabelProperty = type.getString(KIRI.E.LABEL_PROPERTY);
if (typesLabelProperty == null) return null;
return thing.getString(typesLabelProperty);
}

private @Nullable String getLabel_(@Nullable Thing thing) {
var label = getString(thing, KIRI.RDFS.LABEL);
if (label != null) return label;
Expand Down Expand Up @@ -184,18 +195,18 @@ private String getImageHTML(Thing thing) {
var emoji = getString(thing, KIRI.E.EMOJI);
if (emoji != null) return emoji;

emoji = getAlternative(thing, KIRI.RDFS.RANGE, thingX -> getEmoji_(thingX));
emoji = getAlternative(thing, KIRI.RDFS.RANGE, range -> getEmoji_(range));
if (emoji != null) return emoji;

emoji = getAlternative(thing, KIRI.RDF.TYPE, thingX -> getEmoji_(thingX));
emoji = getAlternative(thing, KIRI.RDF.TYPE, type -> getEmoji_(type));
return emoji;
}

private @Nullable String getImageURL_(Thing thing) {
var imageURL = getAlternative(thing, KIRI.RDFS.RANGE, thingX -> getImageURL__(thingX));
var imageURL = getAlternative(thing, KIRI.RDFS.RANGE, range -> getImageURL__(range));
if (imageURL != null) return imageURL;

imageURL = getAlternative(thing, KIRI.RDF.TYPE, thingX -> getImageURL__(thingX));
imageURL = getAlternative(thing, KIRI.RDF.TYPE, type -> getImageURL__(type));
return imageURL;
}

Expand Down
17 changes: 17 additions & 0 deletions java/dev/enola/thing/metadata/ThingMetadataProviderTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,25 @@

import static com.google.common.truth.Truth.assertThat;

import dev.enola.common.context.testlib.EnolaTestTLCRules;
import dev.enola.common.context.testlib.TestTLCRule;
import dev.enola.common.io.iri.namespace.NamespaceConverter;
import dev.enola.common.io.iri.namespace.NamespaceConverterIdentity;
import dev.enola.thing.KIRI;
import dev.enola.thing.Thing;
import dev.enola.thing.impl.ImmutableThing;
import dev.enola.thing.io.Loader;
import dev.enola.thing.repo.ThingMemoryRepositoryRW;
import dev.enola.thing.repo.ThingProvider;

import org.jspecify.annotations.Nullable;
import org.junit.Rule;
import org.junit.Test;

public class ThingMetadataProviderTest {

@Rule public TestTLCRule rlcRule = EnolaTestTLCRules.BASIC;

private static final NamespaceConverter NONS = new NamespaceConverterIdentity();

private static final ThingProvider NO_THING_PROVIDER = iri -> null;
Expand Down Expand Up @@ -80,6 +87,16 @@ public void label() {
.isEqualTo(THING_LABEL);
}

@Test
public void labelViaAlternativeLabelProperty() {
var uri = java.net.URI.create("classpath:/metadata-label-property.ttl");
var repo = new ThingMemoryRepositoryRW();
var things = new Loader().load(uri, repo);
var metadataProvider = new ThingMetadataProvider(repo, NONS);
var metadata = metadataProvider.get("https://example.org/test-metadata-label-property");
assertThat(metadata.label()).isEqualTo("LABEL");
}

@Test
public void description() {
assertThat(new ThingMetadataProvider(test, NONS).get(THING_IRI).descriptionHTML())
Expand Down
6 changes: 6 additions & 0 deletions models/enola.dev/enola.ttl
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,12 @@ enola:emoji a rdf:Property;
schema:description "Emoji 😃 of a Thing, from Unicode or <a href='https://www.nerdfonts.com'>Nerdfonts</a>.";
enola:emoji "😃".

enola:labelProperty a rdf:Property;
schema:name "Label Property";
rdfs:domain rdfs:Class;
rdfs:range xsd:anyURI;
schema:description "The IRI of a property to be used as Label for Things of this Class; see https://docs.enola.dev/concepts/metadata/".

enola:parent a rdf:Property;
rdfs:range schema:Thing;
rdfs:comment "A 'hierarchical' parent. This is typically subclassed - and thus there could be several different kinds of parents. Similar to https://schema.org/isPartOf; but that's specific to CreativeWork, while this is not.".
Expand Down
2 changes: 1 addition & 1 deletion test/metadata-label-property.ttl
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>.

example:test-metadata-label-property-class a rdfs:Class;
enola:label-property enola:altlab.
enola:labelProperty enola:altlab.

example:test-metadata-label-property a example:test-metadata-label-property-class;
enola:altlab "LABEL".