From effe53894f958b7316b134c94bff9404b39c2ef5 Mon Sep 17 00:00:00 2001
From: Pierre Maillot
Date: Fri, 28 Nov 2025 10:13:24 +0100
Subject: [PATCH 01/13] RDFa vocabulary
---
.../next/impl/common/vocabulary/RDFa.java | 63 +++++++++++++++++++
1 file changed, 63 insertions(+)
create mode 100644 src/main/java/fr/inria/corese/core/next/impl/common/vocabulary/RDFa.java
diff --git a/src/main/java/fr/inria/corese/core/next/impl/common/vocabulary/RDFa.java b/src/main/java/fr/inria/corese/core/next/impl/common/vocabulary/RDFa.java
new file mode 100644
index 000000000..a25b74f26
--- /dev/null
+++ b/src/main/java/fr/inria/corese/core/next/impl/common/vocabulary/RDFa.java
@@ -0,0 +1,63 @@
+package fr.inria.corese.core.next.impl.common.vocabulary;
+
+import fr.inria.corese.core.next.api.IRI;
+import fr.inria.corese.core.next.impl.common.BasicIRI;
+import fr.inria.corese.core.next.impl.exception.IncorrectFormatException;
+
+public enum RDFa implements Vocabulary {
+
+ PGClass("PGClass"),
+ Pattern("Pattern"),
+ PrefixOrTermMapping("PrefixOrTermMapping"),
+ DocumentError("DocumentError"),
+ Info("Info"),
+ PrefixRedefinition("PrefixRedefinition"),
+ UnresolvedCURIE("UnresolvedCURIE"),
+ UnresolvedTerm("UnresolvedTerm"),
+ VocabReferenceError("VocabReferenceError"),
+ context("context"),
+ copy("copy"),
+ prefix("prefix"),
+ term("term"),
+ uri("uri"),
+ usesVocabulary("usesVocabulary"),
+ vocabulary("vocabulary"),
+ Error("Error"),
+ PrefixMapping("PrefixMapping"),
+ TermMapping("TermMapping"),
+ Warning("Warning");
+
+ private final IRI iri;
+
+ /**
+ * Constructor for the RDFa vocabulary enum.
+ *
+ * @param localName the local name of the IRI
+ * @throws IncorrectFormatException if the namespace and the local name do not form a correct IRI
+ */
+ RDFa(String localName) {
+ this.iri = new BasicIRI(getNamespace(), localName);
+ }
+ @Override
+ public IRI getIRI() {
+ return this.iri;
+ }
+
+ @Override
+ public String getNamespace() {
+ return getVocabularyNamespace();
+ }
+
+ @Override
+ public String getPreferredPrefix() {
+ return getVocabularyPreferredPrefix();
+ }
+
+ public static String getVocabularyNamespace() {
+ return "http://www.w3.org/ns/rdfa#";
+ }
+
+ public static String getVocabularyPreferredPrefix() {
+ return "rdfa";
+ }
+}
From 6aa3c6fe0dd07f98a355d5803f39f15fc5ba3cba Mon Sep 17 00:00:00 2001
From: Pierre Maillot
Date: Thu, 4 Dec 2025 10:20:53 +0100
Subject: [PATCH 02/13] RDF11 processing first pass
---
.../inria/corese/core/next/api/Namespace.java | 2 +-
.../core/next/api/base/io/RDFFormat.java | 19 +-
.../next/impl/io/parser/ParserFactory.java | 10 +-
.../io/parser/rdfa/AbstractRDFaParser.java | 80 +++
.../{RDFaParser.java => RDFa10Parser.java} | 209 +++----
.../impl/io/parser/rdfa/RDFa11Parser.java | 559 ++++++++++++++++++
.../io/parser/rdfa/RDFaEvaluationContext.java | 176 ------
.../model/AbstractRDFaEvaluationContext.java | 160 +++++
.../rdfa/model/RDFa10EvaluationContext.java | 51 ++
.../rdfa/model/RDFa11EvaluationContext.java | 101 ++++
.../io/parser/rdfa/model/RDFaAttributes.java | 29 +
.../rdfa/model/RDFaEvaluationContext.java | 38 ++
.../rdfa/model/RDFaIncompleteStatement.java | 3 +-
.../rdfa/model/RDFaInitialPrefixes.java | 121 ++++
.../core/next/api/base/io/RDFFormatTest.java | 2 +-
...aParserTest.java => RDFa10ParserTest.java} | 16 +-
.../impl/io/parser/rdfa/RDFa11ParserTest.java | 27 +
17 files changed, 1266 insertions(+), 337 deletions(-)
create mode 100644 src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/AbstractRDFaParser.java
rename src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/{RDFaParser.java => RDFa10Parser.java} (59%)
create mode 100644 src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/RDFa11Parser.java
delete mode 100644 src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/RDFaEvaluationContext.java
create mode 100644 src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/model/AbstractRDFaEvaluationContext.java
create mode 100644 src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/model/RDFa10EvaluationContext.java
create mode 100644 src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/model/RDFa11EvaluationContext.java
create mode 100644 src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/model/RDFaAttributes.java
create mode 100644 src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/model/RDFaEvaluationContext.java
create mode 100644 src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/model/RDFaInitialPrefixes.java
rename src/test/java/fr/inria/corese/core/next/impl/io/parser/rdfa/{RDFaParserTest.java => RDFa10ParserTest.java} (96%)
create mode 100644 src/test/java/fr/inria/corese/core/next/impl/io/parser/rdfa/RDFa11ParserTest.java
diff --git a/src/main/java/fr/inria/corese/core/next/api/Namespace.java b/src/main/java/fr/inria/corese/core/next/api/Namespace.java
index 76a7f3a52..42c5bde5c 100644
--- a/src/main/java/fr/inria/corese/core/next/api/Namespace.java
+++ b/src/main/java/fr/inria/corese/core/next/api/Namespace.java
@@ -5,7 +5,7 @@
/**
* Represents a namespace with a prefix and the start of an IRI as its name.
*/
-public interface Namespace extends Serializable, Comparable {
+public interface Namespace extends Serializable {
/**
* @return The prefix of the namespace.
diff --git a/src/main/java/fr/inria/corese/core/next/api/base/io/RDFFormat.java b/src/main/java/fr/inria/corese/core/next/api/base/io/RDFFormat.java
index 14970afa1..f2b8ab814 100644
--- a/src/main/java/fr/inria/corese/core/next/api/base/io/RDFFormat.java
+++ b/src/main/java/fr/inria/corese/core/next/api/base/io/RDFFormat.java
@@ -47,7 +47,7 @@ public class RDFFormat extends FileFormat {
public static final RDFFormat RDFXML = new RDFFormat(
"RDF/XML",
List.of("rdf", "xml"),
- List.of("application/rdf+xml"),
+ List.of("application/rdf+xml", "application/xml", "text/xml"),
true,
false);
@@ -65,10 +65,17 @@ public class RDFFormat extends FileFormat {
false,
true);
- public static final RDFFormat RDFa = new RDFFormat(
- "RDFa",
- List.of("html", "xhtml"),
- List.of("text/html", "application/xhtml+xml"),
+ public static final RDFFormat RDFa_1_0 = new RDFFormat(
+ "RDFa 1.0",
+ List.of("html"),
+ List.of("text/html"),
+ true,
+ false);
+
+ public static final RDFFormat RDFa_1_1 = new RDFFormat(
+ "RDFa 1.1",
+ List.of("xhtml", "svg", "xml"),
+ List.of("application/xhtml+xml", "image/svg+xml", "application/xml", "text/xml"),
true,
false);
@@ -158,7 +165,7 @@ public static Optional byMimeType(String mimeType) {
* @return An unmodifiable List of all RdfFormat constants.
*/
public static List all() {
- return List.of(TURTLE, NTRIPLES, NQUADS, JSONLD, RDFXML, TRIG, RDFC_1_0, RDFa);
+ return List.of(TURTLE, NTRIPLES, NQUADS, JSONLD, RDFXML, TRIG, RDFC_1_0, RDFa_1_0, RDFa_1_1);
}
@Override
diff --git a/src/main/java/fr/inria/corese/core/next/impl/io/parser/ParserFactory.java b/src/main/java/fr/inria/corese/core/next/impl/io/parser/ParserFactory.java
index 29f5b11fb..7812e44d3 100644
--- a/src/main/java/fr/inria/corese/core/next/impl/io/parser/ParserFactory.java
+++ b/src/main/java/fr/inria/corese/core/next/impl/io/parser/ParserFactory.java
@@ -9,7 +9,7 @@
import fr.inria.corese.core.next.impl.io.parser.jsonld.JSONLDParser;
import fr.inria.corese.core.next.impl.io.parser.nquads.NQuadsParser;
import fr.inria.corese.core.next.impl.io.parser.ntriples.NTriplesParser;
-import fr.inria.corese.core.next.impl.io.parser.rdfa.RDFaParser;
+import fr.inria.corese.core.next.impl.io.parser.rdfa.RDFa10Parser;
import fr.inria.corese.core.next.impl.io.parser.rdfxml.RDFXMLParser;
import fr.inria.corese.core.next.impl.io.parser.turtle.TurtleParser;
import fr.inria.corese.core.next.impl.io.parser.trig.TriGParser;
@@ -53,8 +53,8 @@ public RDFParser createRDFParser(RDFFormat format, Model model, ValueFactory fac
return new TriGParser(model, factory, config);
} else if(format == RDFFormat.RDFC_1_0) {
return new NQuadsParser(model, factory, config);
- } else if (format == RDFFormat.RDFa) {
- return new RDFaParser(model, factory, config);
+ } else if (format == RDFFormat.RDFa_1_0) {
+ return new RDFa10Parser(model, factory, config);
}
throw new IllegalArgumentException("Unsupported format: " + format);
}
@@ -80,8 +80,8 @@ public RDFParser createRDFParser(RDFFormat format, Model model, ValueFactory fac
return new RDFXMLParser(model, factory);
} else if (format == RDFFormat.TRIG) {
return new TriGParser(model, factory);
- } else if (format == RDFFormat.RDFa) {
- return new RDFaParser(model, factory);
+ } else if (format == RDFFormat.RDFa_1_0) {
+ return new RDFa10Parser(model, factory);
}
throw new IllegalArgumentException("Unsupported format: " + format);
}
diff --git a/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/AbstractRDFaParser.java b/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/AbstractRDFaParser.java
new file mode 100644
index 000000000..d9fee9f6f
--- /dev/null
+++ b/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/AbstractRDFaParser.java
@@ -0,0 +1,80 @@
+package fr.inria.corese.core.next.impl.io.parser.rdfa;
+
+import fr.inria.corese.core.next.api.IRI;
+import fr.inria.corese.core.next.api.Model;
+import fr.inria.corese.core.next.api.Resource;
+import fr.inria.corese.core.next.api.ValueFactory;
+import fr.inria.corese.core.next.api.base.io.parser.AbstractRDFParser;
+import fr.inria.corese.core.next.api.io.IOOptions;
+import fr.inria.corese.core.next.impl.common.util.IRIUtils;
+import fr.inria.corese.core.next.impl.exception.ParsingErrorException;
+import fr.inria.corese.core.next.impl.io.parser.rdfa.model.RDFaEvaluationContext;
+
+import java.util.Optional;
+
+public abstract class AbstractRDFaParser extends AbstractRDFParser {
+
+ protected RDFaEvaluationContext currentContext;
+
+ protected AbstractRDFaParser(Model model, ValueFactory factory) {
+ super(model, factory);
+ }
+
+ protected AbstractRDFaParser(Model model, ValueFactory factory, IOOptions config) {
+ super(model, factory, config);
+ }
+
+ /**
+ * Resolves the string representation of a resource found in attributes of an element, be it an IRI, CURIE or relative URI
+ *
+ * @param stringResource the resource as stored in the attribute of the HTML element
+ * @param context the context of the element evalation
+ * @return the full IRI if it is a relative IRI, full IRI or CURIE, nothing otherwise
+ */
+ protected Optional resolveStringResource(String stringResource, RDFaEvaluationContext context) {
+ String resultString = stringResource;
+ if (resultString.startsWith("[") && resultString.endsWith("]")) {
+ resultString = resultString.replaceFirst("\\[", "");
+ resultString = resultString.replaceFirst("]", "");
+ }
+
+
+ if (stringUriIsCURIE(resultString)) { // CURIE
+ int colonIndex = resultString.indexOf(":");
+ String prefixString = resultString.substring(0, colonIndex);
+ String localNameString = resultString.substring(colonIndex + 1);
+ // Basic resolution following https://www.w3.org/TR/rdfa-syntax/#s_convertingcurietouri
+ if (context.hasIriMapping(prefixString)) {
+ IRI namespaceIRI = context.getIriMapping(prefixString);
+
+ return Optional.of(this.getValueFactory().createIRI(namespaceIRI.stringValue(), localNameString));
+ } else if (prefixString.isEmpty()) { // CURIE is relative to the base URI
+ return Optional.of(this.getValueFactory().createIRI(context.getBaseIri().stringValue(), localNameString));
+ } else {
+ throw new ParsingErrorException("CURIE " + stringResource + " uses unknown prefix");
+ }
+ } else if (IRIUtils.isStandardIRI(resultString)) { // Full IRI
+ return Optional.of(this.getValueFactory().createIRI(resultString));
+
+ } else if (resultString.startsWith("_:")) { // Blank Node
+ int colonIndex = resultString.indexOf(":");
+ String localNameString = resultString.substring(colonIndex + 1);
+ return Optional.of(this.getValueFactory().createBNode(localNameString));
+ } else if (IRIUtils.isStandardIRI(context.getBaseIri().stringValue() + resultString)) {
+ String concatenatedRelativeUri = context.getBaseIri().stringValue() + resultString;
+ return Optional.of(getValueFactory().createIRI(concatenatedRelativeUri));
+ }
+ return Optional.empty();
+ }
+
+ /**
+ * Equivalent to test if it has a colon, and it is not a blank node
+ *
+ * @param stringIri
+ * @return
+ */
+ protected boolean stringUriIsCURIE(String stringIri) {
+ int colonIndex = stringIri.indexOf(":");
+ return colonIndex > -1 && !stringIri.contains("://") && !stringIri.startsWith("_:") && !stringIri.startsWith("[_:");
+ }
+}
diff --git a/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/RDFaParser.java b/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/RDFa10Parser.java
similarity index 59%
rename from src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/RDFaParser.java
rename to src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/RDFa10Parser.java
index c601825e5..689c15ba9 100644
--- a/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/RDFaParser.java
+++ b/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/RDFa10Parser.java
@@ -9,15 +9,15 @@
import fr.inria.corese.core.next.impl.common.vocabulary.RDF;
import fr.inria.corese.core.next.impl.exception.ParsingErrorException;
import fr.inria.corese.core.next.impl.io.common.IOConstants;
+import fr.inria.corese.core.next.impl.io.parser.rdfa.model.RDFa10EvaluationContext;
+import fr.inria.corese.core.next.impl.io.parser.rdfa.model.RDFaAttributes;
+import fr.inria.corese.core.next.impl.io.parser.rdfa.model.RDFaEvaluationContext;
import fr.inria.corese.core.next.impl.io.parser.rdfa.model.RDFaIncompleteStatement;
-import fr.inria.corese.core.next.impl.io.parser.util.ParserConstants;
import org.apache.commons.io.input.ReaderInputStream;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Attribute;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import java.io.InputStream;
import java.io.InputStreamReader;
@@ -28,35 +28,23 @@
/**
* RDFa parser. This parser will load the RDF data stored as RDFa in an HTML page. Its inner implementation is based on the jsoup library. It loads the html page as DOM and process it following the recommended algorithm in the RDFa recommendation.
*/
-public class RDFaParser extends AbstractRDFParser {
+public class RDFa10Parser extends AbstractRDFaParser {
private static final String BASE_TAG = "base";
- private static final String REL_ATTR = "rel";
- private static final String REV_ATTR = "rev";
- private static final String CONTENT_ATTR = "content";
- private static final String HREF_ATTR = "href";
- private static final String SRC_ATTR = "src";
- private static final String ABOUT_ATTR = "about";
- private static final String PROPERTY_ATTR = "property";
- private static final String RESOURCE_ATTR = "resource";
- private static final String DATATYPE_ATTR = "datatype";
- private static final String TYPEOF_ATTR = "typeof";
- private static final String LANG_ATTR = "xml:lang";
-
private static final String XMLNS_PREFIX = "xmlns";
- public RDFaParser(Model model, ValueFactory factory) {
+ public RDFa10Parser(Model model, ValueFactory factory) {
this(model, factory, new RDFaParserOptions.Builder().build());
}
- public RDFaParser(Model model, ValueFactory factory, IOOptions config) {
+ public RDFa10Parser(Model model, ValueFactory factory, IOOptions config) {
super(model, factory, config);
}
@Override
public RDFFormat getRDFFormat() {
- return RDFFormat.RDFa;
+ return RDFFormat.RDFa_1_0;
}
@Override
@@ -96,7 +84,7 @@ private void processDocument(Document document, IRI baseIri) {
Iterator baseElementIterator = document.stream().filter(element -> element.nameIs(BASE_TAG)).iterator();
while (baseElementIterator.hasNext()) {
Element baseElement = baseElementIterator.next();
- Attribute baseElementHrefAttribute = baseElement.attribute(HREF_ATTR);
+ Attribute baseElementHrefAttribute = baseElement.attribute(RDFaAttributes.HREF.getName());
if (baseElementHrefAttribute != null) {
String baseIriString = baseElementHrefAttribute.getValue();
baseIriFromXml = getValueFactory().createIRI(baseIriString);
@@ -107,7 +95,7 @@ private void processDocument(Document document, IRI baseIri) {
}
for (Element element : document.children()) {
- processElement(element, new RDFaEvaluationContext(baseIri));
+ processElement(element, new RDFa10EvaluationContext(baseIri));
}
}
@@ -118,96 +106,93 @@ private void processDocument(Document document, IRI baseIri) {
* @param skipElement Flag thet indicates whether the [current element] can safely be ignored since it has no relevant RDFa attributes. Note that descendant elements will still be processed.
* @see RDFa processing in details
*/
- private void processElement(Element element, RDFaEvaluationContext context, boolean recursive, boolean skipElement) {
+ private void processElement(Element element, fr.inria.corese.core.next.impl.io.parser.rdfa.model.RDFa10EvaluationContext context, boolean recursive, boolean skipElement) {
// 1. First, the local values are initialized
Resource newSubject = null;
Resource currentObject = null;
Literal currentObjectLiteral = null;
- Map currentMappings = context.uriMappings();
+ Map currentMappings = context.getIriMappings();
Set incompleteStatementSet = new HashSet<>();
String language = context.getLanguage();
// 2. Next the [current element] is parsed for [URI mapping]s and these are added to the [local list of URI mappings]. Note that a [URI mapping] will simply overwrite any current mapping in the list that has the same name;
// Looking for namespace declarations
// Namespace declaration are done using the XML namespace declaration mechanism, that can be seen as an attributes prefixed by "xmlns" and looks like this: "xmlns:prefix=namespace"
- Iterator itAttribute = element.attributes().iterator();
- while(itAttribute.hasNext()) {
- Attribute attribute = itAttribute.next();
+ for (Attribute attribute : element.attributes()) {
if (attribute.getKey().startsWith(XMLNS_PREFIX)) {
String prefixName = attribute.localName();
IRI prefixNamespace = getValueFactory().createIRI(attribute.getValue(), "");
- context.addUriMapping(prefixName, prefixNamespace);
+ context.addIriMapping(prefixName, prefixNamespace);
}
}
// 3. The [current element] is also parsed for any language information, and if present, [current language] is set accordingly;
- if (element.attribute(LANG_ATTR) != null) {
- String langString = element.attr(LANG_ATTR);
- language = langString;
+ if (element.attribute(RDFaAttributes.LANG.getName()) != null) {
+ language = element.attr(RDFaAttributes.LANG.getName());
}
// 4. If the [current element] contains no @rel or @rev attribute, then the next step is to establish a value for [new subject]. Any of the attributes that can carry a resource can set [new subject];
- if(element.attribute(REL_ATTR) == null && element.attribute(REV_ATTR) == null) {
+ if(element.attribute(RDFaAttributes.REL.getName()) == null && element.attribute(RDFaAttributes.REV.getName()) == null) {
// [new subject] is set to the URI obtained from the first match from the following rules:
- if (element.attribute(ABOUT_ATTR) != null) { // by using the URI from @about, if present, obtained according to the section on CURIE and URI Processing;
- Optional newSubjectResource = getResourceFromElementAttribute(element, ABOUT_ATTR, context);
+ if (element.attribute(RDFaAttributes.ABOUT.getName()) != null) { // by using the URI from @about, if present, obtained according to the section on CURIE and URI Processing;
+ Optional newSubjectResource = getResourceFromElementAttribute(element, RDFaAttributes.ABOUT.getName(), context);
if (newSubjectResource.isPresent()) {
newSubject = newSubjectResource.get();
}
- } else if (element.attribute(SRC_ATTR) != null) { // otherwise, by using the URI from @src, if present, obtained according to the section on CURIE and URI Processing.
- Optional newSubjectResource = getResourceFromElementAttribute(element, SRC_ATTR, context);
+ } else if (element.attribute(RDFaAttributes.SRC.getName()) != null) { // otherwise, by using the URI from @src, if present, obtained according to the section on CURIE and URI Processing.
+ Optional newSubjectResource = getResourceFromElementAttribute(element, RDFaAttributes.SRC.getName(), context);
if (newSubjectResource.isPresent()) {
newSubject = newSubjectResource.get();
}
- } else if (element.attribute(RESOURCE_ATTR) != null) { // otherwise, by using the URI from @resource, if present, obtained according to the section on CURIE and URI Processing;
- Optional newSubjectResource = getResourceFromElementAttribute(element, RESOURCE_ATTR, context);
+ } else if (element.attribute(RDFaAttributes.RESOURCE.getName()) != null) { // otherwise, by using the URI from @resource, if present, obtained according to the section on CURIE and URI Processing;
+ Optional newSubjectResource = getResourceFromElementAttribute(element, RDFaAttributes.RESOURCE.getName(), context);
if (newSubjectResource.isPresent()) {
newSubject = newSubjectResource.get();
}
- } else if (element.attribute(HREF_ATTR) != null) { // otherwise, by using the URI from @href, if present, obtained according to the section on CURIE and URI Processing.
- Optional newSubjectResource = getResourceFromElementAttribute(element, HREF_ATTR, context);
+ } else if (element.attribute(RDFaAttributes.HREF.getName()) != null) { // otherwise, by using the URI from @href, if present, obtained according to the section on CURIE and URI Processing.
+ Optional newSubjectResource = getResourceFromElementAttribute(element, RDFaAttributes.HREF.getName(), context);
if (newSubjectResource.isPresent()) {
newSubject = newSubjectResource.get();
}
} else if (element.nameIs("body") || element.nameIs("head")) { // if the element is the head or body element then act as if there is an empty @about present, and process it according to the rule for @about, above;
- newSubject = context.baseIri();
- } else if (element.attribute(TYPEOF_ATTR) != null) { // if @typeof is present, obtained according to the section on CURIE and URI Processing, then [new subject] is set to be a newly created [bnode].
+ newSubject = context.getBaseIri();
+ } else if (element.attribute(RDFaAttributes.TYPEOF.getName()) != null) { // if @typeof is present, obtained according to the section on CURIE and URI Processing, then [new subject] is set to be a newly created [bnode].
newSubject = this.getValueFactory().createBNode();
- } else if (context.parentObjectResource() != null) { // otherwise, if [parent object] is present, [new subject] is set to the value of [parent object]. Additionally, if @property is not present then the [skip element] flag is set to 'true';
- newSubject = context.parentObjectResource();
- if(element.attribute(PROPERTY_ATTR) == null) {
+ } else if (context.getParentObjectResource() != null) { // otherwise, if [parent object] is present, [new subject] is set to the value of [parent object]. Additionally, if @property is not present then the [skip element] flag is set to 'true';
+ newSubject = context.getParentObjectResource();
+ if(element.attribute(RDFaAttributes.PROPERTY.getName()) == null) {
skipElement = true;
}
}
} else {
// [new subject] is set to the URI obtained from the first match from the following rules:
- if (element.attribute(ABOUT_ATTR) != null) { // by using the URI from @about, if present, obtained according to the section on CURIE and URI Processing;
- Optional newSubjectResource = getResourceFromElementAttribute(element, ABOUT_ATTR, context);
+ if (element.attribute(RDFaAttributes.ABOUT.getName()) != null) { // by using the URI from @about, if present, obtained according to the section on CURIE and URI Processing;
+ Optional newSubjectResource = getResourceFromElementAttribute(element, RDFaAttributes.ABOUT.getName(), context);
if (newSubjectResource.isPresent()) {
newSubject = newSubjectResource.get();
}
- } else if (element.attribute(SRC_ATTR) != null) { // otherwise, by using the URI from @src, if present, obtained according to the section on CURIE and URI Processing.
- Optional newSubjectResource = getResourceFromElementAttribute(element, SRC_ATTR, context);
+ } else if (element.attribute(RDFaAttributes.SRC.getName()) != null) { // otherwise, by using the URI from @src, if present, obtained according to the section on CURIE and URI Processing.
+ Optional newSubjectResource = getResourceFromElementAttribute(element, RDFaAttributes.SRC.getName(), context);
if (newSubjectResource.isPresent()) {
newSubject = newSubjectResource.get();
}
} else if (element.nameIs("body") || element.nameIs("head")) { // if the element is the head or body element then act as if there is an empty @about present, and process it according to the rule for @about, above;
- newSubject = context.baseIri();
- } else if (element.attribute(TYPEOF_ATTR) != null) { // if @typeof is present, obtained according to the section on CURIE and URI Processing, then [new subject] is set to be a newly created [bnode].
+ newSubject = context.getBaseIri();
+ } else if (element.attribute(RDFaAttributes.TYPEOF.getName()) != null) { // if @typeof is present, obtained according to the section on CURIE and URI Processing, then [new subject] is set to be a newly created [bnode].
newSubject = this.getValueFactory().createBNode();
- } else if(context.parentObjectResource() != null) { // otherwise, if [parent object] is present, [new subject] is set to that.
- newSubject = context.parentObjectResource();
+ } else if(context.getParentObjectResource() != null) { // otherwise, if [parent object] is present, [new subject] is set to that.
+ newSubject = context.getParentObjectResource();
}
// Then the [current object resource] is set to the URI obtained from the first match from the following rules:
- if (element.attribute(RESOURCE_ATTR) != null) { // by using the URI from @resource, if present, obtained according to the section on CURIE and URI Processing;
- Optional newObjectResource = getResourceFromElementAttribute(element, RESOURCE_ATTR, context);
+ if (element.attribute(RDFaAttributes.RESOURCE.getName()) != null) { // by using the URI from @resource, if present, obtained according to the section on CURIE and URI Processing;
+ Optional newObjectResource = getResourceFromElementAttribute(element, RDFaAttributes.RESOURCE.getName(), context);
if (newObjectResource.isPresent()) {
currentObject = newObjectResource.get();
}
- } else if (element.attribute(HREF_ATTR) != null) { // otherwise, by using the URI from @href, if present, obtained according to the section on CURIE and URI Processing.
- Optional newObjectResource = getResourceFromElementAttribute(element, RESOURCE_ATTR, context);
+ } else if (element.attribute(RDFaAttributes.HREF.getName()) != null) { // otherwise, by using the URI from @href, if present, obtained according to the section on CURIE and URI Processing.
+ Optional newObjectResource = getResourceFromElementAttribute(element, RDFaAttributes.RESOURCE.getName(), context);
if (newObjectResource.isPresent()) {
currentObject = newObjectResource.get();
}
@@ -216,28 +201,28 @@ private void processElement(Element element, RDFaEvaluationContext context, bool
// 6. If in any of the previous steps a [new subject] was set to a non-null value, it is now used to provide a subject for type values;
if(newSubject != null) {
- if(element.attribute(TYPEOF_ATTR) != null) { // One or more 'types' for the [new subject] can be set by using @typeof. If present, the attribute must contain one or more URIs, obtained according to the section on URI and CURIE Processing, each of which is used to generate a triple as follows:
- Optional typeIri = getResourceFromElementAttribute(element, TYPEOF_ATTR, context);
+ if(element.attribute(RDFaAttributes.TYPEOF.getName()) != null) { // One or more 'types' for the [new subject] can be set by using @typeof. If present, the attribute must contain one or more URIs, obtained according to the section on URI and CURIE Processing, each of which is used to generate a triple as follows:
+ Optional typeIri = getResourceFromElementAttribute(element, RDFaAttributes.TYPEOF.getName(), context);
if (typeIri.isPresent()) {
Statement stat = this.getValueFactory().createStatement(newSubject, RDF.type.getIRI(), typeIri.get());
this.getModel().add(stat);
} else {
- throw new ParsingErrorException("Typeof statement uses unknown type " + element.attr(TYPEOF_ATTR));
+ throw new ParsingErrorException("Typeof statement uses unknown type " + element.attr(RDFaAttributes.TYPEOF.getName()));
}
}
}
// 7. If in any of the previous steps a [current object resource] was set to a non-null value, it is now used to generate triples:
- if (currentObject != null && (element.attribute(REL_ATTR) != null || element.attribute(REV_ATTR) != null)) {
- if(element.attribute(REL_ATTR) != null) {
- Optional propertyOpt = getResourceFromElementAttribute(element, REL_ATTR, context);
+ if (currentObject != null && (element.attribute(RDFaAttributes.REL.getName()) != null || element.attribute(RDFaAttributes.REV.getName()) != null)) {
+ if(element.attribute(RDFaAttributes.REL.getName()) != null) {
+ Optional propertyOpt = getResourceFromElementAttribute(element, RDFaAttributes.REL.getName(), context);
if(propertyOpt.isPresent() && propertyOpt.get().isIRI()) {
IRI property = (IRI) propertyOpt.get();
this.getModel().add(newSubject, property, currentObject);
}
}
- if(element.attribute(REV_ATTR) != null) {
- Optional propertyOpt = getResourceFromElementAttribute(element, REL_ATTR, context);
+ if(element.attribute(RDFaAttributes.REV.getName()) != null) {
+ Optional propertyOpt = getResourceFromElementAttribute(element, RDFaAttributes.REL.getName(), context);
if(propertyOpt.isPresent() && propertyOpt.get().isIRI() && currentObject.isResource()) {
IRI property = (IRI) propertyOpt.get();
this.getModel().add(currentObject, property, newSubject);
@@ -246,18 +231,18 @@ private void processElement(Element element, RDFaEvaluationContext context, bool
}
// 8. If however [current object resource] was set to null, but there are predicates present, then they must be stored as [incomplete triple]s, pending the discovery of a subject that can be used as the object. Also, [current object resource] should be set to a newly created [bnode];
- if (currentObject == null && (element.attribute(REL_ATTR) != null || element.attribute(REV_ATTR) != null)) {
+ if (currentObject == null && (element.attribute(RDFaAttributes.REL.getName()) != null || element.attribute(RDFaAttributes.REV.getName()) != null)) {
currentObject = getValueFactory().createBNode();
- if(element.attribute(REL_ATTR) != null) {
- Optional propertyOpt = getResourceFromElementAttribute(element, REL_ATTR, context);
+ if(element.attribute(RDFaAttributes.REL.getName()) != null) {
+ Optional propertyOpt = getResourceFromElementAttribute(element, RDFaAttributes.REL.getName(), context);
if(propertyOpt.isPresent() && propertyOpt.get().isIRI()) {
IRI property = (IRI) propertyOpt.get();
RDFaIncompleteStatement statement = new RDFaIncompleteStatement(property);
incompleteStatementSet.add(statement);
}
}
- if(element.attribute(REV_ATTR) != null) {
- Optional propertyOpt = getResourceFromElementAttribute(element, REL_ATTR, context);
+ if(element.attribute(RDFaAttributes.REV.getName()) != null) {
+ Optional propertyOpt = getResourceFromElementAttribute(element, RDFaAttributes.REL.getName(), context);
if(propertyOpt.isPresent() && propertyOpt.get().isIRI() && currentObject.isResource()) {
IRI property = (IRI) propertyOpt.get();
RDFaIncompleteStatement statement = new RDFaIncompleteStatement(property);
@@ -268,21 +253,21 @@ private void processElement(Element element, RDFaEvaluationContext context, bool
}
// 9. The next step of the iteration is to establish any [current object literal];
- if(element.attribute(PROPERTY_ATTR) != null) { // Predicates for the [current object literal] can be set by using @property. If present, one or more URIs are obtained according to the section on CURIE and URI Processing, and then the actual literal value is obtained as follows:
- Optional propertyOpt = getResourceFromElementAttribute(element, PROPERTY_ATTR, context);
+ if(element.attribute(RDFaAttributes.PROPERTY.getName()) != null) { // Predicates for the [current object literal] can be set by using @property. If present, one or more URIs are obtained according to the section on CURIE and URI Processing, and then the actual literal value is obtained as follows:
+ Optional propertyOpt = getResourceFromElementAttribute(element, RDFaAttributes.PROPERTY.getName(), context);
if(propertyOpt.isPresent() && propertyOpt.get().isIRI()) {
IRI property = (IRI)propertyOpt.get();
IRI datatype = null;
- if(element.attribute(DATATYPE_ATTR) != null && ! element.attr(DATATYPE_ATTR).isEmpty()) {
- Optional datatypeOpt = getResourceFromElementAttribute(element, DATATYPE_ATTR, context);
+ if(element.attribute(RDFaAttributes.DATATYPE.getName()) != null && ! element.attr(RDFaAttributes.DATATYPE.getName()).isEmpty()) {
+ Optional datatypeOpt = getResourceFromElementAttribute(element, RDFaAttributes.DATATYPE.getName(), context);
if(datatypeOpt.isPresent() && datatypeOpt.get().isIRI() && ! datatypeOpt.get().equals(RDF.XMLLiteral.getIRI())) {
datatype = (IRI) datatypeOpt.get();
}
}
String value = element.text();
- if(element.attribute(CONTENT_ATTR) != null) {
- value = element.attr(CONTENT_ATTR);
+ if(element.attribute(RDFaAttributes.CONTENT.getName()) != null) {
+ value = element.attr(RDFaAttributes.CONTENT.getName());
}
if(datatype != null) {
currentObjectLiteral = this.getValueFactory().createLiteral(value, datatype);
@@ -301,29 +286,29 @@ private void processElement(Element element, RDFaEvaluationContext context, bool
while(itStat.hasNext()) {
RDFaIncompleteStatement statement = itStat.next();
if(statement.isForward()) {
- this.getModel().add(context.parentSubjectResource(), statement.getPredicate(), newSubject);
+ this.getModel().add(context.getParentSubjectResource(), statement.getPredicate(), newSubject);
} else if (statement.isBackward()){
- this.getModel().add(newSubject, statement.getPredicate(), context.parentSubjectResource());
+ this.getModel().add(newSubject, statement.getPredicate(), context.getParentSubjectResource());
}
}
// 11. If the [recurse] flag is 'true', all elements that are children of the [current element] are processed using the rules described here, using a new [evaluation context],
if(recursive) {
if(skipElement) {
- RDFaEvaluationContext newContext = new RDFaEvaluationContext(context);
+ RDFa10EvaluationContext newContext = new fr.inria.corese.core.next.impl.io.parser.rdfa.model.RDFa10EvaluationContext(context);
newContext.setLanguage(language);
- newContext.uriMappings(currentMappings);
+ newContext.setIriMappings(currentMappings);
context = newContext;
} else {
- context = new RDFaEvaluationContext(context.baseIri());
+ context = new RDFa10EvaluationContext(context.getBaseIri());
if(newSubject != null) {
- context.parentObjectResource(newSubject);
+ context.setParentObjectResource(newSubject);
}
if(currentObject != null) {
- context.parentObjectResource(currentObject);
+ context.setParentObjectResource(currentObject);
}
- context.uriMappings(currentMappings);
- context.incompleteStatements(incompleteStatementSet);
+ context.setIriMappings(currentMappings);
+ context.setIncompleteStatements(incompleteStatementSet);
context.setLanguage(language);
}
@@ -339,7 +324,7 @@ private void processElement(Element element, RDFaEvaluationContext context, bool
* @param element HTML element
* @param context current evaluation context
*/
- private void processElement(Element element, RDFaEvaluationContext context) {
+ private void processElement(Element element, fr.inria.corese.core.next.impl.io.parser.rdfa.model.RDFa10EvaluationContext context) {
processElement(element, context, true, false);
}
@@ -349,60 +334,6 @@ public void parse(Reader reader, String baseURI) {
parse(inputStream , baseURI);
}
- /**
- * Resolves the string representation of a resource found in attributes of an element, be it an IRI, CURIE or relative URI
- *
- * @param stringResource the resource as stored in the attribute of the HTML element
- * @param context the context of the element evalation
- * @return the full IRI if it is a relative IRI, full IRI or CURIE, nothing otherwise
- */
- private Optional resolveStringResource(String stringResource, RDFaEvaluationContext context) {
- String resultString = stringResource;
- if (resultString.startsWith("[") && resultString.endsWith("]")) {
- resultString = resultString.replaceFirst("\\[", "");
- resultString = resultString.replaceFirst("]", "");
- }
-
-
- if (stringUriIsCURIE(resultString)) { // CURIE
- int colonIndex = resultString.indexOf(":");
- String prefixString = resultString.substring(0, colonIndex);
- String localNameString = resultString.substring(colonIndex + 1);
- // Basic resolution following https://www.w3.org/TR/rdfa-syntax/#s_convertingcurietouri
- if (context.hasUriMapping(prefixString)) {
- IRI namespaceIRI = context.uriMapping(prefixString);
-
- return Optional.of(this.getValueFactory().createIRI(namespaceIRI.stringValue(), localNameString));
- } else if (prefixString.isEmpty()) { // CURIE is relative to the base URI
- return Optional.of(this.getValueFactory().createIRI(context.baseIri().stringValue(), localNameString));
- } else {
- throw new ParsingErrorException("CURIE " + stringResource + " uses unknown prefix");
- }
- } else if (IRIUtils.isStandardIRI(resultString)) { // Full IRI
- return Optional.of(this.getValueFactory().createIRI(resultString));
-
- } else if (resultString.startsWith("_:")) { // Blank Node
- int colonIndex = resultString.indexOf(":");
- String localNameString = resultString.substring(colonIndex + 1);
- return Optional.of(this.getValueFactory().createBNode(localNameString));
- } else if (IRIUtils.isStandardIRI(context.baseIri().stringValue() + resultString)) {
- String concatenatedRelativeUri = context.baseIri().stringValue() + resultString;
- return Optional.of(getValueFactory().createIRI(concatenatedRelativeUri));
- }
- return Optional.empty();
- }
-
- /**
- * Equivalent to test if it has a colon, and it is not a blank node
- *
- * @param stringIri
- * @return
- */
- private boolean stringUriIsCURIE(String stringIri) {
- int colonIndex = stringIri.indexOf(":");
- return colonIndex > -1 && !stringIri.contains("://") && !stringIri.startsWith("_:") && !stringIri.startsWith("[_:");
- }
-
private Optional getResourceFromElementAttribute(Element element, String attributeName, RDFaEvaluationContext context) {
if (element.attribute(attributeName) != null) { // otherwise, by using the URI from @resource, if present, obtained according to the section on CURIE and URI Processing;
String newSubjectString = element.attr(attributeName);
diff --git a/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/RDFa11Parser.java b/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/RDFa11Parser.java
new file mode 100644
index 000000000..7ab3e26c6
--- /dev/null
+++ b/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/RDFa11Parser.java
@@ -0,0 +1,559 @@
+package fr.inria.corese.core.next.impl.io.parser.rdfa;
+
+import fr.inria.corese.core.next.api.*;
+import fr.inria.corese.core.next.api.base.io.RDFFormat;
+import fr.inria.corese.core.next.api.io.IOOptions;
+import fr.inria.corese.core.next.api.io.common.BaseIRIOptions;
+import fr.inria.corese.core.next.impl.common.vocabulary.RDF;
+import fr.inria.corese.core.next.impl.common.vocabulary.RDFS;
+import fr.inria.corese.core.next.impl.common.vocabulary.RDFa;
+import fr.inria.corese.core.next.impl.exception.ParsingErrorException;
+import fr.inria.corese.core.next.impl.io.parser.rdfa.model.RDFa11EvaluationContext;
+import fr.inria.corese.core.next.impl.io.parser.rdfa.model.RDFaAttributes;
+import fr.inria.corese.core.next.impl.io.parser.rdfa.model.RDFaIncompleteStatement;
+import fr.inria.corese.core.next.impl.io.parser.rdfa.model.RDFaInitialPrefixes;
+import fr.inria.corese.core.next.impl.temp.CoreseModel;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.helpers.DefaultHandler;
+
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.nio.charset.StandardCharsets;
+import java.util.*;
+
+/**
+ * SAX-based RDFa 1.1 parser.
+ *
+ *
This parser processes XML+RDFa documents (XHTMl, SVG, etc.) using the SAX streaming API.
+ * It follows the W3C recommendation, using buffers to replace DOM traversal.
+ *
+ *
+ * This parser does NOT support vocabulary expansion
+ *
+ */
+public class RDFa11Parser extends AbstractRDFaParser {
+
+ private static final Logger logger = LoggerFactory.getLogger(RDFa11Parser.class);
+
+ private static final String BASE_TAG = "base";
+ private static final String XMLNS_PREFIX = "xmlns";
+
+ private RDFa11EvaluationContext currentContext = null;
+
+ /**
+ * Buffer for accumulating character data between start and end tags.
+ */
+ private StringBuilder characters = new StringBuilder();
+
+ // Local context
+ private boolean skipElement = false;
+ private Resource newSubject = null;
+ private Resource currentObjectResource = null;
+ private Resource typedResource = null;
+ private Map localIRIMappings = null;
+ private Set localIncompleteStatements = null;
+ private Map> localListMappings = null;
+ private String currentLanguage = null;
+ private Map localTermMappings = null;
+ private String localDefaultVocabulary = null;
+
+ private boolean isRootElement = true;
+ private Attributes currentElementAttributes = null;
+
+ private Model parsingModel = new CoreseModel();
+
+ public RDFa11Parser(Model model, ValueFactory factory) {
+ this(model, factory, new RDFaParserOptions.Builder().build());
+ }
+
+ public RDFa11Parser(Model model, ValueFactory factory, IOOptions config) {
+ super(model, factory, config);
+ }
+
+
+ @Override
+ public void parse(InputStream in) {
+ if (getConfig() instanceof BaseIRIOptions baseIRIOptions) {
+ String baseIRI = baseIRIOptions.getBaseIRI();
+ parse(new InputStreamReader(in, StandardCharsets.UTF_8), baseIRI);
+ } else {
+ parse(new InputStreamReader(in, StandardCharsets.UTF_8), null);
+ }
+ }
+
+ @Override
+ public void parse(InputStream in, String baseURIString) {
+ parse(new InputStreamReader(in, StandardCharsets.UTF_8), baseURIString);
+ }
+
+ @Override
+ public RDFFormat getRDFFormat() {
+ return RDFFormat.RDFa_1_1;
+ }
+
+ @Override
+ public void parse(Reader reader, String baseURI) {
+ try {
+ this.currentContext = new RDFa11EvaluationContext(getValueFactory().createIRI(baseURI));
+ this.currentContext.setParentSubjectResource(this.currentContext.getBaseIri());
+ this.currentContext.setParentObjectResource(null);
+ this.currentContext.setLanguage(null);
+
+ // Initializing the iri mappings with the default prefixes as defined by https://www.w3.org/TR/rdfa-core/#xmlrdfaconformance
+ for (RDFaInitialPrefixes prefixObject : RDFaInitialPrefixes.values()) {
+ currentContext.addIriMapping(prefixObject.getPrefix(), getValueFactory().createIRI(prefixObject.getName()));
+ }
+
+ // https://www.w3.org/2011/rdfa-context/rdfa-1.1 sets a list of predefined terms mappings for RDFa contexts.
+ this.currentContext.addTermMapping("describedby", getValueFactory().createIRI("http://www.w3.org/2007/05/powder-s#describedby"));
+ this.currentContext.addTermMapping("license", getValueFactory().createIRI("http://www.w3.org/1999/xhtml/vocab#license"));
+ this.currentContext.addTermMapping("role", getValueFactory().createIRI("http://www.w3.org/1999/xhtml/vocab#role"));
+
+ this.currentContext.setDefaultVocabulary(null);
+
+
+ skipElement = false;
+ newSubject = null;
+ currentObjectResource = null;
+ typedResource = null;
+ localIRIMappings = new HashMap<>();
+ localIncompleteStatements = new HashSet<>();
+ localListMappings = this.currentContext.getListMappings();
+ currentLanguage = this.currentContext.getLanguage();
+ localTermMappings = this.currentContext.getTermMappings();
+ localDefaultVocabulary = this.currentContext.getDefaultVocabulary();
+
+ SAXParserFactory factory = SAXParserFactory.newInstance();
+ factory.setNamespaceAware(true);
+ SAXParser saxParser = factory.newSAXParser();
+ InputSource inputSource = new InputSource(reader);
+ saxParser.parse(inputSource, new XMLSaxHandler());
+ } catch (IOException e) {
+ throw new ParsingErrorException("Failed to parse XML+RDFa input stream: " + e.getMessage(), e);
+ } catch (Exception e) {
+ throw new ParsingErrorException("Unexpected error during XML+RDFa parsing: " + e.getMessage(), e);
+ }
+ }
+
+ private void addPrefix(String prefix, String uri) {
+ IRI prefixIRI = getValueFactory().createIRI(uri);
+ this.currentContext.addIriMapping(prefix, prefixIRI);
+ }
+
+ /**
+ * Handles character data between XML elements
+ */
+ private void handleCharacters(char[] ch, int start, int length) {
+ characters.append(ch, start, length);
+ }
+
+ private void startProcessElement(String uri, String localName, String qName, Attributes attrs) {
+ this.currentElementAttributes = attrs;
+ }
+
+ private void endProcessElement(String uri, String localName, String qName) {
+ String currentElementName = qName;
+
+ // The current element is examined for any change to the default vocabulary via @vocab. If @vocab is present and contains a value, the local default vocabulary is updated according to the section on CURIE and IRI Processing. If the value is empty, then the local default vocabulary MUST be reset to the Host Language defined default (if any).
+ if (this.currentElementAttributes.getValue(RDFaAttributes.VOCAB.getName()) != null
+ && !this.currentElementAttributes.getValue(RDFaAttributes.VOCAB.getName()).isEmpty()) {
+ String vocabValue = this.currentElementAttributes.getValue(RDFaAttributes.VOCAB.getName());
+ localDefaultVocabulary = vocabValue;
+ parsingModel.add(this.currentContext.getBaseIri(), RDFa.usesVocabulary.getIRI(), getValueFactory().createLiteral(vocabValue));
+ }
+
+ // The current element is examined for IRI mappings and these are added to the local list of IRI mappings. Note that an IRI mapping will simply overwrite any current mapping in the list that has the same name;
+ for (int i = 0; i < this.currentElementAttributes.getLength(); i++) {
+ String attribute = this.currentElementAttributes.getQName(i);
+ if (attribute.startsWith(XMLNS_PREFIX)) {
+ String attributeValue = this.currentElementAttributes.getValue(i);
+ String prefixName = this.currentElementAttributes.getLocalName(i);
+ IRI prefixNamespace = getValueFactory().createIRI(attributeValue, "");
+ localIRIMappings.put(prefixName, prefixNamespace);
+ }
+ }
+ if (this.currentElementAttributes.getValue(RDFaAttributes.PREFIX.getName()) != null
+ && !this.currentElementAttributes.getValue(RDFaAttributes.PREFIX.getName()).isEmpty()) {
+ String prefixDeclaration = this.currentElementAttributes.getValue(RDFaAttributes.PREFIX.getName());
+ String prefixName = getPrefixFromDeclaration(prefixDeclaration);
+ IRI prefixIRI = getPrefixIriFromDeclaration(prefixDeclaration);
+ localIRIMappings.put(prefixName, prefixIRI);
+ }
+
+ // If the current element contains no @rel or @rev attribute, then the next step is to establish a value for new subject. This step has two possible alternatives.
+ if (this.currentElementAttributes.getValue(RDFaAttributes.REL.getName()) == null
+ && this.currentElementAttributes.getValue(RDFaAttributes.REV.getName()) == null) {
+ // If the current element contains the @property attribute, but does not contain either the @content or @datatype attributes, then
+ if (this.currentElementAttributes.getValue(RDFaAttributes.PROPERTY.getName()) != null
+ && !this.currentElementAttributes.getValue(RDFaAttributes.PROPERTY.getName()).isEmpty()
+ && this.currentElementAttributes.getValue(RDFaAttributes.CONTENT.getName()) == null
+ && this.currentElementAttributes.getValue(RDFaAttributes.DATATYPE.getName()) == null) {
+ if (this.currentElementAttributes.getValue(RDFaAttributes.ABOUT.getName()) != null) {
+ this.newSubject = getResourceFromElementAttribute(RDFaAttributes.ABOUT);
+ } else if (isRootElement) {
+ this.newSubject = this.currentContext.getBaseIri();
+ } else if (this.currentContext.getParentObjectResource() != null) {
+ this.newSubject = this.currentContext.getParentObjectResource();
+ }
+ if (this.currentElementAttributes.getValue(RDFaAttributes.TYPEOF.getName()) != null) {
+ if (this.currentElementAttributes.getValue(RDFaAttributes.ABOUT.getName()) != null) {
+ this.typedResource = this.newSubject;
+ } else if (isRootElement) {
+ this.typedResource = resolveStringResource("", this.currentContext).get();
+ } else {
+ if (this.currentElementAttributes.getValue(RDFaAttributes.RESOURCE.getName()) != null) {
+ this.newSubject = getResourceFromElementAttribute(RDFaAttributes.RESOURCE);
+ } else if (this.currentElementAttributes.getValue(RDFaAttributes.HREF.getName()) != null) {
+ this.newSubject = getResourceFromElementAttribute( RDFaAttributes.HREF);
+ } else if (this.currentElementAttributes.getValue(RDFaAttributes.SRC.getName()) != null) {
+ this.newSubject = getResourceFromElementAttribute( RDFaAttributes.SRC);
+ } else {
+ this.typedResource = getValueFactory().createBNode();
+ }
+ this.currentObjectResource = this.typedResource;
+ }
+ }
+ // otherwise:
+ } else {
+ if (this.currentElementAttributes.getValue(RDFaAttributes.ABOUT.getName()) != null
+ && this.currentElementAttributes.getValue(RDFaAttributes.HREF.getName()) != null
+ && this.currentElementAttributes.getValue(RDFaAttributes.SRC.getName()) != null
+ && this.currentElementAttributes.getValue(RDFaAttributes.RESOURCE.getName()) != null) {
+ if (this.currentElementAttributes.getValue(RDFaAttributes.ABOUT.getName()) != null) {
+ this.newSubject = getResourceFromElementAttribute( RDFaAttributes.ABOUT);
+ } else if (this.currentElementAttributes.getValue(RDFaAttributes.RESOURCE.getName()) != null) {
+ this.newSubject = getResourceFromElementAttribute( RDFaAttributes.RESOURCE);
+ } else if (this.currentElementAttributes.getValue(RDFaAttributes.HREF.getName()) != null) {
+ this.newSubject = getResourceFromElementAttribute( RDFaAttributes.HREF);
+ } else if (this.currentElementAttributes.getValue(RDFaAttributes.SRC.getName()) != null) {
+ this.newSubject = getResourceFromElementAttribute( RDFaAttributes.SRC);
+ }
+ } else {
+ if (isRootElement) {
+ this.newSubject = resolveStringResource("", this.currentContext).get();
+ } else if (this.currentElementAttributes.getValue(RDFaAttributes.TYPEOF.getName()) != null) {
+ this.newSubject = getValueFactory().createBNode();
+ } else if (this.currentContext.getParentObjectResource() != null) {
+ this.newSubject = this.currentContext.getParentObjectResource();
+ if (this.currentElementAttributes.getValue(RDFaAttributes.PROPERTY.getName()) == null) {
+ skipElement = true;
+ }
+ }
+ if (this.currentElementAttributes.getValue(RDFaAttributes.TYPEOF.getName()) != null) {
+ this.typedResource = this.newSubject;
+ }
+ }
+ }
+ }
+
+ // If the current element does contain a @rel or @rev attribute, then the next step is to establish both a value for new subject and a value for current object resource:
+ if (this.currentElementAttributes.getValue(RDFaAttributes.REL.getName()) != null
+ && this.currentElementAttributes.getValue(RDFaAttributes.REV.getName()) != null) {
+ if (this.currentElementAttributes.getValue(RDFaAttributes.ABOUT.getName()) != null) {
+ this.newSubject = getResourceFromElementAttribute( RDFaAttributes.ABOUT);
+ }
+ if (this.currentElementAttributes.getValue(RDFaAttributes.TYPEOF.getName()) != null) {
+ this.typedResource = this.newSubject;
+ }
+ if (this.newSubject == null) {
+ if (isRootElement) {
+ this.typedResource = resolveStringResource("", this.currentContext).get();
+ } else if (this.currentContext.getParentObjectResource() != null) {
+ this.newSubject = this.currentContext.getParentObjectResource();
+ }
+ }
+ if (this.currentElementAttributes.getValue(RDFaAttributes.RESOURCE.getName()) != null) {
+ this.currentObjectResource = getResourceFromElementAttribute( RDFaAttributes.RESOURCE);
+ } else if (this.currentElementAttributes.getValue(RDFaAttributes.HREF.getName()) != null) {
+ this.currentObjectResource = getResourceFromElementAttribute( RDFaAttributes.HREF);
+ } else if (this.currentElementAttributes.getValue(RDFaAttributes.SRC.getName()) != null) {
+ this.currentObjectResource = getResourceFromElementAttribute( RDFaAttributes.SRC);
+ } else if (this.currentElementAttributes.getValue(RDFaAttributes.TYPEOF.getName()) != null
+ && this.currentElementAttributes.getValue(RDFaAttributes.ABOUT.getName()) == null) {
+ this.currentObjectResource = this.getValueFactory().createBNode();
+ }
+ if (this.currentElementAttributes.getValue(RDFaAttributes.TYPEOF.getName()) != null
+ && this.currentElementAttributes.getValue(RDFaAttributes.ABOUT.getName()) == null
+ && (this.currentObjectResource == null || this.currentObjectResource.isResource())) {
+ this.typedResource = (Resource) this.currentObjectResource;
+ }
+ }
+
+ // If in any of the previous steps a typed resource was set to a non-null value, it is now used to provide a subject for type values;
+ if (this.typedResource != null) {
+ Resource typeIri = getResourceFromElementAttribute( RDFaAttributes.TYPEOF);
+ this.getModel().add(this.typedResource, RDF.type.getIRI(), typeIri);
+ }
+
+ // If in any of the previous steps a new subject was set to a non-null value different from the parent object;
+ if (this.newSubject != null && this.newSubject != this.currentContext.getParentObjectResource()) {
+ this.localListMappings = new HashMap<>();
+ }
+
+ // If in any of the previous steps a current object resource was set to a non-null value, it is now used to generate triples and add entries to the local list mapping:
+ if (this.currentObjectResource != null) {
+ if (this.currentElementAttributes.getValue(RDFaAttributes.INLIST.getName()) != null
+ && this.currentElementAttributes.getValue(RDFaAttributes.REL.getName()) != null) {
+ IRI relResource = (IRI) getResourceFromElementAttribute( RDFaAttributes.REL);
+ if (!localListMappings.containsKey(relResource)) {
+ this.localListMappings.put(relResource, new HashSet<>());
+ }
+ this.localListMappings.get(relResource).add(this.currentObjectResource);
+ }
+ if (this.currentElementAttributes.getValue(RDFaAttributes.INLIST.getName()) == null) {
+ if (this.currentElementAttributes.getValue(RDFaAttributes.REL.getName()) != null) {
+ Resource relResource = getResourceFromElementAttribute( RDFaAttributes.REL);
+ if (relResource.isIRI()) {
+ this.getModel().add(newSubject, (IRI) relResource, currentObjectResource);
+ } else {
+ throw new ParsingErrorException("Value of attribute @rel expected to be an IRI but was " + this.currentElementAttributes.getValue(RDFaAttributes.REL.getName()));
+ }
+ }
+ if (this.currentElementAttributes.getValue(RDFaAttributes.REV.getName()) != null) {
+ Resource revResource = getResourceFromElementAttribute( RDFaAttributes.REV);
+ if (!revResource.isIRI()) {
+ throw new ParsingErrorException("Value of attribute @rev expected to be an IRI but was " + this.currentElementAttributes.getValue(RDFaAttributes.REV.getName()));
+ }
+ if (!currentObjectResource.isResource()) {
+ throw new ParsingErrorException("object resource expected to be a resource but was " + currentObjectResource);
+ }
+ this.getModel().add((Resource) currentObjectResource, (IRI) revResource, newSubject);
+ }
+ }
+ }
+
+ // If however current object resource was set to null, but there are predicates present, then they must be stored as incomplete triples, pending the discovery of a subject that can be used as the object. Also, current object resource should be set to a newly created bnode (so that the incomplete triples have a subject to connect to if they are ultimately turned into triples);
+ if (this.currentObjectResource == null) {
+ this.currentObjectResource = getValueFactory().createBNode();
+ if (this.currentElementAttributes.getValue(RDFaAttributes.REL.getName()) != null) {
+ if(! getResourceFromElementAttribute( RDFaAttributes.REL).isIRI()) {
+ throw new ParsingErrorException("Value of attribute @rel expected to be an IRI but was " + this.currentElementAttributes.getValue(RDFaAttributes.REL.getName()));
+ }
+ IRI relIRI = (IRI) getResourceFromElementAttribute( RDFaAttributes.REL);
+ if(this.currentElementAttributes.getValue(RDFaAttributes.INLIST.getName()) != null) { // TODO: Step to be double checked, standard unclear
+ if (!localListMappings.containsKey(relIRI)) {
+ this.localListMappings.put(relIRI, new HashSet<>());
+ }
+ this.localListMappings.get(relIRI).add(this.currentObjectResource);
+ } else {
+ this.localIncompleteStatements.add(new RDFaIncompleteStatement(relIRI, RDFaIncompleteStatement.Direction.FORWARD));
+ }
+ } else if (this.currentElementAttributes.getValue(RDFaAttributes.REV.getName()) != null) {
+ if(! getResourceFromElementAttribute( RDFaAttributes.REV).isIRI()) {
+ throw new ParsingErrorException("Value of attribute @rev expected to be an IRI but was " + this.currentElementAttributes.getValue(RDFaAttributes.REV.getName()));
+ }
+ IRI revIRI = (IRI) getResourceFromElementAttribute( RDFaAttributes.REV);
+ this.localIncompleteStatements.add(new RDFaIncompleteStatement(revIRI, RDFaIncompleteStatement.Direction.BACKWARD));
+ }
+ }
+
+ // The next step of the iteration is to establish any current property value;
+ if(this.currentElementAttributes.getValue(RDFaAttributes.PROPERTY.getName()) != null) {
+ IRI propertyIRI = (IRI) getResourceFromElementAttribute(RDFaAttributes.PROPERTY);
+ Value currentPropertyValue = null;
+ if (this.currentElementAttributes.getValue(RDFaAttributes.DATATYPE.getName()) != null
+ && getResourceFromElementAttribute(RDFaAttributes.DATATYPE).isIRI()
+ && getResourceFromElementAttribute(RDFaAttributes.DATATYPE) != RDF.XMLLiteral.getIRI()) {
+ IRI datatypeIRI = (IRI) getResourceFromElementAttribute(RDFaAttributes.DATATYPE);
+ if (this.currentElementAttributes.getValue(RDFaAttributes.CONTENT.getName()) != null) {
+ String contentString = this.currentElementAttributes.getValue(RDFaAttributes.CONTENT.getName());
+ currentPropertyValue = getValueFactory().createLiteral(contentString, datatypeIRI);
+ } else {
+ String contentString = this.characters.toString().trim();
+ currentPropertyValue = getValueFactory().createLiteral(contentString);
+ this.characters = new StringBuilder();
+ }
+ } else if (this.currentElementAttributes.getValue(RDFaAttributes.DATATYPE.getName()) != null
+ && this.currentElementAttributes.getValue(RDFaAttributes.DATATYPE.getName()).isEmpty()) {
+ if (this.currentElementAttributes.getValue(RDFaAttributes.CONTENT.getName()) != null) {
+ String contentString = this.currentElementAttributes.getValue(RDFaAttributes.CONTENT.getName());
+ currentPropertyValue = getValueFactory().createLiteral(contentString);
+ } else {
+ String contentString = this.characters.toString().trim();
+ currentPropertyValue = getValueFactory().createLiteral(contentString);
+ this.characters = new StringBuilder();
+ }
+ //} else if (this.currentElementAttributes.getValue(RDFaAttributes.DATATYPE.getName()) != null
+ // && getResourceFromElementAttribute( RDFaAttributes.DATATYPE).isIRI()
+ // && getResourceFromElementAttribute( RDFaAttributes.DATATYPE) == RDF.XMLLiteral.getIRI()) {
+ } else if (this.currentElementAttributes.getValue(RDFaAttributes.CONTENT.getName()) != null) {
+ String contentString = this.currentElementAttributes.getValue(RDFaAttributes.CONTENT.getName());
+ currentPropertyValue = getValueFactory().createLiteral(contentString);
+ } else if (this.currentElementAttributes.getValue(RDFaAttributes.REL.getName()) == null
+ && this.currentElementAttributes.getValue(RDFaAttributes.REV.getName()) == null
+ && this.currentElementAttributes.getValue(RDFaAttributes.CONTENT.getName()) == null) {
+ if(this.currentElementAttributes.getValue(RDFaAttributes.RESOURCE.getName()) != null) {
+ currentPropertyValue = getResourceFromElementAttribute(RDFaAttributes.RESOURCE);
+ } else if(this.currentElementAttributes.getValue(RDFaAttributes.HREF.getName()) != null) {
+ currentPropertyValue = getResourceFromElementAttribute(RDFaAttributes.HREF);
+ } else if(this.currentElementAttributes.getValue(RDFaAttributes.SRC.getName()) != null) {
+ currentPropertyValue = getResourceFromElementAttribute(RDFaAttributes.SRC);
+ }
+ } else if (this.currentElementAttributes.getValue(RDFaAttributes.TYPEOF.getName()) != null
+ && this.currentElementAttributes.getValue(RDFaAttributes.ABOUT.getName()) == null) {
+ currentPropertyValue = typedResource;
+ } else {
+ String contentString = this.characters.toString().trim();
+ if(this.currentLanguage != null
+ && ! this.currentLanguage.isEmpty()) {
+ currentPropertyValue = getValueFactory().createLiteral(contentString, this.currentLanguage);
+ } else {
+ currentPropertyValue = getValueFactory().createLiteral(contentString);
+ }
+ this.characters = new StringBuilder();
+ }
+
+ if(this.currentElementAttributes.getValue(RDFaAttributes.INLIST.getName()) != null) {
+ if(! this.localListMappings.containsKey(propertyIRI)) {
+ this.localListMappings.put(propertyIRI, new HashSet<>());
+ }
+ this.localListMappings.get(propertyIRI).add(currentPropertyValue);
+ } else {
+ this.getModel().add(this.newSubject, propertyIRI, currentPropertyValue);
+ }
+ }
+
+ // If the skip element flag is 'false', and new subject was set to a non-null value, then any incomplete triples within the current context should be completed:
+ if(! skipElement
+ && newSubject != null) {
+ for(RDFaIncompleteStatement incompleteStatement : this.currentContext.getIncompleteStatement()) {
+ if(incompleteStatement.getDirection() == RDFaIncompleteStatement.Direction.NONE) {
+ localListMappings.get(incompleteStatement.getPredicate()).add(newSubject);
+ } else if(incompleteStatement.getDirection() == RDFaIncompleteStatement.Direction.FORWARD) {
+ this.getModel().add(currentContext.getParentSubjectResource(), incompleteStatement.getPredicate(), newSubject);
+ } else if(incompleteStatement.getDirection() == RDFaIncompleteStatement.Direction.BACKWARD) {
+ this.getModel().add(newSubject, incompleteStatement.getPredicate(), currentContext.getParentSubjectResource());
+ }
+ }
+ }
+
+ // Next, all elements that are children of the current element are processed using the rules described here, using a new evaluation context, initialized as follows:
+ Map> oldListMappings = currentContext.getListMappings();
+ if(skipElement) {
+ currentContext = new RDFa11EvaluationContext(this.currentContext);
+ currentContext.setLanguage(currentLanguage);
+ currentContext.setIriMappings(localIRIMappings);
+ } else {
+ Resource oldParentSubject = this.currentContext.getParentSubjectResource();
+ currentContext = new RDFa11EvaluationContext(this.currentContext.getBaseIri());
+ currentContext.setParentSubjectResource(newSubject);
+ if(currentObjectResource != null) {
+ currentContext.setParentObjectResource(currentObjectResource);
+ } if (newSubject != null) {
+ currentContext.setParentObjectResource(newSubject);
+ } else {
+ currentContext.setParentObjectResource(oldParentSubject);
+ }
+ currentContext.setIriMappings(localIRIMappings);
+ currentContext.setIncompleteStatements(localIncompleteStatements);
+ currentContext.setListMappings(localListMappings);
+ currentContext.setLanguage(currentLanguage);
+ currentContext.setDefaultVocabulary(localDefaultVocabulary);
+ }
+
+ // Finally, if there is one or more mapping in the local list mapping, list triples are generated as follows:
+ for(Map.Entry> listMapping : localListMappings.entrySet()) {
+ IRI propertyIRI = listMapping.getKey();
+ Set propertyList = listMapping.getValue();
+
+ if(!oldListMappings.containsKey(propertyIRI)) {
+ if(propertyList.isEmpty()) {
+ getModel().add(newSubject, propertyIRI, RDF.nil.getIRI());
+ } else {
+ ArrayList bnodes = new ArrayList<>();
+ for(int i = 0; i < propertyList.size(); i++) {
+ bnodes.add(getValueFactory().createBNode());
+ }
+ int bnodeIndex = 0;
+ for(Value listElement : propertyList) {
+ BNode elementNode = bnodes.get(bnodeIndex);
+ Resource nextElementNode = RDF.nil.getIRI();
+ if(bnodeIndex < bnodes.size() - 1) {
+ nextElementNode = bnodes.get(bnodeIndex + 1);
+ }
+ getModel().add(elementNode, RDF.first.getIRI(), listElement);
+ getModel().add(elementNode, RDF.rest.getIRI(), nextElementNode);
+
+ bnodeIndex++;
+ }
+ getModel().add(newSubject, propertyIRI, bnodes.getFirst());
+ }
+ }
+ }
+
+ isRootElement = false;
+ }
+
+ /**
+ * Internal SAX handler that delegates to the parser's methods
+ */
+ private class XMLSaxHandler extends DefaultHandler {
+ @Override
+ public void characters(char[] ch, int start, int length) {
+ RDFa11Parser.this.handleCharacters(ch, start, length);
+ }
+
+ @Override
+ public void startPrefixMapping(String prefix, String uri) {
+ RDFa11Parser.this.addPrefix(prefix, uri);
+ }
+
+ @Override
+ public void startElement(String uri, String localName, String qName, Attributes attrs) {
+ startProcessElement(uri, localName, qName, attrs);
+ }
+
+ @Override
+ public void endElement(String uri, String localName, String qName) {
+ endProcessElement(uri, localName, qName);
+ }
+
+ @Override
+ public void error(SAXParseException e) {
+ throw new ParsingErrorException("Failed to parse XML+RDFa: " + e.getMessage(), e);
+ }
+
+ @Override
+ public void fatalError(SAXParseException e) {
+ throw new ParsingErrorException("Failed to parse XML+RDFa: " + e.getMessage(), e);
+ }
+
+ @Override
+ public void warning(SAXParseException e) {
+ logger.warn("Warning during parsing of XML+RDFa: ", e);
+ }
+ }
+
+ private String getPrefixFromDeclaration(String declaration) {
+ String[] prefixArray = declaration.split(": ");
+ if (prefixArray.length != 2) {
+ throw new ParsingErrorException("Error during prefix extraction of " + declaration);
+ }
+ return prefixArray[0].toLowerCase();
+ }
+
+ private IRI getPrefixIriFromDeclaration(String declaration) {
+ String[] prefixArray = declaration.split(": ");
+ if (prefixArray.length != 2) {
+ throw new ParsingErrorException("Error during prefix extraction of " + declaration);
+ }
+ return getValueFactory().createIRI(prefixArray[1].toLowerCase());
+ }
+
+ private Resource getResourceFromElementAttribute(RDFaAttributes attribute) {
+ String attributeValue = this.currentElementAttributes.getValue(attribute.getName());
+ if (resolveStringResource(attributeValue, this.currentContext).isPresent()) {
+ return resolveStringResource(attributeValue, this.currentContext).get();
+ } else {
+ throw new ParsingErrorException("Could not parse @" + attribute.getName() + " value: " + attributeValue);
+ }
+ }
+}
diff --git a/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/RDFaEvaluationContext.java b/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/RDFaEvaluationContext.java
deleted file mode 100644
index 088cf6c6a..000000000
--- a/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/RDFaEvaluationContext.java
+++ /dev/null
@@ -1,176 +0,0 @@
-package fr.inria.corese.core.next.impl.io.parser.rdfa;
-
-import fr.inria.corese.core.next.api.IRI;
-import fr.inria.corese.core.next.api.Resource;
-import fr.inria.corese.core.next.api.Value;
-import fr.inria.corese.core.next.impl.io.parser.rdfa.model.RDFaIncompleteStatement;
-
-import java.util.*;
-
-/**
- * This class is to be used during the evaluation of an HTML file to generate triples during the DOM traversal.
- * @see RDFa recommandation
- */
-public class RDFaEvaluationContext {
-
- /**
- * This will usually be the URL of the document being processed, but it could be some other URL, set by some other mechanism, such as the XHTML base element. The important thing is that it establishes a URL against which relative paths can be resolved.
- */
- private IRI baseIri;
-
- /**
- * The initial value will be the same as the initial value of [base], but it will usually change during the course of processing.
- */
- private Resource parentSubjectResource ;
-
- /**
- * In some situations the object of a statement becomes the subject of any nested statements, and this property is used to convey this value. Note that this value may be a bnode, since in some situations a number of nested statements are grouped together on one bnode. This means that the bnode must be set in the containing statement and passed down, and this property is used to convey this value.
- */
- private Resource parentObjectResource = null;
-
- /**
- * An index of locally defined IRI prefixes
- */
- private Map uriMappings = new HashMap<>();
-
- /**
- * Set of statement in the process of building.
- */
- private Set incompleteStatement = new HashSet<>();
-
- /**
- * The language of the document. Note that there is no default language.
- */
- private String language = null;
-
- public RDFaEvaluationContext(IRI baseIri) {
- this.baseIri = baseIri;
- this.parentSubjectResource = baseIri;
- }
-
- public RDFaEvaluationContext(IRI baseIri, IRI parentSubjectResource) {
- this.baseIri = baseIri;
- this.parentSubjectResource = parentSubjectResource;
- }
-
- public RDFaEvaluationContext(RDFaEvaluationContext context) {
- this.baseIri = context.baseIri;
- this.parentSubjectResource = context.parentSubjectResource;
- this.parentObjectResource = context.parentObjectResource;
- this.uriMappings = new HashMap<>(context.uriMappings);
- this.incompleteStatement = new HashSet<>(context.incompleteStatement);
- this.language = context.language;
- }
-
- public IRI baseIri() {
- return baseIri;
- }
-
- public RDFaEvaluationContext baseIri(IRI baseIri) {
- this.baseIri = baseIri;
- return this;
- }
-
- public RDFaEvaluationContext incompleteStatements(Set incompleteStatement) {
- this.incompleteStatement = new HashSet<>(incompleteStatement);
- return this;
- }
-
- public Iterator getIncompleteStatementIterator() {
- return this.incompleteStatement.iterator();
- }
-
- public RDFaEvaluationContext addStatementWithoutSubject(IRI property, Value object) {
- RDFaIncompleteStatement newStatement = new RDFaIncompleteStatement(property);
- newStatement.setObject(object);
- this.incompleteStatement.add(newStatement);
- return this;
- }
-
- public RDFaEvaluationContext addStatementWithoutObject(Resource subject, IRI property) {
- RDFaIncompleteStatement newStatement = new RDFaIncompleteStatement(property);
- newStatement.setSubject(subject);
- this.incompleteStatement.add(newStatement);
- return this;
- }
-
- public void clearIncompleteStatements() {
- this.incompleteStatement.clear();
- }
-
- public Resource parentSubjectResource() {
- return parentSubjectResource;
- }
-
- public RDFaEvaluationContext parentSubjectResource(Resource parentSubjectResource) {
- this.parentSubjectResource = parentSubjectResource;
- return this;
- }
-
- public Resource parentObjectResource() {
- return parentObjectResource;
- }
-
- public RDFaEvaluationContext parentObjectResource(Resource parentObjectResource) {
- this.parentObjectResource = parentObjectResource;
- return this;
- }
-
- public Map uriMappings() {
- return uriMappings;
- }
-
- public RDFaEvaluationContext uriMappings(Map uriMappings) {
- this.uriMappings = uriMappings;
- return this;
- }
-
- public boolean hasUriMapping(String prefix) {
- return this.uriMappings.containsKey(prefix);
- }
-
- /**
- * @param prefix the prefix WITHOUT ":"
- * @return the IRI associated to the prefix in this context
- */
- public IRI uriMapping(String prefix) {
- return this.uriMappings.get(prefix);
- }
-
- public void addUriMapping(String prefix, IRI prefixIri) {
- this.uriMappings.put(prefix, prefixIri);
- }
-
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
-
- sb.append("BaseURI: ").append(this.baseIri.stringValue()).append(" ");
- sb.append("Mappings: [");
- this.uriMappings.forEach((key, value) -> sb.append("(").append(key).append(", ").append(value.stringValue()).append(") "));
- sb.append("] ");
- if(this.parentSubjectResource != null) {
- sb.append("Subject:").append(this.parentSubjectResource.stringValue()).append(" ");
- } else {
- sb.append("Subject:").append((Object) null).append(" ");
- }
- if(this.parentObjectResource != null) {
- sb.append("Object: ").append(this.parentObjectResource.stringValue()).append(" ");
- } else {
- sb.append("Object: ").append((Object) null).append(" ");
- }
- if(! this.incompleteStatement.isEmpty()) {
- sb.append(this.incompleteStatement.size()).append(" incomplete statements.");
- }
-
- return sb.toString();
- }
-
- public String getLanguage() {
- return language;
- }
-
- public void setLanguage(String language) {
- this.language = language;
- }
-}
diff --git a/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/model/AbstractRDFaEvaluationContext.java b/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/model/AbstractRDFaEvaluationContext.java
new file mode 100644
index 000000000..59e6ffd9a
--- /dev/null
+++ b/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/model/AbstractRDFaEvaluationContext.java
@@ -0,0 +1,160 @@
+package fr.inria.corese.core.next.impl.io.parser.rdfa.model;
+
+import fr.inria.corese.core.next.api.IRI;
+import fr.inria.corese.core.next.api.Resource;
+import fr.inria.corese.core.next.api.Value;
+
+import java.util.*;
+
+public abstract class AbstractRDFaEvaluationContext implements RDFaEvaluationContext {
+
+ /**
+ * The base. This will usually be the IRI of the document being processed, but it could be some other IRI, set by some other mechanism, such as the (X)HTML base element. The important thing is that it establishes an IRI against which relative paths can be resolved.
+ */
+ private IRI baseIri;
+
+ /**
+ * The initial value will be the same as the initial value of [base], but it will usually change during the course of processing.
+ */
+ private Resource parentSubjectResource ;
+
+ /**
+ * In some situations the object of a statement becomes the subject of any nested statements, and this property is used to convey this value. Note that this value may be a bnode, since in some situations a number of nested statements are grouped together on one bnode. This means that the bnode must be set in the containing statement and passed down, and this property is used to convey this value.
+ */
+ private Resource parentObjectResource = null;
+
+ /**
+ * An index of locally defined IRI prefixes
+ */
+ private Map iriMappings = new HashMap<>();
+
+ /**
+ * Set of statement in the process of building.
+ */
+ private Set incompleteStatement = new HashSet<>();
+
+ /**
+ * The language of the document. Note that there is no default language.
+ */
+ private String language = null;
+
+ protected AbstractRDFaEvaluationContext(IRI baseIri) {
+ this(baseIri, baseIri);
+ }
+
+ protected AbstractRDFaEvaluationContext(IRI baseIri, IRI parentSubjectResource) {
+ this.baseIri = baseIri;
+ this.parentSubjectResource = parentSubjectResource;
+ }
+
+ protected AbstractRDFaEvaluationContext(AbstractRDFaEvaluationContext context) {
+ this.baseIri = context.baseIri;
+ this.parentSubjectResource = context.parentSubjectResource;
+ this.parentObjectResource = context.parentObjectResource;
+ this.iriMappings = new HashMap<>(context.iriMappings);
+ this.incompleteStatement = new HashSet<>(context.incompleteStatement);
+ this.language = context.language;
+ }
+
+ @Override
+ public IRI getBaseIri() {
+ return baseIri;
+ }
+
+ @Override
+ public void setBaseIri(IRI baseIri) {
+ this.baseIri = baseIri;
+ }
+
+ @Override
+ public Resource getParentSubjectResource() {
+ return parentSubjectResource;
+ }
+
+ @Override
+ public void setParentSubjectResource(Resource parentSubjectResource) {
+ this.parentSubjectResource = parentSubjectResource;
+ }
+
+ @Override
+ public Resource getParentObjectResource() {
+ return parentObjectResource;
+ }
+
+ @Override
+ public void setParentObjectResource(Resource parentObjectResource) {
+ this.parentObjectResource = parentObjectResource;
+ }
+
+ @Override
+ public Map getIriMappings() {
+ return iriMappings;
+ }
+
+ @Override
+ public void setIriMappings(Map iriMappings) {
+ this.iriMappings = iriMappings;
+ }
+
+ @Override
+ public boolean hasIriMapping(String prefix) {
+ return this.iriMappings.containsKey(prefix);
+ }
+
+ /**
+ * @param prefix the prefix WITHOUT ":"
+ * @return the IRI associated to the prefix in this context
+ */
+ @Override
+ public IRI getIriMapping(String prefix) {
+ return this.iriMappings.get(prefix);
+ }
+
+ @Override
+ public void addIriMapping(String prefix, IRI prefixIri) {
+ this.iriMappings.put(prefix, prefixIri);
+ }
+
+ @Override
+ public Set getIncompleteStatement() {
+ return incompleteStatement;
+ }
+
+ @Override
+ public void setIncompleteStatements(Set incompleteStatement) {
+ this.incompleteStatement = incompleteStatement;
+ }
+
+ @Override
+ public Iterator getIncompleteStatementIterator() {
+ return this.incompleteStatement.iterator();
+ }
+
+ @Override
+ public void addStatementWithoutSubject(IRI property, Value object) {
+ RDFaIncompleteStatement newStatement = new RDFaIncompleteStatement(property);
+ newStatement.setObject(object);
+ this.incompleteStatement.add(newStatement);
+ }
+
+ @Override
+ public void addStatementWithoutObject(Resource subject, IRI property) {
+ RDFaIncompleteStatement newStatement = new RDFaIncompleteStatement(property);
+ newStatement.setSubject(subject);
+ this.incompleteStatement.add(newStatement);
+ }
+
+ public void clearIncompleteStatements() {
+ this.incompleteStatement.clear();
+ }
+
+ @Override
+ public String getLanguage() {
+ return language;
+ }
+
+ @Override
+ public void setLanguage(String language) {
+ this.language = language;
+ }
+}
diff --git a/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/model/RDFa10EvaluationContext.java b/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/model/RDFa10EvaluationContext.java
new file mode 100644
index 000000000..ca9406762
--- /dev/null
+++ b/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/model/RDFa10EvaluationContext.java
@@ -0,0 +1,51 @@
+package fr.inria.corese.core.next.impl.io.parser.rdfa.model;
+
+import fr.inria.corese.core.next.api.IRI;
+import fr.inria.corese.core.next.api.Resource;
+import fr.inria.corese.core.next.api.Value;
+
+import java.util.*;
+
+/**
+ * This class is to be used during the evaluation of an HTML file to generate triples during the DOM traversal.
+ * @see RDFa recommandation
+ */
+public class RDFa10EvaluationContext extends AbstractRDFaEvaluationContext {
+
+ public RDFa10EvaluationContext(IRI baseIri) {
+ this(baseIri, baseIri);
+ }
+
+ public RDFa10EvaluationContext(IRI baseIri, IRI parentSubjectResource) {
+ super(baseIri, parentSubjectResource);
+ }
+
+ public RDFa10EvaluationContext(RDFa10EvaluationContext context) {
+ super(context);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+
+ sb.append("BaseURI: ").append(this.getBaseIri().stringValue()).append(" ");
+ sb.append("Mappings: [");
+ this.getIriMappings().forEach((key, value) -> sb.append("(").append(key).append(", ").append(value.stringValue()).append(") "));
+ sb.append("] ");
+ if(this.getParentSubjectResource() != null) {
+ sb.append("Subject:").append(this.getParentSubjectResource().stringValue()).append(" ");
+ } else {
+ sb.append("Subject:").append((Object) null).append(" ");
+ }
+ if(this.getParentObjectResource() != null) {
+ sb.append("Object: ").append(this.getParentObjectResource().stringValue()).append(" ");
+ } else {
+ sb.append("Object: ").append((Object) null).append(" ");
+ }
+ if(! this.getIncompleteStatement().isEmpty()) {
+ sb.append(this.getIncompleteStatement().size()).append(" incomplete statements.");
+ }
+
+ return sb.toString();
+ }
+}
diff --git a/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/model/RDFa11EvaluationContext.java b/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/model/RDFa11EvaluationContext.java
new file mode 100644
index 000000000..36c3c82d0
--- /dev/null
+++ b/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/model/RDFa11EvaluationContext.java
@@ -0,0 +1,101 @@
+package fr.inria.corese.core.next.impl.io.parser.rdfa.model;
+
+import fr.inria.corese.core.next.api.IRI;
+import fr.inria.corese.core.next.api.Resource;
+import fr.inria.corese.core.next.api.Value;
+
+import java.util.*;
+
+/**
+ * This class is to be used during the evaluation of an HTML file to generate triples during the DOM traversal.
+ * @see RDFa recommandation
+ */
+public class RDFa11EvaluationContext extends AbstractRDFaEvaluationContext {
+
+ /**
+ * A list mapping that associates IRIs with lists.
+ */
+ private Map> listMappings = new HashMap<>();
+ /**
+ * The language. Note that there is no default language.
+ */
+ private String language = null;
+ /**
+ * The term mappings, a list of terms and their associated IRIs. This specification does not define an initial list. Host Languages MAY define an initial list.
+ */
+ private Map termMappings = new HashMap<>();
+
+ /**
+ * The default vocabulary, a value to use as the prefix IRI when a term unknown to the RDFa Processor is used. This specification does not define an initial setting for the default vocabulary. Host Languages MAY define an initial setting.
+ */
+ private String defaultVocabulary = null;
+
+
+ public RDFa11EvaluationContext(IRI baseIri) {
+ this(baseIri, baseIri);
+ }
+
+ public RDFa11EvaluationContext(IRI baseIri, IRI parentSubjectResource) {
+ super(baseIri, parentSubjectResource);
+ }
+
+ public RDFa11EvaluationContext(RDFa11EvaluationContext context) {
+ super(context);
+ this.listMappings = new HashMap<>(context.listMappings);
+ this.termMappings = new HashMap<>(context.termMappings);
+ this.defaultVocabulary = context.defaultVocabulary;;
+ }
+
+ public String getDefaultVocabulary() {
+ return defaultVocabulary;
+ }
+
+ public void setDefaultVocabulary(String defaultVocabulary) {
+ this.defaultVocabulary = defaultVocabulary;
+ }
+
+ public void addTermMapping(String term, IRI iri) {
+ this.termMappings.put(term, iri);
+ }
+
+ public IRI getTermMapping(String term) {
+ return this.termMappings.get(term);
+ }
+
+ public Map getTermMappings() {
+ return this.termMappings;
+ }
+
+ public Map> getListMappings() {
+ return listMappings;
+ }
+
+ public void setListMappings(Map> listMappings) {
+ this.listMappings = listMappings;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+
+ sb.append("BaseURI: ").append(this.getBaseIri().stringValue()).append(" ");
+ sb.append("Mappings: [");
+ this.getIriMappings().forEach((key, value) -> sb.append("(").append(key).append(", ").append(value.stringValue()).append(") "));
+ sb.append("] ");
+ if(this.getParentSubjectResource() != null) {
+ sb.append("Subject:").append(this.getParentSubjectResource().stringValue()).append(" ");
+ } else {
+ sb.append("Subject:").append((Object) null).append(" ");
+ }
+ if(this.getParentObjectResource() != null) {
+ sb.append("Object: ").append(this.getParentObjectResource().stringValue()).append(" ");
+ } else {
+ sb.append("Object: ").append((Object) null).append(" ");
+ }
+ if(! this.getIncompleteStatement().isEmpty()) {
+ sb.append(this.getIncompleteStatement().size()).append(" incomplete statements.");
+ }
+
+ return sb.toString();
+ }
+}
diff --git a/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/model/RDFaAttributes.java b/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/model/RDFaAttributes.java
new file mode 100644
index 000000000..6d23908b6
--- /dev/null
+++ b/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/model/RDFaAttributes.java
@@ -0,0 +1,29 @@
+package fr.inria.corese.core.next.impl.io.parser.rdfa.model;
+
+public enum RDFaAttributes {
+ ABOUT("about"),
+ CONTENT("content"),
+ DATATYPE("datatype"),
+ HREF("href"),
+ INLIST("inlist"),
+ PREFIX("prefix"),
+ PROPERTY("property"),
+ REL("rel"),
+ RESOURCE("resource"),
+ REV("rev"),
+ SRC("src"),
+ TYPEOF("typeof"),
+ VOCAB("vocab"),
+ LANG("lang"),
+ LANG_ALT("xml:lang");
+
+ private final String name;
+
+ RDFaAttributes(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+}
diff --git a/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/model/RDFaEvaluationContext.java b/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/model/RDFaEvaluationContext.java
new file mode 100644
index 000000000..438f70537
--- /dev/null
+++ b/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/model/RDFaEvaluationContext.java
@@ -0,0 +1,38 @@
+package fr.inria.corese.core.next.impl.io.parser.rdfa.model;
+
+import fr.inria.corese.core.next.api.IRI;
+import fr.inria.corese.core.next.api.Resource;
+import fr.inria.corese.core.next.api.Value;
+
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+public interface RDFaEvaluationContext {
+
+ IRI getBaseIri();
+ void setBaseIri(IRI baseIri);
+
+ void setParentSubjectResource(Resource parentSubjectResource);
+ Resource getParentSubjectResource();
+
+ void setParentObjectResource(Resource parentObjectResource);
+ Resource getParentObjectResource();
+
+ void setIncompleteStatements(Set incompleteStatement);
+ Set getIncompleteStatement();
+ Iterator getIncompleteStatementIterator();
+ void addStatementWithoutSubject(IRI property, Value object);
+ void addStatementWithoutObject(Resource subject, IRI property);
+ void clearIncompleteStatements();
+
+ boolean hasIriMapping(String prefix);
+ IRI getIriMapping(String prefix);
+ Map getIriMappings();
+ void addIriMapping(String prefix, IRI prefixIri);
+ void setIriMappings(Map iriMappings);
+
+ String getLanguage();
+ void setLanguage(String language);
+
+}
diff --git a/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/model/RDFaIncompleteStatement.java b/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/model/RDFaIncompleteStatement.java
index d30a7fe54..524491a8f 100644
--- a/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/model/RDFaIncompleteStatement.java
+++ b/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/model/RDFaIncompleteStatement.java
@@ -13,7 +13,8 @@ public class RDFaIncompleteStatement {
public enum Direction {
FORWARD,
- BACKWARD
+ BACKWARD,
+ NONE
}
private Resource subject = null;
diff --git a/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/model/RDFaInitialPrefixes.java b/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/model/RDFaInitialPrefixes.java
new file mode 100644
index 000000000..6dc5ce248
--- /dev/null
+++ b/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/model/RDFaInitialPrefixes.java
@@ -0,0 +1,121 @@
+package fr.inria.corese.core.next.impl.io.parser.rdfa.model;
+
+import fr.inria.corese.core.next.api.Namespace;
+
+/**
+ * https://www.w3.org/2011/rdfa-context/rdfa-1.1 sets a list of predefined prefixes for RDFa contexts.
+ */
+public enum RDFaInitialPrefixes implements Namespace {
+
+ // as "https://www.w3.org/ns/activitystreams#"
+ AS("as", "https://www.w3.org/ns/activitystreams#"),
+ // cc "http://creativecommons.org/ns#"
+ CC("cc", "http://creativecommons.org/ns#"),
+ // csvw "http://www.w3.org/ns/csvw#"
+ CSVW("cc", "http://www.w3.org/ns/csvw#"),
+ // ctag "http://commontag.org/ns#"
+ CTAG("ctag", "http://commontag.org/ns#"),
+ // dc "http://purl.org/dc/terms/"
+ DC("dc", "http://purl.org/dc/terms/"),
+ // dc11 "http://purl.org/dc/elements/1.1/"
+ DC11("dc11", "http://purl.org/dc/elements/1.1/"),
+ // dcat "http://www.w3.org/ns/dcat#"
+ DCAT("dcat", "http://www.w3.org/ns/dcat#"),
+ // dcterms "http://purl.org/dc/terms/"
+ DCTERMS("dcterms", "http://purl.org/dc/terms/"),
+ // dqv "http://www.w3.org/ns/dqv#"
+ DQV("dqv", "http://www.w3.org/ns/dqv#"),
+ // duv "https://www.w3.org/ns/duv#"
+ DUV("duv", "https://www.w3.org/ns/duv#"),
+ // foaf "http://xmlns.com/foaf/0.1/"
+ FOAF(fr.inria.corese.core.next.impl.common.vocabulary.FOAF.getVocabularyPreferredPrefix(), fr.inria.corese.core.next.impl.common.vocabulary.FOAF.getVocabularyNamespace()),
+ // gr "http://purl.org/goodrelations/v1#"
+ GR("gr", "http://purl.org/goodrelations/v1#"),
+ // grddl "http://www.w3.org/2003/g/data-view#"
+ GRDDL("grddl", "http://www.w3.org/2003/g/data-view#"),
+ // ical "http://www.w3.org/2002/12/cal/icaltzd#"
+ ICAL("ical", "http://www.w3.org/2002/12/cal/icaltzd#"),
+ // jsonld "http://www.w3.org/ns/json-ld#"
+ JSONLD("jsonld", "http://www.w3.org/ns/json-ld#"),
+ // ldp "http://www.w3.org/ns/ldp#"
+ LDP("ldp", "http://www.w3.org/ns/ldp#"),
+ // ma "http://www.w3.org/ns/ma-ont#"
+ MA("ma", "http://www.w3.org/ns/ma-ont#"),
+ // oa "http://www.w3.org/ns/oa#"
+ OA("oa", "http://www.w3.org/ns/oa#"),
+ // odrl "http://www.w3.org/ns/odrl/2/"
+ ODRL("odrl", "http://www.w3.org/ns/odrl/2/"),
+ // og "http://ogp.me/ns#"
+ OG("og", "http://ogp.me/ns#"),
+ // org "http://www.w3.org/ns/org#"
+ ORG("org", "http://www.w3.org/ns/org#"),
+ // owl "http://www.w3.org/2002/07/owl#"
+ OWL(fr.inria.corese.core.next.impl.common.vocabulary.OWL.getVocabularyPreferredPrefix(), fr.inria.corese.core.next.impl.common.vocabulary.OWL.getVocabularyNamespace()),
+ // prov "http://www.w3.org/ns/prov#"
+ PROV("prov", "http://www.w3.org/ns/prov#"),
+ // qb "http://purl.org/linked-data/cube#"
+ QB("qb", "http://purl.org/linked-data/cube#"),
+ // rdf "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ RDF(fr.inria.corese.core.next.impl.common.vocabulary.RDF.getVocabularyPreferredPrefix(), fr.inria.corese.core.next.impl.common.vocabulary.RDF.getVocabularyNamespace()),
+ // rdfa "http://www.w3.org/ns/rdfa#"
+ RDFA(fr.inria.corese.core.next.impl.common.vocabulary.RDFa.getVocabularyPreferredPrefix(), fr.inria.corese.core.next.impl.common.vocabulary.RDFa.getVocabularyNamespace()),
+ // rdfs "http://www.w3.org/2000/01/rdf-schema#"
+ RDFS(fr.inria.corese.core.next.impl.common.vocabulary.RDFS.getVocabularyPreferredPrefix(), fr.inria.corese.core.next.impl.common.vocabulary.RDFS.getVocabularyNamespace()),
+ // rev "http://purl.org/stuff/rev#"
+ REV("rev", "http://purl.org/stuff/rev#"),
+ // rif "http://www.w3.org/2007/rif#"
+ RIF("rif", "http://www.w3.org/2007/rif#"),
+ // rr "http://www.w3.org/ns/r2rml#"
+ RR("rr", "http://www.w3.org/ns/r2rml#"),
+ // schema "http://schema.org/"
+ SCHEMA("schema", "http://schema.org/"),
+ // sd "http://www.w3.org/ns/sparql-service-description#"
+ SD("sd", "http://www.w3.org/ns/sparql-service-description#"),
+ // sioc "http://rdfs.org/sioc/ns#"
+ SIOC("sioc", "http://rdfs.org/sioc/ns#"),
+ // skos "http://www.w3.org/2004/02/skos/core#"
+ SKOS("skos", "http://www.w3.org/2004/02/skos/core#"),
+ // skosxl "http://www.w3.org/2008/05/skos-xl#"
+ SKOSXL("skosxl", "http://www.w3.org/2008/05/skos-xl#"),
+ // sosa "http://www.w3.org/ns/sosa/"
+ SOSA("sosa", "http://www.w3.org/ns/sosa/"),
+ // ssn "http://www.w3.org/ns/ssn/"
+ SSN("ssn", "http://www.w3.org/ns/ssn/"),
+ // time "http://www.w3.org/2006/time#"
+ TIME("time", "http://www.w3.org/2006/time#"),
+ // v "http://rdf.data-vocabulary.org/#"
+ V("v", "http://rdf.data-vocabulary.org/#"),
+ // vcard "http://www.w3.org/2006/vcard/ns#"
+ VCARD("vcard", "http://www.w3.org/2006/vcard/ns#"),
+ // void "http://rdfs.org/ns/void#"
+ VOID("void", "http://rdfs.org/ns/void#"),
+ // wdr "http://www.w3.org/2007/05/powder#"
+ WDR("wdr", "http://www.w3.org/2007/05/powder#"),
+ // wdrs "http://www.w3.org/2007/05/powder-s#"
+ WDRS("wdrs", "http://www.w3.org/2007/05/powder-s#"),
+ // xhv "http://www.w3.org/1999/xhtml/vocab#"
+ XHV("xhv", "http://www.w3.org/1999/xhtml/vocab#"),
+ // xml "http://www.w3.org/XML/1998/namespace"
+ XML("xml", "http://www.w3.org/XML/1998/namespace"),
+ // xsd "http://www.w3.org/2001/XMLSchema#"
+ XSD(fr.inria.corese.core.next.impl.common.vocabulary.XSD.getVocabularyPreferredPrefix(), fr.inria.corese.core.next.impl.common.vocabulary.XSD.getVocabularyNamespace()),
+ ;
+
+ private final String prefix;
+ private final String name;
+
+ RDFaInitialPrefixes(String name, String prefix) {
+ this.name = name;
+ this.prefix = prefix;
+ }
+
+ @Override
+ public String getPrefix() {
+ return this.prefix;
+ }
+
+ @Override
+ public String getName() {
+ return this.name;
+ }
+}
diff --git a/src/test/java/fr/inria/corese/core/next/api/base/io/RDFFormatTest.java b/src/test/java/fr/inria/corese/core/next/api/base/io/RDFFormatTest.java
index 4d4c1bfe3..540f8d847 100644
--- a/src/test/java/fr/inria/corese/core/next/api/base/io/RDFFormatTest.java
+++ b/src/test/java/fr/inria/corese/core/next/api/base/io/RDFFormatTest.java
@@ -306,7 +306,7 @@ void allFormats() {
assertTrue(allFormats.contains(RDFFormat.JSONLD));
assertTrue(allFormats.contains(RDFFormat.RDFXML));
assertTrue(allFormats.contains(RDFFormat.TRIG));
- assertTrue(allFormats.contains(RDFFormat.RDFa));
+ assertTrue(allFormats.contains(RDFFormat.RDFa_1_0));
assertTrue(allFormats.contains(RDFFormat.RDFC_1_0));
assertThrows(UnsupportedOperationException.class, () -> allFormats.add(RDFFormat.TURTLE),
diff --git a/src/test/java/fr/inria/corese/core/next/impl/io/parser/rdfa/RDFaParserTest.java b/src/test/java/fr/inria/corese/core/next/impl/io/parser/rdfa/RDFa10ParserTest.java
similarity index 96%
rename from src/test/java/fr/inria/corese/core/next/impl/io/parser/rdfa/RDFaParserTest.java
rename to src/test/java/fr/inria/corese/core/next/impl/io/parser/rdfa/RDFa10ParserTest.java
index 2458067d9..3ee8a809c 100644
--- a/src/test/java/fr/inria/corese/core/next/impl/io/parser/rdfa/RDFaParserTest.java
+++ b/src/test/java/fr/inria/corese/core/next/impl/io/parser/rdfa/RDFa10ParserTest.java
@@ -16,7 +16,7 @@
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
-public class RDFaParserTest {
+public class RDFa10ParserTest {
private static final ValueFactory factory = new CoreseAdaptedValueFactory();
@@ -45,11 +45,11 @@ public void basicBaseTest() {
referenceModel.add(subject, predicate, object);
- RDFParser parser = new ParserFactory().createRDFParser(RDFFormat.RDFa, testModel, factory);
+ RDFParser parser = new ParserFactory().createRDFParser(RDFFormat.RDFa_1_0, testModel, factory);
parser.parse(new ByteArrayInputStream(testDataString.getBytes()));
- assertEquals(RDFFormat.RDFa, parser.getRDFFormat());
+ assertEquals(RDFFormat.RDFa_1_0, parser.getRDFFormat());
assertEquals(referenceModel.size(), testModel.size());
Iterator itStatementRef = referenceModel.iterator();
Iterator itStatementTest = testModel.iterator();
@@ -79,7 +79,7 @@ public void aboutTest() {
Model testModel = new CoreseModel();
- RDFParser parser = new ParserFactory().createRDFParser(RDFFormat.RDFa, testModel, factory);
+ RDFParser parser = new ParserFactory().createRDFParser(RDFFormat.RDFa_1_0, testModel, factory);
parser.parse(new ByteArrayInputStream(testDataString.getBytes()), "http://not.the.right.base.uri");
@@ -108,7 +108,7 @@ public void basicIRItoIRITest() {
Model testModel = new CoreseModel();
Model referenceModel = new CoreseModel();
- RDFParser parser = new ParserFactory().createRDFParser(RDFFormat.RDFa, testModel, factory);
+ RDFParser parser = new ParserFactory().createRDFParser(RDFFormat.RDFa_1_0, testModel, factory);
parser.parse(new ByteArrayInputStream(testDataString.getBytes()), "http://not.the.right.base.uri");
@@ -143,7 +143,7 @@ public void basicIRItoStringTest() {
Model testModel = new CoreseModel();
Model referenceModel = new CoreseModel();
- RDFParser parser = new ParserFactory().createRDFParser(RDFFormat.RDFa, testModel, factory);
+ RDFParser parser = new ParserFactory().createRDFParser(RDFFormat.RDFa_1_0, testModel, factory);
parser.parse(new ByteArrayInputStream(testDataString.getBytes()), "http://not.the.right.base.uri");
@@ -179,7 +179,7 @@ public void basicIRItoTypedLiteralTest() {
Model testModel = new CoreseModel();
Model referenceModel = new CoreseModel();
- RDFParser parser = new ParserFactory().createRDFParser(RDFFormat.RDFa, testModel, factory);
+ RDFParser parser = new ParserFactory().createRDFParser(RDFFormat.RDFa_1_0, testModel, factory);
parser.parse(new ByteArrayInputStream(testDataString.getBytes()), "http://not.the.right.base.uri");
@@ -226,7 +226,7 @@ public void basicChainTest() {
Model testModel = new CoreseModel();
Model referenceModel = new CoreseModel();
- RDFParser parser = new ParserFactory().createRDFParser(RDFFormat.RDFa, testModel, factory);
+ RDFParser parser = new ParserFactory().createRDFParser(RDFFormat.RDFa_1_0, testModel, factory);
parser.parse(new ByteArrayInputStream(testDataString.getBytes()), "http://not.the.right.base.uri");
diff --git a/src/test/java/fr/inria/corese/core/next/impl/io/parser/rdfa/RDFa11ParserTest.java b/src/test/java/fr/inria/corese/core/next/impl/io/parser/rdfa/RDFa11ParserTest.java
new file mode 100644
index 000000000..538fa6b13
--- /dev/null
+++ b/src/test/java/fr/inria/corese/core/next/impl/io/parser/rdfa/RDFa11ParserTest.java
@@ -0,0 +1,27 @@
+package fr.inria.corese.core.next.impl.io.parser.rdfa;
+
+import fr.inria.corese.core.next.api.Model;
+import fr.inria.corese.core.next.api.ValueFactory;
+import fr.inria.corese.core.next.api.base.io.RDFFormat;
+import fr.inria.corese.core.next.api.io.parser.RDFParser;
+import fr.inria.corese.core.next.impl.temp.CoreseAdaptedValueFactory;
+import fr.inria.corese.core.next.impl.temp.CoreseModel;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class RDFa11ParserTest {
+
+
+ @Test
+ void getRDFFormat() {
+ Model model = new CoreseModel();
+ ValueFactory factory = new CoreseAdaptedValueFactory();
+ RDFParser parser = new RDFa11Parser(model, factory);
+ assertEquals(RDFFormat.RDFa_1_1, parser.getRDFFormat());
+ }
+
+ @Test
+ void parse() {
+ }
+}
\ No newline at end of file
From a9ca6798b0b2532dfbd6fe64e950b99d8f977d54 Mon Sep 17 00:00:00 2001
From: Pierre Maillot
Date: Thu, 4 Dec 2025 15:01:03 +0100
Subject: [PATCH 03/13] removing namespace comparison
---
.../next/api/base/model/AbstractNamespace.java | 16 ----------------
.../next/impl/common/prefix/PrefixHandler.java | 2 +-
.../core/next/api/base/AbstractModelTest.java | 11 -----------
3 files changed, 1 insertion(+), 28 deletions(-)
diff --git a/src/main/java/fr/inria/corese/core/next/api/base/model/AbstractNamespace.java b/src/main/java/fr/inria/corese/core/next/api/base/model/AbstractNamespace.java
index 795c7959b..f6e2d49ad 100644
--- a/src/main/java/fr/inria/corese/core/next/api/base/model/AbstractNamespace.java
+++ b/src/main/java/fr/inria/corese/core/next/api/base/model/AbstractNamespace.java
@@ -19,22 +19,6 @@ public abstract class AbstractNamespace implements Namespace {
@Serial
private static final long serialVersionUID = 1L;
- /**
- * Comparator that orders namespaces by prefix, then by URI.
- * Null values are ordered first.
- */
- private static final Comparator ORDERING = Comparator.nullsFirst(
- Comparator.comparing(Namespace::getPrefix)
- .thenComparing(Namespace::getName));
-
- /**
- * Compares this namespace to another based on prefix and name.
- */
- @Override
- public int compareTo(Namespace other) {
- return ORDERING.compare(this, other);
- }
-
/**
* Checks equality based on prefix and name.
*/
diff --git a/src/main/java/fr/inria/corese/core/next/impl/common/prefix/PrefixHandler.java b/src/main/java/fr/inria/corese/core/next/impl/common/prefix/PrefixHandler.java
index 9e2722fcd..6115e136c 100644
--- a/src/main/java/fr/inria/corese/core/next/impl/common/prefix/PrefixHandler.java
+++ b/src/main/java/fr/inria/corese/core/next/impl/common/prefix/PrefixHandler.java
@@ -444,8 +444,8 @@ public String getPrefix() {
public String getName() {
return name;
}
+
@SuppressWarnings("NullableProblems")
- @Override
public int compareTo(Namespace o) {
Objects.requireNonNull(o);
int cmp = this.name.compareTo(o.getName());
diff --git a/src/test/java/fr/inria/corese/core/next/api/base/AbstractModelTest.java b/src/test/java/fr/inria/corese/core/next/api/base/AbstractModelTest.java
index 92552b1f1..fa7f118c6 100644
--- a/src/test/java/fr/inria/corese/core/next/api/base/AbstractModelTest.java
+++ b/src/test/java/fr/inria/corese/core/next/api/base/AbstractModelTest.java
@@ -692,16 +692,5 @@ public String getPrefix() {
public String getName() {
return name;
}
-
- @Override
- public int compareTo(Namespace other) {
-
- int prefixComparison = this.getPrefix().compareTo(other.getPrefix());
- if (prefixComparison != 0) {
- return prefixComparison;
- }
-
- return this.getName().compareTo(other.getName());
- }
}
}
\ No newline at end of file
From ede15484f1112f162ac45dfc7a5fcaa94d8338c1 Mon Sep 17 00:00:00 2001
From: Pierre Maillot
Date: Thu, 4 Dec 2025 15:01:35 +0100
Subject: [PATCH 04/13] Moving RDFa to only the 1.1 version, removing the old
one
---
.../core/next/api/base/io/RDFFormat.java | 15 +-
.../next/impl/io/parser/ParserFactory.java | 10 +-
.../io/parser/rdfa/AbstractRDFaParser.java | 80 ----
.../impl/io/parser/rdfa/RDFa10Parser.java | 344 ------------------
.../{RDFa11Parser.java => RDFaParser.java} | 248 ++++++++-----
.../model/AbstractRDFaEvaluationContext.java | 160 --------
.../rdfa/model/RDFa10EvaluationContext.java | 51 ---
.../rdfa/model/RDFa11EvaluationContext.java | 101 -----
.../rdfa/model/RDFaEvaluationContext.java | 225 ++++++++++--
.../rdfa/model/RDFaInitialPrefixes.java | 2 +-
.../core/next/api/base/io/RDFFormatTest.java | 2 +-
.../impl/io/parser/rdfa/RDFa10ParserTest.java | 227 ------------
.../impl/io/parser/rdfa/RDFa11ParserTest.java | 27 --
.../impl/io/parser/rdfa/RDFaParserTest.java | 337 +++++++++++++++++
14 files changed, 715 insertions(+), 1114 deletions(-)
delete mode 100644 src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/AbstractRDFaParser.java
delete mode 100644 src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/RDFa10Parser.java
rename src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/{RDFa11Parser.java => RDFaParser.java} (73%)
delete mode 100644 src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/model/AbstractRDFaEvaluationContext.java
delete mode 100644 src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/model/RDFa10EvaluationContext.java
delete mode 100644 src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/model/RDFa11EvaluationContext.java
delete mode 100644 src/test/java/fr/inria/corese/core/next/impl/io/parser/rdfa/RDFa11ParserTest.java
create mode 100644 src/test/java/fr/inria/corese/core/next/impl/io/parser/rdfa/RDFaParserTest.java
diff --git a/src/main/java/fr/inria/corese/core/next/api/base/io/RDFFormat.java b/src/main/java/fr/inria/corese/core/next/api/base/io/RDFFormat.java
index f2b8ab814..46606499a 100644
--- a/src/main/java/fr/inria/corese/core/next/api/base/io/RDFFormat.java
+++ b/src/main/java/fr/inria/corese/core/next/api/base/io/RDFFormat.java
@@ -65,17 +65,10 @@ public class RDFFormat extends FileFormat {
false,
true);
- public static final RDFFormat RDFa_1_0 = new RDFFormat(
- "RDFa 1.0",
- List.of("html"),
- List.of("text/html"),
- true,
- false);
-
- public static final RDFFormat RDFa_1_1 = new RDFFormat(
+ public static final RDFFormat RDFA = new RDFFormat(
"RDFa 1.1",
- List.of("xhtml", "svg", "xml"),
- List.of("application/xhtml+xml", "image/svg+xml", "application/xml", "text/xml"),
+ List.of("xhtml", "svg", "html"),
+ List.of("application/xhtml+xml", "image/svg+xml", "application/xml", "text/xml", "text/html"),
true,
false);
@@ -165,7 +158,7 @@ public static Optional byMimeType(String mimeType) {
* @return An unmodifiable List of all RdfFormat constants.
*/
public static List all() {
- return List.of(TURTLE, NTRIPLES, NQUADS, JSONLD, RDFXML, TRIG, RDFC_1_0, RDFa_1_0, RDFa_1_1);
+ return List.of(JSONLD, NQUADS, NTRIPLES, RDFA, RDFC_1_0, RDFXML, TRIG, TURTLE);
}
@Override
diff --git a/src/main/java/fr/inria/corese/core/next/impl/io/parser/ParserFactory.java b/src/main/java/fr/inria/corese/core/next/impl/io/parser/ParserFactory.java
index 7812e44d3..0293f1ff0 100644
--- a/src/main/java/fr/inria/corese/core/next/impl/io/parser/ParserFactory.java
+++ b/src/main/java/fr/inria/corese/core/next/impl/io/parser/ParserFactory.java
@@ -9,7 +9,7 @@
import fr.inria.corese.core.next.impl.io.parser.jsonld.JSONLDParser;
import fr.inria.corese.core.next.impl.io.parser.nquads.NQuadsParser;
import fr.inria.corese.core.next.impl.io.parser.ntriples.NTriplesParser;
-import fr.inria.corese.core.next.impl.io.parser.rdfa.RDFa10Parser;
+import fr.inria.corese.core.next.impl.io.parser.rdfa.RDFaParser;
import fr.inria.corese.core.next.impl.io.parser.rdfxml.RDFXMLParser;
import fr.inria.corese.core.next.impl.io.parser.turtle.TurtleParser;
import fr.inria.corese.core.next.impl.io.parser.trig.TriGParser;
@@ -53,8 +53,8 @@ public RDFParser createRDFParser(RDFFormat format, Model model, ValueFactory fac
return new TriGParser(model, factory, config);
} else if(format == RDFFormat.RDFC_1_0) {
return new NQuadsParser(model, factory, config);
- } else if (format == RDFFormat.RDFa_1_0) {
- return new RDFa10Parser(model, factory, config);
+ } else if (format == RDFFormat.RDFA) {
+ return new RDFaParser(model, factory, config);
}
throw new IllegalArgumentException("Unsupported format: " + format);
}
@@ -80,8 +80,8 @@ public RDFParser createRDFParser(RDFFormat format, Model model, ValueFactory fac
return new RDFXMLParser(model, factory);
} else if (format == RDFFormat.TRIG) {
return new TriGParser(model, factory);
- } else if (format == RDFFormat.RDFa_1_0) {
- return new RDFa10Parser(model, factory);
+ } else if (format == RDFFormat.RDFA) {
+ return new RDFaParser(model, factory);
}
throw new IllegalArgumentException("Unsupported format: " + format);
}
diff --git a/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/AbstractRDFaParser.java b/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/AbstractRDFaParser.java
deleted file mode 100644
index d9fee9f6f..000000000
--- a/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/AbstractRDFaParser.java
+++ /dev/null
@@ -1,80 +0,0 @@
-package fr.inria.corese.core.next.impl.io.parser.rdfa;
-
-import fr.inria.corese.core.next.api.IRI;
-import fr.inria.corese.core.next.api.Model;
-import fr.inria.corese.core.next.api.Resource;
-import fr.inria.corese.core.next.api.ValueFactory;
-import fr.inria.corese.core.next.api.base.io.parser.AbstractRDFParser;
-import fr.inria.corese.core.next.api.io.IOOptions;
-import fr.inria.corese.core.next.impl.common.util.IRIUtils;
-import fr.inria.corese.core.next.impl.exception.ParsingErrorException;
-import fr.inria.corese.core.next.impl.io.parser.rdfa.model.RDFaEvaluationContext;
-
-import java.util.Optional;
-
-public abstract class AbstractRDFaParser extends AbstractRDFParser {
-
- protected RDFaEvaluationContext currentContext;
-
- protected AbstractRDFaParser(Model model, ValueFactory factory) {
- super(model, factory);
- }
-
- protected AbstractRDFaParser(Model model, ValueFactory factory, IOOptions config) {
- super(model, factory, config);
- }
-
- /**
- * Resolves the string representation of a resource found in attributes of an element, be it an IRI, CURIE or relative URI
- *
- * @param stringResource the resource as stored in the attribute of the HTML element
- * @param context the context of the element evalation
- * @return the full IRI if it is a relative IRI, full IRI or CURIE, nothing otherwise
- */
- protected Optional resolveStringResource(String stringResource, RDFaEvaluationContext context) {
- String resultString = stringResource;
- if (resultString.startsWith("[") && resultString.endsWith("]")) {
- resultString = resultString.replaceFirst("\\[", "");
- resultString = resultString.replaceFirst("]", "");
- }
-
-
- if (stringUriIsCURIE(resultString)) { // CURIE
- int colonIndex = resultString.indexOf(":");
- String prefixString = resultString.substring(0, colonIndex);
- String localNameString = resultString.substring(colonIndex + 1);
- // Basic resolution following https://www.w3.org/TR/rdfa-syntax/#s_convertingcurietouri
- if (context.hasIriMapping(prefixString)) {
- IRI namespaceIRI = context.getIriMapping(prefixString);
-
- return Optional.of(this.getValueFactory().createIRI(namespaceIRI.stringValue(), localNameString));
- } else if (prefixString.isEmpty()) { // CURIE is relative to the base URI
- return Optional.of(this.getValueFactory().createIRI(context.getBaseIri().stringValue(), localNameString));
- } else {
- throw new ParsingErrorException("CURIE " + stringResource + " uses unknown prefix");
- }
- } else if (IRIUtils.isStandardIRI(resultString)) { // Full IRI
- return Optional.of(this.getValueFactory().createIRI(resultString));
-
- } else if (resultString.startsWith("_:")) { // Blank Node
- int colonIndex = resultString.indexOf(":");
- String localNameString = resultString.substring(colonIndex + 1);
- return Optional.of(this.getValueFactory().createBNode(localNameString));
- } else if (IRIUtils.isStandardIRI(context.getBaseIri().stringValue() + resultString)) {
- String concatenatedRelativeUri = context.getBaseIri().stringValue() + resultString;
- return Optional.of(getValueFactory().createIRI(concatenatedRelativeUri));
- }
- return Optional.empty();
- }
-
- /**
- * Equivalent to test if it has a colon, and it is not a blank node
- *
- * @param stringIri
- * @return
- */
- protected boolean stringUriIsCURIE(String stringIri) {
- int colonIndex = stringIri.indexOf(":");
- return colonIndex > -1 && !stringIri.contains("://") && !stringIri.startsWith("_:") && !stringIri.startsWith("[_:");
- }
-}
diff --git a/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/RDFa10Parser.java b/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/RDFa10Parser.java
deleted file mode 100644
index 689c15ba9..000000000
--- a/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/RDFa10Parser.java
+++ /dev/null
@@ -1,344 +0,0 @@
-package fr.inria.corese.core.next.impl.io.parser.rdfa;
-
-import fr.inria.corese.core.next.api.*;
-import fr.inria.corese.core.next.api.base.io.RDFFormat;
-import fr.inria.corese.core.next.api.base.io.parser.AbstractRDFParser;
-import fr.inria.corese.core.next.api.io.IOOptions;
-import fr.inria.corese.core.next.api.io.common.BaseIRIOptions;
-import fr.inria.corese.core.next.impl.common.util.IRIUtils;
-import fr.inria.corese.core.next.impl.common.vocabulary.RDF;
-import fr.inria.corese.core.next.impl.exception.ParsingErrorException;
-import fr.inria.corese.core.next.impl.io.common.IOConstants;
-import fr.inria.corese.core.next.impl.io.parser.rdfa.model.RDFa10EvaluationContext;
-import fr.inria.corese.core.next.impl.io.parser.rdfa.model.RDFaAttributes;
-import fr.inria.corese.core.next.impl.io.parser.rdfa.model.RDFaEvaluationContext;
-import fr.inria.corese.core.next.impl.io.parser.rdfa.model.RDFaIncompleteStatement;
-import org.apache.commons.io.input.ReaderInputStream;
-import org.jsoup.Jsoup;
-import org.jsoup.nodes.Attribute;
-import org.jsoup.nodes.Document;
-import org.jsoup.nodes.Element;
-
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.nio.charset.StandardCharsets;
-import java.util.*;
-
-/**
- * RDFa parser. This parser will load the RDF data stored as RDFa in an HTML page. Its inner implementation is based on the jsoup library. It loads the html page as DOM and process it following the recommended algorithm in the RDFa recommendation.
- */
-public class RDFa10Parser extends AbstractRDFaParser {
-
- private static final String BASE_TAG = "base";
-
- private static final String XMLNS_PREFIX = "xmlns";
-
- public RDFa10Parser(Model model, ValueFactory factory) {
- this(model, factory, new RDFaParserOptions.Builder().build());
- }
-
- public RDFa10Parser(Model model, ValueFactory factory, IOOptions config) {
- super(model, factory, config);
- }
-
- @Override
- public RDFFormat getRDFFormat() {
- return RDFFormat.RDFa_1_0;
- }
-
- @Override
- public void parse(InputStream in) {
- if(getConfig() instanceof BaseIRIOptions baseIRIOptions) {
- String baseIRI = baseIRIOptions.getBaseIRI();
- parse(new InputStreamReader(in, StandardCharsets.UTF_8), baseIRI);
- } else {
- parse(new InputStreamReader(in, StandardCharsets.UTF_8), null);
- }
- }
-
- @Override
- public void parse(InputStream in, String baseURIString) {
- try {
- Document document = Jsoup.parse(in, null, baseURIString);
-
- IRI baseIri = getValueFactory().createIRI(baseURIString);
- processDocument(document, baseIri);
- } catch (Exception e) {
- throw new ParsingErrorException("Error during parsing of HTML document", e);
- }
- }
-
- /**
- * Intermediary function to configure the processing of a document using some basic HTML traversal to determine if a baseIri has been defined in the document.
- * If the baseIri in argument is the Corese default base IRI, the value stored in the document is used instead.
- *
- * @param document Jsoup HTML document to be processed
- * @param baseIri An IRI object
- */
- private void processDocument(Document document, IRI baseIri) {
- // If the base Iri in argument is not the default baseIri, then we take it, else we use the one in the document
- if (baseIri.stringValue().equals(IOConstants.getDefaultBaseURI())) {
- // Looking for the node in the document
- IRI baseIriFromXml = baseIri;
- Iterator baseElementIterator = document.stream().filter(element -> element.nameIs(BASE_TAG)).iterator();
- while (baseElementIterator.hasNext()) {
- Element baseElement = baseElementIterator.next();
- Attribute baseElementHrefAttribute = baseElement.attribute(RDFaAttributes.HREF.getName());
- if (baseElementHrefAttribute != null) {
- String baseIriString = baseElementHrefAttribute.getValue();
- baseIriFromXml = getValueFactory().createIRI(baseIriString);
- }
- }
-
- baseIri = this.getValueFactory().createIRI(baseIriFromXml.stringValue());
- }
-
- for (Element element : document.children()) {
- processElement(element, new RDFa10EvaluationContext(baseIri));
- }
- }
-
- /**
- * @param element Current element
- * @param context Active context
- * @param recursive Processing generally continues recursively through the entire tree of elements available. However, if an author indicates that some branch of the tree should be treated as an XML literal, no further processing should take place on that branch, and setting this flag to false would have that effect.
- * @param skipElement Flag thet indicates whether the [current element] can safely be ignored since it has no relevant RDFa attributes. Note that descendant elements will still be processed.
- * @see RDFa processing in details
- */
- private void processElement(Element element, fr.inria.corese.core.next.impl.io.parser.rdfa.model.RDFa10EvaluationContext context, boolean recursive, boolean skipElement) {
-
- // 1. First, the local values are initialized
- Resource newSubject = null;
- Resource currentObject = null;
- Literal currentObjectLiteral = null;
- Map currentMappings = context.getIriMappings();
- Set incompleteStatementSet = new HashSet<>();
- String language = context.getLanguage();
-
- // 2. Next the [current element] is parsed for [URI mapping]s and these are added to the [local list of URI mappings]. Note that a [URI mapping] will simply overwrite any current mapping in the list that has the same name;
- // Looking for namespace declarations
- // Namespace declaration are done using the XML namespace declaration mechanism, that can be seen as an attributes prefixed by "xmlns" and looks like this: "xmlns:prefix=namespace"
- for (Attribute attribute : element.attributes()) {
- if (attribute.getKey().startsWith(XMLNS_PREFIX)) {
- String prefixName = attribute.localName();
- IRI prefixNamespace = getValueFactory().createIRI(attribute.getValue(), "");
- context.addIriMapping(prefixName, prefixNamespace);
- }
- }
-
- // 3. The [current element] is also parsed for any language information, and if present, [current language] is set accordingly;
- if (element.attribute(RDFaAttributes.LANG.getName()) != null) {
- language = element.attr(RDFaAttributes.LANG.getName());
- }
-
- // 4. If the [current element] contains no @rel or @rev attribute, then the next step is to establish a value for [new subject]. Any of the attributes that can carry a resource can set [new subject];
- if(element.attribute(RDFaAttributes.REL.getName()) == null && element.attribute(RDFaAttributes.REV.getName()) == null) {
- // [new subject] is set to the URI obtained from the first match from the following rules:
- if (element.attribute(RDFaAttributes.ABOUT.getName()) != null) { // by using the URI from @about, if present, obtained according to the section on CURIE and URI Processing;
- Optional newSubjectResource = getResourceFromElementAttribute(element, RDFaAttributes.ABOUT.getName(), context);
- if (newSubjectResource.isPresent()) {
- newSubject = newSubjectResource.get();
- }
- } else if (element.attribute(RDFaAttributes.SRC.getName()) != null) { // otherwise, by using the URI from @src, if present, obtained according to the section on CURIE and URI Processing.
- Optional newSubjectResource = getResourceFromElementAttribute(element, RDFaAttributes.SRC.getName(), context);
- if (newSubjectResource.isPresent()) {
- newSubject = newSubjectResource.get();
- }
- } else if (element.attribute(RDFaAttributes.RESOURCE.getName()) != null) { // otherwise, by using the URI from @resource, if present, obtained according to the section on CURIE and URI Processing;
- Optional newSubjectResource = getResourceFromElementAttribute(element, RDFaAttributes.RESOURCE.getName(), context);
- if (newSubjectResource.isPresent()) {
- newSubject = newSubjectResource.get();
- }
- } else if (element.attribute(RDFaAttributes.HREF.getName()) != null) { // otherwise, by using the URI from @href, if present, obtained according to the section on CURIE and URI Processing.
- Optional newSubjectResource = getResourceFromElementAttribute(element, RDFaAttributes.HREF.getName(), context);
- if (newSubjectResource.isPresent()) {
- newSubject = newSubjectResource.get();
- }
- } else if (element.nameIs("body") || element.nameIs("head")) { // if the element is the head or body element then act as if there is an empty @about present, and process it according to the rule for @about, above;
- newSubject = context.getBaseIri();
- } else if (element.attribute(RDFaAttributes.TYPEOF.getName()) != null) { // if @typeof is present, obtained according to the section on CURIE and URI Processing, then [new subject] is set to be a newly created [bnode].
- newSubject = this.getValueFactory().createBNode();
- } else if (context.getParentObjectResource() != null) { // otherwise, if [parent object] is present, [new subject] is set to the value of [parent object]. Additionally, if @property is not present then the [skip element] flag is set to 'true';
- newSubject = context.getParentObjectResource();
- if(element.attribute(RDFaAttributes.PROPERTY.getName()) == null) {
- skipElement = true;
- }
- }
- } else {
- // [new subject] is set to the URI obtained from the first match from the following rules:
- if (element.attribute(RDFaAttributes.ABOUT.getName()) != null) { // by using the URI from @about, if present, obtained according to the section on CURIE and URI Processing;
- Optional newSubjectResource = getResourceFromElementAttribute(element, RDFaAttributes.ABOUT.getName(), context);
- if (newSubjectResource.isPresent()) {
- newSubject = newSubjectResource.get();
- }
- } else if (element.attribute(RDFaAttributes.SRC.getName()) != null) { // otherwise, by using the URI from @src, if present, obtained according to the section on CURIE and URI Processing.
- Optional newSubjectResource = getResourceFromElementAttribute(element, RDFaAttributes.SRC.getName(), context);
- if (newSubjectResource.isPresent()) {
- newSubject = newSubjectResource.get();
- }
- } else if (element.nameIs("body") || element.nameIs("head")) { // if the element is the head or body element then act as if there is an empty @about present, and process it according to the rule for @about, above;
- newSubject = context.getBaseIri();
- } else if (element.attribute(RDFaAttributes.TYPEOF.getName()) != null) { // if @typeof is present, obtained according to the section on CURIE and URI Processing, then [new subject] is set to be a newly created [bnode].
- newSubject = this.getValueFactory().createBNode();
- } else if(context.getParentObjectResource() != null) { // otherwise, if [parent object] is present, [new subject] is set to that.
- newSubject = context.getParentObjectResource();
- }
-
- // Then the [current object resource] is set to the URI obtained from the first match from the following rules:
- if (element.attribute(RDFaAttributes.RESOURCE.getName()) != null) { // by using the URI from @resource, if present, obtained according to the section on CURIE and URI Processing;
- Optional newObjectResource = getResourceFromElementAttribute(element, RDFaAttributes.RESOURCE.getName(), context);
- if (newObjectResource.isPresent()) {
- currentObject = newObjectResource.get();
- }
- } else if (element.attribute(RDFaAttributes.HREF.getName()) != null) { // otherwise, by using the URI from @href, if present, obtained according to the section on CURIE and URI Processing.
- Optional newObjectResource = getResourceFromElementAttribute(element, RDFaAttributes.RESOURCE.getName(), context);
- if (newObjectResource.isPresent()) {
- currentObject = newObjectResource.get();
- }
- }
- }
-
- // 6. If in any of the previous steps a [new subject] was set to a non-null value, it is now used to provide a subject for type values;
- if(newSubject != null) {
- if(element.attribute(RDFaAttributes.TYPEOF.getName()) != null) { // One or more 'types' for the [new subject] can be set by using @typeof. If present, the attribute must contain one or more URIs, obtained according to the section on URI and CURIE Processing, each of which is used to generate a triple as follows:
- Optional typeIri = getResourceFromElementAttribute(element, RDFaAttributes.TYPEOF.getName(), context);
- if (typeIri.isPresent()) {
- Statement stat = this.getValueFactory().createStatement(newSubject, RDF.type.getIRI(), typeIri.get());
- this.getModel().add(stat);
- } else {
- throw new ParsingErrorException("Typeof statement uses unknown type " + element.attr(RDFaAttributes.TYPEOF.getName()));
- }
- }
- }
-
- // 7. If in any of the previous steps a [current object resource] was set to a non-null value, it is now used to generate triples:
- if (currentObject != null && (element.attribute(RDFaAttributes.REL.getName()) != null || element.attribute(RDFaAttributes.REV.getName()) != null)) {
- if(element.attribute(RDFaAttributes.REL.getName()) != null) {
- Optional propertyOpt = getResourceFromElementAttribute(element, RDFaAttributes.REL.getName(), context);
- if(propertyOpt.isPresent() && propertyOpt.get().isIRI()) {
- IRI property = (IRI) propertyOpt.get();
- this.getModel().add(newSubject, property, currentObject);
- }
- }
- if(element.attribute(RDFaAttributes.REV.getName()) != null) {
- Optional propertyOpt = getResourceFromElementAttribute(element, RDFaAttributes.REL.getName(), context);
- if(propertyOpt.isPresent() && propertyOpt.get().isIRI() && currentObject.isResource()) {
- IRI property = (IRI) propertyOpt.get();
- this.getModel().add(currentObject, property, newSubject);
- }
- }
- }
-
- // 8. If however [current object resource] was set to null, but there are predicates present, then they must be stored as [incomplete triple]s, pending the discovery of a subject that can be used as the object. Also, [current object resource] should be set to a newly created [bnode];
- if (currentObject == null && (element.attribute(RDFaAttributes.REL.getName()) != null || element.attribute(RDFaAttributes.REV.getName()) != null)) {
- currentObject = getValueFactory().createBNode();
- if(element.attribute(RDFaAttributes.REL.getName()) != null) {
- Optional propertyOpt = getResourceFromElementAttribute(element, RDFaAttributes.REL.getName(), context);
- if(propertyOpt.isPresent() && propertyOpt.get().isIRI()) {
- IRI property = (IRI) propertyOpt.get();
- RDFaIncompleteStatement statement = new RDFaIncompleteStatement(property);
- incompleteStatementSet.add(statement);
- }
- }
- if(element.attribute(RDFaAttributes.REV.getName()) != null) {
- Optional propertyOpt = getResourceFromElementAttribute(element, RDFaAttributes.REL.getName(), context);
- if(propertyOpt.isPresent() && propertyOpt.get().isIRI() && currentObject.isResource()) {
- IRI property = (IRI) propertyOpt.get();
- RDFaIncompleteStatement statement = new RDFaIncompleteStatement(property);
- statement.setBackward();
- incompleteStatementSet.add(statement);
- }
- }
- }
-
- // 9. The next step of the iteration is to establish any [current object literal];
- if(element.attribute(RDFaAttributes.PROPERTY.getName()) != null) { // Predicates for the [current object literal] can be set by using @property. If present, one or more URIs are obtained according to the section on CURIE and URI Processing, and then the actual literal value is obtained as follows:
- Optional propertyOpt = getResourceFromElementAttribute(element, RDFaAttributes.PROPERTY.getName(), context);
- if(propertyOpt.isPresent() && propertyOpt.get().isIRI()) {
- IRI property = (IRI)propertyOpt.get();
-
- IRI datatype = null;
- if(element.attribute(RDFaAttributes.DATATYPE.getName()) != null && ! element.attr(RDFaAttributes.DATATYPE.getName()).isEmpty()) {
- Optional datatypeOpt = getResourceFromElementAttribute(element, RDFaAttributes.DATATYPE.getName(), context);
- if(datatypeOpt.isPresent() && datatypeOpt.get().isIRI() && ! datatypeOpt.get().equals(RDF.XMLLiteral.getIRI())) {
- datatype = (IRI) datatypeOpt.get();
- }
- }
- String value = element.text();
- if(element.attribute(RDFaAttributes.CONTENT.getName()) != null) {
- value = element.attr(RDFaAttributes.CONTENT.getName());
- }
- if(datatype != null) {
- currentObjectLiteral = this.getValueFactory().createLiteral(value, datatype);
- recursive = false;
- } else if(language != null) {
- currentObjectLiteral = this.getValueFactory().createLiteral(value, language);
- } else {
- currentObjectLiteral = this.getValueFactory().createLiteral(value);
- }
- this.getModel().add(newSubject, property, currentObjectLiteral);
- }
- }
-
- // 10. If the [skip element] flag is 'false', and [new subject] was set to a non-null value, then any [incomplete triple]s within the current context should be completed:
- Iterator itStat = context.getIncompleteStatementIterator();
- while(itStat.hasNext()) {
- RDFaIncompleteStatement statement = itStat.next();
- if(statement.isForward()) {
- this.getModel().add(context.getParentSubjectResource(), statement.getPredicate(), newSubject);
- } else if (statement.isBackward()){
- this.getModel().add(newSubject, statement.getPredicate(), context.getParentSubjectResource());
- }
- }
-
- // 11. If the [recurse] flag is 'true', all elements that are children of the [current element] are processed using the rules described here, using a new [evaluation context],
- if(recursive) {
- if(skipElement) {
- RDFa10EvaluationContext newContext = new fr.inria.corese.core.next.impl.io.parser.rdfa.model.RDFa10EvaluationContext(context);
- newContext.setLanguage(language);
- newContext.setIriMappings(currentMappings);
- context = newContext;
- } else {
- context = new RDFa10EvaluationContext(context.getBaseIri());
- if(newSubject != null) {
- context.setParentObjectResource(newSubject);
- }
- if(currentObject != null) {
- context.setParentObjectResource(currentObject);
- }
- context.setIriMappings(currentMappings);
- context.setIncompleteStatements(incompleteStatementSet);
- context.setLanguage(language);
- }
-
- for (Element child : element.children()) {
- processElement(child, context, recursive, skipElement);
- }
- }
- }
-
- /**
- * Surcharge function that initialize the flags and subject and objet to their initial values for processing
- *
- * @param element HTML element
- * @param context current evaluation context
- */
- private void processElement(Element element, fr.inria.corese.core.next.impl.io.parser.rdfa.model.RDFa10EvaluationContext context) {
- processElement(element, context, true, false);
- }
-
- @Override
- public void parse(Reader reader, String baseURI) {
- InputStream inputStream = new ReaderInputStream(reader, StandardCharsets.UTF_8);
- parse(inputStream , baseURI);
- }
-
- private Optional getResourceFromElementAttribute(Element element, String attributeName, RDFaEvaluationContext context) {
- if (element.attribute(attributeName) != null) { // otherwise, by using the URI from @resource, if present, obtained according to the section on CURIE and URI Processing;
- String newSubjectString = element.attr(attributeName);
- return resolveStringResource(newSubjectString, context);
- }
- return Optional.empty();
- }
-}
diff --git a/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/RDFa11Parser.java b/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/RDFaParser.java
similarity index 73%
rename from src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/RDFa11Parser.java
rename to src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/RDFaParser.java
index 7ab3e26c6..7dc79c6c9 100644
--- a/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/RDFa11Parser.java
+++ b/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/RDFaParser.java
@@ -2,17 +2,16 @@
import fr.inria.corese.core.next.api.*;
import fr.inria.corese.core.next.api.base.io.RDFFormat;
+import fr.inria.corese.core.next.api.base.io.parser.AbstractRDFParser;
import fr.inria.corese.core.next.api.io.IOOptions;
import fr.inria.corese.core.next.api.io.common.BaseIRIOptions;
+import fr.inria.corese.core.next.impl.common.util.IRIUtils;
import fr.inria.corese.core.next.impl.common.vocabulary.RDF;
-import fr.inria.corese.core.next.impl.common.vocabulary.RDFS;
-import fr.inria.corese.core.next.impl.common.vocabulary.RDFa;
import fr.inria.corese.core.next.impl.exception.ParsingErrorException;
-import fr.inria.corese.core.next.impl.io.parser.rdfa.model.RDFa11EvaluationContext;
import fr.inria.corese.core.next.impl.io.parser.rdfa.model.RDFaAttributes;
+import fr.inria.corese.core.next.impl.io.parser.rdfa.model.RDFaEvaluationContext;
import fr.inria.corese.core.next.impl.io.parser.rdfa.model.RDFaIncompleteStatement;
import fr.inria.corese.core.next.impl.io.parser.rdfa.model.RDFaInitialPrefixes;
-import fr.inria.corese.core.next.impl.temp.CoreseModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.Attributes;
@@ -39,14 +38,14 @@
* This parser does NOT support vocabulary expansion
*
*/
-public class RDFa11Parser extends AbstractRDFaParser {
+public class RDFaParser extends AbstractRDFParser {
- private static final Logger logger = LoggerFactory.getLogger(RDFa11Parser.class);
+ private static final Logger logger = LoggerFactory.getLogger(RDFaParser.class);
private static final String BASE_TAG = "base";
private static final String XMLNS_PREFIX = "xmlns";
- private RDFa11EvaluationContext currentContext = null;
+ private RDFaEvaluationContext currentContext = null;
/**
* Buffer for accumulating character data between start and end tags.
@@ -68,13 +67,11 @@ public class RDFa11Parser extends AbstractRDFaParser {
private boolean isRootElement = true;
private Attributes currentElementAttributes = null;
- private Model parsingModel = new CoreseModel();
-
- public RDFa11Parser(Model model, ValueFactory factory) {
+ public RDFaParser(Model model, ValueFactory factory) {
this(model, factory, new RDFaParserOptions.Builder().build());
}
- public RDFa11Parser(Model model, ValueFactory factory, IOOptions config) {
+ public RDFaParser(Model model, ValueFactory factory, IOOptions config) {
super(model, factory, config);
}
@@ -96,30 +93,19 @@ public void parse(InputStream in, String baseURIString) {
@Override
public RDFFormat getRDFFormat() {
- return RDFFormat.RDFa_1_1;
+ return RDFFormat.RDFA;
}
@Override
public void parse(Reader reader, String baseURI) {
try {
- this.currentContext = new RDFa11EvaluationContext(getValueFactory().createIRI(baseURI));
+ this.currentContext = getNewContext(getValueFactory().createIRI(baseURI));
this.currentContext.setParentSubjectResource(this.currentContext.getBaseIri());
this.currentContext.setParentObjectResource(null);
this.currentContext.setLanguage(null);
- // Initializing the iri mappings with the default prefixes as defined by https://www.w3.org/TR/rdfa-core/#xmlrdfaconformance
- for (RDFaInitialPrefixes prefixObject : RDFaInitialPrefixes.values()) {
- currentContext.addIriMapping(prefixObject.getPrefix(), getValueFactory().createIRI(prefixObject.getName()));
- }
-
- // https://www.w3.org/2011/rdfa-context/rdfa-1.1 sets a list of predefined terms mappings for RDFa contexts.
- this.currentContext.addTermMapping("describedby", getValueFactory().createIRI("http://www.w3.org/2007/05/powder-s#describedby"));
- this.currentContext.addTermMapping("license", getValueFactory().createIRI("http://www.w3.org/1999/xhtml/vocab#license"));
- this.currentContext.addTermMapping("role", getValueFactory().createIRI("http://www.w3.org/1999/xhtml/vocab#role"));
-
this.currentContext.setDefaultVocabulary(null);
-
skipElement = false;
newSubject = null;
currentObjectResource = null;
@@ -165,9 +151,7 @@ private void endProcessElement(String uri, String localName, String qName) {
// The current element is examined for any change to the default vocabulary via @vocab. If @vocab is present and contains a value, the local default vocabulary is updated according to the section on CURIE and IRI Processing. If the value is empty, then the local default vocabulary MUST be reset to the Host Language defined default (if any).
if (this.currentElementAttributes.getValue(RDFaAttributes.VOCAB.getName()) != null
&& !this.currentElementAttributes.getValue(RDFaAttributes.VOCAB.getName()).isEmpty()) {
- String vocabValue = this.currentElementAttributes.getValue(RDFaAttributes.VOCAB.getName());
- localDefaultVocabulary = vocabValue;
- parsingModel.add(this.currentContext.getBaseIri(), RDFa.usesVocabulary.getIRI(), getValueFactory().createLiteral(vocabValue));
+ localDefaultVocabulary = this.currentElementAttributes.getValue(RDFaAttributes.VOCAB.getName());
}
// The current element is examined for IRI mappings and these are added to the local list of IRI mappings. Note that an IRI mapping will simply overwrite any current mapping in the list that has the same name;
@@ -207,14 +191,19 @@ private void endProcessElement(String uri, String localName, String qName) {
if (this.currentElementAttributes.getValue(RDFaAttributes.ABOUT.getName()) != null) {
this.typedResource = this.newSubject;
} else if (isRootElement) {
- this.typedResource = resolveStringResource("", this.currentContext).get();
+ Optional emptyAboutResource = resolveStringResource("");
+ if (emptyAboutResource.isPresent()) {
+ this.typedResource = emptyAboutResource.get();
+ } else {
+ throw new ParsingErrorException("Expected to be able to generate typedResource from empty CURIE");
+ }
} else {
if (this.currentElementAttributes.getValue(RDFaAttributes.RESOURCE.getName()) != null) {
this.newSubject = getResourceFromElementAttribute(RDFaAttributes.RESOURCE);
} else if (this.currentElementAttributes.getValue(RDFaAttributes.HREF.getName()) != null) {
- this.newSubject = getResourceFromElementAttribute( RDFaAttributes.HREF);
+ this.newSubject = getResourceFromElementAttribute(RDFaAttributes.HREF);
} else if (this.currentElementAttributes.getValue(RDFaAttributes.SRC.getName()) != null) {
- this.newSubject = getResourceFromElementAttribute( RDFaAttributes.SRC);
+ this.newSubject = getResourceFromElementAttribute(RDFaAttributes.SRC);
} else {
this.typedResource = getValueFactory().createBNode();
}
@@ -228,17 +217,22 @@ private void endProcessElement(String uri, String localName, String qName) {
&& this.currentElementAttributes.getValue(RDFaAttributes.SRC.getName()) != null
&& this.currentElementAttributes.getValue(RDFaAttributes.RESOURCE.getName()) != null) {
if (this.currentElementAttributes.getValue(RDFaAttributes.ABOUT.getName()) != null) {
- this.newSubject = getResourceFromElementAttribute( RDFaAttributes.ABOUT);
+ this.newSubject = getResourceFromElementAttribute(RDFaAttributes.ABOUT);
} else if (this.currentElementAttributes.getValue(RDFaAttributes.RESOURCE.getName()) != null) {
- this.newSubject = getResourceFromElementAttribute( RDFaAttributes.RESOURCE);
+ this.newSubject = getResourceFromElementAttribute(RDFaAttributes.RESOURCE);
} else if (this.currentElementAttributes.getValue(RDFaAttributes.HREF.getName()) != null) {
- this.newSubject = getResourceFromElementAttribute( RDFaAttributes.HREF);
+ this.newSubject = getResourceFromElementAttribute(RDFaAttributes.HREF);
} else if (this.currentElementAttributes.getValue(RDFaAttributes.SRC.getName()) != null) {
- this.newSubject = getResourceFromElementAttribute( RDFaAttributes.SRC);
+ this.newSubject = getResourceFromElementAttribute(RDFaAttributes.SRC);
}
} else {
if (isRootElement) {
- this.newSubject = resolveStringResource("", this.currentContext).get();
+ Optional emptyAboutResource = resolveStringResource("");
+ if (emptyAboutResource.isPresent()) {
+ this.newSubject = emptyAboutResource.get();
+ } else {
+ throw new ParsingErrorException("Expected to be able to generate newSubject from empty CURIE");
+ }
} else if (this.currentElementAttributes.getValue(RDFaAttributes.TYPEOF.getName()) != null) {
this.newSubject = getValueFactory().createBNode();
} else if (this.currentContext.getParentObjectResource() != null) {
@@ -258,24 +252,29 @@ private void endProcessElement(String uri, String localName, String qName) {
if (this.currentElementAttributes.getValue(RDFaAttributes.REL.getName()) != null
&& this.currentElementAttributes.getValue(RDFaAttributes.REV.getName()) != null) {
if (this.currentElementAttributes.getValue(RDFaAttributes.ABOUT.getName()) != null) {
- this.newSubject = getResourceFromElementAttribute( RDFaAttributes.ABOUT);
+ this.newSubject = getResourceFromElementAttribute(RDFaAttributes.ABOUT);
}
if (this.currentElementAttributes.getValue(RDFaAttributes.TYPEOF.getName()) != null) {
this.typedResource = this.newSubject;
}
if (this.newSubject == null) {
if (isRootElement) {
- this.typedResource = resolveStringResource("", this.currentContext).get();
+ Optional emptyAboutResource = resolveStringResource("");
+ if (emptyAboutResource.isPresent()) {
+ this.typedResource = emptyAboutResource.get();
+ } else {
+ throw new ParsingErrorException("Expected to be able to generate typedResource from empty CURIE");
+ }
} else if (this.currentContext.getParentObjectResource() != null) {
this.newSubject = this.currentContext.getParentObjectResource();
}
}
if (this.currentElementAttributes.getValue(RDFaAttributes.RESOURCE.getName()) != null) {
- this.currentObjectResource = getResourceFromElementAttribute( RDFaAttributes.RESOURCE);
+ this.currentObjectResource = getResourceFromElementAttribute(RDFaAttributes.RESOURCE);
} else if (this.currentElementAttributes.getValue(RDFaAttributes.HREF.getName()) != null) {
- this.currentObjectResource = getResourceFromElementAttribute( RDFaAttributes.HREF);
+ this.currentObjectResource = getResourceFromElementAttribute(RDFaAttributes.HREF);
} else if (this.currentElementAttributes.getValue(RDFaAttributes.SRC.getName()) != null) {
- this.currentObjectResource = getResourceFromElementAttribute( RDFaAttributes.SRC);
+ this.currentObjectResource = getResourceFromElementAttribute(RDFaAttributes.SRC);
} else if (this.currentElementAttributes.getValue(RDFaAttributes.TYPEOF.getName()) != null
&& this.currentElementAttributes.getValue(RDFaAttributes.ABOUT.getName()) == null) {
this.currentObjectResource = this.getValueFactory().createBNode();
@@ -289,7 +288,7 @@ private void endProcessElement(String uri, String localName, String qName) {
// If in any of the previous steps a typed resource was set to a non-null value, it is now used to provide a subject for type values;
if (this.typedResource != null) {
- Resource typeIri = getResourceFromElementAttribute( RDFaAttributes.TYPEOF);
+ Resource typeIri = getResourceFromElementAttribute(RDFaAttributes.TYPEOF);
this.getModel().add(this.typedResource, RDF.type.getIRI(), typeIri);
}
@@ -302,7 +301,7 @@ private void endProcessElement(String uri, String localName, String qName) {
if (this.currentObjectResource != null) {
if (this.currentElementAttributes.getValue(RDFaAttributes.INLIST.getName()) != null
&& this.currentElementAttributes.getValue(RDFaAttributes.REL.getName()) != null) {
- IRI relResource = (IRI) getResourceFromElementAttribute( RDFaAttributes.REL);
+ IRI relResource = (IRI) getResourceFromElementAttribute(RDFaAttributes.REL);
if (!localListMappings.containsKey(relResource)) {
this.localListMappings.put(relResource, new HashSet<>());
}
@@ -310,7 +309,7 @@ private void endProcessElement(String uri, String localName, String qName) {
}
if (this.currentElementAttributes.getValue(RDFaAttributes.INLIST.getName()) == null) {
if (this.currentElementAttributes.getValue(RDFaAttributes.REL.getName()) != null) {
- Resource relResource = getResourceFromElementAttribute( RDFaAttributes.REL);
+ Resource relResource = getResourceFromElementAttribute(RDFaAttributes.REL);
if (relResource.isIRI()) {
this.getModel().add(newSubject, (IRI) relResource, currentObjectResource);
} else {
@@ -318,7 +317,7 @@ private void endProcessElement(String uri, String localName, String qName) {
}
}
if (this.currentElementAttributes.getValue(RDFaAttributes.REV.getName()) != null) {
- Resource revResource = getResourceFromElementAttribute( RDFaAttributes.REV);
+ Resource revResource = getResourceFromElementAttribute(RDFaAttributes.REV);
if (!revResource.isIRI()) {
throw new ParsingErrorException("Value of attribute @rev expected to be an IRI but was " + this.currentElementAttributes.getValue(RDFaAttributes.REV.getName()));
}
@@ -334,29 +333,29 @@ private void endProcessElement(String uri, String localName, String qName) {
if (this.currentObjectResource == null) {
this.currentObjectResource = getValueFactory().createBNode();
if (this.currentElementAttributes.getValue(RDFaAttributes.REL.getName()) != null) {
- if(! getResourceFromElementAttribute( RDFaAttributes.REL).isIRI()) {
+ if (!getResourceFromElementAttribute(RDFaAttributes.REL).isIRI()) {
throw new ParsingErrorException("Value of attribute @rel expected to be an IRI but was " + this.currentElementAttributes.getValue(RDFaAttributes.REL.getName()));
}
- IRI relIRI = (IRI) getResourceFromElementAttribute( RDFaAttributes.REL);
- if(this.currentElementAttributes.getValue(RDFaAttributes.INLIST.getName()) != null) { // TODO: Step to be double checked, standard unclear
+ IRI relIRI = (IRI) getResourceFromElementAttribute(RDFaAttributes.REL);
+ if (this.currentElementAttributes.getValue(RDFaAttributes.INLIST.getName()) != null) {
if (!localListMappings.containsKey(relIRI)) {
this.localListMappings.put(relIRI, new HashSet<>());
}
- this.localListMappings.get(relIRI).add(this.currentObjectResource);
+ this.localIncompleteStatements.add(new RDFaIncompleteStatement(relIRI, RDFaIncompleteStatement.Direction.NONE));
} else {
this.localIncompleteStatements.add(new RDFaIncompleteStatement(relIRI, RDFaIncompleteStatement.Direction.FORWARD));
}
} else if (this.currentElementAttributes.getValue(RDFaAttributes.REV.getName()) != null) {
- if(! getResourceFromElementAttribute( RDFaAttributes.REV).isIRI()) {
+ if (!getResourceFromElementAttribute(RDFaAttributes.REV).isIRI()) {
throw new ParsingErrorException("Value of attribute @rev expected to be an IRI but was " + this.currentElementAttributes.getValue(RDFaAttributes.REV.getName()));
}
- IRI revIRI = (IRI) getResourceFromElementAttribute( RDFaAttributes.REV);
+ IRI revIRI = (IRI) getResourceFromElementAttribute(RDFaAttributes.REV);
this.localIncompleteStatements.add(new RDFaIncompleteStatement(revIRI, RDFaIncompleteStatement.Direction.BACKWARD));
}
}
// The next step of the iteration is to establish any current property value;
- if(this.currentElementAttributes.getValue(RDFaAttributes.PROPERTY.getName()) != null) {
+ if (this.currentElementAttributes.getValue(RDFaAttributes.PROPERTY.getName()) != null) {
IRI propertyIRI = (IRI) getResourceFromElementAttribute(RDFaAttributes.PROPERTY);
Value currentPropertyValue = null;
if (this.currentElementAttributes.getValue(RDFaAttributes.DATATYPE.getName()) != null
@@ -381,20 +380,20 @@ && getResourceFromElementAttribute(RDFaAttributes.DATATYPE) != RDF.XMLLiteral.ge
currentPropertyValue = getValueFactory().createLiteral(contentString);
this.characters = new StringBuilder();
}
- //} else if (this.currentElementAttributes.getValue(RDFaAttributes.DATATYPE.getName()) != null
- // && getResourceFromElementAttribute( RDFaAttributes.DATATYPE).isIRI()
- // && getResourceFromElementAttribute( RDFaAttributes.DATATYPE) == RDF.XMLLiteral.getIRI()) {
+ //} else if (this.currentElementAttributes.getValue(RDFaAttributes.DATATYPE.getName()) != null
+ // && getResourceFromElementAttribute( RDFaAttributes.DATATYPE).isIRI()
+ // && getResourceFromElementAttribute( RDFaAttributes.DATATYPE) == RDF.XMLLiteral.getIRI()) {
} else if (this.currentElementAttributes.getValue(RDFaAttributes.CONTENT.getName()) != null) {
String contentString = this.currentElementAttributes.getValue(RDFaAttributes.CONTENT.getName());
currentPropertyValue = getValueFactory().createLiteral(contentString);
} else if (this.currentElementAttributes.getValue(RDFaAttributes.REL.getName()) == null
&& this.currentElementAttributes.getValue(RDFaAttributes.REV.getName()) == null
&& this.currentElementAttributes.getValue(RDFaAttributes.CONTENT.getName()) == null) {
- if(this.currentElementAttributes.getValue(RDFaAttributes.RESOURCE.getName()) != null) {
+ if (this.currentElementAttributes.getValue(RDFaAttributes.RESOURCE.getName()) != null) {
currentPropertyValue = getResourceFromElementAttribute(RDFaAttributes.RESOURCE);
- } else if(this.currentElementAttributes.getValue(RDFaAttributes.HREF.getName()) != null) {
+ } else if (this.currentElementAttributes.getValue(RDFaAttributes.HREF.getName()) != null) {
currentPropertyValue = getResourceFromElementAttribute(RDFaAttributes.HREF);
- } else if(this.currentElementAttributes.getValue(RDFaAttributes.SRC.getName()) != null) {
+ } else if (this.currentElementAttributes.getValue(RDFaAttributes.SRC.getName()) != null) {
currentPropertyValue = getResourceFromElementAttribute(RDFaAttributes.SRC);
}
} else if (this.currentElementAttributes.getValue(RDFaAttributes.TYPEOF.getName()) != null
@@ -402,8 +401,8 @@ && getResourceFromElementAttribute(RDFaAttributes.DATATYPE) != RDF.XMLLiteral.ge
currentPropertyValue = typedResource;
} else {
String contentString = this.characters.toString().trim();
- if(this.currentLanguage != null
- && ! this.currentLanguage.isEmpty()) {
+ if (this.currentLanguage != null
+ && !this.currentLanguage.isEmpty()) {
currentPropertyValue = getValueFactory().createLiteral(contentString, this.currentLanguage);
} else {
currentPropertyValue = getValueFactory().createLiteral(contentString);
@@ -411,8 +410,8 @@ && getResourceFromElementAttribute(RDFaAttributes.DATATYPE) != RDF.XMLLiteral.ge
this.characters = new StringBuilder();
}
- if(this.currentElementAttributes.getValue(RDFaAttributes.INLIST.getName()) != null) {
- if(! this.localListMappings.containsKey(propertyIRI)) {
+ if (this.currentElementAttributes.getValue(RDFaAttributes.INLIST.getName()) != null) {
+ if (!this.localListMappings.containsKey(propertyIRI)) {
this.localListMappings.put(propertyIRI, new HashSet<>());
}
this.localListMappings.get(propertyIRI).add(currentPropertyValue);
@@ -422,14 +421,14 @@ && getResourceFromElementAttribute(RDFaAttributes.DATATYPE) != RDF.XMLLiteral.ge
}
// If the skip element flag is 'false', and new subject was set to a non-null value, then any incomplete triples within the current context should be completed:
- if(! skipElement
+ if (!skipElement
&& newSubject != null) {
- for(RDFaIncompleteStatement incompleteStatement : this.currentContext.getIncompleteStatement()) {
- if(incompleteStatement.getDirection() == RDFaIncompleteStatement.Direction.NONE) {
+ for (RDFaIncompleteStatement incompleteStatement : this.currentContext.getIncompleteStatement()) {
+ if (incompleteStatement.getDirection() == RDFaIncompleteStatement.Direction.NONE) {
localListMappings.get(incompleteStatement.getPredicate()).add(newSubject);
- } else if(incompleteStatement.getDirection() == RDFaIncompleteStatement.Direction.FORWARD) {
+ } else if (incompleteStatement.getDirection() == RDFaIncompleteStatement.Direction.FORWARD) {
this.getModel().add(currentContext.getParentSubjectResource(), incompleteStatement.getPredicate(), newSubject);
- } else if(incompleteStatement.getDirection() == RDFaIncompleteStatement.Direction.BACKWARD) {
+ } else if (incompleteStatement.getDirection() == RDFaIncompleteStatement.Direction.BACKWARD) {
this.getModel().add(newSubject, incompleteStatement.getPredicate(), currentContext.getParentSubjectResource());
}
}
@@ -437,22 +436,26 @@ && getResourceFromElementAttribute(RDFaAttributes.DATATYPE) != RDF.XMLLiteral.ge
// Next, all elements that are children of the current element are processed using the rules described here, using a new evaluation context, initialized as follows:
Map> oldListMappings = currentContext.getListMappings();
- if(skipElement) {
- currentContext = new RDFa11EvaluationContext(this.currentContext);
+ if (skipElement) {
+ currentContext = new RDFaEvaluationContext(this.currentContext);
+ currentContext.clearIriMappings();
+ initializeNewContext(currentContext);
currentContext.setLanguage(currentLanguage);
- currentContext.setIriMappings(localIRIMappings);
+ currentContext.addIriMappings(localIRIMappings);
} else {
Resource oldParentSubject = this.currentContext.getParentSubjectResource();
- currentContext = new RDFa11EvaluationContext(this.currentContext.getBaseIri());
+ currentContext = new RDFaEvaluationContext(this.currentContext.getBaseIri());
+ initializeNewContext(currentContext);
currentContext.setParentSubjectResource(newSubject);
- if(currentObjectResource != null) {
+ if (currentObjectResource != null) {
currentContext.setParentObjectResource(currentObjectResource);
- } if (newSubject != null) {
+ }
+ if (newSubject != null) {
currentContext.setParentObjectResource(newSubject);
} else {
currentContext.setParentObjectResource(oldParentSubject);
}
- currentContext.setIriMappings(localIRIMappings);
+ currentContext.addIriMappings(localIRIMappings);
currentContext.setIncompleteStatements(localIncompleteStatements);
currentContext.setListMappings(localListMappings);
currentContext.setLanguage(currentLanguage);
@@ -460,23 +463,23 @@ && getResourceFromElementAttribute(RDFaAttributes.DATATYPE) != RDF.XMLLiteral.ge
}
// Finally, if there is one or more mapping in the local list mapping, list triples are generated as follows:
- for(Map.Entry> listMapping : localListMappings.entrySet()) {
+ for (Map.Entry> listMapping : localListMappings.entrySet()) {
IRI propertyIRI = listMapping.getKey();
Set propertyList = listMapping.getValue();
- if(!oldListMappings.containsKey(propertyIRI)) {
- if(propertyList.isEmpty()) {
+ if (!oldListMappings.containsKey(propertyIRI)) {
+ if (propertyList.isEmpty()) {
getModel().add(newSubject, propertyIRI, RDF.nil.getIRI());
} else {
ArrayList bnodes = new ArrayList<>();
- for(int i = 0; i < propertyList.size(); i++) {
+ for (int i = 0; i < propertyList.size(); i++) {
bnodes.add(getValueFactory().createBNode());
}
int bnodeIndex = 0;
- for(Value listElement : propertyList) {
+ for (Value listElement : propertyList) {
BNode elementNode = bnodes.get(bnodeIndex);
Resource nextElementNode = RDF.nil.getIRI();
- if(bnodeIndex < bnodes.size() - 1) {
+ if (bnodeIndex < bnodes.size() - 1) {
nextElementNode = bnodes.get(bnodeIndex + 1);
}
getModel().add(elementNode, RDF.first.getIRI(), listElement);
@@ -498,12 +501,12 @@ && getResourceFromElementAttribute(RDFaAttributes.DATATYPE) != RDF.XMLLiteral.ge
private class XMLSaxHandler extends DefaultHandler {
@Override
public void characters(char[] ch, int start, int length) {
- RDFa11Parser.this.handleCharacters(ch, start, length);
+ RDFaParser.this.handleCharacters(ch, start, length);
}
@Override
public void startPrefixMapping(String prefix, String uri) {
- RDFa11Parser.this.addPrefix(prefix, uri);
+ RDFaParser.this.addPrefix(prefix, uri);
}
@Override
@@ -550,10 +553,89 @@ private IRI getPrefixIriFromDeclaration(String declaration) {
private Resource getResourceFromElementAttribute(RDFaAttributes attribute) {
String attributeValue = this.currentElementAttributes.getValue(attribute.getName());
- if (resolveStringResource(attributeValue, this.currentContext).isPresent()) {
- return resolveStringResource(attributeValue, this.currentContext).get();
+ Optional resourceResolution = resolveStringResource(attributeValue);
+ if (resourceResolution.isPresent()) {
+ return resourceResolution.get();
} else {
throw new ParsingErrorException("Could not parse @" + attribute.getName() + " value: " + attributeValue);
}
}
+
+
+ /**
+ * Resolves the string representation of a resource found in attributes of an element, be it an IRI, CURIE or relative URI
+ *
+ * @param stringResource the resource as stored in the attribute of the HTML element
+ * @return the full IRI if it is a relative IRI, full IRI or CURIE, nothing otherwise
+ */
+ protected Optional resolveStringResource(String stringResource) {
+ String resultString = stringResource;
+ if (resultString.startsWith("[") && resultString.endsWith("]")) {
+ resultString = resultString.replaceFirst("\\[", "");
+ resultString = resultString.replaceFirst("]", "");
+ }
+
+
+ if (stringUriIsCURIE(resultString)) { // CURIE
+ int colonIndex = resultString.indexOf(":");
+ String prefixString = resultString.substring(0, colonIndex);
+ String localNameString = resultString.substring(colonIndex + 1);
+ // Basic resolution following https://www.w3.org/TR/rdfa-syntax/#s_convertingcurietouri
+ if (currentContext.hasIriMapping(prefixString)) {
+ IRI namespaceIRI = currentContext.getIriMapping(prefixString);
+
+ return Optional.of(this.getValueFactory().createIRI(namespaceIRI.stringValue(), localNameString));
+ } else if (localIRIMappings.containsKey(prefixString)) {
+ IRI namespaceIRI = localIRIMappings.get(prefixString);
+
+ return Optional.of(this.getValueFactory().createIRI(namespaceIRI.stringValue(), localNameString));
+ } else if (prefixString.isEmpty()) { // CURIE is relative to the base URI
+ return Optional.of(this.getValueFactory().createIRI(currentContext.getBaseIri().stringValue(), localNameString));
+ } else {
+ logger.info("{} context mappings", currentContext.getIriMappings().size());
+ logger.info("{} local mappings", localIRIMappings.size());
+ throw new ParsingErrorException("CURIE " + stringResource + " uses unknown prefix");
+ }
+ } else if (IRIUtils.isStandardIRI(resultString)) { // Full IRI
+ return Optional.of(this.getValueFactory().createIRI(resultString));
+
+ } else if (resultString.startsWith("_:")) { // Blank Node
+ int colonIndex = resultString.indexOf(":");
+ String localNameString = resultString.substring(colonIndex + 1);
+ return Optional.of(this.getValueFactory().createBNode(localNameString));
+ } else if (IRIUtils.isStandardIRI(currentContext.getBaseIri().stringValue() + resultString)) {
+ String concatenatedRelativeUri = currentContext.getBaseIri().stringValue() + resultString;
+ return Optional.of(getValueFactory().createIRI(concatenatedRelativeUri));
+ }
+ return Optional.empty();
+ }
+
+ /**
+ * Equivalent to test if it contains a colon, and it is not a blank node
+ *
+ * @param stringIri Attribute or text value
+ * @return true if it is a valid CURIE
+ */
+ protected boolean stringUriIsCURIE(String stringIri) {
+ int colonIndex = stringIri.indexOf(":");
+ return colonIndex > -1 && !stringIri.contains("://") && !stringIri.startsWith("_:") && !stringIri.startsWith("[_:");
+ }
+
+ private RDFaEvaluationContext getNewContext(IRI baseIRI) {
+ RDFaEvaluationContext result = new RDFaEvaluationContext(baseIRI);
+ initializeNewContext(result);
+ return result;
+ }
+
+ private void initializeNewContext(RDFaEvaluationContext context) {
+ // Initializing the iri mappings with the default prefixes as defined by https://www.w3.org/TR/rdfa-core/#xmlrdfaconformance
+ for (RDFaInitialPrefixes prefixObject : RDFaInitialPrefixes.values()) {
+ context.addIriMapping(prefixObject.getPrefix(), getValueFactory().createIRI(prefixObject.getName()));
+ }
+
+ // https://www.w3.org/2011/rdfa-context/rdfa-1.1 sets a list of predefined terms mappings for RDFa contexts.
+ context.addTermMapping("describedby", getValueFactory().createIRI("http://www.w3.org/2007/05/powder-s#describedby"));
+ context.addTermMapping("license", getValueFactory().createIRI("http://www.w3.org/1999/xhtml/vocab#license"));
+ context.addTermMapping("role", getValueFactory().createIRI("http://www.w3.org/1999/xhtml/vocab#role"));
+ }
}
diff --git a/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/model/AbstractRDFaEvaluationContext.java b/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/model/AbstractRDFaEvaluationContext.java
deleted file mode 100644
index 59e6ffd9a..000000000
--- a/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/model/AbstractRDFaEvaluationContext.java
+++ /dev/null
@@ -1,160 +0,0 @@
-package fr.inria.corese.core.next.impl.io.parser.rdfa.model;
-
-import fr.inria.corese.core.next.api.IRI;
-import fr.inria.corese.core.next.api.Resource;
-import fr.inria.corese.core.next.api.Value;
-
-import java.util.*;
-
-public abstract class AbstractRDFaEvaluationContext implements RDFaEvaluationContext {
-
- /**
- * The base. This will usually be the IRI of the document being processed, but it could be some other IRI, set by some other mechanism, such as the (X)HTML base element. The important thing is that it establishes an IRI against which relative paths can be resolved.
- */
- private IRI baseIri;
-
- /**
- * The initial value will be the same as the initial value of [base], but it will usually change during the course of processing.
- */
- private Resource parentSubjectResource ;
-
- /**
- * In some situations the object of a statement becomes the subject of any nested statements, and this property is used to convey this value. Note that this value may be a bnode, since in some situations a number of nested statements are grouped together on one bnode. This means that the bnode must be set in the containing statement and passed down, and this property is used to convey this value.
- */
- private Resource parentObjectResource = null;
-
- /**
- * An index of locally defined IRI prefixes
- */
- private Map iriMappings = new HashMap<>();
-
- /**
- * Set of statement in the process of building.
- */
- private Set incompleteStatement = new HashSet<>();
-
- /**
- * The language of the document. Note that there is no default language.
- */
- private String language = null;
-
- protected AbstractRDFaEvaluationContext(IRI baseIri) {
- this(baseIri, baseIri);
- }
-
- protected AbstractRDFaEvaluationContext(IRI baseIri, IRI parentSubjectResource) {
- this.baseIri = baseIri;
- this.parentSubjectResource = parentSubjectResource;
- }
-
- protected AbstractRDFaEvaluationContext(AbstractRDFaEvaluationContext context) {
- this.baseIri = context.baseIri;
- this.parentSubjectResource = context.parentSubjectResource;
- this.parentObjectResource = context.parentObjectResource;
- this.iriMappings = new HashMap<>(context.iriMappings);
- this.incompleteStatement = new HashSet<>(context.incompleteStatement);
- this.language = context.language;
- }
-
- @Override
- public IRI getBaseIri() {
- return baseIri;
- }
-
- @Override
- public void setBaseIri(IRI baseIri) {
- this.baseIri = baseIri;
- }
-
- @Override
- public Resource getParentSubjectResource() {
- return parentSubjectResource;
- }
-
- @Override
- public void setParentSubjectResource(Resource parentSubjectResource) {
- this.parentSubjectResource = parentSubjectResource;
- }
-
- @Override
- public Resource getParentObjectResource() {
- return parentObjectResource;
- }
-
- @Override
- public void setParentObjectResource(Resource parentObjectResource) {
- this.parentObjectResource = parentObjectResource;
- }
-
- @Override
- public Map getIriMappings() {
- return iriMappings;
- }
-
- @Override
- public void setIriMappings(Map iriMappings) {
- this.iriMappings = iriMappings;
- }
-
- @Override
- public boolean hasIriMapping(String prefix) {
- return this.iriMappings.containsKey(prefix);
- }
-
- /**
- * @param prefix the prefix WITHOUT ":"
- * @return the IRI associated to the prefix in this context
- */
- @Override
- public IRI getIriMapping(String prefix) {
- return this.iriMappings.get(prefix);
- }
-
- @Override
- public void addIriMapping(String prefix, IRI prefixIri) {
- this.iriMappings.put(prefix, prefixIri);
- }
-
- @Override
- public Set getIncompleteStatement() {
- return incompleteStatement;
- }
-
- @Override
- public void setIncompleteStatements(Set incompleteStatement) {
- this.incompleteStatement = incompleteStatement;
- }
-
- @Override
- public Iterator getIncompleteStatementIterator() {
- return this.incompleteStatement.iterator();
- }
-
- @Override
- public void addStatementWithoutSubject(IRI property, Value object) {
- RDFaIncompleteStatement newStatement = new RDFaIncompleteStatement(property);
- newStatement.setObject(object);
- this.incompleteStatement.add(newStatement);
- }
-
- @Override
- public void addStatementWithoutObject(Resource subject, IRI property) {
- RDFaIncompleteStatement newStatement = new RDFaIncompleteStatement(property);
- newStatement.setSubject(subject);
- this.incompleteStatement.add(newStatement);
- }
-
- public void clearIncompleteStatements() {
- this.incompleteStatement.clear();
- }
-
- @Override
- public String getLanguage() {
- return language;
- }
-
- @Override
- public void setLanguage(String language) {
- this.language = language;
- }
-}
diff --git a/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/model/RDFa10EvaluationContext.java b/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/model/RDFa10EvaluationContext.java
deleted file mode 100644
index ca9406762..000000000
--- a/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/model/RDFa10EvaluationContext.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package fr.inria.corese.core.next.impl.io.parser.rdfa.model;
-
-import fr.inria.corese.core.next.api.IRI;
-import fr.inria.corese.core.next.api.Resource;
-import fr.inria.corese.core.next.api.Value;
-
-import java.util.*;
-
-/**
- * This class is to be used during the evaluation of an HTML file to generate triples during the DOM traversal.
- * @see RDFa recommandation
- */
-public class RDFa10EvaluationContext extends AbstractRDFaEvaluationContext {
-
- public RDFa10EvaluationContext(IRI baseIri) {
- this(baseIri, baseIri);
- }
-
- public RDFa10EvaluationContext(IRI baseIri, IRI parentSubjectResource) {
- super(baseIri, parentSubjectResource);
- }
-
- public RDFa10EvaluationContext(RDFa10EvaluationContext context) {
- super(context);
- }
-
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
-
- sb.append("BaseURI: ").append(this.getBaseIri().stringValue()).append(" ");
- sb.append("Mappings: [");
- this.getIriMappings().forEach((key, value) -> sb.append("(").append(key).append(", ").append(value.stringValue()).append(") "));
- sb.append("] ");
- if(this.getParentSubjectResource() != null) {
- sb.append("Subject:").append(this.getParentSubjectResource().stringValue()).append(" ");
- } else {
- sb.append("Subject:").append((Object) null).append(" ");
- }
- if(this.getParentObjectResource() != null) {
- sb.append("Object: ").append(this.getParentObjectResource().stringValue()).append(" ");
- } else {
- sb.append("Object: ").append((Object) null).append(" ");
- }
- if(! this.getIncompleteStatement().isEmpty()) {
- sb.append(this.getIncompleteStatement().size()).append(" incomplete statements.");
- }
-
- return sb.toString();
- }
-}
diff --git a/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/model/RDFa11EvaluationContext.java b/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/model/RDFa11EvaluationContext.java
deleted file mode 100644
index 36c3c82d0..000000000
--- a/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/model/RDFa11EvaluationContext.java
+++ /dev/null
@@ -1,101 +0,0 @@
-package fr.inria.corese.core.next.impl.io.parser.rdfa.model;
-
-import fr.inria.corese.core.next.api.IRI;
-import fr.inria.corese.core.next.api.Resource;
-import fr.inria.corese.core.next.api.Value;
-
-import java.util.*;
-
-/**
- * This class is to be used during the evaluation of an HTML file to generate triples during the DOM traversal.
- * @see RDFa recommandation
- */
-public class RDFa11EvaluationContext extends AbstractRDFaEvaluationContext {
-
- /**
- * A list mapping that associates IRIs with lists.
- */
- private Map> listMappings = new HashMap<>();
- /**
- * The language. Note that there is no default language.
- */
- private String language = null;
- /**
- * The term mappings, a list of terms and their associated IRIs. This specification does not define an initial list. Host Languages MAY define an initial list.
- */
- private Map termMappings = new HashMap<>();
-
- /**
- * The default vocabulary, a value to use as the prefix IRI when a term unknown to the RDFa Processor is used. This specification does not define an initial setting for the default vocabulary. Host Languages MAY define an initial setting.
- */
- private String defaultVocabulary = null;
-
-
- public RDFa11EvaluationContext(IRI baseIri) {
- this(baseIri, baseIri);
- }
-
- public RDFa11EvaluationContext(IRI baseIri, IRI parentSubjectResource) {
- super(baseIri, parentSubjectResource);
- }
-
- public RDFa11EvaluationContext(RDFa11EvaluationContext context) {
- super(context);
- this.listMappings = new HashMap<>(context.listMappings);
- this.termMappings = new HashMap<>(context.termMappings);
- this.defaultVocabulary = context.defaultVocabulary;;
- }
-
- public String getDefaultVocabulary() {
- return defaultVocabulary;
- }
-
- public void setDefaultVocabulary(String defaultVocabulary) {
- this.defaultVocabulary = defaultVocabulary;
- }
-
- public void addTermMapping(String term, IRI iri) {
- this.termMappings.put(term, iri);
- }
-
- public IRI getTermMapping(String term) {
- return this.termMappings.get(term);
- }
-
- public Map getTermMappings() {
- return this.termMappings;
- }
-
- public Map> getListMappings() {
- return listMappings;
- }
-
- public void setListMappings(Map> listMappings) {
- this.listMappings = listMappings;
- }
-
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
-
- sb.append("BaseURI: ").append(this.getBaseIri().stringValue()).append(" ");
- sb.append("Mappings: [");
- this.getIriMappings().forEach((key, value) -> sb.append("(").append(key).append(", ").append(value.stringValue()).append(") "));
- sb.append("] ");
- if(this.getParentSubjectResource() != null) {
- sb.append("Subject:").append(this.getParentSubjectResource().stringValue()).append(" ");
- } else {
- sb.append("Subject:").append((Object) null).append(" ");
- }
- if(this.getParentObjectResource() != null) {
- sb.append("Object: ").append(this.getParentObjectResource().stringValue()).append(" ");
- } else {
- sb.append("Object: ").append((Object) null).append(" ");
- }
- if(! this.getIncompleteStatement().isEmpty()) {
- sb.append(this.getIncompleteStatement().size()).append(" incomplete statements.");
- }
-
- return sb.toString();
- }
-}
diff --git a/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/model/RDFaEvaluationContext.java b/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/model/RDFaEvaluationContext.java
index 438f70537..6a11a4809 100644
--- a/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/model/RDFaEvaluationContext.java
+++ b/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/model/RDFaEvaluationContext.java
@@ -4,35 +4,214 @@
import fr.inria.corese.core.next.api.Resource;
import fr.inria.corese.core.next.api.Value;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
-public interface RDFaEvaluationContext {
+/**
+ * This class is to be used during the evaluation of an HTML file to generate triples during the DOM traversal.
+ * @see RDFa recommandation
+ */
+public class RDFaEvaluationContext {
+ /**
+ * The base. This will usually be the IRI of the document being processed, but it could be some other IRI, set by some other mechanism, such as the (X)HTML base element. The important thing is that it establishes an IRI against which relative paths can be resolved.
+ */
+ private IRI baseIri;
- IRI getBaseIri();
- void setBaseIri(IRI baseIri);
+ /**
+ * The initial value will be the same as the initial value of [base], but it will usually change during the course of processing.
+ */
+ private Resource parentSubjectResource ;
- void setParentSubjectResource(Resource parentSubjectResource);
- Resource getParentSubjectResource();
+ /**
+ * In some situations the object of a statement becomes the subject of any nested statements, and this property is used to convey this value. Note that this value may be a bnode, since in some situations a number of nested statements are grouped together on one bnode. This means that the bnode must be set in the containing statement and passed down, and this property is used to convey this value.
+ */
+ private Resource parentObjectResource = null;
- void setParentObjectResource(Resource parentObjectResource);
- Resource getParentObjectResource();
+ /**
+ * An index of locally defined IRI prefixes
+ */
+ private Map iriMappings = new HashMap<>();
- void setIncompleteStatements(Set incompleteStatement);
- Set getIncompleteStatement();
- Iterator getIncompleteStatementIterator();
- void addStatementWithoutSubject(IRI property, Value object);
- void addStatementWithoutObject(Resource subject, IRI property);
- void clearIncompleteStatements();
+ /**
+ * Set of statement in the process of building.
+ */
+ private Set incompleteStatement = new HashSet<>();
- boolean hasIriMapping(String prefix);
- IRI getIriMapping(String prefix);
- Map getIriMappings();
- void addIriMapping(String prefix, IRI prefixIri);
- void setIriMappings(Map iriMappings);
+ /**
+ * The language of the document. Note that there is no default language.
+ */
+ private String language = null;
+ /**
+ * A list mapping that associates IRIs with lists.
+ */
+ private Map> listMappings = new HashMap<>();
+ /**
+ * The term mappings, a list of terms and their associated IRIs. This specification does not define an initial list. Host Languages MAY define an initial list.
+ */
+ private Map termMappings = new HashMap<>();
- String getLanguage();
- void setLanguage(String language);
+ /**
+ * The default vocabulary, a value to use as the prefix IRI when a term unknown to the RDFa Processor is used. This specification does not define an initial setting for the default vocabulary. Host Languages MAY define an initial setting.
+ */
+ private String defaultVocabulary = null;
+ public RDFaEvaluationContext(IRI baseIri) {
+ this.baseIri = baseIri;
+ }
+
+ public RDFaEvaluationContext(RDFaEvaluationContext context) {
+ this.baseIri = context.baseIri;
+ this.parentSubjectResource = context.parentSubjectResource;
+ this.parentObjectResource = context.parentObjectResource;
+ this.iriMappings = new HashMap<>(context.iriMappings);
+ this.incompleteStatement = new HashSet<>(context.incompleteStatement);
+ this.language = context.language;
+ this.listMappings = new HashMap<>(context.listMappings);
+ this.termMappings = new HashMap<>(context.termMappings);
+ this.defaultVocabulary = context.defaultVocabulary;;
+ }
+
+ public IRI getBaseIri() {
+ return baseIri;
+ }
+
+ public void setBaseIri(IRI baseIri) {
+ this.baseIri = baseIri;
+ }
+
+ public Resource getParentSubjectResource() {
+ return parentSubjectResource;
+ }
+
+ public void setParentSubjectResource(Resource parentSubjectResource) {
+ this.parentSubjectResource = parentSubjectResource;
+ }
+
+ public Resource getParentObjectResource() {
+ return parentObjectResource;
+ }
+
+ public void setParentObjectResource(Resource parentObjectResource) {
+ this.parentObjectResource = parentObjectResource;
+ }
+
+ public Map getIriMappings() {
+ return iriMappings;
+ }
+
+ public void setIriMappings(Map iriMappings) {
+ this.iriMappings = iriMappings;
+ }
+
+ public boolean hasIriMapping(String prefix) {
+ return this.iriMappings.containsKey(prefix);
+ }
+
+ /**
+ * @param prefix the prefix WITHOUT ":"
+ * @return the IRI associated to the prefix in this context
+ */
+ public IRI getIriMapping(String prefix) {
+ return this.iriMappings.get(prefix);
+ }
+
+ public void addIriMapping(String prefix, IRI prefixIri) {
+ this.iriMappings.put(prefix, prefixIri);
+ }
+
+ public void addIriMappings(Map otherMappings) {
+ this.iriMappings.putAll(otherMappings);
+ }
+
+ public void clearIriMappings() {
+ this.iriMappings.clear();
+ }
+
+ public Set getIncompleteStatement() {
+ return incompleteStatement;
+ }
+
+ public void setIncompleteStatements(Set incompleteStatement) {
+ this.incompleteStatement = incompleteStatement;
+ }
+
+ public Iterator getIncompleteStatementIterator() {
+ return this.incompleteStatement.iterator();
+ }
+
+ public void addStatementWithoutSubject(IRI property, Value object) {
+ RDFaIncompleteStatement newStatement = new RDFaIncompleteStatement(property);
+ newStatement.setObject(object);
+ this.incompleteStatement.add(newStatement);
+ }
+
+ public void addStatementWithoutObject(Resource subject, IRI property) {
+ RDFaIncompleteStatement newStatement = new RDFaIncompleteStatement(property);
+ newStatement.setSubject(subject);
+ this.incompleteStatement.add(newStatement);
+ }
+
+ public void clearIncompleteStatements() {
+ this.incompleteStatement.clear();
+ }
+
+ public String getLanguage() {
+ return language;
+ }
+
+ public void setLanguage(String language) {
+ this.language = language;
+ }
+
+ public String getDefaultVocabulary() {
+ return defaultVocabulary;
+ }
+
+ public void setDefaultVocabulary(String defaultVocabulary) {
+ this.defaultVocabulary = defaultVocabulary;
+ }
+
+ public void addTermMapping(String term, IRI iri) {
+ this.termMappings.put(term, iri);
+ }
+
+ public IRI getTermMapping(String term) {
+ return this.termMappings.get(term);
+ }
+
+ public Map getTermMappings() {
+ return this.termMappings;
+ }
+
+ public Map> getListMappings() {
+ return listMappings;
+ }
+
+ public void setListMappings(Map> listMappings) {
+ this.listMappings = listMappings;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+
+ sb.append("BaseURI: ").append(this.getBaseIri().stringValue()).append(" ");
+ sb.append("Mappings: [");
+ this.getIriMappings().forEach((key, value) -> sb.append("(").append(key).append(", ").append(value.stringValue()).append(") "));
+ sb.append("] ");
+ if(this.getParentSubjectResource() != null) {
+ sb.append("Subject:").append(this.getParentSubjectResource().stringValue()).append(" ");
+ } else {
+ sb.append("Subject:").append((Object) null).append(" ");
+ }
+ if(this.getParentObjectResource() != null) {
+ sb.append("Object: ").append(this.getParentObjectResource().stringValue()).append(" ");
+ } else {
+ sb.append("Object: ").append((Object) null).append(" ");
+ }
+ if(! this.getIncompleteStatement().isEmpty()) {
+ sb.append(this.getIncompleteStatement().size()).append(" incomplete statements.");
+ }
+
+ return sb.toString();
+ }
}
diff --git a/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/model/RDFaInitialPrefixes.java b/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/model/RDFaInitialPrefixes.java
index 6dc5ce248..814b06ed1 100644
--- a/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/model/RDFaInitialPrefixes.java
+++ b/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/model/RDFaInitialPrefixes.java
@@ -104,7 +104,7 @@ public enum RDFaInitialPrefixes implements Namespace {
private final String prefix;
private final String name;
- RDFaInitialPrefixes(String name, String prefix) {
+ RDFaInitialPrefixes(String prefix, String name) {
this.name = name;
this.prefix = prefix;
}
diff --git a/src/test/java/fr/inria/corese/core/next/api/base/io/RDFFormatTest.java b/src/test/java/fr/inria/corese/core/next/api/base/io/RDFFormatTest.java
index 540f8d847..949c0408c 100644
--- a/src/test/java/fr/inria/corese/core/next/api/base/io/RDFFormatTest.java
+++ b/src/test/java/fr/inria/corese/core/next/api/base/io/RDFFormatTest.java
@@ -306,7 +306,7 @@ void allFormats() {
assertTrue(allFormats.contains(RDFFormat.JSONLD));
assertTrue(allFormats.contains(RDFFormat.RDFXML));
assertTrue(allFormats.contains(RDFFormat.TRIG));
- assertTrue(allFormats.contains(RDFFormat.RDFa_1_0));
+ assertTrue(allFormats.contains(RDFFormat.RDFA));
assertTrue(allFormats.contains(RDFFormat.RDFC_1_0));
assertThrows(UnsupportedOperationException.class, () -> allFormats.add(RDFFormat.TURTLE),
diff --git a/src/test/java/fr/inria/corese/core/next/impl/io/parser/rdfa/RDFa10ParserTest.java b/src/test/java/fr/inria/corese/core/next/impl/io/parser/rdfa/RDFa10ParserTest.java
index 3ee8a809c..47394b257 100644
--- a/src/test/java/fr/inria/corese/core/next/impl/io/parser/rdfa/RDFa10ParserTest.java
+++ b/src/test/java/fr/inria/corese/core/next/impl/io/parser/rdfa/RDFa10ParserTest.java
@@ -20,231 +20,4 @@ public class RDFa10ParserTest {
private static final ValueFactory factory = new CoreseAdaptedValueFactory();
- @Test
- public void basicBaseTest() {
- String testDataString = """
-
-
-
-
-
- Test 0001
-
-
-
+
+
+ """;
+
+ Model testModel = new CoreseModel();
+ Model referenceModel = new CoreseModel();
+
+ RDFParser parser = new ParserFactory().createRDFParser(RDFFormat.RDFA, testModel, valueFactory);
+
+ parser.parse(new ByteArrayInputStream(testDataString.getBytes()), "http://not.the.right.base.uri");
+
+ IRI albertEinstein = valueFactory.createIRI("http://dbpedia.org/resource/Albert_Einstein");
+ IRI birthPlace = valueFactory.createIRI("http://dbpedia.org/property/birthPlace");
+ IRI germany = valueFactory.createIRI("http://dbpedia.org/resource/Germany");
+ IRI conventionalLongName = valueFactory.createIRI("http://dbpedia.org/property/conventionalLongName");
+ Literal gerLongName = valueFactory.createLiteral("Federal Republic of Germany");
+
+ Statement aeBirthPlaceStatement = valueFactory.createStatement(albertEinstein, birthPlace, germany);
+ Statement germanyNameStatement = valueFactory.createStatement(germany, conventionalLongName, gerLongName);
+
+ referenceModel.add(aeBirthPlaceStatement);
+ referenceModel.add(germanyNameStatement);
+
+ assertEquals(2, testModel.size());
+ assertEquals(referenceModel, testModel);
+ assertTrue(referenceModel.containsAll(testModel));
+
+ }
+}
\ No newline at end of file
From fbe7c1fd4d69040527676fdd1a20184c5ed35559 Mon Sep 17 00:00:00 2001
From: Pierre Maillot
Date: Wed, 7 Jan 2026 17:28:03 +0100
Subject: [PATCH 05/13] attribute retrieval fix
---
.../next/impl/io/parser/rdfa/RDFaParser.java | 436 +++++++++++-------
.../io/parser/rdfa/model/RDFaAttributes.java | 1 +
.../io/serialization/SerializerFactory.java | 1 +
.../base/AbstractGraphSerializer.java | 2 +-
.../impl/io/parser/rdfa/RDFa10ParserTest.java | 23 -
.../impl/io/parser/rdfa/RDFaParserTest.java | 105 ++++-
6 files changed, 362 insertions(+), 206 deletions(-)
delete mode 100644 src/test/java/fr/inria/corese/core/next/impl/io/parser/rdfa/RDFa10ParserTest.java
diff --git a/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/RDFaParser.java b/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/RDFaParser.java
index 7dc79c6c9..5b298cd38 100644
--- a/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/RDFaParser.java
+++ b/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/RDFaParser.java
@@ -61,6 +61,7 @@ public class RDFaParser extends AbstractRDFParser {
private Set localIncompleteStatements = null;
private Map> localListMappings = null;
private String currentLanguage = null;
+ private Value currentPropertyValue = null;
private Map localTermMappings = null;
private String localDefaultVocabulary = null;
@@ -106,19 +107,7 @@ public void parse(Reader reader, String baseURI) {
this.currentContext.setDefaultVocabulary(null);
- skipElement = false;
- newSubject = null;
- currentObjectResource = null;
- typedResource = null;
- localIRIMappings = new HashMap<>();
- localIncompleteStatements = new HashSet<>();
- localListMappings = this.currentContext.getListMappings();
- currentLanguage = this.currentContext.getLanguage();
- localTermMappings = this.currentContext.getTermMappings();
- localDefaultVocabulary = this.currentContext.getDefaultVocabulary();
-
SAXParserFactory factory = SAXParserFactory.newInstance();
- factory.setNamespaceAware(true);
SAXParser saxParser = factory.newSAXParser();
InputSource inputSource = new InputSource(reader);
saxParser.parse(inputSource, new XMLSaxHandler());
@@ -143,53 +132,89 @@ private void handleCharacters(char[] ch, int start, int length) {
private void startProcessElement(String uri, String localName, String qName, Attributes attrs) {
this.currentElementAttributes = attrs;
- }
-
- private void endProcessElement(String uri, String localName, String qName) {
- String currentElementName = qName;
+ logger.info("{} {}", qName, debugAttributesToString());
+
+ this.characters = new StringBuilder();
+
+ this.skipElement = false;
+ this.newSubject = null;
+ this.currentObjectResource = null;
+ this.typedResource = null;
+ this.localIRIMappings = this.currentContext.getIriMappings();
+ this.localIncompleteStatements = null;
+ this.localListMappings = this.currentContext.getListMappings();
+ this.currentLanguage = this.currentContext.getLanguage();
+ this.localTermMappings = this.currentContext.getTermMappings();
+ this.localDefaultVocabulary = this.currentContext.getDefaultVocabulary();
+
+ // HTML-specific base element
+ if (qName.equals(BASE_TAG)
+ && isAttributePresent(RDFaAttributes.HREF)) {
+ Resource resourceBase = getAttributeResourceValue(RDFaAttributes.HREF);
+ if (resourceBase.isIRI()) {
+ this.currentContext.setBaseIri((IRI) resourceBase);
+ }
+ }
- // The current element is examined for any change to the default vocabulary via @vocab. If @vocab is present and contains a value, the local default vocabulary is updated according to the section on CURIE and IRI Processing. If the value is empty, then the local default vocabulary MUST be reset to the Host Language defined default (if any).
- if (this.currentElementAttributes.getValue(RDFaAttributes.VOCAB.getName()) != null
- && !this.currentElementAttributes.getValue(RDFaAttributes.VOCAB.getName()).isEmpty()) {
- localDefaultVocabulary = this.currentElementAttributes.getValue(RDFaAttributes.VOCAB.getName());
+ // 2. The current element is examined for any change to the default vocabulary via @vocab. If @vocab is present and contains a value, the local default vocabulary is updated according to the section on CURIE and IRI Processing. If the value is empty, then the local default vocabulary MUST be reset to the Host Language defined default (if any).
+ if (isAttributePresent(RDFaAttributes.VOCAB)
+ && !getAttributeStringValue(RDFaAttributes.VOCAB).isEmpty()) {
+ this.localDefaultVocabulary = getAttributeStringValue(RDFaAttributes.VOCAB);
}
- // The current element is examined for IRI mappings and these are added to the local list of IRI mappings. Note that an IRI mapping will simply overwrite any current mapping in the list that has the same name;
+ // 3. The current element is examined for IRI mappings and these are added to the local list of IRI mappings. Note that an IRI mapping will simply overwrite any current mapping in the list that has the same name;
for (int i = 0; i < this.currentElementAttributes.getLength(); i++) {
String attribute = this.currentElementAttributes.getQName(i);
if (attribute.startsWith(XMLNS_PREFIX)) {
String attributeValue = this.currentElementAttributes.getValue(i);
- String prefixName = this.currentElementAttributes.getLocalName(i);
+ String prefixName = attribute.replace(XMLNS_PREFIX + ":", "");
IRI prefixNamespace = getValueFactory().createIRI(attributeValue, "");
- localIRIMappings.put(prefixName, prefixNamespace);
+ this.localIRIMappings.put(prefixName, prefixNamespace);
}
}
- if (this.currentElementAttributes.getValue(RDFaAttributes.PREFIX.getName()) != null
- && !this.currentElementAttributes.getValue(RDFaAttributes.PREFIX.getName()).isEmpty()) {
- String prefixDeclaration = this.currentElementAttributes.getValue(RDFaAttributes.PREFIX.getName());
+ if (isAttributePresent(RDFaAttributes.PREFIX)
+ && !getAttributeStringValue(RDFaAttributes.PREFIX).isEmpty()) {
+ String prefixDeclaration = getAttributeStringValue(RDFaAttributes.PREFIX);
String prefixName = getPrefixFromDeclaration(prefixDeclaration);
IRI prefixIRI = getPrefixIriFromDeclaration(prefixDeclaration);
- localIRIMappings.put(prefixName, prefixIRI);
+ this.localIRIMappings.put(prefixName, prefixIRI);
+ }
+
+ // 4. The current element is also parsed for any language information, and if present, current language is set accordingly;
+ // Host Languages that incorporate RDFa MAY provide a mechanism for specifying the natural language of an element and its contents (e.g., XML provides the general-purpose XML attribute @xml:lang).
+ if (isAttributePresent(RDFaAttributes.LANG_ALT)
+ && !getAttributeStringValue(RDFaAttributes.LANG_ALT).isEmpty()) {
+ this.currentLanguage = getAttributeStringValue(RDFaAttributes.LANG_ALT);
}
- // If the current element contains no @rel or @rev attribute, then the next step is to establish a value for new subject. This step has two possible alternatives.
- if (this.currentElementAttributes.getValue(RDFaAttributes.REL.getName()) == null
- && this.currentElementAttributes.getValue(RDFaAttributes.REV.getName()) == null) {
- // If the current element contains the @property attribute, but does not contain either the @content or @datatype attributes, then
- if (this.currentElementAttributes.getValue(RDFaAttributes.PROPERTY.getName()) != null
- && !this.currentElementAttributes.getValue(RDFaAttributes.PROPERTY.getName()).isEmpty()
- && this.currentElementAttributes.getValue(RDFaAttributes.CONTENT.getName()) == null
- && this.currentElementAttributes.getValue(RDFaAttributes.DATATYPE.getName()) == null) {
- if (this.currentElementAttributes.getValue(RDFaAttributes.ABOUT.getName()) != null) {
- this.newSubject = getResourceFromElementAttribute(RDFaAttributes.ABOUT);
+ // 5. If the current element contains no @rel or @rev attribute, then the next step is to establish a value for new subject. This step has two possible alternatives.
+ if (!isAttributePresent(RDFaAttributes.REL)
+ && !isAttributePresent(RDFaAttributes.REV)) {
+ // 5.1. If the current element contains the @property attribute, but does not contain either the @content or @datatype attributes, then
+ if (isAttributePresent(RDFaAttributes.PROPERTY)
+ && !getAttributeStringValue(RDFaAttributes.PROPERTY).isEmpty()
+ && !isAttributePresent(RDFaAttributes.CONTENT)
+ && !isAttributePresent(RDFaAttributes.DATATYPE)
+ && (isAttributePresent(RDFaAttributes.ABOUT)
+ || isRootElement
+ || this.currentContext.getParentObjectResource() != null)) {
+ // new subject is set to the resource obtained from the first match from the following rule:
+ // by using the resource from @about, if present, obtained according to the section on CURIE and IRI Processing;
+ if (isAttributePresent(RDFaAttributes.ABOUT)) {
+ this.newSubject = getAttributeResourceValue(RDFaAttributes.ABOUT);
+ // otherwise, if the element is the root element of the document, then act as if there is an empty @about present, and process it according to the rule for @about, above;
} else if (isRootElement) {
this.newSubject = this.currentContext.getBaseIri();
+ // otherwise, if parent object is present, new subject is set to the value of parent object.
} else if (this.currentContext.getParentObjectResource() != null) {
this.newSubject = this.currentContext.getParentObjectResource();
}
- if (this.currentElementAttributes.getValue(RDFaAttributes.TYPEOF.getName()) != null) {
- if (this.currentElementAttributes.getValue(RDFaAttributes.ABOUT.getName()) != null) {
+ // If @typeof is present then typed resource is set to the resource obtained from the first match from the following rules:
+ if (isAttributePresent(RDFaAttributes.TYPEOF)) {
+ // by using the resource from @about, if present, obtained according to the section on CURIE and IRI Processing;
+ if (isAttributePresent(RDFaAttributes.ABOUT)) {
this.typedResource = this.newSubject;
+ // otherwise, if the element is the root element of the document, then act as if there is an empty @about present and process it according to the previous rule;
} else if (isRootElement) {
Optional emptyAboutResource = resolveStringResource("");
if (emptyAboutResource.isPresent()) {
@@ -197,33 +222,46 @@ private void endProcessElement(String uri, String localName, String qName) {
} else {
throw new ParsingErrorException("Expected to be able to generate typedResource from empty CURIE");
}
+ // otherwise,
} else {
- if (this.currentElementAttributes.getValue(RDFaAttributes.RESOURCE.getName()) != null) {
- this.newSubject = getResourceFromElementAttribute(RDFaAttributes.RESOURCE);
- } else if (this.currentElementAttributes.getValue(RDFaAttributes.HREF.getName()) != null) {
- this.newSubject = getResourceFromElementAttribute(RDFaAttributes.HREF);
- } else if (this.currentElementAttributes.getValue(RDFaAttributes.SRC.getName()) != null) {
- this.newSubject = getResourceFromElementAttribute(RDFaAttributes.SRC);
+ // by using the resource from @resource, if present, obtained according to the section on CURIE and IRI Processing;
+ if (isAttributePresent(RDFaAttributes.RESOURCE)) {
+ this.typedResource = getAttributeResourceValue(RDFaAttributes.RESOURCE);
+ // otherwise, by using the IRI from @href, if present, obtained according to the section on CURIE and IRI Processing;
+ } else if (isAttributePresent(RDFaAttributes.HREF)) {
+ this.typedResource = getAttributeResourceValue(RDFaAttributes.HREF);
+ // otherwise, by using the IRI from @src, if present, obtained according to the section on CURIE and IRI Processing;
+ } else if (isAttributePresent(RDFaAttributes.SRC)) {
+ this.typedResource = getAttributeResourceValue(RDFaAttributes.SRC);
+ // otherwise, the value of typed resource is set to a newly created bnode.
} else {
this.typedResource = getValueFactory().createBNode();
}
+ // The value of the current object resource is then set to the value of typed resource.
this.currentObjectResource = this.typedResource;
}
}
- // otherwise:
+ logger.info("{}", this.newSubject);
+ // 5.2. otherwise:
} else {
- if (this.currentElementAttributes.getValue(RDFaAttributes.ABOUT.getName()) != null
- && this.currentElementAttributes.getValue(RDFaAttributes.HREF.getName()) != null
- && this.currentElementAttributes.getValue(RDFaAttributes.SRC.getName()) != null
- && this.currentElementAttributes.getValue(RDFaAttributes.RESOURCE.getName()) != null) {
- if (this.currentElementAttributes.getValue(RDFaAttributes.ABOUT.getName()) != null) {
- this.newSubject = getResourceFromElementAttribute(RDFaAttributes.ABOUT);
- } else if (this.currentElementAttributes.getValue(RDFaAttributes.RESOURCE.getName()) != null) {
- this.newSubject = getResourceFromElementAttribute(RDFaAttributes.RESOURCE);
- } else if (this.currentElementAttributes.getValue(RDFaAttributes.HREF.getName()) != null) {
- this.newSubject = getResourceFromElementAttribute(RDFaAttributes.HREF);
- } else if (this.currentElementAttributes.getValue(RDFaAttributes.SRC.getName()) != null) {
- this.newSubject = getResourceFromElementAttribute(RDFaAttributes.SRC);
+ if (isAttributePresent(RDFaAttributes.ABOUT)
+ || isAttributePresent(RDFaAttributes.HREF)
+ || isAttributePresent(RDFaAttributes.SRC)
+ || isAttributePresent(RDFaAttributes.RESOURCE)) {
+ if (isAttributePresent(RDFaAttributes.ABOUT)) {
+ this.newSubject = getAttributeResourceValue(RDFaAttributes.ABOUT);
+ logger.info("{}", this.newSubject);
+ } else if (isAttributePresent(RDFaAttributes.RESOURCE)) {
+ this.newSubject = getAttributeResourceValue(RDFaAttributes.RESOURCE);
+ logger.info("{}", this.newSubject);
+ } else if (isAttributePresent(RDFaAttributes.HREF)) {
+ this.newSubject = getAttributeResourceValue(RDFaAttributes.HREF);
+ logger.info("{}", this.newSubject);
+ } else if (isAttributePresent(RDFaAttributes.SRC)) {
+ this.newSubject = getAttributeResourceValue(RDFaAttributes.SRC);
+ logger.info("{}", this.newSubject);
+ } else {
+ logger.info("No subject retrieved");
}
} else {
if (isRootElement) {
@@ -233,28 +271,30 @@ private void endProcessElement(String uri, String localName, String qName) {
} else {
throw new ParsingErrorException("Expected to be able to generate newSubject from empty CURIE");
}
- } else if (this.currentElementAttributes.getValue(RDFaAttributes.TYPEOF.getName()) != null) {
+ } else if (isAttributePresent(RDFaAttributes.TYPEOF)) {
this.newSubject = getValueFactory().createBNode();
+ logger.info("{}", this.newSubject);
} else if (this.currentContext.getParentObjectResource() != null) {
this.newSubject = this.currentContext.getParentObjectResource();
- if (this.currentElementAttributes.getValue(RDFaAttributes.PROPERTY.getName()) == null) {
+ if (!isAttributePresent(RDFaAttributes.PROPERTY)) {
skipElement = true;
}
}
- if (this.currentElementAttributes.getValue(RDFaAttributes.TYPEOF.getName()) != null) {
- this.typedResource = this.newSubject;
- }
+ }
+ if (isAttributePresent(RDFaAttributes.TYPEOF)) {
+ this.typedResource = this.newSubject;
}
}
}
- // If the current element does contain a @rel or @rev attribute, then the next step is to establish both a value for new subject and a value for current object resource:
- if (this.currentElementAttributes.getValue(RDFaAttributes.REL.getName()) != null
- && this.currentElementAttributes.getValue(RDFaAttributes.REV.getName()) != null) {
- if (this.currentElementAttributes.getValue(RDFaAttributes.ABOUT.getName()) != null) {
- this.newSubject = getResourceFromElementAttribute(RDFaAttributes.ABOUT);
+ // 6. If the current element does contain a @rel or @rev attribute, then the next step is to establish both a value for new subject and a value for current object resource:
+ if (isAttributePresent(RDFaAttributes.REL)
+ || isAttributePresent(RDFaAttributes.REV)) {
+ if (isAttributePresent(RDFaAttributes.ABOUT)) {
+ this.newSubject = getAttributeResourceValue(RDFaAttributes.ABOUT);
+ logger.info("{}", this.newSubject);
}
- if (this.currentElementAttributes.getValue(RDFaAttributes.TYPEOF.getName()) != null) {
+ if (isAttributePresent(RDFaAttributes.TYPEOF)) {
this.typedResource = this.newSubject;
}
if (this.newSubject == null) {
@@ -269,57 +309,58 @@ private void endProcessElement(String uri, String localName, String qName) {
this.newSubject = this.currentContext.getParentObjectResource();
}
}
- if (this.currentElementAttributes.getValue(RDFaAttributes.RESOURCE.getName()) != null) {
- this.currentObjectResource = getResourceFromElementAttribute(RDFaAttributes.RESOURCE);
- } else if (this.currentElementAttributes.getValue(RDFaAttributes.HREF.getName()) != null) {
- this.currentObjectResource = getResourceFromElementAttribute(RDFaAttributes.HREF);
- } else if (this.currentElementAttributes.getValue(RDFaAttributes.SRC.getName()) != null) {
- this.currentObjectResource = getResourceFromElementAttribute(RDFaAttributes.SRC);
- } else if (this.currentElementAttributes.getValue(RDFaAttributes.TYPEOF.getName()) != null
- && this.currentElementAttributes.getValue(RDFaAttributes.ABOUT.getName()) == null) {
+ if (isAttributePresent(RDFaAttributes.RESOURCE)) {
+ this.currentObjectResource = getAttributeResourceValue(RDFaAttributes.RESOURCE);
+ } else if (isAttributePresent(RDFaAttributes.HREF)) {
+ this.currentObjectResource = getAttributeResourceValue(RDFaAttributes.HREF);
+ } else if (isAttributePresent(RDFaAttributes.SRC)) {
+ this.currentObjectResource = getAttributeResourceValue(RDFaAttributes.SRC);
+ } else if (isAttributePresent(RDFaAttributes.TYPEOF)
+ && !isAttributePresent(RDFaAttributes.ABOUT)) {
this.currentObjectResource = this.getValueFactory().createBNode();
}
- if (this.currentElementAttributes.getValue(RDFaAttributes.TYPEOF.getName()) != null
- && this.currentElementAttributes.getValue(RDFaAttributes.ABOUT.getName()) == null
+ if (isAttributePresent(RDFaAttributes.TYPEOF)
+ && !isAttributePresent(RDFaAttributes.ABOUT)
&& (this.currentObjectResource == null || this.currentObjectResource.isResource())) {
- this.typedResource = (Resource) this.currentObjectResource;
+ this.typedResource = this.currentObjectResource;
}
}
+ logger.info("{} : subject {}", qName, this.newSubject);
- // If in any of the previous steps a typed resource was set to a non-null value, it is now used to provide a subject for type values;
+ // 7. If in any of the previous steps a typed resource was set to a non-null value, it is now used to provide a subject for type values;
if (this.typedResource != null) {
- Resource typeIri = getResourceFromElementAttribute(RDFaAttributes.TYPEOF);
+ Resource typeIri = getAttributeResourceValue(RDFaAttributes.TYPEOF);
this.getModel().add(this.typedResource, RDF.type.getIRI(), typeIri);
}
- // If in any of the previous steps a new subject was set to a non-null value different from the parent object;
+ // 8. If in any of the previous steps a new subject was set to a non-null value different from the parent object;
if (this.newSubject != null && this.newSubject != this.currentContext.getParentObjectResource()) {
this.localListMappings = new HashMap<>();
}
- // If in any of the previous steps a current object resource was set to a non-null value, it is now used to generate triples and add entries to the local list mapping:
+ // 9. If in any of the previous steps a current object resource was set to a non-null value, it is now used to generate triples and add entries to the local list mapping:
if (this.currentObjectResource != null) {
- if (this.currentElementAttributes.getValue(RDFaAttributes.INLIST.getName()) != null
- && this.currentElementAttributes.getValue(RDFaAttributes.REL.getName()) != null) {
- IRI relResource = (IRI) getResourceFromElementAttribute(RDFaAttributes.REL);
+ if (isAttributePresent(RDFaAttributes.INLIST)
+ && isAttributePresent(RDFaAttributes.REL)) {
+ IRI relResource = (IRI) getAttributeResourceValue(RDFaAttributes.REL);
if (!localListMappings.containsKey(relResource)) {
this.localListMappings.put(relResource, new HashSet<>());
}
this.localListMappings.get(relResource).add(this.currentObjectResource);
}
- if (this.currentElementAttributes.getValue(RDFaAttributes.INLIST.getName()) == null) {
- if (this.currentElementAttributes.getValue(RDFaAttributes.REL.getName()) != null) {
- Resource relResource = getResourceFromElementAttribute(RDFaAttributes.REL);
+ if (!isAttributePresent(RDFaAttributes.INLIST)) {
+ if (isAttributePresent(RDFaAttributes.REL)) {
+ Resource relResource = getAttributeResourceValue(RDFaAttributes.REL);
if (relResource.isIRI()) {
this.getModel().add(newSubject, (IRI) relResource, currentObjectResource);
} else {
throw new ParsingErrorException("Value of attribute @rel expected to be an IRI but was " + this.currentElementAttributes.getValue(RDFaAttributes.REL.getName()));
}
}
- if (this.currentElementAttributes.getValue(RDFaAttributes.REV.getName()) != null) {
- Resource revResource = getResourceFromElementAttribute(RDFaAttributes.REV);
+ if (isAttributePresent(RDFaAttributes.REV)) {
+ Resource revResource = getAttributeResourceValue(RDFaAttributes.REV);
if (!revResource.isIRI()) {
- throw new ParsingErrorException("Value of attribute @rev expected to be an IRI but was " + this.currentElementAttributes.getValue(RDFaAttributes.REV.getName()));
+ throw new ParsingErrorException("Value of attribute @rev expected to be an IRI but was " + getAttributeStringValue(RDFaAttributes.REV));
}
if (!currentObjectResource.isResource()) {
throw new ParsingErrorException("object resource expected to be a resource but was " + currentObjectResource);
@@ -329,15 +370,18 @@ private void endProcessElement(String uri, String localName, String qName) {
}
}
- // If however current object resource was set to null, but there are predicates present, then they must be stored as incomplete triples, pending the discovery of a subject that can be used as the object. Also, current object resource should be set to a newly created bnode (so that the incomplete triples have a subject to connect to if they are ultimately turned into triples);
+ // 10. If however current object resource was set to null, but there are predicates present, then they must be stored as incomplete triples, pending the discovery of a subject that can be used as the object. Also, current object resource should be set to a newly created bnode (so that the incomplete triples have a subject to connect to if they are ultimately turned into triples);
if (this.currentObjectResource == null) {
+ if(this.localIncompleteStatements == null) {
+ this.localIncompleteStatements = new HashSet<>();
+ }
this.currentObjectResource = getValueFactory().createBNode();
- if (this.currentElementAttributes.getValue(RDFaAttributes.REL.getName()) != null) {
- if (!getResourceFromElementAttribute(RDFaAttributes.REL).isIRI()) {
+ if (isAttributePresent(RDFaAttributes.REL)) {
+ if (!getAttributeResourceValue(RDFaAttributes.REL).isIRI()) {
throw new ParsingErrorException("Value of attribute @rel expected to be an IRI but was " + this.currentElementAttributes.getValue(RDFaAttributes.REL.getName()));
}
- IRI relIRI = (IRI) getResourceFromElementAttribute(RDFaAttributes.REL);
- if (this.currentElementAttributes.getValue(RDFaAttributes.INLIST.getName()) != null) {
+ IRI relIRI = (IRI) getAttributeResourceValue(RDFaAttributes.REL);
+ if (isAttributePresent(RDFaAttributes.INLIST)) {
if (!localListMappings.containsKey(relIRI)) {
this.localListMappings.put(relIRI, new HashSet<>());
}
@@ -345,34 +389,37 @@ private void endProcessElement(String uri, String localName, String qName) {
} else {
this.localIncompleteStatements.add(new RDFaIncompleteStatement(relIRI, RDFaIncompleteStatement.Direction.FORWARD));
}
- } else if (this.currentElementAttributes.getValue(RDFaAttributes.REV.getName()) != null) {
- if (!getResourceFromElementAttribute(RDFaAttributes.REV).isIRI()) {
+ } else if (isAttributePresent(RDFaAttributes.REV)) {
+ if (!getAttributeResourceValue(RDFaAttributes.REV).isIRI()) {
throw new ParsingErrorException("Value of attribute @rev expected to be an IRI but was " + this.currentElementAttributes.getValue(RDFaAttributes.REV.getName()));
}
- IRI revIRI = (IRI) getResourceFromElementAttribute(RDFaAttributes.REV);
+ IRI revIRI = (IRI) getAttributeResourceValue(RDFaAttributes.REV);
this.localIncompleteStatements.add(new RDFaIncompleteStatement(revIRI, RDFaIncompleteStatement.Direction.BACKWARD));
}
}
- // The next step of the iteration is to establish any current property value;
- if (this.currentElementAttributes.getValue(RDFaAttributes.PROPERTY.getName()) != null) {
- IRI propertyIRI = (IRI) getResourceFromElementAttribute(RDFaAttributes.PROPERTY);
- Value currentPropertyValue = null;
- if (this.currentElementAttributes.getValue(RDFaAttributes.DATATYPE.getName()) != null
- && getResourceFromElementAttribute(RDFaAttributes.DATATYPE).isIRI()
- && getResourceFromElementAttribute(RDFaAttributes.DATATYPE) != RDF.XMLLiteral.getIRI()) {
- IRI datatypeIRI = (IRI) getResourceFromElementAttribute(RDFaAttributes.DATATYPE);
- if (this.currentElementAttributes.getValue(RDFaAttributes.CONTENT.getName()) != null) {
- String contentString = this.currentElementAttributes.getValue(RDFaAttributes.CONTENT.getName());
+ // 11. The next step of the iteration is to establish any current property value;
+ if (isAttributePresent(RDFaAttributes.PROPERTY)) {
+ IRI propertyIRI = (IRI) getAttributeResourceValue(RDFaAttributes.PROPERTY);
+ // as a typed literal if @datatype is present, does not have an empty value according to the section on CURIE and IRI Processing, and is not set to XMLLiteral in the vocabulary http://www.w3.org/1999/02/22-rdf-syntax-ns#.
+ // The actual literal is either the value of @content (if present) or a string created by concatenating the value of all descendant text nodes, of the current element in turn. The final string includes the datatype IRI, as described in [RDF-SYNTAX-GRAMMAR], which will have been obtained according to the section on CURIE and IRI Processing.
+ if (isAttributePresent(RDFaAttributes.DATATYPE)
+ && getAttributeResourceValue(RDFaAttributes.DATATYPE).isIRI()
+ && getAttributeResourceValue(RDFaAttributes.DATATYPE) != RDF.XMLLiteral.getIRI()) {
+ IRI datatypeIRI = (IRI) getAttributeResourceValue(RDFaAttributes.DATATYPE);
+ if (isAttributePresent(RDFaAttributes.CONTENT)) {
+ String contentString = getAttributeStringValue(RDFaAttributes.CONTENT);
currentPropertyValue = getValueFactory().createLiteral(contentString, datatypeIRI);
} else {
String contentString = this.characters.toString().trim();
currentPropertyValue = getValueFactory().createLiteral(contentString);
this.characters = new StringBuilder();
}
- } else if (this.currentElementAttributes.getValue(RDFaAttributes.DATATYPE.getName()) != null
- && this.currentElementAttributes.getValue(RDFaAttributes.DATATYPE.getName()).isEmpty()) {
- if (this.currentElementAttributes.getValue(RDFaAttributes.CONTENT.getName()) != null) {
+ // otherwise, as a plain literal if @datatype is present but has an empty value according to the section on CURIE and IRI Processing.
+ // The actual literal is either the value of @content (if present) or a string created by concatenating the value of all descendant text nodes, of the current element in turn.
+ } else if (isAttributePresent(RDFaAttributes.DATATYPE)
+ && getAttributeStringValue(RDFaAttributes.DATATYPE).isEmpty()) {
+ if (isAttributePresent(RDFaAttributes.CONTENT)) {
String contentString = this.currentElementAttributes.getValue(RDFaAttributes.CONTENT.getName());
currentPropertyValue = getValueFactory().createLiteral(contentString);
} else {
@@ -380,27 +427,41 @@ && getResourceFromElementAttribute(RDFaAttributes.DATATYPE) != RDF.XMLLiteral.ge
currentPropertyValue = getValueFactory().createLiteral(contentString);
this.characters = new StringBuilder();
}
+ // otherwise, as an XML literal if @datatype is present and is set to XMLLiteral in the vocabulary http://www.w3.org/1999/02/22-rdf-syntax-ns#.
+ // The value of the XML literal is a string created by serializing to text, all nodes that are descendants of the current element, i.e., not including the element itself, and giving it a datatype of XMLLiteral in the vocabulary http://www.w3.org/1999/02/22-rdf-syntax-ns#. The format of the resulting serialized content is as defined in Exclusive XML Canonicalization Version 1.0 [XML-EXC-C14N].
//} else if (this.currentElementAttributes.getValue(RDFaAttributes.DATATYPE.getName()) != null
- // && getResourceFromElementAttribute( RDFaAttributes.DATATYPE).isIRI()
- // && getResourceFromElementAttribute( RDFaAttributes.DATATYPE) == RDF.XMLLiteral.getIRI()) {
- } else if (this.currentElementAttributes.getValue(RDFaAttributes.CONTENT.getName()) != null) {
+ // && getAttributeResourceValue( RDFaAttributes.DATATYPE).isIRI()
+ // && getAttributeResourceValue( RDFaAttributes.DATATYPE) == RDF.XMLLiteral.getIRI()) {
+ // otherwise, as a plain literal using the value of @content if @content is present.
+ } else if (isAttributePresent(RDFaAttributes.CONTENT)) {
String contentString = this.currentElementAttributes.getValue(RDFaAttributes.CONTENT.getName());
currentPropertyValue = getValueFactory().createLiteral(contentString);
- } else if (this.currentElementAttributes.getValue(RDFaAttributes.REL.getName()) == null
- && this.currentElementAttributes.getValue(RDFaAttributes.REV.getName()) == null
- && this.currentElementAttributes.getValue(RDFaAttributes.CONTENT.getName()) == null) {
- if (this.currentElementAttributes.getValue(RDFaAttributes.RESOURCE.getName()) != null) {
- currentPropertyValue = getResourceFromElementAttribute(RDFaAttributes.RESOURCE);
- } else if (this.currentElementAttributes.getValue(RDFaAttributes.HREF.getName()) != null) {
- currentPropertyValue = getResourceFromElementAttribute(RDFaAttributes.HREF);
- } else if (this.currentElementAttributes.getValue(RDFaAttributes.SRC.getName()) != null) {
- currentPropertyValue = getResourceFromElementAttribute(RDFaAttributes.SRC);
+ // otherwise, if the @rel, @rev, and @content attributes are not present, as a resource obtained from one of the following:
+ // by using the resource from @resource, if present, obtained according to the section on CURIE and IRI Processing;
+ // otherwise, by using the IRI from @href, if present, obtained according to the section on CURIE and IRI Processing;
+ // otherwise, by using the IRI from @src, if present, obtained according to the section on CURIE and IRI Processing.
+ } else if (!isAttributePresent(RDFaAttributes.REL)
+ && !isAttributePresent(RDFaAttributes.REV)
+ && !isAttributePresent(RDFaAttributes.CONTENT)
+ && (isAttributePresent(RDFaAttributes.RESOURCE)
+ || isAttributePresent(RDFaAttributes.HREF)
+ || isAttributePresent(RDFaAttributes.SRC)
+ )) {
+ if (isAttributePresent(RDFaAttributes.RESOURCE)) {
+ currentPropertyValue = getAttributeResourceValue(RDFaAttributes.RESOURCE);
+ } else if (isAttributePresent(RDFaAttributes.HREF)) {
+ currentPropertyValue = getAttributeResourceValue(RDFaAttributes.HREF);
+ } else if (isAttributePresent(RDFaAttributes.SRC)) {
+ currentPropertyValue = getAttributeResourceValue(RDFaAttributes.SRC);
}
- } else if (this.currentElementAttributes.getValue(RDFaAttributes.TYPEOF.getName()) != null
- && this.currentElementAttributes.getValue(RDFaAttributes.ABOUT.getName()) == null) {
+ // otherwise, if @typeof is present and @about is not, the value of typed resource.
+ } else if (isAttributePresent(RDFaAttributes.TYPEOF)
+ && !isAttributePresent(RDFaAttributes.ABOUT)) {
currentPropertyValue = typedResource;
+ // otherwise as a plain literal.
} else {
String contentString = this.characters.toString().trim();
+ // Additionally, if there is a value for current language then the value of the plain literal should include this language information, as described in [RDF-SYNTAX-GRAMMAR]. The actual literal is either the value of @content (if present) or a string created by concatenating the text content of each of the descendant elements of the current element in document order.
if (this.currentLanguage != null
&& !this.currentLanguage.isEmpty()) {
currentPropertyValue = getValueFactory().createLiteral(contentString, this.currentLanguage);
@@ -410,66 +471,91 @@ && getResourceFromElementAttribute(RDFaAttributes.DATATYPE) != RDF.XMLLiteral.ge
this.characters = new StringBuilder();
}
- if (this.currentElementAttributes.getValue(RDFaAttributes.INLIST.getName()) != null) {
+ // The current property value is then used with each predicate as follows:
+ // If the element also includes the @inlist attribute, the current property value is added to the local list mapping as follows:
+ if (isAttributePresent(RDFaAttributes.INLIST)) {
+ // if the local list mapping does not contain a list associated with the predicate IRI, instantiate a new list and add to local list mappings
if (!this.localListMappings.containsKey(propertyIRI)) {
this.localListMappings.put(propertyIRI, new HashSet<>());
}
+ // add the current property value to the list associated with the predicate IRI in the local list mapping
this.localListMappings.get(propertyIRI).add(currentPropertyValue);
+ // Otherwise the current property value is used to generate a triple as follows:
+ // subject new subject
+ // predicate full IRI
+ // object current property value
} else {
- this.getModel().add(this.newSubject, propertyIRI, currentPropertyValue);
+ this.getModel().add(this.newSubject, propertyIRI, this.currentPropertyValue);
}
}
- // If the skip element flag is 'false', and new subject was set to a non-null value, then any incomplete triples within the current context should be completed:
- if (!skipElement
- && newSubject != null) {
+ // 12. If the skip element flag is 'false', and new subject was set to a non-null value, then any incomplete triples within the current context should be completed:
+ if (!this.skipElement
+ && this.newSubject != null) {
+ if(this.localIncompleteStatements == null) {
+ this.localIncompleteStatements = new HashSet<>();
+ }
for (RDFaIncompleteStatement incompleteStatement : this.currentContext.getIncompleteStatement()) {
if (incompleteStatement.getDirection() == RDFaIncompleteStatement.Direction.NONE) {
- localListMappings.get(incompleteStatement.getPredicate()).add(newSubject);
+ localListMappings.get(incompleteStatement.getPredicate()).add(this.newSubject);
} else if (incompleteStatement.getDirection() == RDFaIncompleteStatement.Direction.FORWARD) {
- this.getModel().add(currentContext.getParentSubjectResource(), incompleteStatement.getPredicate(), newSubject);
+ this.getModel().add(this.currentContext.getParentSubjectResource(), incompleteStatement.getPredicate(), this.newSubject);
} else if (incompleteStatement.getDirection() == RDFaIncompleteStatement.Direction.BACKWARD) {
- this.getModel().add(newSubject, incompleteStatement.getPredicate(), currentContext.getParentSubjectResource());
+ this.getModel().add(this.newSubject, incompleteStatement.getPredicate(), this.currentContext.getParentSubjectResource());
}
}
}
- // Next, all elements that are children of the current element are processed using the rules described here, using a new evaluation context, initialized as follows:
- Map> oldListMappings = currentContext.getListMappings();
- if (skipElement) {
- currentContext = new RDFaEvaluationContext(this.currentContext);
- currentContext.clearIriMappings();
- initializeNewContext(currentContext);
- currentContext.setLanguage(currentLanguage);
- currentContext.addIriMappings(localIRIMappings);
+ // 13. Next, all elements that are children of the current element are processed using the rules described here, using a new evaluation context, initialized as follows:
+ // If the skip element flag is 'true' then the new evaluation context is a copy of the current context that was passed in to this level of processing, with the language and list of IRI mappings values replaced with the local values;
+ if (this.skipElement) {
+ this.currentContext = new RDFaEvaluationContext(this.currentContext);
+ this.currentContext.clearIriMappings();
+ initializeNewContext(this.currentContext);
+ this.currentContext.setLanguage(this.currentLanguage);
+ this.currentContext.addIriMappings(this.localIRIMappings);
+ // Otherwise, the values are:
} else {
Resource oldParentSubject = this.currentContext.getParentSubjectResource();
- currentContext = new RDFaEvaluationContext(this.currentContext.getBaseIri());
- initializeNewContext(currentContext);
- currentContext.setParentSubjectResource(newSubject);
- if (currentObjectResource != null) {
- currentContext.setParentObjectResource(currentObjectResource);
- }
- if (newSubject != null) {
- currentContext.setParentObjectResource(newSubject);
+ // the base is set to the base value of the current evaluation context;
+ this.currentContext = new RDFaEvaluationContext(this.currentContext.getBaseIri());
+ initializeNewContext(this.currentContext);
+ // the parent subject is set to the value of new subject, if non-null, or the value of the parent subject of the current evaluation context;
+ this.currentContext.setParentSubjectResource(this.newSubject);
+ // the parent object is set to value of current object resource, if non-null, or the value of new subject, if non-null, or the value of the parent subject of the current evaluation context;
+ if (this.currentObjectResource != null) {
+ this.currentContext.setParentObjectResource(this.currentObjectResource);
+ } else if (this.newSubject != null) {
+ this.currentContext.setParentObjectResource(this.newSubject);
} else {
- currentContext.setParentObjectResource(oldParentSubject);
+ this.currentContext.setParentObjectResource(oldParentSubject);
}
- currentContext.addIriMappings(localIRIMappings);
- currentContext.setIncompleteStatements(localIncompleteStatements);
- currentContext.setListMappings(localListMappings);
- currentContext.setLanguage(currentLanguage);
- currentContext.setDefaultVocabulary(localDefaultVocabulary);
+ // the list of IRI mappings is set to the local list of IRI mappings;
+ this.currentContext.addIriMappings(this.localIRIMappings);
+ // the list of incomplete triples is set to the local list of incomplete triples;
+ this.currentContext.setIncompleteStatements(this.localIncompleteStatements);
+ // the list mapping is set to the local list mapping;
+ this.currentContext.setListMappings(this.localListMappings);
+ // language is set to the value of current language.
+ this.currentContext.setLanguage(this.currentLanguage);
+ // the default vocabulary is set to the value of the local default vocabulary.
+ this.currentContext.setDefaultVocabulary(this.localDefaultVocabulary);
}
- // Finally, if there is one or more mapping in the local list mapping, list triples are generated as follows:
- for (Map.Entry> listMapping : localListMappings.entrySet()) {
+ this.isRootElement = false;
+ }
+
+ private void endProcessElement(String uri, String localName, String qName) {
+ Map> oldListMappings = this.currentContext.getListMappings();
+
+ // 14. Finally, if there is one or more mapping in the local list mapping, list triples are generated as follows:
+ for (Map.Entry> listMapping : this.localListMappings.entrySet()) {
IRI propertyIRI = listMapping.getKey();
Set propertyList = listMapping.getValue();
if (!oldListMappings.containsKey(propertyIRI)) {
if (propertyList.isEmpty()) {
- getModel().add(newSubject, propertyIRI, RDF.nil.getIRI());
+ getModel().add(this.newSubject, propertyIRI, RDF.nil.getIRI());
} else {
ArrayList bnodes = new ArrayList<>();
for (int i = 0; i < propertyList.size(); i++) {
@@ -487,12 +573,11 @@ && getResourceFromElementAttribute(RDFaAttributes.DATATYPE) != RDF.XMLLiteral.ge
bnodeIndex++;
}
- getModel().add(newSubject, propertyIRI, bnodes.getFirst());
+ getModel().add(this.newSubject, propertyIRI, bnodes.getFirst());
}
}
}
- isRootElement = false;
}
/**
@@ -551,7 +636,7 @@ private IRI getPrefixIriFromDeclaration(String declaration) {
return getValueFactory().createIRI(prefixArray[1].toLowerCase());
}
- private Resource getResourceFromElementAttribute(RDFaAttributes attribute) {
+ private Resource getAttributeResourceValue(RDFaAttributes attribute) {
String attributeValue = this.currentElementAttributes.getValue(attribute.getName());
Optional resourceResolution = resolveStringResource(attributeValue);
if (resourceResolution.isPresent()) {
@@ -561,6 +646,13 @@ private Resource getResourceFromElementAttribute(RDFaAttributes attribute) {
}
}
+ private boolean isAttributePresent(RDFaAttributes attribute) {
+ return this.currentElementAttributes.getValue(attribute.getName()) != null;
+ }
+
+ private String getAttributeStringValue(RDFaAttributes attribute) {
+ return this.currentElementAttributes.getValue(attribute.getName());
+ }
/**
* Resolves the string representation of a resource found in attributes of an element, be it an IRI, CURIE or relative URI
@@ -605,7 +697,7 @@ protected Optional resolveStringResource(String stringResource) {
return Optional.of(this.getValueFactory().createBNode(localNameString));
} else if (IRIUtils.isStandardIRI(currentContext.getBaseIri().stringValue() + resultString)) {
String concatenatedRelativeUri = currentContext.getBaseIri().stringValue() + resultString;
- return Optional.of(getValueFactory().createIRI(concatenatedRelativeUri));
+ return Optional.of(this.getValueFactory().createIRI(concatenatedRelativeUri));
}
return Optional.empty();
}
@@ -638,4 +730,18 @@ private void initializeNewContext(RDFaEvaluationContext context) {
context.addTermMapping("license", getValueFactory().createIRI("http://www.w3.org/1999/xhtml/vocab#license"));
context.addTermMapping("role", getValueFactory().createIRI("http://www.w3.org/1999/xhtml/vocab#role"));
}
+
+ private String debugAttributesToString() {
+ StringBuilder sb = new StringBuilder();
+
+ if (this.currentElementAttributes != null) {
+ for (int i = 0; i < this.currentElementAttributes.getLength(); i++) {
+ String attributeLocalName = this.currentElementAttributes.getQName(i);
+ String attributeValue = this.currentElementAttributes.getValue(i);
+ sb.append(attributeLocalName).append(" : ").append(attributeValue).append(" ");
+ }
+ }
+
+ return sb.toString();
+ }
}
diff --git a/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/model/RDFaAttributes.java b/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/model/RDFaAttributes.java
index 6d23908b6..265712e3d 100644
--- a/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/model/RDFaAttributes.java
+++ b/src/main/java/fr/inria/corese/core/next/impl/io/parser/rdfa/model/RDFaAttributes.java
@@ -2,6 +2,7 @@
public enum RDFaAttributes {
ABOUT("about"),
+ BASE("base"),
CONTENT("content"),
DATATYPE("datatype"),
HREF("href"),
diff --git a/src/main/java/fr/inria/corese/core/next/impl/io/serialization/SerializerFactory.java b/src/main/java/fr/inria/corese/core/next/impl/io/serialization/SerializerFactory.java
index 8693e1d5e..4468b8a74 100644
--- a/src/main/java/fr/inria/corese/core/next/impl/io/serialization/SerializerFactory.java
+++ b/src/main/java/fr/inria/corese/core/next/impl/io/serialization/SerializerFactory.java
@@ -92,6 +92,7 @@ public SerializerFactory() {
RDFFormat.RDFC_1_0.getName()
);
});
+
tempDefaultRegistry.put(RDFFormat.RDFC_1_0, model -> {
RDFC10SerializerOptions defaultConfig = RDFC10SerializerOptions.defaultConfig();
RDFC10Canonicalizer rdfc10Canonicalizer = new RDFC10Canonicalizer(
diff --git a/src/main/java/fr/inria/corese/core/next/impl/io/serialization/base/AbstractGraphSerializer.java b/src/main/java/fr/inria/corese/core/next/impl/io/serialization/base/AbstractGraphSerializer.java
index 6e247f9ca..a25b83e4f 100644
--- a/src/main/java/fr/inria/corese/core/next/impl/io/serialization/base/AbstractGraphSerializer.java
+++ b/src/main/java/fr/inria/corese/core/next/impl/io/serialization/base/AbstractGraphSerializer.java
@@ -129,7 +129,7 @@ protected void writeHeader(Writer writer) throws IOException {
/**
* Collects all namespaces used in the model and attempts to assign prefixes to them
- * if auto-declaration is enabled and they are not already mapped.
+ * if auto-declaration is enabled, and they are not already mapped.
*/
protected Set collectUsedNamespaces() {
Set namespaces = model.stream()
diff --git a/src/test/java/fr/inria/corese/core/next/impl/io/parser/rdfa/RDFa10ParserTest.java b/src/test/java/fr/inria/corese/core/next/impl/io/parser/rdfa/RDFa10ParserTest.java
deleted file mode 100644
index 47394b257..000000000
--- a/src/test/java/fr/inria/corese/core/next/impl/io/parser/rdfa/RDFa10ParserTest.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package fr.inria.corese.core.next.impl.io.parser.rdfa;
-
-import fr.inria.corese.core.next.api.*;
-import fr.inria.corese.core.next.api.base.io.RDFFormat;
-import fr.inria.corese.core.next.api.io.parser.RDFParser;
-import fr.inria.corese.core.next.impl.common.vocabulary.RDF;
-import fr.inria.corese.core.next.impl.common.vocabulary.XSD;
-import fr.inria.corese.core.next.impl.io.parser.ParserFactory;
-import fr.inria.corese.core.next.impl.temp.CoreseAdaptedValueFactory;
-import fr.inria.corese.core.next.impl.temp.CoreseModel;
-import org.junit.jupiter.api.Test;
-
-import java.io.ByteArrayInputStream;
-import java.util.Iterator;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
-public class RDFa10ParserTest {
-
- private static final ValueFactory factory = new CoreseAdaptedValueFactory();
-
-}
diff --git a/src/test/java/fr/inria/corese/core/next/impl/io/parser/rdfa/RDFaParserTest.java b/src/test/java/fr/inria/corese/core/next/impl/io/parser/rdfa/RDFaParserTest.java
index 90ea19d90..9db341d31 100644
--- a/src/test/java/fr/inria/corese/core/next/impl/io/parser/rdfa/RDFaParserTest.java
+++ b/src/test/java/fr/inria/corese/core/next/impl/io/parser/rdfa/RDFaParserTest.java
@@ -3,6 +3,8 @@
import fr.inria.corese.core.next.api.*;
import fr.inria.corese.core.next.api.base.io.RDFFormat;
import fr.inria.corese.core.next.api.io.parser.RDFParser;
+import fr.inria.corese.core.next.api.io.serializer.RDFSerializer;
+import fr.inria.corese.core.next.impl.io.serialization.SerializerFactory;
import fr.inria.corese.core.next.impl.common.vocabulary.RDF;
import fr.inria.corese.core.next.impl.common.vocabulary.XSD;
import fr.inria.corese.core.next.impl.io.parser.ParserFactory;
@@ -11,12 +13,17 @@
import org.junit.jupiter.api.Test;
import java.io.ByteArrayInputStream;
+import java.io.StringWriter;
import java.util.Iterator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import static org.junit.jupiter.api.Assertions.*;
class RDFaParserTest {
+ private static final Logger logger = LoggerFactory.getLogger(RDFaParserTest.class);
+
private ParserFactory parserFactory = new ParserFactory();
private ValueFactory valueFactory = new CoreseAdaptedValueFactory();
private final String defaultTurtlePrefixes = """
@@ -59,8 +66,8 @@ void parseCurrentSubjectCreatorHead() {