mHandlerStack = new Stack<>();
private StringBuilder mCharsForTextNode = new StringBuilder();
- private JenaSink sink;
public OdfFileSaxHandler(Node rootNode) throws SAXException {
if (rootNode instanceof OdfFileDom) {
@@ -138,9 +136,6 @@ public void startElement(String uri, String localName, String qName, Attributes
mCurrentNode.appendChild(element);
// push the new element as the context node...
mCurrentNode = element;
- if (!localName.equals("bookmark-start")) {
- setContextNode(mCurrentNode);
- }
}
/**
@@ -171,22 +166,4 @@ public InputSource resolveEntity(String publicId, String systemId)
throws IOException, SAXException {
return super.resolveEntity(publicId, systemId);
}
-
- /**
- * Expose the current node to JenaSink to for caching the parsed RDF triples.
- */
- protected void setContextNode(Node node) {
- if (this.sink != null) {
- sink.setContextNode(node);
- }
- }
-
- /**
- * Set the JenaSink object.
- *
- * @param sink
- */
- public void setSink(JenaSink sink) {
- this.sink = sink;
- }
}
diff --git a/odfdom/src/main/java/org/odftoolkit/odfdom/pkg/rdfa/DOMAttributes.java b/odfdom/src/main/java/org/odftoolkit/odfdom/pkg/rdfa/DOMAttributes.java
deleted file mode 100644
index caead04d05..0000000000
--- a/odfdom/src/main/java/org/odftoolkit/odfdom/pkg/rdfa/DOMAttributes.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/**
- * **********************************************************************
- *
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
- *
- *
Copyright 2008, 2010 Oracle and/or its affiliates. All rights reserved.
- *
- *
Use is subject to license terms.
- *
- *
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- * http://www.apache.org/licenses/LICENSE-2.0. You can also obtain a copy of the License at
- * http://odftoolkit.org/docs/license.txt
- *
- *
Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
- * express or implied.
- *
- *
See the License for the specific language governing permissions and limitations under the
- * License.
- *
- *
**********************************************************************
- */
-package org.odftoolkit.odfdom.pkg.rdfa;
-
-import org.w3c.dom.NamedNodeMap;
-import org.xml.sax.Attributes;
-
-/** Simple wrapper class for NamedNodeMap as Attributes */
-public class DOMAttributes implements Attributes {
-
- private NamedNodeMap attributes;
-
- /**
- * Class constructor
- *
- * @param attributes
- */
- public DOMAttributes(NamedNodeMap attributes) {
- this.attributes = attributes;
- }
-
- public int getLength() {
- return attributes.getLength();
- }
-
- public String getURI(int index) {
- return attributes.item(index).getNamespaceURI();
- }
-
- public String getLocalName(int index) {
- return attributes.item(index).getLocalName();
- }
-
- public String getQName(int index) {
- return attributes.item(index).getNodeName();
- }
-
- public String getType(int index) {
- throw new RuntimeException("DOMAttributes.getType() is not supported");
- }
-
- public String getValue(int index) {
- return attributes.item(index).getNodeValue();
- }
-
- public int getIndex(String uri, String localName) {
- throw new RuntimeException(
- "DOMAttributes.getIndex(String uri, String localName) is not supported");
- }
-
- public int getIndex(String qName) {
- throw new RuntimeException("DOMAttributes.getIndex(String qName) is not supported");
- }
-
- public String getType(String uri, String localName) {
- throw new RuntimeException(
- "DOMAttributes.getType(String uri, String localName) is not supported");
- }
-
- public String getType(String qName) {
- throw new RuntimeException("DOMAttributes.getType(String qName) is not supported");
- }
-
- public String getValue(String uri, String localName) {
- throw new RuntimeException(
- "DOMAttributes.getValue(String uri, String localName) is not supported");
- }
-
- public String getValue(String qName) {
- throw new RuntimeException("DOMAttributes.getValue(String qName) is not supported");
- }
-}
diff --git a/odfdom/src/main/java/org/odftoolkit/odfdom/pkg/rdfa/DOMRDFaParser.java b/odfdom/src/main/java/org/odftoolkit/odfdom/pkg/rdfa/DOMRDFaParser.java
deleted file mode 100644
index ec11d4379a..0000000000
--- a/odfdom/src/main/java/org/odftoolkit/odfdom/pkg/rdfa/DOMRDFaParser.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/**
- * **********************************************************************
- *
- *
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
- *
- *
Copyright 2008, 2010 Oracle and/or its affiliates. All rights reserved.
- *
- *
Use is subject to license terms.
- *
- *
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- * http://www.apache.org/licenses/LICENSE-2.0. You can also obtain a copy of the License at
- * http://odftoolkit.org/docs/license.txt
- *
- *
Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
- * express or implied.
- *
- *
See the License for the specific language governing permissions and limitations under the
- * License.
- *
- *
**********************************************************************
- */
-package org.odftoolkit.odfdom.pkg.rdfa;
-
-import javax.xml.stream.XMLEventFactory;
-import javax.xml.stream.XMLOutputFactory;
-import org.odftoolkit.odfdom.dom.element.text.TextBookmarkStartElement;
-import org.w3c.dom.Node;
-
-/** A RDFa parser for DOM */
-public class DOMRDFaParser extends RDFaParser {
-
- private static final XMLOutputFactory DEFAULT_XML_OUTPUT_FACTORY = XMLOutputFactory.newFactory();
- private static final XMLEventFactory DEFAULT_XML_EVENT_FACTORY = XMLEventFactory.newFactory();
-
- public static DOMRDFaParser createInstance(JenaSink sink) {
- sink.getExtractor().setForSAX(false);
- return new DOMRDFaParser(sink, sink.getExtractor());
- }
-
- public DOMRDFaParser(
- JenaSink sink,
- XMLOutputFactory outputFactory,
- XMLEventFactory eventFactory,
- URIExtractor extractor) {
- super(sink, outputFactory, eventFactory, extractor);
- }
-
- public DOMRDFaParser(JenaSink sink, URIExtractor extractor) {
- this(sink, DEFAULT_XML_OUTPUT_FACTORY, DEFAULT_XML_EVENT_FACTORY, extractor);
- }
-
- /**
- * Parse the RDFa in-content metadata of the node.
- *
- * @param node
- */
- public void parse(Node node) {
- process(node);
- }
-
- private void process(Node node) {
-
- switch (node.getNodeType()) {
- case Node.ELEMENT_NODE:
- if (!(node instanceof TextBookmarkStartElement)) {
- sink.setContextNode(node);
- }
- // Start element
- beginRDFaElement(
- node.getNamespaceURI(),
- node.getLocalName(),
- node.getNodeName(),
- new DOMAttributes(node.getAttributes()));
- // Recurse to child
- // if (node.hasChildNodes() == true) {
- // process(node.getFirstChild());
- // }
- if (node.hasChildNodes() == true) {
- Node n = node.getFirstChild();
- process(n);
- while (n.getNextSibling() != null) {
- process(n.getNextSibling());
- n = n.getNextSibling();
- }
- }
-
- // End element
- endRDFaElement(node.getNamespaceURI(), node.getLocalName(), node.getNodeName());
- break;
- case Node.CDATA_SECTION_NODE:
- case Node.TEXT_NODE:
- // Text or CDATA
- writeCharacters(node.getNodeValue());
- break;
- }
- }
-}
diff --git a/odfdom/src/main/java/org/odftoolkit/odfdom/pkg/rdfa/EvalContext.java b/odfdom/src/main/java/org/odftoolkit/odfdom/pkg/rdfa/EvalContext.java
deleted file mode 100644
index 96dac6fd18..0000000000
--- a/odfdom/src/main/java/org/odftoolkit/odfdom/pkg/rdfa/EvalContext.java
+++ /dev/null
@@ -1,203 +0,0 @@
-/**
- * **********************************************************************
- *
- *
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
- *
- *
Copyright 2008, 2010 Oracle and/or its affiliates. All rights reserved.
- *
- *
Use is subject to license terms.
- *
- *
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- * http://www.apache.org/licenses/LICENSE-2.0. You can also obtain a copy of the License at
- * http://odftoolkit.org/docs/license.txt
- *
- *
Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
- * express or implied.
- *
- *
See the License for the specific language governing permissions and limitations under the
- * License.
- *
- *
**********************************************************************
- */
-package org.odftoolkit.odfdom.pkg.rdfa;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import javax.xml.namespace.NamespaceContext;
-
-/** EvalContext modified from net.rootdev.javardfa.EvalContext */
-final class EvalContext implements NamespaceContext {
-
- EvalContext parent;
- String base;
- String parentSubject;
- String parentObject;
- String language;
- String vocab;
- List forwardProperties;
- List backwardProperties;
- Map xmlnsMap = Collections.emptyMap();
- Map prefixMap = Collections.emptyMap();
-
- protected EvalContext(String base) {
- super();
- this.base = base;
- this.parentSubject = base;
- this.forwardProperties = new ArrayList<>();
- this.backwardProperties = new ArrayList<>();
- }
-
- public EvalContext(EvalContext toCopy) {
- super();
- this.base = toCopy.base;
- this.parentSubject = toCopy.parentSubject;
- this.parentObject = toCopy.parentObject;
- this.language = toCopy.language;
- this.forwardProperties = new ArrayList<>(toCopy.forwardProperties);
- this.backwardProperties = new ArrayList<>(toCopy.backwardProperties);
- this.parent = toCopy;
- this.vocab = toCopy.vocab;
- }
-
- public void setBase(String abase) {
- // This is very dodgy. We want to check if ps and po have been changed
- // from their typical values (base).
- // Base changing happens very late in the day when we're streaming, and
- // it is very fiddly to handle
- boolean setPS = Objects.equals(parentSubject, base);
- boolean setPO = Objects.equals(parentObject, base);
-
- if (abase.contains("#")) {
- this.base = abase.substring(0, abase.indexOf("#"));
- } else {
- this.base = abase;
- }
-
- if (setPS) this.parentSubject = base;
- if (setPO) this.parentObject = base;
-
- if (parent != null) {
- parent.setBase(base);
- }
- }
-
- @Override
- public String toString() {
- return String.format(
- "[\n\tBase: %s\n\tPS: %s\n\tPO: %s\n\tlang: %s\n\tIncomplete: -> %s <- %s\n]",
- base,
- parentSubject,
- parentObject,
- language,
- forwardProperties.size(),
- backwardProperties.size());
- }
-
- /**
- * RDFa 1.1 prefix support
- *
- * @param prefix Prefix
- * @param uri URI
- */
- public void setPrefix(String prefix, String uri) {
- if (uri.length() == 0) {
- uri = base;
- }
- if (prefixMap == Collections.EMPTY_MAP) prefixMap = new HashMap<>();
- prefixMap.put(prefix, uri);
- }
-
- /**
- * RDFa 1.1 prefix support.
- *
- * @param prefix
- * @return
- */
- public String getURIForPrefix(String prefix) {
- if (prefixMap.containsKey(prefix)) {
- return prefixMap.get(prefix);
- } else if (xmlnsMap.containsKey(prefix)) {
- return xmlnsMap.get(prefix);
- } else if (parent != null) {
- return parent.getURIForPrefix(prefix);
- } else {
- return null;
- }
- }
-
- // Namespace methods
- public void setNamespaceURI(String prefix, String uri) {
- if (uri.length() == 0) {
- uri = base;
- }
- if (xmlnsMap == Collections.EMPTY_MAP) xmlnsMap = new HashMap<>();
- xmlnsMap.put(prefix, uri);
- }
-
- public String getNamespaceURI(String prefix) {
- if (xmlnsMap.containsKey(prefix)) {
- return xmlnsMap.get(prefix);
- } else if (parent != null) {
- return parent.getNamespaceURI(prefix);
- } else {
- return null;
- }
- }
-
- public String getPrefix(String uri) {
- throw new UnsupportedOperationException("Not supported yet.");
- }
-
- public Iterator getPrefixes(String uri) {
- throw new UnsupportedOperationException("Not supported yet.");
- }
-
- // I'm not sure about this 1.1 term business. Reuse prefix map
- public void setTerm(String term, String uri) {
- setPrefix(term + ":", uri);
- }
-
- public String getURIForTerm(String term) {
- return getURIForPrefix(term + ":");
- }
-
- public String getBase() {
- return base;
- }
-
- public String getVocab() {
- return vocab;
- }
-}
-
-/*
- * (c) Copyright 2009 University of Bristol All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer. 2. Redistributions in
- * binary form must reproduce the above copyright notice, this list of
- * conditions and the following disclaimer in the documentation and/or other
- * materials provided with the distribution. 3. The name of the author may not
- * be used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
diff --git a/odfdom/src/main/java/org/odftoolkit/odfdom/pkg/rdfa/InContentMetadata.java b/odfdom/src/main/java/org/odftoolkit/odfdom/pkg/rdfa/InContentMetadata.java
new file mode 100644
index 0000000000..bc220fb0f1
--- /dev/null
+++ b/odfdom/src/main/java/org/odftoolkit/odfdom/pkg/rdfa/InContentMetadata.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright 2026 The Document Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.odftoolkit.odfdom.pkg.rdfa;
+
+import java.util.Map;
+import org.apache.jena.datatypes.TypeMapper;
+import org.apache.jena.rdf.model.AnonId;
+import org.apache.jena.rdf.model.Literal;
+import org.apache.jena.rdf.model.Model;
+import org.apache.jena.rdf.model.ModelFactory;
+import org.apache.jena.rdf.model.Resource;
+import org.odftoolkit.odfdom.dom.element.text.TextBookmarkStartElement;
+import org.odftoolkit.odfdom.pkg.OdfFileDom;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+/**
+ * Reads the RDF statements that ODF in-content metadata attributes state about an element.
+ *
+ * ODF allows RDF metadata on the elements <text:p>, <text:h>
+ * , <text:meta>, <text:bookmark-start>,
+ * <table:table-cell> and <table:covered-table-cell> using four
+ * attributes of the XHTML namespace (ODF 1.2 Part 1, §4.2.1 "In Content Metadata (RDFa)" and
+ * §19.905 to §19.908). The ODF schema only permits xhtml:about and
+ * xhtml:property together, so every such element is self-contained and states one RDF
+ * statement per predicate:
+ *
+ *
+ * Mapping of ODF attributes to an RDF statement
+ * | RDF | ODF source | Interpretation |
+ *
+ * | subject |
+ * xhtml:about (URIorSafeCURIE) |
+ * [prefix:reference] is a safe CURIE, expanded as described below.
+ * [_:label] or _:label is a blank node, identical for equal labels in the
+ * same ODF document. An empty value refers to the ODF document itself, the {@link
+ * OdfFileDom#getRDFBaseUri() RDF base IRI}. Any other value is taken as an IRI, unchanged,
+ * even when relative. |
+ *
+ *
+ * | predicates |
+ * xhtml:property (CURIEs) |
+ * A whitespace separated list of CURIEs, each one resulting in a separate statement. |
+ *
+ *
+ * | object |
+ * xhtml:content (string), or the text of the element |
+ * Always a literal, without surrounding whitespace. Without xhtml:content it
+ * is the text of all descendant text nodes, as for {@link Node#getTextContent()}. Markup
+ * within the element does not create an XML literal, as ODF defines the object as the
+ * "literal content" of the element. Empty literals create no statement. |
+ *
+ *
+ * | datatype |
+ * xhtml:datatype (CURIE) |
+ * The expanded CURIE is the datatype IRI of the literal, e.g. xsd:date. If
+ * it is missing, empty or cannot be expanded, the literal has no explicit datatype. |
+ *
+ *
+ *
+ * A CURIE (compact URI, RDFa 1.0 §7) prefix:reference is expanded by
+ * concatenating the namespace IRI bound to prefix by an XML namespace declaration
+ * with reference. For example, dc:title becomes
+ * http://purl.org/dc/elements/1.1/title when the file declares
+ * xmlns:dc="http://purl.org/dc/elements/1.1/". The prefixes are looked up in the {@link
+ * OdfFileDom} as {@link javax.xml.namespace.NamespaceContext}, as ODFDOM moves all namespace
+ * declarations of a file to its root element while loading, and because elements are processed
+ * before they are inserted into the DOM tree. An empty prefix, as in :reference,
+ * refers to the XHTML vocabulary http://www.w3.org/1999/xhtml/vocab#. A CURIE
+ * without a colon or with an undeclared prefix is ignored.
+ *
+ *
The object of a <text:bookmark-start> is the text up to the matching
+ * <text:bookmark-end>, which is not part of the bookmark element itself. This
+ * text is collected by {@link org.odftoolkit.odfdom.dom.rdfa.BookmarkRDFMetadataExtractor}, which
+ * calls {@link #addStatements(Model, Element, String)} with it. Therefore {@link #collect(Node,
+ * Map)} skips bookmarks.
+ */
+public final class InContentMetadata {
+
+ /** Namespace of the ODF in-content metadata attributes, e.g. xhtml:about. */
+ private static final String XHTML = "http://www.w3.org/1999/xhtml";
+
+ /** IRI prefix for CURIEs with an empty prefix, e.g. :next (RDFa 1.0 §7). */
+ private static final String XHTML_VOCAB = "http://www.w3.org/1999/xhtml/vocab#";
+
+ private InContentMetadata() {}
+
+ /**
+ * Refreshes the cache entries of the given node and of all its descendant elements.
+ *
+ *
Every element whose attributes state RDF statements gets a new model containing exactly
+ * these statements. Every other element loses its entry, so that removed attributes or emptied
+ * text do not leave stale statements behind. Bookmarks are skipped, see {@link
+ * InContentMetadata}.
+ *
+ *
Note that the object of an element may be the text of its descendants. A text change within
+ * a descendant, e.g. of a <text:span> within a <text:p>,
+ * only reaches the cache when collect is called for the ancestor carrying the
+ * metadata.
+ *
+ * @param node the root of the subtree to be refreshed, ignored unless it is an element
+ * @param cache the cache to be refreshed, keyed by element identity
+ */
+ public static void collect(Node node, Map cache) {
+ if (node instanceof Element element) {
+ Model model = null;
+ if (element.hasAttributeNS(XHTML, "about")
+ && !(element instanceof TextBookmarkStartElement)) {
+ model = ModelFactory.createDefaultModel();
+ addStatements(model, element, element.getTextContent());
+ }
+ if (model == null || model.isEmpty()) {
+ cache.remove(element);
+ } else {
+ cache.put(element, model);
+ }
+ for (Node child = element.getFirstChild(); child != null; child = child.getNextSibling()) {
+ collect(child, cache);
+ }
+ }
+ }
+
+ /**
+ * Adds the RDF statements stated by the in-content metadata attributes of an element to a model.
+ *
+ * Nothing is added, if the element lacks xhtml:about or xhtml:property
+ * , if the subject cannot be determined or if the literal is empty.
+ *
+ * @param model the model receiving the statements
+ * @param element an element of an {@link OdfFileDom}, carrying in-content metadata attributes
+ * @param text the literal content of the element, used unless xhtml:content exists
+ */
+ public static void addStatements(Model model, Element element, String text) {
+ String about = attribute(element, "about");
+ String properties = attribute(element, "property");
+ String content = attribute(element, "content");
+ String lexicalForm = (content != null ? content : text == null ? "" : text).trim();
+ Resource subject = about == null ? null : subject(model, element, about.trim());
+ if (subject == null || properties == null || lexicalForm.isEmpty()) {
+ return;
+ }
+ String datatype = expand(element, attribute(element, "datatype"));
+ Literal object =
+ datatype == null
+ ? model.createLiteral(lexicalForm)
+ : model.createTypedLiteral(
+ lexicalForm, TypeMapper.getInstance().getSafeTypeByName(datatype));
+ for (String curie : properties.trim().split("\\s+")) {
+ String predicate = expand(element, curie);
+ if (predicate != null) {
+ model.add(subject, model.createProperty(predicate), object);
+ }
+ }
+ }
+
+ /** Returns the subject of an xhtml:about value, or null if it has none. */
+ private static Resource subject(Model model, Element element, String about) {
+ boolean safeCurie = about.startsWith("[") && about.endsWith("]");
+ String value = safeCurie ? about.substring(1, about.length() - 1) : about;
+ String baseUri = ((OdfFileDom) element.getOwnerDocument()).getRDFBaseUri();
+ if (value.startsWith("_:")) {
+ return model.createResource(AnonId.create(baseUri + value));
+ }
+ String iri = safeCurie ? expand(element, value) : value.isEmpty() ? baseUri : value;
+ return iri == null ? null : model.createResource(iri);
+ }
+
+ /** Returns the IRI of a CURIE, or null if it is null, has no colon or an unknown prefix. */
+ private static String expand(Element element, String curie) {
+ int colon = curie == null ? -1 : curie.indexOf(':');
+ if (colon < 0) {
+ return null;
+ }
+ String prefix = curie.substring(0, colon);
+ String namespace =
+ prefix.isEmpty()
+ ? XHTML_VOCAB
+ : ((OdfFileDom) element.getOwnerDocument()).getNamespaceURI(prefix);
+ return namespace.isEmpty() ? null : namespace + curie.substring(colon + 1);
+ }
+
+ /** Returns the value of an attribute of the XHTML namespace, or null if it is missing. */
+ private static String attribute(Element element, String localName) {
+ return element.hasAttributeNS(XHTML, localName)
+ ? element.getAttributeNS(XHTML, localName)
+ : null;
+ }
+}
diff --git a/odfdom/src/main/java/org/odftoolkit/odfdom/pkg/rdfa/JenaSink.java b/odfdom/src/main/java/org/odftoolkit/odfdom/pkg/rdfa/JenaSink.java
deleted file mode 100644
index aba9a50c0c..0000000000
--- a/odfdom/src/main/java/org/odftoolkit/odfdom/pkg/rdfa/JenaSink.java
+++ /dev/null
@@ -1,157 +0,0 @@
-/**
- * **********************************************************************
- *
- *
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
- *
- *
Copyright 2008, 2010 Oracle and/or its affiliates. All rights reserved.
- *
- *
Use is subject to license terms.
- *
- *
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- * http://www.apache.org/licenses/LICENSE-2.0. You can also obtain a copy of the License at
- * http://odftoolkit.org/docs/license.txt
- *
- *
Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
- * express or implied.
- *
- *
See the License for the specific language governing permissions and limitations under the
- * License.
- *
- *
**********************************************************************
- */
-package org.odftoolkit.odfdom.pkg.rdfa;
-
-import java.util.HashMap;
-import java.util.Map;
-import net.rootdev.javardfa.StatementSink;
-import org.apache.jena.rdf.model.Literal;
-import org.apache.jena.rdf.model.Model;
-import org.apache.jena.rdf.model.ModelFactory;
-import org.apache.jena.rdf.model.Property;
-import org.apache.jena.rdf.model.Resource;
-import org.odftoolkit.odfdom.pkg.OdfFileDom;
-import org.w3c.dom.Node;
-
-/** To cache the Jena RDF triples parsed from RDFaParser */
-public class JenaSink implements StatementSink {
-
- // private OdfFileSaxHandler odf;
- private Node contextNode;
- private OdfFileDom mFileDom;
- private Map bnodeLookup;
- private URIExtractor extractor;
- private EvalContext context;
-
- public JenaSink(OdfFileDom mFileDom) {
- this.mFileDom = mFileDom;
- this.bnodeLookup = new HashMap<>();
- }
-
- // @Override
- public void start() {
- bnodeLookup = new HashMap<>();
- }
-
- // @Override
- public void end() {
- bnodeLookup = null;
- }
-
- // @Override
- public void addObject(String subject, String predicate, String object) {
- Model model = getContextModel();
- Resource s = getResource(model, subject.trim());
- Property p = model.createProperty(predicate.trim());
- Resource o = getResource(model, object.trim());
- model.add(s, p, o);
- }
-
- // @Override
- public void addLiteral(
- String subject, String predicate, String lex, String lang, String datatype) {
- if (lex.isEmpty()) {
- return;
- }
- Model model = getContextModel();
- Resource s = getResource(model, subject.trim());
- Property p = model.createProperty(predicate.trim());
- Literal o;
- if (lang == null && datatype == null) {
- o = model.createLiteral(lex.trim());
- } else if (lang != null) {
- o = model.createLiteral(lex.trim(), lang.trim());
- } else {
- o = model.createTypedLiteral(lex.trim(), datatype.trim());
- }
- model.add(s, p, o);
- }
-
- private Resource getResource(Model model, String res) {
- if (res.startsWith("_:")) {
- if (bnodeLookup.containsKey(res)) {
- return bnodeLookup.get(res);
- }
- Resource bnode = model.createResource();
- bnodeLookup.put(res, bnode);
- return bnode;
- } else {
- return model.createResource(res);
- }
- }
-
- public void addPrefix(String prefix, String uri) {
- // Model model =getContextModel();
- // try {
- // model.setNsPrefix(prefix.trim(), uri.trim());
- // } catch (IllegalPrefixException e) {
- // }
- }
-
- public void setBase(String base) {}
-
- private Model getContextModel() {
- Map cache = this.mFileDom.getInContentMetadataCache();
- Model model = cache.get(contextNode);
- if (model == null) {
- model = ModelFactory.createDefaultModel();
- this.mFileDom.getInContentMetadataCache().put(contextNode, model);
- }
- return model;
- }
-
- public Node getContextNode() {
- return contextNode;
- }
-
- public void setContextNode(Node contextNode) {
- this.contextNode = contextNode;
- }
-
- public URIExtractor getExtractor() {
- return extractor;
- }
-
- public void setExtractor(URIExtractor extractor) {
- this.extractor = extractor;
- }
-
- public EvalContext getContext() {
- return context;
- }
-
- public void setContext(EvalContext context) {
- this.context = context;
- }
-
- // // Namespace methods
- // public void setNamespaceURI(String prefix, String uri) {
- // if (uri.length() == 0) {
- // uri = base;
- // }
- // if (xmlnsMap == Collections.EMPTY_MAP) xmlnsMap = new HashMap();
- // xmlnsMap.put(prefix, uri);
- // }
-
-}
diff --git a/odfdom/src/main/java/org/odftoolkit/odfdom/pkg/rdfa/MultiContentHandler.java b/odfdom/src/main/java/org/odftoolkit/odfdom/pkg/rdfa/MultiContentHandler.java
deleted file mode 100644
index 257c307e89..0000000000
--- a/odfdom/src/main/java/org/odftoolkit/odfdom/pkg/rdfa/MultiContentHandler.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/**
- * **********************************************************************
- *
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
- *
- *
Copyright 2008, 2010 Oracle and/or its affiliates. All rights reserved.
- *
- *
Use is subject to license terms.
- *
- *
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- * http://www.apache.org/licenses/LICENSE-2.0. You can also obtain a copy of the License at
- * http://odftoolkit.org/docs/license.txt
- *
- *
Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
- * express or implied.
- *
- *
See the License for the specific language governing permissions and limitations under the
- * License.
- *
- *
**********************************************************************
- */
-package org.odftoolkit.odfdom.pkg.rdfa;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-
-import org.xml.sax.Attributes;
-import org.xml.sax.ContentHandler;
-import org.xml.sax.Locator;
-import org.xml.sax.SAXException;
-
-/** A proxy for delegating the parsing events to its sub ContentHandler(s). */
-public class MultiContentHandler implements ContentHandler {
- ArrayList subContentHandlers;
-
- public MultiContentHandler(ContentHandler... subs) {
- subContentHandlers = new ArrayList<>(Arrays.asList(subs));
- }
-
- public void setDocumentLocator(Locator locator) {
- for (ContentHandler sub : subContentHandlers) {
- sub.setDocumentLocator(locator);
- }
- }
-
- public void startDocument() throws SAXException {
- for (ContentHandler sub : subContentHandlers) {
- sub.startDocument();
- }
- }
-
- public void endDocument() throws SAXException {
- for (ContentHandler sub : subContentHandlers) {
- sub.endDocument();
- }
- }
-
- public void startPrefixMapping(String prefix, String uri) throws SAXException {
- for (ContentHandler sub : subContentHandlers) {
- sub.startPrefixMapping(prefix, uri);
- }
- }
-
- public void endPrefixMapping(String prefix) throws SAXException {
- for (ContentHandler sub : subContentHandlers) {
- sub.endPrefixMapping(prefix);
- }
- }
-
- public void startElement(String uri, String localName, String qName, Attributes atts)
- throws SAXException {
- for (ContentHandler sub : subContentHandlers) {
- sub.startElement(uri, localName, qName, atts);
- }
- }
-
- public void endElement(String uri, String localName, String qName) throws SAXException {
- for (ContentHandler sub : subContentHandlers) {
- sub.endElement(uri, localName, qName);
- }
- }
-
- public void characters(char[] ch, int start, int length) throws SAXException {
- for (ContentHandler sub : subContentHandlers) {
- sub.characters(ch, start, length);
- }
- }
-
- public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
- for (ContentHandler sub : subContentHandlers) {
- sub.ignorableWhitespace(ch, start, length);
- }
- }
-
- public void processingInstruction(String target, String data) throws SAXException {
- for (ContentHandler sub : subContentHandlers) {
- sub.processingInstruction(target, data);
- }
- }
-
- public void skippedEntity(String name) throws SAXException {
- for (ContentHandler sub : subContentHandlers) {
- sub.skippedEntity(name);
- }
- }
-}
diff --git a/odfdom/src/main/java/org/odftoolkit/odfdom/pkg/rdfa/RDFaParser.java b/odfdom/src/main/java/org/odftoolkit/odfdom/pkg/rdfa/RDFaParser.java
deleted file mode 100644
index 31000086b7..0000000000
--- a/odfdom/src/main/java/org/odftoolkit/odfdom/pkg/rdfa/RDFaParser.java
+++ /dev/null
@@ -1,413 +0,0 @@
-/**
- * **********************************************************************
- *
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
- *
- *
Copyright 2008, 2010 Oracle and/or its affiliates. All rights reserved.
- *
- *
Use is subject to license terms.
- *
- *
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- * http://www.apache.org/licenses/LICENSE-2.0. You can also obtain a copy of the License at
- * http://odftoolkit.org/docs/license.txt
- *
- *
Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
- * express or implied.
- *
- *
See the License for the specific language governing permissions and limitations under the
- * License.
- *
- *
**********************************************************************
- */
-package org.odftoolkit.odfdom.pkg.rdfa;
-
-import java.util.EnumSet;
-import java.util.Iterator;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Set;
-import javax.xml.namespace.QName;
-import javax.xml.stream.XMLEventFactory;
-import javax.xml.stream.XMLOutputFactory;
-import javax.xml.stream.XMLStreamException;
-import javax.xml.stream.events.Attribute;
-import javax.xml.stream.events.StartElement;
-import javax.xml.stream.events.XMLEvent;
-import net.rootdev.javardfa.Constants;
-import net.rootdev.javardfa.Setting;
-import net.rootdev.javardfa.literal.LiteralCollector;
-import net.rootdev.javardfa.uri.IRIResolver;
-import net.rootdev.javardfa.uri.URIExtractor10;
-import org.xml.sax.Attributes;
-import org.xml.sax.Locator;
-
-/** A RDFa Parser modified from net.rootdev.javardfa.Parser */
-class RDFaParser extends net.rootdev.javardfa.Parser {
-
- boolean ignore = false;
-
- protected XMLEventFactory eventFactory;
- protected JenaSink sink;
- protected Set settings;
- protected LiteralCollector literalCollector;
- protected URIExtractor extractor;
- protected Locator locator;
- protected EvalContext context;
-
- protected RDFaParser(
- JenaSink sink,
- XMLOutputFactory outputFactory,
- XMLEventFactory eventFactory,
- URIExtractor extractor) {
- super(sink, outputFactory, eventFactory, new URIExtractor10(new IRIResolver()));
- this.sink = sink;
- this.eventFactory = eventFactory;
- this.settings = EnumSet.noneOf(Setting.class);
- this.extractor = extractor;
-
- this.literalCollector = new LiteralCollector(this, eventFactory, outputFactory);
-
- extractor.setSettings(settings);
-
- // Important, although I guess the caller doesn't get total control
- outputFactory.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, true);
- }
-
- protected void beginRDFaElement(String arg0, String localname, String qname, Attributes arg3) {
- if (localname.equals("bookmark-start")) {
- ignore = true;
- return;
- }
- try {
- // System.err.println("Start element: " + arg0 + " " + arg1 + " " +
- // arg2);
-
- // This is set very late in some html5 cases (not even ready by
- // document start)
- if (context == null) {
- this.setBase(locator.getSystemId());
- }
-
- // Dammit, not quite the same as XMLEventFactory
- String prefix = /* (localname.equals(qname)) */
- (qname.indexOf(':') == -1) ? "" : qname.substring(0, qname.indexOf(':'));
- if (settings.contains(Setting.ManualNamespaces)) {
- getNamespaces(arg3);
- if (prefix.length() != 0) {
- arg0 = context.getNamespaceURI(prefix);
- localname = localname.substring(prefix.length() + 1);
- }
- }
- StartElement e =
- eventFactory.createStartElement(
- prefix, arg0, localname, fromAttributes(arg3), null, context);
-
- if (literalCollector.isCollecting()) literalCollector.handleEvent(e);
-
- // If we are gathering XML we stop parsing
- if (!literalCollector.isCollectingXML()) context = parse(context, e);
- } catch (XMLStreamException ex) {
- throw new RuntimeException("Streaming issue", ex);
- }
- }
-
- protected void endRDFaElement(String arg0, String localname, String qname) {
- if (localname.equals("bookmark-start")) {
- ignore = false;
- return;
- }
- if (literalCollector.isCollecting()) {
- String prefix = (localname.equals(qname)) ? "" : qname.substring(0, qname.indexOf(':'));
- XMLEvent e = eventFactory.createEndElement(prefix, arg0, localname);
- literalCollector.handleEvent(e);
- }
- // If we aren't collecting an XML literal keep parsing
- if (!literalCollector.isCollectingXML()) context = context.parent;
- }
-
- protected void writeCharacters(String value) {
- if (!ignore) {
- if (literalCollector.isCollecting()) {
- XMLEvent e = eventFactory.createCharacters(value);
- literalCollector.handleEvent(e);
- }
- }
- }
-
- /** Set the base uri of the DOM. */
- public void setBase(String base) {
- this.context = new EvalContext(base);
- sink.setBase(context.getBase());
- }
-
- protected EvalContext parse(EvalContext context, StartElement element) throws XMLStreamException {
- boolean skipElement = false;
- String newSubject = null;
- String currentObject = null;
- List forwardProperties = new ArrayList<>();
- List backwardProperties = new ArrayList<>();
- String currentLanguage = context.language;
-
- if (settings.contains(Setting.OnePointOne)) {
-
- if (getAttributeByName(element, Constants.vocab) != null) {
- context.vocab = getAttributeByName(element, Constants.vocab).getValue().trim();
- }
-
- if (getAttributeByName(element, Constants.prefix) != null) {
- parsePrefixes(getAttributeByName(element, Constants.prefix).getValue(), context);
- }
- }
-
- // The xml / html namespace matching is a bit ropey. I wonder if the
- // html 5
- // parser has a setting for this?
- if (settings.contains(Setting.ManualNamespaces)) {
- if (getAttributeByName(element, Constants.xmllang) != null) {
- currentLanguage = getAttributeByName(element, Constants.xmllang).getValue();
- if (currentLanguage.length() == 0) currentLanguage = null;
- } else if (getAttributeByName(element, Constants.lang) != null) {
- currentLanguage = getAttributeByName(element, Constants.lang).getValue();
- if (currentLanguage.length() == 0) currentLanguage = null;
- }
- } else if (getAttributeByName(element, Constants.xmllangNS) != null) {
- currentLanguage = getAttributeByName(element, Constants.xmllangNS).getValue();
- if (currentLanguage.length() == 0) currentLanguage = null;
- }
-
- if (Constants.base.equals(element.getName())
- && getAttributeByName(element, Constants.href) != null) {
- context.setBase(getAttributeByName(element, Constants.href).getValue());
- sink.setBase(context.getBase());
- }
- if (getAttributeByName(element, Constants.rev) == null
- && getAttributeByName(element, Constants.rel) == null) {
- Attribute nSubj = findAttribute(element, Constants.about);
- if (nSubj != null) {
- newSubject = extractor.getURI(element, nSubj, context);
- }
- if (newSubject == null) {
- if (Constants.body.equals(element.getName()) || Constants.head.equals(element.getName())) {
- newSubject = context.base;
- } else if (getAttributeByName(element, Constants.typeof) != null) {
- newSubject = createBNode();
- } else {
- if (context.parentObject != null) {
- newSubject = context.parentObject;
- }
- if (getAttributeByName(element, Constants.property) == null) {
- skipElement = true;
- }
- }
- }
- } else {
- Attribute nSubj = findAttribute(element, Constants.about, Constants.src);
- if (nSubj != null) {
- newSubject = extractor.getURI(element, nSubj, context);
- }
- if (newSubject == null) {
- // if element is head or body assume about=""
- if (Constants.head.equals(element.getName()) || Constants.body.equals(element.getName())) {
- newSubject = context.base;
- } else if (getAttributeByName(element, Constants.typeof) != null) {
- newSubject = createBNode();
- } else if (context.parentObject != null) {
- newSubject = context.parentObject;
- }
- }
- Attribute cObj = findAttribute(element, Constants.resource, Constants.href);
- if (cObj != null) {
- currentObject = extractor.getURI(element, cObj, context);
- }
- }
-
- if (newSubject != null && getAttributeByName(element, Constants.typeof) != null) {
- List types =
- extractor.getURIs(element, getAttributeByName(element, Constants.typeof), context);
- for (String type : types) {
- emitTriples(newSubject, Constants.rdfType, type);
- }
- }
-
- if (currentObject != null) {
- if (getAttributeByName(element, Constants.rel) != null) {
- emitTriples(
- newSubject,
- extractor.getURIs(element, getAttributeByName(element, Constants.rel), context),
- currentObject);
- }
- if (getAttributeByName(element, Constants.rev) != null) {
- emitTriples(
- currentObject,
- extractor.getURIs(element, getAttributeByName(element, Constants.rev), context),
- newSubject);
- }
- } else {
- if (getAttributeByName(element, Constants.rel) != null) {
- forwardProperties.addAll(
- extractor.getURIs(element, getAttributeByName(element, Constants.rel), context));
- }
- if (getAttributeByName(element, Constants.rev) != null) {
- backwardProperties.addAll(
- extractor.getURIs(element, getAttributeByName(element, Constants.rev), context));
- }
- if (!forwardProperties.isEmpty() || !backwardProperties.isEmpty()) {
- // if predicate present
- currentObject = createBNode();
- }
- }
-
- // Getting literal values. Complicated!
- if (getAttributeByName(element, Constants.property) != null) {
- List props =
- extractor.getURIs(element, getAttributeByName(element, Constants.property), context);
- String dt = getDatatype(element);
- if (getAttributeByName(element, Constants.content) != null) { // The
- // easy
- // bit
- String lex = getAttributeByName(element, Constants.content).getValue();
- if (dt == null || dt.length() == 0) {
- emitTriplesPlainLiteral(newSubject, props, lex, currentLanguage);
- } else {
- emitTriplesDatatypeLiteral(newSubject, props, lex, dt);
- }
- } else {
- literalCollector.collect(newSubject, props, dt, currentLanguage);
- }
- }
-
- if (!skipElement && newSubject != null) {
- emitTriples(context.parentSubject, context.forwardProperties, newSubject);
-
- emitTriples(newSubject, context.backwardProperties, context.parentSubject);
- }
-
- EvalContext ec = new EvalContext(context);
- if (skipElement) {
- ec.language = currentLanguage;
- } else {
- if (newSubject != null) {
- ec.parentSubject = newSubject;
- } else {
- ec.parentSubject = context.parentSubject;
- }
-
- if (currentObject != null) {
- ec.parentObject = currentObject;
- } else if (newSubject != null) {
- ec.parentObject = newSubject;
- } else {
- ec.parentObject = context.parentSubject;
- }
-
- ec.language = currentLanguage;
- ec.forwardProperties = forwardProperties;
- ec.backwardProperties = backwardProperties;
- }
- return ec;
- }
-
- private void getNamespaces(Attributes attrs) {
- for (int i = 0; i < attrs.getLength(); i++) {
- String qname = attrs.getQName(i);
- String prefix = getPrefix(qname);
- if ("xmlns".equals(prefix)) {
- String pre = getLocal(prefix, qname);
- String uri = attrs.getValue(i);
- if (!settings.contains(Setting.ManualNamespaces) && pre.contains("_"))
- continue; // not permitted
- context.setNamespaceURI(pre, uri);
- extractor.setNamespaceURI(pre, uri);
- sink.addPrefix(pre, uri);
- }
- }
- }
-
- private String getPrefix(String qname) {
- if (!qname.contains(":")) {
- return "";
- }
- return qname.substring(0, qname.indexOf(":"));
- }
-
- private String getLocal(String prefix, String qname) {
- if (prefix.length() == 0) {
- return qname;
- }
- return qname.substring(prefix.length() + 1);
- }
-
- private Iterator fromAttributes(Attributes attributes) {
- List toReturn = new ArrayList<>();
-
- for (int i = 0; i < attributes.getLength(); i++) {
- String qname = attributes.getQName(i);
- String prefix = qname.contains(":") ? qname.substring(0, qname.indexOf(":")) : "";
- Attribute attr =
- eventFactory.createAttribute(
- prefix, attributes.getURI(i), attributes.getLocalName(i), attributes.getValue(i));
-
- if (!qname.equals("xmlns") && !qname.startsWith("xmlns:")) toReturn.add(attr);
- }
-
- return toReturn.iterator();
- }
-
- private Attribute findAttribute(StartElement element, QName... names) {
- for (QName aName : names) {
- Attribute a = getAttributeByName(element, aName);
- if (a != null) {
- return a;
- }
- }
- return null;
- }
-
- private void parsePrefixes(String value, EvalContext context) {
- String[] parts = value.split("\\s+");
- for (int i = 0; i < parts.length; i += 2) {
- String prefix = parts[i];
- if (i + 1 < parts.length && prefix.endsWith(":")) {
- String prefixFix = prefix.substring(0, prefix.length() - 1);
- context.setPrefix(prefixFix, parts[i + 1]);
- sink.addPrefix(prefixFix, parts[i + 1]);
- }
- }
- }
-
- private Attribute getAttributeByName(StartElement element, QName name) {
- if (name == null || element == null) {
- return null;
- }
- Iterator it = element.getAttributes();
- while (it.hasNext()) {
- Attribute at = it.next();
- if (Util.qNameEquals(at.getName(), name)) {
- return at;
- }
- }
- return null;
- }
-
- int bnodeId = 0;
-
- private String createBNode() // TODO probably broken? Can you write bnodes
- // in rdfa directly?
- {
- return "_:node" + (bnodeId++);
- }
-
- private String getDatatype(StartElement element) {
- Attribute de = getAttributeByName(element, Constants.datatype);
- if (de == null) {
- return null;
- }
- String dt = de.getValue();
- if (dt.length() == 0) {
- return dt;
- }
- return extractor.expandCURIE(element, dt, context);
- }
-}
diff --git a/odfdom/src/main/java/org/odftoolkit/odfdom/pkg/rdfa/SAXRDFaParser.java b/odfdom/src/main/java/org/odftoolkit/odfdom/pkg/rdfa/SAXRDFaParser.java
deleted file mode 100644
index 6b76916886..0000000000
--- a/odfdom/src/main/java/org/odftoolkit/odfdom/pkg/rdfa/SAXRDFaParser.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/**
- * **********************************************************************
- *
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
- *
- *
Copyright 2008, 2010 Oracle and/or its affiliates. All rights reserved.
- *
- *
Use is subject to license terms.
- *
- *
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- * http://www.apache.org/licenses/LICENSE-2.0. You can also obtain a copy of the License at
- * http://odftoolkit.org/docs/license.txt
- *
- *
Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
- * express or implied.
- *
- *
See the License for the specific language governing permissions and limitations under the
- * License.
- *
- *
**********************************************************************
- */
-package org.odftoolkit.odfdom.pkg.rdfa;
-
-import java.util.Collection;
-import javax.xml.stream.XMLEventFactory;
-import javax.xml.stream.XMLOutputFactory;
-import javax.xml.stream.events.XMLEvent;
-import net.rootdev.javardfa.uri.IRIResolver;
-import org.xml.sax.Attributes;
-import org.xml.sax.Locator;
-import org.xml.sax.SAXException;
-
-/** A RDFa parser for SAX */
-public class SAXRDFaParser extends RDFaParser {
-
- public static SAXRDFaParser createInstance(JenaSink sink) {
- URIExtractor extractor = new URIExtractorImpl(new IRIResolver(), true);
- sink.setExtractor(extractor);
- return new SAXRDFaParser(
- sink, XMLOutputFactory.newInstance(), XMLEventFactory.newInstance(), extractor);
- }
-
- private SAXRDFaParser(
- JenaSink sink,
- XMLOutputFactory outputFactory,
- XMLEventFactory eventFactory,
- URIExtractor extractor) {
- super(sink, outputFactory, eventFactory, extractor);
- }
-
- public void emitTriples(String subj, Collection props, String obj) {
- for (String prop : props) {
- sink.addObject(subj, prop, obj);
- }
- }
-
- public void emitTriplesPlainLiteral(
- String subj, Collection props, String lex, String language) {
- for (String prop : props) {
- sink.addLiteral(subj, prop, lex, language, null);
- }
- }
-
- public void emitTriplesDatatypeLiteral(
- String subj, Collection props, String lex, String datatype) {
- for (String prop : props) {
- sink.addLiteral(subj, prop, lex, null, datatype);
- }
- }
-
- public void setDocumentLocator(Locator arg0) {
- this.locator = arg0;
- if (locator.getSystemId() != null) this.setBase(arg0.getSystemId());
- }
-
- public void startDocument() throws SAXException {
- sink.start();
- }
-
- public void endDocument() throws SAXException {
- sink.end();
- sink.setContext(context);
- }
-
- public void startPrefixMapping(String arg0, String arg1) throws SAXException {
- context.setNamespaceURI(arg0, arg1);
- extractor.setNamespaceURI(arg0, arg1);
- sink.addPrefix(arg0, arg1);
- }
-
- public void endPrefixMapping(String arg0) throws SAXException {}
-
- public void startElement(String arg0, String localname, String qname, Attributes arg3)
- throws SAXException {
- super.beginRDFaElement(arg0, localname, qname, arg3);
- }
-
- public void endElement(String arg0, String localname, String qname) throws SAXException {
- super.endRDFaElement(arg0, localname, qname);
- }
-
- public void characters(char[] arg0, int arg1, int arg2) throws SAXException {
- super.writeCharacters(String.valueOf(arg0, arg1, arg2));
- }
-
- public void ignorableWhitespace(char[] arg0, int arg1, int arg2) throws SAXException {
- // System.err.println("Whitespace...");
- if (literalCollector.isCollecting()) {
- XMLEvent e = eventFactory.createIgnorableSpace(String.valueOf(arg0, arg1, arg2));
- literalCollector.handleEvent(e);
- }
- }
-
- public void processingInstruction(String arg0, String arg1) throws SAXException {}
-
- public void skippedEntity(String arg0) throws SAXException {}
-}
-
-/*
- * (c) Copyright 2009 University of Bristol All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer. 2. Redistributions in
- * binary form must reproduce the above copyright notice, this list of
- * conditions and the following disclaimer in the documentation and/or other
- * materials provided with the distribution. 3. The name of the author may not
- * be used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
diff --git a/odfdom/src/main/java/org/odftoolkit/odfdom/pkg/rdfa/URIExtractor.java b/odfdom/src/main/java/org/odftoolkit/odfdom/pkg/rdfa/URIExtractor.java
deleted file mode 100644
index e95ec8b4a1..0000000000
--- a/odfdom/src/main/java/org/odftoolkit/odfdom/pkg/rdfa/URIExtractor.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/**
- * **********************************************************************
- *
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
- *
- *
Copyright 2008, 2010 Oracle and/or its affiliates. All rights reserved.
- *
- *
Use is subject to license terms.
- *
- *
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- * http://www.apache.org/licenses/LICENSE-2.0. You can also obtain a copy of the License at
- * http://odftoolkit.org/docs/license.txt
- *
- *
Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
- * express or implied.
- *
- *
See the License for the specific language governing permissions and limitations under the
- * License.
- *
- *
**********************************************************************
- */
-package org.odftoolkit.odfdom.pkg.rdfa;
-
-import java.util.List;
-import java.util.Set;
-import javax.xml.stream.events.Attribute;
-import javax.xml.stream.events.StartElement;
-import net.rootdev.javardfa.Setting;
-
-/** URIExtractor modified from net.rootdev.javardfa.uri.URIExtractor */
-public interface URIExtractor {
-
- void setSettings(Set settings);
-
- String expandCURIE(StartElement element, String value, EvalContext context);
-
- String expandSafeCURIE(StartElement element, String value, EvalContext context);
-
- String getURI(StartElement element, Attribute attr, EvalContext context);
-
- List getURIs(StartElement element, Attribute attr, EvalContext context);
-
- String resolveURI(String uri, EvalContext context);
-
- void setForSAX(boolean isForSAX);
-
- void setNamespaceURI(String prefix, String namespaceURI);
-}
-
-/*
- * (c) Copyright 2009 University of Bristol All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer. 2. Redistributions in
- * binary form must reproduce the above copyright notice, this list of
- * conditions and the following disclaimer in the documentation and/or other
- * materials provided with the distribution. 3. The name of the author may not
- * be used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
diff --git a/odfdom/src/main/java/org/odftoolkit/odfdom/pkg/rdfa/URIExtractorImpl.java b/odfdom/src/main/java/org/odftoolkit/odfdom/pkg/rdfa/URIExtractorImpl.java
deleted file mode 100644
index f4e79349c4..0000000000
--- a/odfdom/src/main/java/org/odftoolkit/odfdom/pkg/rdfa/URIExtractorImpl.java
+++ /dev/null
@@ -1,202 +0,0 @@
-/**
- * **********************************************************************
- *
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
- *
- *
Copyright 2008, 2010 Oracle and/or its affiliates. All rights reserved.
- *
- *
Use is subject to license terms.
- *
- *
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of the License at
- * http://www.apache.org/licenses/LICENSE-2.0. You can also obtain a copy of the License at
- * http://odftoolkit.org/docs/license.txt
- *
- *
Unless required by applicable law or agreed to in writing, software distributed under the
- * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
- * express or implied.
- *
- *
See the License for the specific language governing permissions and limitations under the
- * License.
- *
- *
**********************************************************************
- */
-package org.odftoolkit.odfdom.pkg.rdfa;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import javax.xml.namespace.QName;
-import javax.xml.stream.events.Attribute;
-import javax.xml.stream.events.StartElement;
-import net.rootdev.javardfa.Constants;
-import net.rootdev.javardfa.Resolver;
-import net.rootdev.javardfa.Setting;
-import org.apache.commons.validator.routines.UrlValidator;
-
-/** URIExtractorImpl modified from net.rootdev.javardfa.uri.URIExtractor */
-class URIExtractorImpl implements URIExtractor {
- private Set settings;
- private final Resolver resolver;
- private Map xmlnsMap = Collections.emptyMap();
- private boolean isForSAX;
- private UrlValidator urlValidator;
-
- public URIExtractorImpl(Resolver resolver, boolean isForSAX) {
- this.resolver = resolver;
- this.isForSAX = isForSAX;
- this.urlValidator = new UrlValidator();
- }
-
- public void setForSAX(boolean isForSAX) {
- this.isForSAX = isForSAX;
- }
-
- public void setSettings(Set settings) {
- this.settings = settings;
- }
-
- public String getURI(StartElement element, Attribute attr, EvalContext context) {
- QName attrName = attr.getName();
- if (Util.qNameEquals(attrName, Constants.about)) // Safe CURIE or URI
- {
- return expandSafeCURIE(element, attr.getValue(), context);
- }
- if (Util.qNameEquals(attrName, Constants.datatype)) // A CURIE
- {
- return expandCURIE(element, attr.getValue(), context);
- }
- throw new RuntimeException("Unexpected attribute: " + attr);
- }
-
- private boolean isValidURI(String uri) {
- return this.urlValidator.isValid(uri);
- }
-
- public List getURIs(StartElement element, Attribute attr, EvalContext context) {
-
- List uris = new ArrayList<>();
-
- String[] curies = attr.getValue().split("\\s+");
- boolean permitReserved =
- Util.qNameEquals(Constants.rel, attr.getName())
- || Util.qNameEquals(Constants.rev, attr.getName());
- for (String curie : curies) {
- if (Constants.SpecialRels.contains(curie.toLowerCase())) {
- if (permitReserved) uris.add("http://www.w3.org/1999/xhtml/vocab#" + curie.toLowerCase());
- } else {
- String uri = expandCURIE(element, curie, context);
- if (uri != null) {
- uris.add(uri);
- }
- }
- }
- return uris;
- }
-
- public String expandCURIE(StartElement element, String value, EvalContext context) {
-
- if (value.startsWith("_:")) {
- if (!settings.contains(Setting.ManualNamespaces)) return value;
- if (element.getNamespaceURI("_") == null) return value;
- }
- if (settings.contains(Setting.FormMode)
- && // variable
- value.startsWith("?")) {
- return value;
- }
- int offset = value.indexOf(":") + 1;
- if (offset == 0) {
- return null;
- }
- String prefix = value.substring(0, offset - 1);
-
- // Apparently these are not allowed to expand
- if ("xml".equals(prefix) || "xmlns".equals(prefix)) return null;
-
- String namespaceURI = null;
- if (prefix.length() == 0) {
- namespaceURI = "http://www.w3.org/1999/xhtml/vocab#";
- } else {
- namespaceURI = element.getNamespaceURI(prefix);
- if (isForSAX) {
- if (namespaceURI != null) {
- if (xmlnsMap == Collections.EMPTY_MAP) xmlnsMap = new HashMap<>();
- xmlnsMap.put(prefix, namespaceURI);
- }
- } else {
- if (namespaceURI == null) {
- namespaceURI = xmlnsMap.get(prefix);
- }
- }
- }
- if (namespaceURI == null) {
- return null;
- // throw new RuntimeException("Unknown prefix: " + prefix);
- }
-
- return namespaceURI + value.substring(offset);
- }
-
- @Override
- public String expandSafeCURIE(StartElement element, String value, EvalContext context) {
- if (value.startsWith("[") && value.endsWith("]")) {
- return expandCURIE(element, value.substring(1, value.length() - 1), context);
- } else {
- if (value.length() == 0) {
- return context.getBase();
- }
-
- if (settings.contains(Setting.FormMode) && value.startsWith("?")) {
- return value;
- }
-
- // earlier "return resolver.resolve(context.getBase(), value);"
- // now has JENA problem with '/' slash as base URL
- // > Code: 57/REQUIRED_COMPONENT_MISSING in SCHEME: A component that is required by the
- // scheme is missing.
- return value;
- }
- }
-
- public String resolveURI(String uri, EvalContext context) {
- return resolver.resolve(context.getBase(), uri);
- }
-
- public String getNamespaceURI(String prefix) {
- return xmlnsMap.getOrDefault(prefix, null);
- }
-
- public void setNamespaceURI(String prefix, String namespaceURI) {
- if (xmlnsMap == Collections.EMPTY_MAP) xmlnsMap = new HashMap<>();
- xmlnsMap.put(prefix, namespaceURI);
- }
-}
-
-/*
- * (c) Copyright 2009 University of Bristol All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer. 2. Redistributions in
- * binary form must reproduce the above copyright notice, this list of
- * conditions and the following disclaimer in the documentation and/or other
- * materials provided with the distribution. 3. The name of the author may not
- * be used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
- * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
diff --git a/odfdom/src/main/java/org/odftoolkit/odfdom/pkg/rdfa/package-info.java b/odfdom/src/main/java/org/odftoolkit/odfdom/pkg/rdfa/package-info.java
new file mode 100644
index 0000000000..131529322a
--- /dev/null
+++ b/odfdom/src/main/java/org/odftoolkit/odfdom/pkg/rdfa/package-info.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2026 The Document Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Support for ODF in-content metadata, i.e. RDF statements attached to elements of the
+ * content.xml and styles.xml files.
+ *
+ * In-content metadata in ODF
+ *
+ * Besides RDF/XML files registered in the package's manifest.rdf (ODF 1.2 Part 3,
+ * "Metadata Manifest"), ODF allows RDF metadata within the document content (ODF 1.2 Part 1,
+ * §4.2.1 "In Content Metadata (RDFa)"). It borrows four attributes and their data types from
+ * RDFa 1.0: xhtml:about, xhtml:property, xhtml:datatype
+ * and xhtml:content. Unlike RDFa in XHTML, the ODF schema only allows them on a few
+ * elements and always demands xhtml:about and xhtml:property together.
+ * Other RDFa attributes like rel, rev, typeof or
+ * resource and the RDFa inheritance of subjects between nested elements do not exist in
+ * ODF. For example, the paragraph
+ *
+ *
+ * <text:p xhtml:about="[dbpedia:J._K._Rowling]" xhtml:property="dbpprop:birthDate"
+ * xhtml:datatype="xsd:date" xhtml:content="1965-07-31">July 31st, 1965</text:p>
+ *
+ *
+ * states the RDF statement <http://dbpedia.org/page/J._K._Rowling>
+ * <http://dbpedia.org/property/birthDate> "1965-07-31"^^xsd:date, given the
+ * corresponding namespace declarations. The detailed rules are documented at {@link
+ * org.odftoolkit.odfdom.pkg.rdfa.InContentMetadata}.
+ *
+ * Two ways of retrieving in-content metadata
+ *
+ *
+ * - From the XML files by GRDDL: {@link
+ * org.odftoolkit.odfdom.dom.OdfSchemaDocument#getInContentMetadata()} and {@link
+ * org.odftoolkit.odfdom.dom.OdfSchemaDocument#getRDFMetadata()} transform the XML files
+ * with the XSLT stylesheet
grddl/odf2rdf.xsl into RDF/XML, which Jena parses.
+ * This way does not use this package, except for {@link
+ * org.odftoolkit.odfdom.pkg.rdfa.Util}, and reflects the content as stored in the package.
+ * - From the DOM: {@link
+ * org.odftoolkit.odfdom.dom.OdfSchemaDocument#getInContentMetadataFromCache()} merges the
+ * per element cache of each XML file, see {@link
+ * org.odftoolkit.odfdom.pkg.OdfFileDom#getInContentMetadataCache()}. This way reflects the
+ * current state of the DOM, including changes not yet saved. The metadata of bookmarks is
+ * available by {@link org.odftoolkit.odfdom.pkg.OdfFileDom#getBookmarkRDFMetadata()} and
+ * {@link org.odftoolkit.odfdom.dom.rdfa.BookmarkRDFMetadataExtractor}.
+ *
+ *
+ * Life cycle of the DOM cache
+ *
+ * The cache is created, when it is first requested, by a single traversal of the DOM with
+ * {@link org.odftoolkit.odfdom.pkg.rdfa.InContentMetadata#collect(org.w3c.dom.Node,
+ * java.util.Map)}. Loading a document therefore costs nothing for users not interested in RDF.
+ * Afterwards, the generated classes of the six elements allowing in-content metadata keep the
+ * cache up to date: they call {@link
+ * org.odftoolkit.odfdom.pkg.OdfFileDom#updateInContentMetadataCache(org.w3c.dom.Node)} when
+ * their text content is replaced or when they are inserted into the DOM, and remove their entry
+ * when they are removed from the DOM. Other changes, like setting an xhtml:*
+ * attribute or changing the text of a descendant element, require an explicit call of {@link
+ * org.odftoolkit.odfdom.pkg.OdfFileDom#updateInContentMetadataCache(org.w3c.dom.Node)}.
+ *
+ *
History
+ *
+ * Up to ODFDOM 0.13.0, the DOM cache was filled by a modified copy of the general purpose RDFa
+ * 1.0 parser net.rootdev:java-rdfa:1.0.0-BETA1, which ran as a second SAX handler
+ * while loading every XML file. That library is no longer maintained and depends on the
+ * jena-iri library, which Apache Jena 6 no longer provides. As ODF only uses the small,
+ * self-contained subset of RDFa described above, it is now implemented by {@link
+ * org.odftoolkit.odfdom.pkg.rdfa.InContentMetadata} directly. The following public classes of
+ * this package, which were only used internally for the RDFa parsing, have been removed:
+ * DOMAttributes, DOMRDFaParser, JenaSink,
+ * MultiContentHandler, SAXRDFaParser and URIExtractor, together
+ * with OdfFileDom.getSink() and OdfFileSaxHandler.setSink(JenaSink).
+ * The API returning Jena models is unchanged.
+ */
+package org.odftoolkit.odfdom.pkg.rdfa;
diff --git a/odfdom/src/test/java/org/odftoolkit/odfdom/pkg/RDFMetadataTest.java b/odfdom/src/test/java/org/odftoolkit/odfdom/pkg/RDFMetadataTest.java
index 5cda820df2..8844527ae7 100644
--- a/odfdom/src/test/java/org/odftoolkit/odfdom/pkg/RDFMetadataTest.java
+++ b/odfdom/src/test/java/org/odftoolkit/odfdom/pkg/RDFMetadataTest.java
@@ -23,15 +23,23 @@
*/
package org.odftoolkit.odfdom.pkg;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
import java.util.logging.Logger;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import junit.framework.TestCase;
+import org.apache.jena.rdf.model.Literal;
import org.apache.jena.rdf.model.Model;
+import org.apache.jena.rdf.model.ModelFactory;
+import org.apache.jena.rdf.model.Resource;
import org.junit.Test;
import org.odftoolkit.odfdom.doc.OdfDocument;
import org.odftoolkit.odfdom.doc.OdfTextDocument;
import org.odftoolkit.odfdom.dom.OdfContentDom;
+import org.odftoolkit.odfdom.dom.element.office.OfficeTextElement;
+import org.odftoolkit.odfdom.dom.element.text.TextHElement;
+import org.odftoolkit.odfdom.dom.element.text.TextPElement;
import org.odftoolkit.odfdom.dom.element.text.TextBookmarkStartElement;
import org.odftoolkit.odfdom.dom.rdfa.BookmarkRDFMetadataExtractor;
import org.odftoolkit.odfdom.utils.ResourceUtilities;
@@ -41,6 +49,43 @@ public class RDFMetadataTest {
private static final Logger LOG = Logger.getLogger(RDFMetadataTest.class.getName());
private static final String SIMPLE_ODT = "test_rdfmeta.odt";
+ // Refs #445: Jena 6 needs ARQ to preserve RDF/XML metadata support.
+ @Test
+ public void testRdfXmlRoundTrip() {
+ Model original = ModelFactory.createDefaultModel();
+ Model restored = ModelFactory.createDefaultModel();
+ try {
+ Resource document = original.createResource("https://example.org/document.odt");
+ Resource creator = original.createResource();
+ original.add(
+ document,
+ original.createProperty("http://purl.org/dc/elements/1.1/title"),
+ original.createLiteral("Grüße aus Berlin – 東京", "de"));
+ original.add(
+ document, original.createProperty("http://purl.org/dc/elements/1.1/creator"), creator);
+ original.add(
+ creator,
+ original.createProperty("http://xmlns.com/foaf/0.1/name"),
+ original.createLiteral("Zoë"));
+
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
+ original.write(output, "RDF/XML");
+ restored.read(new ByteArrayInputStream(output.toByteArray()), null, "RDF/XML");
+
+ TestCase.assertTrue(
+ "RDF/XML round-trip must preserve the RDF graph", original.isIsomorphicWith(restored));
+ TestCase.assertEquals(
+ "de",
+ restored.getRequiredProperty(
+ restored.getResource(document.getURI()),
+ restored.createProperty("http://purl.org/dc/elements/1.1/title"))
+ .getLanguage());
+ } finally {
+ restored.close();
+ original.close();
+ }
+ }
+
@Test
public void testGetRDFMetaFromGRDDLXSLT() throws Exception {
OdfTextDocument odt =
@@ -273,4 +318,64 @@ public void testGetBookmarkRDFMetadata() throws Exception {
m = extractor.getBookmarkRDFMetadata(tm);
TestCase.assertEquals(1, m.size());
}
+
+ /**
+ * The DOM cache of in-content metadata is built on demand and follows insertions, text changes
+ * and removals of elements carrying RDFa attributes.
+ */
+ @Test
+ public void testGetInContentMetadataFromCache() throws Exception {
+ OdfTextDocument odt =
+ (OdfTextDocument)
+ OdfDocument.loadDocument(ResourceUtilities.getAbsoluteInputPath(SIMPLE_ODT));
+ Model m = odt.getInContentMetadataFromCache();
+ // the of the document; its nested bookmarks are covered by getBookmarkRDFMetadata()
+ TestCase.assertEquals(1, m.size());
+ TestCase.assertEquals(
+ "John Ronald Reuel Tolkien",
+ m.getRequiredProperty(
+ m.getResource("http://dbpedia.org/page/J._R._R._Tolkien"),
+ m.getProperty("http://www.w3.org/2006/vcard/ns#fn"))
+ .getString());
+
+ // safe CURIE subject, two predicates, a typed literal and xhtml:content overriding the text
+ OdfContentDom contentDom = odt.getContentDom();
+ OfficeTextElement text = odt.getContentRoot();
+ TextPElement p = contentDom.newOdfElement(TextPElement.class);
+ p.setXhtmlAboutAttribute("[dbpedia:J._K._Rowling]");
+ p.setXhtmlPropertyAttribute("dbpprop:birthDate dbpprop:dateOfBirth");
+ p.setXhtmlDatatypeAttribute("xsd:date");
+ p.setXhtmlContentAttribute("1965-07-31");
+ p.setTextContent("July 31st, 1965");
+ text.appendChild(p);
+ Model pModel = contentDom.getInContentMetadataCache().get(p);
+ TestCase.assertEquals(2, pModel.size());
+ Resource rowling = pModel.getResource("http://dbpedia.org/page/J._K._Rowling");
+ for (String property : new String[] {"birthDate", "dateOfBirth"}) {
+ String predicate = "http://dbpedia.org/property/" + property;
+ Literal date =
+ pModel.getRequiredProperty(rowling, pModel.getProperty(predicate)).getLiteral();
+ TestCase.assertEquals("1965-07-31", date.getLexicalForm());
+ TestCase.assertEquals("http://www.w3.org/2001/XMLSchema#date", date.getDatatypeURI());
+ }
+ TestCase.assertEquals(3, odt.getInContentMetadataFromCache().size());
+
+ // the element text is the literal, replacing the text updates the cache
+ TextHElement h = contentDom.newOdfElement(TextHElement.class);
+ h.setXhtmlAboutAttribute("http://dbpedia.org/page/J._K._Rowling");
+ h.setXhtmlPropertyAttribute("dbpprop:children");
+ h.setXhtmlDatatypeAttribute("xsd:integer");
+ h.setTextContent("2");
+ text.appendChild(h);
+ h.setTextContent(" 3 ");
+ Model hModel = contentDom.getInContentMetadataCache().get(h);
+ TestCase.assertEquals(1, hModel.size());
+ TestCase.assertEquals(
+ "3", hModel.listStatements().nextStatement().getLiteral().getLexicalForm());
+
+ // removed elements take their statements with them
+ text.removeChild(p);
+ text.removeChild(h);
+ TestCase.assertEquals(1, odt.getInContentMetadataFromCache().size());
+ }
}
diff --git a/pom.xml b/pom.xml
index 6c79ba9769..1eeeb2dffc 100644
--- a/pom.xml
+++ b/pom.xml
@@ -34,10 +34,11 @@
Copyright © {inceptionYear}–2018 Apache Software Foundation; Copyright © 2018–${currentYear} {organizationName}. All rights reserved.
UTF-8
- 17
+ 21
- 17
- 17
+ 21
+ 21
+ 6.2.0
${basedir}/target/release
${release.dir}/${project.version}/binaries
@@ -73,11 +74,6 @@
Making version management easy and consistent! -->
-
- commons-validator
- commons-validator
- 1.10.1
-
commons-fileupload
commons-fileupload
@@ -93,11 +89,6 @@
msv-core
2022.7
-
- net.rootdev
- java-rdfa
- 1.0.0-BETA1
-
org.apache.ant
ant
@@ -107,7 +98,13 @@
org.apache.jena
jena-core
- 5.6.0
+ ${jena.version}
+
+
+
+ org.apache.jena
+ jena-arq
+ ${jena.version}
diff --git a/taglets/.project b/taglets/.project
index eec8a43cae..106eae5742 100644
--- a/taglets/.project
+++ b/taglets/.project
@@ -22,12 +22,12 @@
- 1659282302483
+ 1790677806659
30
org.eclipse.core.resources.regexFilterMatcher
- node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__
+ node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__
diff --git a/validator/.project b/validator/.project
index 325a5959bf..5d16429e17 100644
--- a/validator/.project
+++ b/validator/.project
@@ -29,12 +29,12 @@
- 1659282302451
+ 1790677806652
30
org.eclipse.core.resources.regexFilterMatcher
- node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__
+ node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__
diff --git a/xslt-runner/.project b/xslt-runner/.project
index e3521ac9c7..28ec205880 100644
--- a/xslt-runner/.project
+++ b/xslt-runner/.project
@@ -22,12 +22,12 @@
- 1659282302490
+ 1790677806660
30
org.eclipse.core.resources.regexFilterMatcher
- node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__
+ node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__