Skip to content

Commit

Permalink
Allow for :: in type and property names
Browse files Browse the repository at this point in the history
  • Loading branch information
agarciadom committed Nov 14, 2024
1 parent 5d5c4d4 commit 3687a68
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 20 deletions.
13 changes: 8 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,14 +70,15 @@ To obtain a specific RDF resource by its URL:
var goblin = Model.getElementById('http://example.org/#green-goblin');
```

To list all the resources that have an `rdf:type` predicate with a certain object acting as their type, use `Type.all`:
To list all the resources that have an `rdf:type` predicate with a certain object acting as their type, use `Prefix::Type.all`:

```
`foaf:Person`.all.println('All people: ');
foaf::Person.all.println('All people: ');
```

Note the above use of `foaf:Person`, using both the prefix and the local name, and the use of backticks to escape the name.
If there is no risk of ambiguity, you can just use the local name:
You could also use `` `foaf:Person` `` to follow a more RDF-like style, but you would need backticks to escape the name.

If there is no risk of ambiguity, you can just use the type name:

```
Person.all.println('All people: ');
Expand All @@ -94,7 +95,7 @@ For example:
goblin.`rel:enemyOf`.println('Enemies of the Green Goblin: ');
```

Note that currently `resource.p` will always return a collection, as we do not leverage yet the RDFS descriptions that could indicate the cardinality of `p`.
If we need to specify a prefix, we can use `` x.`prefix:localName` `` or `` x.`prefix::localName` `` (the EOL grammar requires backticks for colons inside property names, whether it's `:` or `::`).

If there is no risk of ambiguity, you can also drop the prefix:

Expand All @@ -105,6 +106,8 @@ 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.

**Note:** currently `resource.p` will always return a collection, as we do not leverage yet the RDFS descriptions that could indicate the cardinality of `p`.

### 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).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,16 @@

import java.util.Map;
import java.util.function.Function;
import java.util.regex.Pattern;

/**
* Represents a partially or fully-qualified name for an RDF resource, with an
* optional namespace URI. Instances are created using {@link #from(String, Map)}.
*/
public class RDFQualifiedName {

protected static final Pattern COLON_SPLITTER = Pattern.compile(":{1,2}");

final String prefix;
final String namespaceURI;
final String localName;
Expand All @@ -33,30 +37,37 @@ public RDFQualifiedName(String prefix, String nsURI, String localName, String la
}

/**
* Parses a property name, which may be in the form
* Parses a property name, which matches
* {@code (prefix:)?localName(@language)?}.
*/
public static RDFQualifiedName from(String property, Function<String, String> prefixToURIMapper) {
int colonIdx = property.indexOf(':');
String prefix = null, nsURI = null;
if (colonIdx != -1) {
prefix = property.substring(0, colonIdx);
nsURI = prefixToURIMapper.apply(prefix);
String[] parts = COLON_SPLITTER.split(property);
if (parts.length > 1) {
String nsURI = prefixToURIMapper.apply(parts[0]);
if (nsURI == null) {
throw new IllegalArgumentException(String.format("Unknown prefix '%s'", prefix));
throw new IllegalArgumentException(String.format("Unknown prefix '%s'", parts[0]));
}

property = property.substring(colonIdx + 1);
return from(parts[0], nsURI, parts[1]);
}

int atIdx = property.indexOf('@');
String languageTag = null;
if (atIdx != -1) {
languageTag = property.substring(atIdx + 1);
property = property.substring(0, atIdx);
return from(null, null, property);
}

/**
* Parses a property where the prefix (if any) has already been resolved to
* a namespace URI, and the local name matches {@code localName(@language)?}.
*/
public static RDFQualifiedName from(String prefix, String nsURI, String localNameWithOptionalTag) {
int atIdx = localNameWithOptionalTag.indexOf('@');
String localName = null, languageTag = null;
if (atIdx == -1) {
localName = localNameWithOptionalTag;
} else {
languageTag = localNameWithOptionalTag.substring(atIdx + 1);
localName = localNameWithOptionalTag.substring(0, atIdx);
}

return new RDFQualifiedName(prefix, nsURI, property, languageTag);
return new RDFQualifiedName(prefix, nsURI, localName, languageTag);
}

public RDFQualifiedName withLocalName(String newLocalName) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,13 @@ public void getNamesWithPrefix() throws Exception {
assertEquals(SPIDERMAN_NAMES, names);
}

@Test
public void getNamesWithDoubleColonPrefix() 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);
Expand Down Expand Up @@ -150,6 +157,15 @@ public void getAllPeopleWithPrefix() throws Exception {
assertEquals(ALL_PERSON_URIS, uris);
}

@Test
public void getAllPeopleWithPrefixDoubleColon() throws Exception {
Set<String> uris = new HashSet<>();
for (Object o : model.getAllOfType("foaf::Person")) {
uris.add((String) pGetter.invoke(o, "uri", context));
}
assertEquals(ALL_PERSON_URIS, uris);
}

@Test
public void knownTypes() {
assertTrue("The model should confirm that it knows the foaf:Person type", model.hasType("foaf:Person"));
Expand Down

0 comments on commit 3687a68

Please sign in to comment.