commit c888c5f681d4543cbe2bf969c5476a5c3b94f973
parent 6443a512e21466244f7dc9fdefe40812cf87fc77
Author: Dan Callaghan <djc@djc.id.au>
Date: Sun, 16 May 2010 16:30:22 +1000
changed group/package to au.id.djc
--HG--
rename : src/main/antlr3/au/com/miskinhill/rdftemplate/selector/Selector.g => src/main/antlr3/au/id/djc/rdftemplate/selector/Selector.g
rename : src/main/java/au/com/miskinhill/rdftemplate/ContentAction.java => src/main/java/au/id/djc/rdftemplate/ContentAction.java
rename : src/main/java/au/com/miskinhill/rdftemplate/ForAction.java => src/main/java/au/id/djc/rdftemplate/ForAction.java
rename : src/main/java/au/com/miskinhill/rdftemplate/IfAction.java => src/main/java/au/id/djc/rdftemplate/IfAction.java
rename : src/main/java/au/com/miskinhill/rdftemplate/JoinAction.java => src/main/java/au/id/djc/rdftemplate/JoinAction.java
rename : src/main/java/au/com/miskinhill/rdftemplate/TemplateAction.java => src/main/java/au/id/djc/rdftemplate/TemplateAction.java
rename : src/main/java/au/com/miskinhill/rdftemplate/TemplateInterpolationException.java => src/main/java/au/id/djc/rdftemplate/TemplateInterpolationException.java
rename : src/main/java/au/com/miskinhill/rdftemplate/TemplateInterpolator.java => src/main/java/au/id/djc/rdftemplate/TemplateInterpolator.java
rename : src/main/java/au/com/miskinhill/rdftemplate/TemplateSyntaxException.java => src/main/java/au/id/djc/rdftemplate/TemplateSyntaxException.java
rename : src/main/java/au/com/miskinhill/rdftemplate/XMLStream.java => src/main/java/au/id/djc/rdftemplate/XMLStream.java
rename : src/main/java/au/com/miskinhill/rdftemplate/datatype/DateDataType.java => src/main/java/au/id/djc/rdftemplate/datatype/DateDataType.java
rename : src/main/java/au/com/miskinhill/rdftemplate/datatype/DateTimeDataType.java => src/main/java/au/id/djc/rdftemplate/datatype/DateTimeDataType.java
rename : src/main/java/au/com/miskinhill/rdftemplate/datatype/Year.java => src/main/java/au/id/djc/rdftemplate/datatype/Year.java
rename : src/main/java/au/com/miskinhill/rdftemplate/datatype/YearMonth.java => src/main/java/au/id/djc/rdftemplate/datatype/YearMonth.java
rename : src/main/java/au/com/miskinhill/rdftemplate/selector/AbstractAdaptation.java => src/main/java/au/id/djc/rdftemplate/selector/AbstractAdaptation.java
rename : src/main/java/au/com/miskinhill/rdftemplate/selector/AbstractSelector.java => src/main/java/au/id/djc/rdftemplate/selector/AbstractSelector.java
rename : src/main/java/au/com/miskinhill/rdftemplate/selector/Adaptation.java => src/main/java/au/id/djc/rdftemplate/selector/Adaptation.java
rename : src/main/java/au/com/miskinhill/rdftemplate/selector/AdaptationFactory.java => src/main/java/au/id/djc/rdftemplate/selector/AdaptationFactory.java
rename : src/main/java/au/com/miskinhill/rdftemplate/selector/AntlrSelectorFactory.java => src/main/java/au/id/djc/rdftemplate/selector/AntlrSelectorFactory.java
rename : src/main/java/au/com/miskinhill/rdftemplate/selector/BooleanAndPredicate.java => src/main/java/au/id/djc/rdftemplate/selector/BooleanAndPredicate.java
rename : src/main/java/au/com/miskinhill/rdftemplate/selector/ComparableLiteralValueAdaptation.java => src/main/java/au/id/djc/rdftemplate/selector/ComparableLiteralValueAdaptation.java
rename : src/main/java/au/com/miskinhill/rdftemplate/selector/DefaultAdaptationFactory.java => src/main/java/au/id/djc/rdftemplate/selector/DefaultAdaptationFactory.java
rename : src/main/java/au/com/miskinhill/rdftemplate/selector/DefaultPredicateResolver.java => src/main/java/au/id/djc/rdftemplate/selector/DefaultPredicateResolver.java
rename : src/main/java/au/com/miskinhill/rdftemplate/selector/EternallyCachingSelectorFactory.java => src/main/java/au/id/djc/rdftemplate/selector/EternallyCachingSelectorFactory.java
rename : src/main/java/au/com/miskinhill/rdftemplate/selector/FormattedDateTimeAdaptation.java => src/main/java/au/id/djc/rdftemplate/selector/FormattedDateTimeAdaptation.java
rename : src/main/java/au/com/miskinhill/rdftemplate/selector/InvalidSelectorSyntaxException.java => src/main/java/au/id/djc/rdftemplate/selector/InvalidSelectorSyntaxException.java
rename : src/main/java/au/com/miskinhill/rdftemplate/selector/LiteralValueAdaptation.java => src/main/java/au/id/djc/rdftemplate/selector/LiteralValueAdaptation.java
rename : src/main/java/au/com/miskinhill/rdftemplate/selector/NoopSelector.java => src/main/java/au/id/djc/rdftemplate/selector/NoopSelector.java
rename : src/main/java/au/com/miskinhill/rdftemplate/selector/Predicate.java => src/main/java/au/id/djc/rdftemplate/selector/Predicate.java
rename : src/main/java/au/com/miskinhill/rdftemplate/selector/PredicateResolver.java => src/main/java/au/id/djc/rdftemplate/selector/PredicateResolver.java
rename : src/main/java/au/com/miskinhill/rdftemplate/selector/Selector.java => src/main/java/au/id/djc/rdftemplate/selector/Selector.java
rename : src/main/java/au/com/miskinhill/rdftemplate/selector/SelectorComparator.java => src/main/java/au/id/djc/rdftemplate/selector/SelectorComparator.java
rename : src/main/java/au/com/miskinhill/rdftemplate/selector/SelectorEvaluationException.java => src/main/java/au/id/djc/rdftemplate/selector/SelectorEvaluationException.java
rename : src/main/java/au/com/miskinhill/rdftemplate/selector/SelectorFactory.java => src/main/java/au/id/djc/rdftemplate/selector/SelectorFactory.java
rename : src/main/java/au/com/miskinhill/rdftemplate/selector/SelectorWithAdaptation.java => src/main/java/au/id/djc/rdftemplate/selector/SelectorWithAdaptation.java
rename : src/main/java/au/com/miskinhill/rdftemplate/selector/StringLiteralValueAdaptation.java => src/main/java/au/id/djc/rdftemplate/selector/StringLiteralValueAdaptation.java
rename : src/main/java/au/com/miskinhill/rdftemplate/selector/Traversal.java => src/main/java/au/id/djc/rdftemplate/selector/Traversal.java
rename : src/main/java/au/com/miskinhill/rdftemplate/selector/TraversingSelector.java => src/main/java/au/id/djc/rdftemplate/selector/TraversingSelector.java
rename : src/main/java/au/com/miskinhill/rdftemplate/selector/TypePredicate.java => src/main/java/au/id/djc/rdftemplate/selector/TypePredicate.java
rename : src/main/java/au/com/miskinhill/rdftemplate/selector/UnionSelector.java => src/main/java/au/id/djc/rdftemplate/selector/UnionSelector.java
rename : src/main/java/au/com/miskinhill/rdftemplate/selector/UriAdaptation.java => src/main/java/au/id/djc/rdftemplate/selector/UriAdaptation.java
rename : src/main/java/au/com/miskinhill/rdftemplate/selector/UriAnchorAdaptation.java => src/main/java/au/id/djc/rdftemplate/selector/UriAnchorAdaptation.java
rename : src/main/java/au/com/miskinhill/rdftemplate/selector/UriPrefixPredicate.java => src/main/java/au/id/djc/rdftemplate/selector/UriPrefixPredicate.java
rename : src/main/java/au/com/miskinhill/rdftemplate/selector/UriSliceAdaptation.java => src/main/java/au/id/djc/rdftemplate/selector/UriSliceAdaptation.java
rename : src/main/java/au/com/miskinhill/rdftemplate/view/RDFTemplateView.java => src/main/java/au/id/djc/rdftemplate/view/RDFTemplateView.java
rename : src/main/java/au/com/miskinhill/rdftemplate/view/RDFTemplateViewResolver.java => src/main/java/au/id/djc/rdftemplate/view/RDFTemplateViewResolver.java
rename : src/test/java/au/com/miskinhill/rdftemplate/TemplateInterpolatorUnitTest.java => src/test/java/au/id/djc/rdftemplate/TemplateInterpolatorUnitTest.java
rename : src/test/java/au/com/miskinhill/rdftemplate/TestNamespacePrefixMap.java => src/test/java/au/id/djc/rdftemplate/TestNamespacePrefixMap.java
rename : src/test/java/au/com/miskinhill/rdftemplate/datatype/DateDataTypeUnitTest.java => src/test/java/au/id/djc/rdftemplate/datatype/DateDataTypeUnitTest.java
rename : src/test/java/au/com/miskinhill/rdftemplate/datatype/DateTimeDataTypeUnitTest.java => src/test/java/au/id/djc/rdftemplate/datatype/DateTimeDataTypeUnitTest.java
rename : src/test/java/au/com/miskinhill/rdftemplate/datatype/YearMonthUnitTest.java => src/test/java/au/id/djc/rdftemplate/datatype/YearMonthUnitTest.java
rename : src/test/java/au/com/miskinhill/rdftemplate/datatype/YearUnitTest.java => src/test/java/au/id/djc/rdftemplate/datatype/YearUnitTest.java
rename : src/test/java/au/com/miskinhill/rdftemplate/selector/AdaptationMatcher.java => src/test/java/au/id/djc/rdftemplate/selector/AdaptationMatcher.java
rename : src/test/java/au/com/miskinhill/rdftemplate/selector/BeanPropertyMatcher.java => src/test/java/au/id/djc/rdftemplate/selector/BeanPropertyMatcher.java
rename : src/test/java/au/com/miskinhill/rdftemplate/selector/EternallyCachingSelectorFactoryUnitTest.java => src/test/java/au/id/djc/rdftemplate/selector/EternallyCachingSelectorFactoryUnitTest.java
rename : src/test/java/au/com/miskinhill/rdftemplate/selector/PredicateMatcher.java => src/test/java/au/id/djc/rdftemplate/selector/PredicateMatcher.java
rename : src/test/java/au/com/miskinhill/rdftemplate/selector/SelectorComparatorMatcher.java => src/test/java/au/id/djc/rdftemplate/selector/SelectorComparatorMatcher.java
rename : src/test/java/au/com/miskinhill/rdftemplate/selector/SelectorEvaluationUnitTest.java => src/test/java/au/id/djc/rdftemplate/selector/SelectorEvaluationUnitTest.java
rename : src/test/java/au/com/miskinhill/rdftemplate/selector/SelectorMatcher.java => src/test/java/au/id/djc/rdftemplate/selector/SelectorMatcher.java
rename : src/test/java/au/com/miskinhill/rdftemplate/selector/SelectorParserUnitTest.java => src/test/java/au/id/djc/rdftemplate/selector/SelectorParserUnitTest.java
rename : src/test/java/au/com/miskinhill/rdftemplate/selector/TraversalMatcher.java => src/test/java/au/id/djc/rdftemplate/selector/TraversalMatcher.java
rename : src/test/java/au/com/miskinhill/rdftemplate/selector/UriAnchorAdaptationUnitTest.java => src/test/java/au/id/djc/rdftemplate/selector/UriAnchorAdaptationUnitTest.java
rename : src/test/resources/au/com/miskinhill/rdftemplate/conditional.xml => src/test/resources/au/id/djc/rdftemplate/conditional.xml
rename : src/test/resources/au/com/miskinhill/rdftemplate/for-seq.xml => src/test/resources/au/id/djc/rdftemplate/for-seq.xml
rename : src/test/resources/au/com/miskinhill/rdftemplate/for.xml => src/test/resources/au/id/djc/rdftemplate/for.xml
rename : src/test/resources/au/com/miskinhill/rdftemplate/join-seq.xml => src/test/resources/au/id/djc/rdftemplate/join-seq.xml
rename : src/test/resources/au/com/miskinhill/rdftemplate/join.xml => src/test/resources/au/id/djc/rdftemplate/join.xml
rename : src/test/resources/au/com/miskinhill/rdftemplate/namespaces.xml => src/test/resources/au/id/djc/rdftemplate/namespaces.xml
rename : src/test/resources/au/com/miskinhill/rdftemplate/replace-subtree.xml => src/test/resources/au/id/djc/rdftemplate/replace-subtree.xml
rename : src/test/resources/au/com/miskinhill/rdftemplate/replace-xml.xml => src/test/resources/au/id/djc/rdftemplate/replace-xml.xml
rename : src/test/resources/au/com/miskinhill/rdftemplate/test-data.xml => src/test/resources/au/id/djc/rdftemplate/test-data.xml
Diffstat:
133 files changed, 3187 insertions(+), 3187 deletions(-)
diff --git a/pom.xml b/pom.xml
@@ -1,24 +1,24 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
- <groupId>au.com.miskinhill</groupId>
+ <groupId>au.id.djc</groupId>
<artifactId>rdftemplate</artifactId>
<packaging>jar</packaging>
<version>1.1-SNAPSHOT</version>
<name>rdftemplate</name>
- <url>http://code.miskinhill.com.au/</url>
+ <url>http://code.djc.id.au/</url>
<distributionManagement>
<repository>
- <id>code.miskinhill.com.au</id>
- <name>Miskin Hill Maven repository</name>
- <url>dav:http://code.miskinhill.com.au/maven2/</url>
+ <id>code.djc.id.au</id>
+ <name>code.djc.id.au Maven repository</name>
+ <url>dav:http://code.djc.id.au/maven2/</url>
</repository>
</distributionManagement>
<scm>
- <url>http://code.miskinhill.com.au/hg/</url>
- <connection>scm:hg:http://code.miskinhill.com.au/hg/</connection>
+ <url>http://code.djc.id.au/hg/rdftemplate-master/</url>
+ <connection>scm:hg:http://code.djc.id.au/hg/rdftemplate-master/</connection>
<developerConnection>scm:hg:file://${project.basedir}</developerConnection>
</scm>
diff --git a/src/main/antlr3/au/com/miskinhill/rdftemplate/selector/Selector.g b/src/main/antlr3/au/id/djc/rdftemplate/selector/Selector.g
diff --git a/src/main/java/au/com/miskinhill/rdftemplate/ContentAction.java b/src/main/java/au/com/miskinhill/rdftemplate/ContentAction.java
@@ -1,68 +0,0 @@
-package au.com.miskinhill.rdftemplate;
-
-import java.util.Set;
-
-import javax.xml.XMLConstants;
-import javax.xml.namespace.QName;
-import javax.xml.stream.XMLEventFactory;
-import javax.xml.stream.XMLStreamException;
-import javax.xml.stream.events.Attribute;
-import javax.xml.stream.events.StartElement;
-import javax.xml.stream.util.XMLEventConsumer;
-
-import com.hp.hpl.jena.rdf.model.Literal;
-import com.hp.hpl.jena.rdf.model.RDFNode;
-import org.apache.commons.lang.StringUtils;
-import org.apache.commons.lang.builder.ToStringBuilder;
-
-import au.com.miskinhill.rdftemplate.selector.Selector;
-
-public class ContentAction extends TemplateAction {
-
- public static final String ACTION_NAME = "content";
- public static final QName ACTION_QNAME = new QName(TemplateInterpolator.NS, ACTION_NAME);
- private static final QName XML_LANG_QNAME = new QName(XMLConstants.XML_NS_URI, "lang", XMLConstants.XML_NS_PREFIX);
- private static final String XHTML_NS_URI = "http://www.w3.org/1999/xhtml";
-
- private final StartElement start;
- private final Selector<?> selector;
-
- public ContentAction(StartElement start, Selector<?> selector) {
- this.start = start;
- this.selector = selector;
- }
-
- public void evaluate(TemplateInterpolator interpolator, RDFNode node, XMLEventConsumer writer, XMLEventFactory eventFactory)
- throws XMLStreamException {
- Object replacement = selector.singleResult(node);
- StartElement start = interpolator.interpolateAttributes(this.start, node);
- Set<Attribute> attributes = interpolator.cloneAttributesWithout(start, ACTION_QNAME);
- if (replacement instanceof Literal) {
- Literal literal = (Literal) replacement;
- if (!StringUtils.isEmpty(literal.getLanguage())) {
- attributes.add(eventFactory.createAttribute(XML_LANG_QNAME, ((Literal) replacement).getLanguage()));
- if (start.getName().getNamespaceURI().equals(XHTML_NS_URI)) {
- String xhtmlPrefixInContext = start.getNamespaceContext().getPrefix(XHTML_NS_URI);
- QName xhtmlLangQNameForContext; // ugh
- if (xhtmlPrefixInContext.isEmpty())
- xhtmlLangQNameForContext = new QName("lang");
- else
- xhtmlLangQNameForContext = new QName(XHTML_NS_URI, "lang", xhtmlPrefixInContext);
- attributes.add(eventFactory.createAttribute(xhtmlLangQNameForContext, literal.getLanguage()));
- }
- }
- }
- writer.add(eventFactory.createStartElement(start.getName(), attributes.iterator(), start.getNamespaces()));
- interpolator.writeTreeForContent(writer, replacement);
- writer.add(eventFactory.createEndElement(start.getName(), start.getNamespaces()));
- }
-
- @Override
- public String toString() {
- return new ToStringBuilder(this)
- .append("start", start)
- .append("selector", selector)
- .toString();
- }
-
-}
diff --git a/src/main/java/au/com/miskinhill/rdftemplate/ForAction.java b/src/main/java/au/com/miskinhill/rdftemplate/ForAction.java
@@ -1,55 +0,0 @@
-package au.com.miskinhill.rdftemplate;
-
-import java.util.List;
-import java.util.logging.Logger;
-
-import javax.xml.namespace.QName;
-import javax.xml.stream.XMLStreamException;
-import javax.xml.stream.events.XMLEvent;
-import javax.xml.stream.util.XMLEventConsumer;
-
-import com.hp.hpl.jena.rdf.model.RDFNode;
-import com.hp.hpl.jena.rdf.model.Resource;
-import com.hp.hpl.jena.rdf.model.Seq;
-import com.hp.hpl.jena.vocabulary.RDF;
-import org.apache.commons.lang.builder.ToStringBuilder;
-
-import au.com.miskinhill.rdftemplate.selector.Selector;
-
-public class ForAction extends TemplateAction {
-
- public static final String ACTION_NAME = "for";
- public static final QName ACTION_QNAME = new QName(TemplateInterpolator.NS, ACTION_NAME);
- private static final Logger LOG = Logger.getLogger(ForAction.class.getName());
-
- private final List<XMLEvent> tree;
- private final Selector<RDFNode> selector;
-
- public ForAction(List<XMLEvent> tree, Selector<RDFNode> selector) {
- this.tree = tree;
- this.selector = selector;
- }
-
- public void evaluate(TemplateInterpolator interpolator, RDFNode node, XMLEventConsumer writer)
- throws XMLStreamException {
- List<RDFNode> result = selector.result(node);
- if (result.size() == 1 && result.get(0).canAs(Resource.class)) {
- if (result.get(0).as(Resource.class).hasProperty(RDF.type, RDF.Seq)) {
- LOG.fine("Apply rdf:Seq special case for " + result.get(0));
- result = result.get(0).as(Seq.class).iterator().toList();
- LOG.fine("Resulting sequence is " + result);
- }
- }
- for (RDFNode eachNode: result) {
- interpolator.interpolate(tree.iterator(), eachNode, writer);
- }
- }
-
- @Override
- public String toString() {
- return new ToStringBuilder(this)
- .append("selector", selector)
- .toString();
- }
-
-}
diff --git a/src/main/java/au/com/miskinhill/rdftemplate/IfAction.java b/src/main/java/au/com/miskinhill/rdftemplate/IfAction.java
@@ -1,46 +0,0 @@
-package au.com.miskinhill.rdftemplate;
-
-import java.util.List;
-
-import javax.xml.namespace.QName;
-import javax.xml.stream.XMLStreamException;
-import javax.xml.stream.events.XMLEvent;
-import javax.xml.stream.util.XMLEventConsumer;
-
-import com.hp.hpl.jena.rdf.model.RDFNode;
-import org.apache.commons.lang.builder.ToStringBuilder;
-
-import au.com.miskinhill.rdftemplate.selector.Selector;
-
-public class IfAction extends TemplateAction {
-
- public static final String ACTION_NAME = "if";
- public static final QName ACTION_QNAME = new QName(TemplateInterpolator.NS, ACTION_NAME);
-
- private final List<XMLEvent> tree;
- private final Selector<?> condition;
- private final boolean negate;
-
- public IfAction(List<XMLEvent> tree, Selector<?> condition, boolean negate) {
- this.tree = tree;
- this.condition = condition;
- this.negate = negate;
- }
-
- public void evaluate(TemplateInterpolator interpolator, RDFNode node, XMLEventConsumer writer)
- throws XMLStreamException {
- List<?> selectorResult = condition.result(node);
- if (negate ? selectorResult.isEmpty() : !selectorResult.isEmpty()) {
- interpolator.interpolate(tree.iterator(), node, writer);
- }
- }
-
- @Override
- public String toString() {
- return new ToStringBuilder(this)
- .append("condition", condition)
- .append("negate", negate)
- .toString();
- }
-
-}
diff --git a/src/main/java/au/com/miskinhill/rdftemplate/JoinAction.java b/src/main/java/au/com/miskinhill/rdftemplate/JoinAction.java
@@ -1,64 +0,0 @@
-package au.com.miskinhill.rdftemplate;
-
-import java.util.List;
-import java.util.logging.Logger;
-
-import javax.xml.namespace.QName;
-import javax.xml.stream.XMLEventFactory;
-import javax.xml.stream.XMLStreamException;
-import javax.xml.stream.events.XMLEvent;
-import javax.xml.stream.util.XMLEventConsumer;
-
-import com.hp.hpl.jena.rdf.model.RDFNode;
-import com.hp.hpl.jena.rdf.model.Resource;
-import com.hp.hpl.jena.rdf.model.Seq;
-import com.hp.hpl.jena.vocabulary.RDF;
-import org.apache.commons.lang.builder.ToStringBuilder;
-
-import au.com.miskinhill.rdftemplate.selector.Selector;
-
-public class JoinAction extends TemplateAction {
-
- public static final String ACTION_NAME = "join";
- public static final QName ACTION_QNAME = new QName(TemplateInterpolator.NS, ACTION_NAME);
- private static final Logger LOG = Logger.getLogger(JoinAction.class.getName());
-
- private final List<XMLEvent> tree;
- private final Selector<RDFNode> selector;
- private final String separator;
-
- public JoinAction(List<XMLEvent> tree, Selector<RDFNode> selector, String separator) {
- this.tree = tree;
- this.selector = selector;
- this.separator = separator;
- }
-
- public void evaluate(TemplateInterpolator interpolator, RDFNode node, XMLEventConsumer writer, XMLEventFactory eventFactory)
- throws XMLStreamException {
- List<RDFNode> result = selector.result(node);
- if (result.size() == 1 && result.get(0).canAs(Resource.class)) {
- if (result.get(0).as(Resource.class).hasProperty(RDF.type, RDF.Seq)) {
- LOG.fine("Apply rdf:Seq special case for " + result.get(0));
- result = result.get(0).as(Seq.class).iterator().toList();
- LOG.fine("Resulting sequence is " + result);
- }
- }
- boolean first = true;
- for (RDFNode eachNode: result) {
- if (!first) {
- writer.add(eventFactory.createCharacters(separator));
- }
- interpolator.interpolate(tree.iterator(), eachNode, writer);
- first = false;
- }
- }
-
- @Override
- public String toString() {
- return new ToStringBuilder(this)
- .append("selector", selector)
- .append("separator", separator)
- .toString();
- }
-
-}
diff --git a/src/main/java/au/com/miskinhill/rdftemplate/TemplateAction.java b/src/main/java/au/com/miskinhill/rdftemplate/TemplateAction.java
@@ -1,5 +0,0 @@
-package au.com.miskinhill.rdftemplate;
-
-public abstract class TemplateAction {
-
-}
diff --git a/src/main/java/au/com/miskinhill/rdftemplate/TemplateInterpolationException.java b/src/main/java/au/com/miskinhill/rdftemplate/TemplateInterpolationException.java
@@ -1,23 +0,0 @@
-package au.com.miskinhill.rdftemplate;
-
-import javax.xml.stream.Location;
-
-import com.hp.hpl.jena.rdf.model.RDFNode;
-
-public class TemplateInterpolationException extends RuntimeException {
-
- private static final long serialVersionUID = -1472104970210074672L;
-
- public TemplateInterpolationException(Location location, TemplateAction action, RDFNode node, Throwable cause) {
- super("Exception evaluating action [" + action + "] " +
- "at location [" + location.getLineNumber() + "," + location.getColumnNumber() + "] " +
- "with context node " + node, cause);
- }
-
- public TemplateInterpolationException(Location location, String selectorExpression, RDFNode node, Throwable cause) {
- super("Exception evaluating selector expression [" + selectorExpression + "] " +
- "at location [" + location.getLineNumber() + "," + location.getColumnNumber() + "] " +
- "with context node " + node, cause);
- }
-
-}
diff --git a/src/main/java/au/com/miskinhill/rdftemplate/TemplateInterpolator.java b/src/main/java/au/com/miskinhill/rdftemplate/TemplateInterpolator.java
@@ -1,431 +0,0 @@
-package au.com.miskinhill.rdftemplate;
-
-import java.io.InputStream;
-import java.io.Reader;
-import java.io.StringReader;
-import java.io.StringWriter;
-import java.io.Writer;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Deque;
-import java.util.Iterator;
-import java.util.LinkedHashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import javax.xml.namespace.QName;
-import javax.xml.stream.XMLEventFactory;
-import javax.xml.stream.XMLEventReader;
-import javax.xml.stream.XMLEventWriter;
-import javax.xml.stream.XMLInputFactory;
-import javax.xml.stream.XMLOutputFactory;
-import javax.xml.stream.XMLStreamConstants;
-import javax.xml.stream.XMLStreamException;
-import javax.xml.stream.events.Attribute;
-import javax.xml.stream.events.Characters;
-import javax.xml.stream.events.EndElement;
-import javax.xml.stream.events.Namespace;
-import javax.xml.stream.events.StartElement;
-import javax.xml.stream.events.XMLEvent;
-import javax.xml.stream.util.XMLEventConsumer;
-
-import com.hp.hpl.jena.rdf.model.Literal;
-import com.hp.hpl.jena.rdf.model.RDFNode;
-
-import au.com.miskinhill.rdftemplate.selector.InvalidSelectorSyntaxException;
-import au.com.miskinhill.rdftemplate.selector.Selector;
-import au.com.miskinhill.rdftemplate.selector.SelectorFactory;
-
-public class TemplateInterpolator {
-
- public static final String NS = "http://code.miskinhill.com.au/rdftemplate/";
-
- private final XMLInputFactory inputFactory = XMLInputFactory.newInstance();
- private final XMLOutputFactory outputFactory = XMLOutputFactory.newInstance();
- private final XMLEventFactory eventFactory = XMLEventFactory.newInstance();
-
- private final SelectorFactory selectorFactory;
-
- public TemplateInterpolator(SelectorFactory selectorFactory) {
- this.selectorFactory = selectorFactory;
- inputFactory.setProperty(XMLInputFactory.IS_COALESCING, true);
- outputFactory.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, true);
- }
-
- public String interpolate(Reader reader, RDFNode node) {
- try {
- StringWriter writer = new StringWriter();
- final XMLEventWriter eventWriter = outputFactory.createXMLEventWriter(writer);
- XMLEventConsumer destination = new XMLEventConsumer() {
- @Override
- public void add(XMLEvent event) throws XMLStreamException {
- eventWriter.add(event);
- }
- };
- interpolate(reader, node, destination);
- return writer.toString();
- } catch (XMLStreamException e) {
- throw new TemplateSyntaxException(e);
- }
- }
-
- @SuppressWarnings("unchecked")
- public void interpolate(Reader reader, RDFNode node, XMLEventConsumer writer) {
- try {
- interpolate(inputFactory.createXMLEventReader(reader), node, writer);
- } catch (XMLStreamException e) {
- throw new RuntimeException(e);
- }
- }
-
- @SuppressWarnings("unchecked")
- public void interpolate(InputStream inputStream, RDFNode node, Writer writer) {
- try {
- final XMLEventWriter eventWriter = outputFactory.createXMLEventWriter(writer);
- XMLEventConsumer destination = new XMLEventConsumer() {
- @Override
- public void add(XMLEvent event) throws XMLStreamException {
- eventWriter.add(event);
- }
- };
- interpolate(inputFactory.createXMLEventReader(inputStream), node, destination);
- } catch (XMLStreamException e) {
- throw new RuntimeException(e);
- }
- }
-
- public void interpolate(Reader reader, RDFNode node, final Collection<XMLEvent> destination) {
- interpolate(reader, node, new XMLEventConsumer() {
- @Override
- public void add(XMLEvent event) {
- destination.add(event);
- }
- });
- }
-
- public void interpolate(Iterator<XMLEvent> reader, RDFNode node, XMLEventConsumer writer)
- throws XMLStreamException {
- while (reader.hasNext()) {
- XMLEvent event = reader.next();
- switch (event.getEventType()) {
- case XMLStreamConstants.START_ELEMENT: {
- StartElement start = (StartElement) event;
- if (start.getName().equals(IfAction.ACTION_QNAME)) {
- Attribute testAttribute = start.getAttributeByName(new QName("test"));
- Attribute notAttribute = start.getAttributeByName(new QName("not"));
- String condition;
- boolean negate = false;
- if (testAttribute != null && notAttribute != null)
- throw new TemplateSyntaxException(start.getLocation(), "test and not attribute on rdf:if are mutually exclusive");
- else if (testAttribute != null)
- condition = testAttribute.getValue();
- else if (notAttribute != null) {
- condition = notAttribute.getValue();
- negate = true;
- } else
- throw new TemplateSyntaxException(start.getLocation(), "rdf:if must have a test attribute or a not attribute");
- Selector<?> conditionSelector;
- try {
- conditionSelector = selectorFactory.get(condition);
- } catch (InvalidSelectorSyntaxException e) {
- throw new TemplateSyntaxException(start.getLocation(), e);
- }
- List<XMLEvent> tree = consumeTree(start, reader);
- // discard enclosing rdf:if
- tree.remove(tree.size() - 1);
- tree.remove(0);
- IfAction action = new IfAction(tree, conditionSelector, negate);
- try {
- action.evaluate(this, node, writer);
- } catch (Exception e) {
- throw new TemplateInterpolationException(start.getLocation(), action, node, e);
- }
- } else if (start.getName().equals(JoinAction.ACTION_QNAME)) {
- Attribute eachAttribute = start.getAttributeByName(new QName("each"));
- if (eachAttribute == null)
- throw new TemplateSyntaxException(start.getLocation(), "rdf:join must have an each attribute");
- String separator = "";
- Attribute separatorAttribute = start.getAttributeByName(new QName("separator"));
- if (separatorAttribute != null)
- separator = separatorAttribute.getValue();
- Selector<RDFNode> selector;
- try {
- selector = selectorFactory.get(eachAttribute.getValue()).withResultType(RDFNode.class);
- } catch (InvalidSelectorSyntaxException e) {
- throw new TemplateSyntaxException(start.getLocation(), e);
- }
- List<XMLEvent> events = consumeTree(start, reader);
- // discard enclosing rdf:join
- events.remove(events.size() - 1);
- events.remove(0);
- JoinAction action = new JoinAction(events, selector, separator);
- try {
- action.evaluate(this, node, writer, eventFactory);
- } catch (Exception e) {
- throw new TemplateInterpolationException(start.getLocation(), action, node, e);
- }
- } else if (start.getName().equals(ForAction.ACTION_QNAME)) {
- Attribute eachAttribute = start.getAttributeByName(new QName("each"));
- if (eachAttribute == null)
- throw new TemplateSyntaxException(start.getLocation(), "rdf:for must have an each attribute");
- Selector<RDFNode> selector;
- try {
- selector = selectorFactory.get(eachAttribute.getValue()).withResultType(RDFNode.class);
- } catch (InvalidSelectorSyntaxException e) {
- throw new TemplateSyntaxException(start.getLocation(), e);
- }
- List<XMLEvent> events = consumeTree(start, reader);
- // discard enclosing rdf:for
- events.remove(events.size() - 1);
- events.remove(0);
- ForAction action = new ForAction(events, selector);
- try {
- action.evaluate(this, node, writer);
- } catch (Exception e) {
- throw new TemplateInterpolationException(start.getLocation(), action, node, e);
- }
- } else {
- Attribute ifAttribute = start.getAttributeByName(IfAction.ACTION_QNAME);
- Attribute contentAttribute = start.getAttributeByName(ContentAction.ACTION_QNAME);
- Attribute forAttribute = start.getAttributeByName(ForAction.ACTION_QNAME);
- if (ifAttribute != null) {
- Selector<?> selector;
- try {
- selector = selectorFactory.get(ifAttribute.getValue());
- } catch (InvalidSelectorSyntaxException e) {
- throw new TemplateSyntaxException(ifAttribute.getLocation(), e);
- }
- start = cloneStart(start, cloneAttributesWithout(start, IfAction.ACTION_QNAME), cloneNamespacesWithoutRdf(start));
- IfAction action = new IfAction(consumeTree(start, reader), selector, false);
- action.evaluate(this, node, writer);
- } else if (contentAttribute != null && forAttribute != null) {
- throw new TemplateSyntaxException(start.getLocation(), "rdf:for and rdf:content cannot both be present on an element");
- } else if (contentAttribute != null) {
- consumeTree(start, reader); // discard
- Selector<?> selector;
- try {
- selector = selectorFactory.get(contentAttribute.getValue());
- } catch (InvalidSelectorSyntaxException e) {
- throw new TemplateSyntaxException(contentAttribute.getLocation(), e);
- }
- ContentAction action = new ContentAction(start, selector);
- try {
- action.evaluate(this, node, writer, eventFactory);
- } catch (Exception e) {
- throw new TemplateInterpolationException(contentAttribute.getLocation(), action, node, e);
- }
- } else if (forAttribute != null) {
- Selector<RDFNode> selector;
- try {
- selector = selectorFactory.get(forAttribute.getValue()).withResultType(RDFNode.class);
- } catch (InvalidSelectorSyntaxException e) {
- throw new TemplateSyntaxException(forAttribute.getLocation(), e);
- }
- start = cloneStart(start, cloneAttributesWithout(start, ForAction.ACTION_QNAME), cloneNamespacesWithoutRdf(start));
- List<XMLEvent> tree = consumeTree(start, reader);
- ForAction action = new ForAction(tree, selector);
- try {
- action.evaluate(this, node, writer);
- } catch (Exception e) {
- throw new TemplateInterpolationException(forAttribute.getLocation(), action, node, e);
- }
- } else {
- start = interpolateAttributes(start, node);
- writer.add(start);
- }
- }
- break;
- }
- case XMLStreamConstants.CHARACTERS: {
- Characters characters = (Characters) event;
- interpolateCharacters(writer, characters, node);
- break;
- }
- case XMLStreamConstants.CDATA: {
- Characters characters = (Characters) event;
- interpolateCharacters(writer, characters, node);
- break;
- }
- default:
- writer.add(event);
- }
- }
- }
-
- private List<XMLEvent> consumeTree(StartElement start, Iterator<XMLEvent> reader) throws XMLStreamException {
- List<XMLEvent> events = new ArrayList<XMLEvent>();
- events.add(start);
- Deque<QName> elementStack = new LinkedList<QName>();
- while (reader.hasNext()) {
- XMLEvent event = reader.next();
- events.add(event);
- switch (event.getEventType()) {
- case XMLStreamConstants.START_ELEMENT:
- elementStack.addLast(((StartElement) event).getName());
- break;
- case XMLStreamConstants.END_ELEMENT:
- if (elementStack.isEmpty()) {
- return events;
- } else {
- if (!elementStack.removeLast().equals(((EndElement) event).getName()))
- throw new IllegalStateException("End element mismatch");
- }
- break;
- default:
- }
- }
- throw new IllegalStateException("Reader exhausted before end element found");
- }
-
- @SuppressWarnings("unchecked")
- protected StartElement interpolateAttributes(StartElement start, RDFNode node) {
- Set<Attribute> replacementAttributes = new LinkedHashSet<Attribute>();
- for (Iterator<Attribute> it = start.getAttributes(); it.hasNext(); ) {
- Attribute attribute = it.next();
- String replacementValue = attribute.getValue();
- if (!attribute.getName().getNamespaceURI().equals(NS)) { // skip rdf: attributes
- try {
- replacementValue = interpolateString(attribute.getValue(), node);
- } catch (Exception e) {
- throw new TemplateInterpolationException(attribute.getLocation(), attribute.getValue(), node, e);
- }
- }
- replacementAttributes.add(eventFactory.createAttribute(attribute.getName(),
- replacementValue));
- }
- return cloneStart(start, replacementAttributes, cloneNamespacesWithoutRdf(start));
- }
-
- private StartElement cloneStart(StartElement start, Iterable<Attribute> attributes, Iterable<Namespace> namespaces) {
- return eventFactory.createStartElement(
- start.getName().getPrefix(),
- start.getName().getNamespaceURI(),
- start.getName().getLocalPart(),
- attributes.iterator(),
- namespaces.iterator(),
- start.getNamespaceContext());
- }
-
- @SuppressWarnings("unchecked")
- private Set<Namespace> cloneNamespacesWithoutRdf(StartElement start) {
- Set<Namespace> clonedNamespaces = new LinkedHashSet<Namespace>();
- for (Iterator<Namespace> it = start.getNamespaces(); it.hasNext(); ) {
- Namespace namespace = it.next();
- if (!namespace.getNamespaceURI().equals(NS))
- clonedNamespaces.add(namespace);
- }
- return clonedNamespaces;
- }
-
- private static final Pattern SUBSTITUTION_PATTERN = Pattern.compile("\\$\\{([^}]*)\\}");
- public String interpolateString(String template, RDFNode node) {
- if (!SUBSTITUTION_PATTERN.matcher(template).find()) {
- return template; // fast path
- }
- StringBuffer substituted = new StringBuffer();
- Matcher matcher = SUBSTITUTION_PATTERN.matcher(template);
- while (matcher.find()) {
- String expression = matcher.group(1);
- Object replacement = selectorFactory.get(expression).singleResult(node);
-
- String replacementValue;
- if (replacement instanceof RDFNode) {
- RDFNode replacementNode = (RDFNode) replacement;
- if (replacementNode.isLiteral()) {
- Literal replacementLiteral = (Literal) replacementNode;
- replacementValue = replacementLiteral.getValue().toString();
- } else {
- throw new UnsupportedOperationException("Not a literal: " + replacementNode);
- }
- } else {
- replacementValue = replacement.toString();
- }
-
- matcher.appendReplacement(substituted, replacementValue.replace("$", "\\$"));
- }
- matcher.appendTail(substituted);
- return substituted.toString();
- }
-
- private void interpolateCharacters(XMLEventConsumer writer, Characters characters, RDFNode node) throws XMLStreamException {
- String template = characters.getData();
- if (!SUBSTITUTION_PATTERN.matcher(template).find()) {
- writer.add(characters); // fast path
- return;
- }
- Matcher matcher = SUBSTITUTION_PATTERN.matcher(template);
- int lastAppendedPos = 0;
- while (matcher.find()) {
- writer.add(eventFactory.createCharacters(template.substring(lastAppendedPos, matcher.start())));
- lastAppendedPos = matcher.end();
- String expression = matcher.group(1);
- Selector<?> selector;
- try {
- selector = selectorFactory.get(expression);
- } catch (InvalidSelectorSyntaxException e) {
- throw new TemplateSyntaxException(characters.getLocation(), e);
- }
- try {
- Object replacement = selector.singleResult(node);
- writeTreeForContent(writer, replacement);
- } catch (Exception e) {
- throw new TemplateInterpolationException(characters.getLocation(), expression, node, e);
- }
- }
- writer.add(eventFactory.createCharacters(template.substring(lastAppendedPos)));
- }
-
- protected void writeTreeForContent(XMLEventConsumer writer, Object replacement)
- throws XMLStreamException {
- if (replacement instanceof RDFNode) {
- RDFNode replacementNode = (RDFNode) replacement;
- if (replacementNode.isLiteral()) {
- Literal literal = (Literal) replacementNode;
- if (literal.isWellFormedXML()) {
- writeXMLLiteral(literal.getLexicalForm(), writer);
- } else {
- writer.add(eventFactory.createCharacters(literal.getValue().toString()));
- }
- } else {
- throw new UnsupportedOperationException("Not a literal: " + replacementNode);
- }
- } else if (replacement instanceof XMLStream) {
- for (XMLEvent event: (XMLStream) replacement) {
- writer.add(event);
- }
- } else {
- writer.add(eventFactory.createCharacters(replacement.toString()));
- }
- }
-
- @SuppressWarnings("unchecked")
- protected Set<Attribute> cloneAttributesWithout(StartElement start, QName omit) {
- // clone attributes, but without rdf:content
- Set<Attribute> attributes = new LinkedHashSet<Attribute>();
- for (Iterator<Attribute> it = start.getAttributes(); it.hasNext(); ) {
- Attribute attribute = it.next();
- if (!attribute.getName().equals(omit))
- attributes.add(attribute);
- }
- return attributes;
- }
-
- private void writeXMLLiteral(String literal, XMLEventConsumer writer)
- throws XMLStreamException {
- XMLEventReader reader = inputFactory.createXMLEventReader(new StringReader(literal));
- while (reader.hasNext()) {
- XMLEvent event = reader.nextEvent();
- switch (event.getEventType()) {
- case XMLStreamConstants.START_DOCUMENT:
- case XMLStreamConstants.END_DOCUMENT:
- break; // discard
- default:
- writer.add(event);
- }
- }
- }
-
-}
diff --git a/src/main/java/au/com/miskinhill/rdftemplate/TemplateSyntaxException.java b/src/main/java/au/com/miskinhill/rdftemplate/TemplateSyntaxException.java
@@ -1,22 +0,0 @@
-package au.com.miskinhill.rdftemplate;
-
-import javax.xml.stream.Location;
-import javax.xml.stream.XMLStreamException;
-
-public class TemplateSyntaxException extends RuntimeException {
-
- private static final long serialVersionUID = 6518982504570154030L;
-
- public TemplateSyntaxException(Location location, String message) {
- super("[location " + location.getLineNumber() + "," + location.getColumnNumber() + "] " + message);
- }
-
- public TemplateSyntaxException(Location location, Throwable cause) {
- super("[location " + location.getLineNumber() + "," + location.getColumnNumber() + "]", cause);
- }
-
- public TemplateSyntaxException(XMLStreamException e) {
- super(e);
- }
-
-}
diff --git a/src/main/java/au/com/miskinhill/rdftemplate/XMLStream.java b/src/main/java/au/com/miskinhill/rdftemplate/XMLStream.java
@@ -1,43 +0,0 @@
-package au.com.miskinhill.rdftemplate;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Iterator;
-import java.util.List;
-
-import javax.xml.stream.XMLStreamConstants;
-import javax.xml.stream.events.XMLEvent;
-
-public class XMLStream implements Iterable<XMLEvent> {
-
- public static XMLStream collect(Iterator<XMLEvent> it) {
- List<XMLEvent> events = new ArrayList<XMLEvent>();
- while (it.hasNext()) {
- XMLEvent event = it.next();
- switch (event.getEventType()) {
- case XMLStreamConstants.START_DOCUMENT:
- case XMLStreamConstants.END_DOCUMENT:
- break; // discard
- default:
- events.add(event);
- }
- }
- return new XMLStream(events);
- }
-
- private final List<XMLEvent> events;
-
- public XMLStream(XMLEvent... events) {
- this.events = Arrays.asList(events);
- }
-
- public XMLStream(List<XMLEvent> events) {
- this.events = events;
- }
-
- @Override
- public Iterator<XMLEvent> iterator() {
- return events.iterator();
- }
-
-}
diff --git a/src/main/java/au/com/miskinhill/rdftemplate/datatype/DateDataType.java b/src/main/java/au/com/miskinhill/rdftemplate/datatype/DateDataType.java
@@ -1,112 +0,0 @@
-package au.com.miskinhill.rdftemplate.datatype;
-
-import org.springframework.stereotype.Component;
-
-import com.hp.hpl.jena.datatypes.DatatypeFormatException;
-import com.hp.hpl.jena.datatypes.RDFDatatype;
-import com.hp.hpl.jena.datatypes.TypeMapper;
-import com.hp.hpl.jena.graph.impl.LiteralLabel;
-import org.joda.time.LocalDate;
-import org.joda.time.format.DateTimeFormat;
-import org.joda.time.format.DateTimeFormatter;
-
-@Component
-public class DateDataType implements RDFDatatype {
-
- public static final String URI = "http://www.w3.org/TR/xmlschema-2/#date";
-
- @SuppressWarnings("unused")
- private static DateDataType instance;
- public static void registerStaticInstance() {
- instance = new DateDataType();
- }
-
- private final DateTimeFormatter yearParser = DateTimeFormat.forPattern("yyyy");
- private final DateTimeFormatter yearMonthParser = DateTimeFormat.forPattern("yyyy-MM");
- private final DateTimeFormatter dateParser = DateTimeFormat.forPattern("yyyy-MM-dd");
-
- public DateDataType() {
- TypeMapper.getInstance().registerDatatype(this);
- }
-
- @Override
- public String getURI() {
- return URI;
- }
-
- @Override
- public Class<LocalDate> getJavaClass() {
- return null;
- }
-
- @Override
- public String unparse(Object value) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public Object cannonicalise(Object value) {
- return value;
- }
-
- @Override
- public Object extendedTypeDefinition() {
- return null;
- }
-
- @Override
- public int getHashCode(LiteralLabel lit) {
- return lit.getValue().hashCode();
- }
-
- @Override
- public boolean isEqual(LiteralLabel left, LiteralLabel right) {
- return left.getValue().equals(right.getValue());
- }
-
- @Override
- public Object parse(String lexicalForm) throws DatatypeFormatException {
- try {
- return dateParser.parseDateTime(lexicalForm).toLocalDate();
- } catch (IllegalArgumentException e) {
- // pass
- }
- try {
- return new YearMonth(yearMonthParser.parseDateTime(lexicalForm).toLocalDate());
- } catch (IllegalArgumentException e) {
- // pass
- }
- try {
- return new Year(yearParser.parseDateTime(lexicalForm).toLocalDate());
- } catch (IllegalArgumentException e) {
- // pass
- }
- throw new DatatypeFormatException(lexicalForm, this, "No matching parsers found");
- }
-
- @Override
- public boolean isValid(String lexicalForm) {
- try {
- parse(lexicalForm);
- return true;
- } catch (DatatypeFormatException e) {
- return false;
- }
- }
-
- @Override
- public boolean isValidLiteral(LiteralLabel lit) {
- return lit.getDatatypeURI().equals(URI) && isValid(lit.getLexicalForm());
- }
-
- @Override
- public boolean isValidValue(Object valueForm) {
- return (valueForm instanceof LocalDate);
- }
-
- @Override
- public RDFDatatype normalizeSubType(Object value, RDFDatatype dt) {
- return dt;
- }
-
-}
-\ No newline at end of file
diff --git a/src/main/java/au/com/miskinhill/rdftemplate/datatype/DateTimeDataType.java b/src/main/java/au/com/miskinhill/rdftemplate/datatype/DateTimeDataType.java
@@ -1,98 +0,0 @@
-package au.com.miskinhill.rdftemplate.datatype;
-
-import com.hp.hpl.jena.datatypes.DatatypeFormatException;
-import com.hp.hpl.jena.datatypes.RDFDatatype;
-import com.hp.hpl.jena.datatypes.TypeMapper;
-import com.hp.hpl.jena.graph.impl.LiteralLabel;
-import org.joda.time.DateTime;
-import org.joda.time.format.DateTimeFormatter;
-import org.joda.time.format.ISODateTimeFormat;
-import org.springframework.stereotype.Component;
-
-@Component
-public class DateTimeDataType implements RDFDatatype {
-
- public static final String URI = "http://www.w3.org/TR/xmlschema-2/#datetime";
-
- @SuppressWarnings("unused")
- private static DateTimeDataType instance;
- public static void registerStaticInstance() {
- instance = new DateTimeDataType();
- }
-
- private final DateTimeFormatter format = ISODateTimeFormat.dateTimeNoMillis().withOffsetParsed();
-
- public DateTimeDataType() {
- TypeMapper.getInstance().registerDatatype(this);
- }
-
- @Override
- public String getURI() {
- return URI;
- }
-
- @Override
- public Class<DateTime> getJavaClass() {
- return DateTime.class;
- }
-
- @Override
- public String unparse(Object value) {
- return ((DateTime) value).toString(format);
- }
-
- @Override
- public Object cannonicalise(Object value) {
- return value;
- }
-
- @Override
- public Object extendedTypeDefinition() {
- return null;
- }
-
- @Override
- public int getHashCode(LiteralLabel lit) {
- return lit.getValue().hashCode();
- }
-
- @Override
- public boolean isEqual(LiteralLabel left, LiteralLabel right) {
- return left.getValue().equals(right.getValue());
- }
-
- @Override
- public DateTime parse(String lexicalForm) throws DatatypeFormatException {
- try {
- return format.parseDateTime(lexicalForm);
- } catch (IllegalArgumentException e) {
- throw new DatatypeFormatException(lexicalForm, this, "Parser barfed");
- }
- }
-
- @Override
- public boolean isValid(String lexicalForm) {
- try {
- parse(lexicalForm);
- return true;
- } catch (DatatypeFormatException e) {
- return false;
- }
- }
-
- @Override
- public boolean isValidLiteral(LiteralLabel lit) {
- return lit.getDatatypeURI().equals(URI) && isValid(lit.getLexicalForm());
- }
-
- @Override
- public boolean isValidValue(Object valueForm) {
- return (valueForm instanceof DateTime);
- }
-
- @Override
- public RDFDatatype normalizeSubType(Object value, RDFDatatype dt) {
- return dt;
- }
-
-}
-\ No newline at end of file
diff --git a/src/main/java/au/com/miskinhill/rdftemplate/datatype/Year.java b/src/main/java/au/com/miskinhill/rdftemplate/datatype/Year.java
@@ -1,50 +0,0 @@
-package au.com.miskinhill.rdftemplate.datatype;
-
-import org.joda.time.LocalDate;
-
-public class Year {
-
- private final int year;
-
- public Year(int value) {
- this.year = value;
- }
-
- public Year(LocalDate date) {
- this.year = date.getYear();
- }
-
- public Year(YearMonth yearMonth) {
- this.year = yearMonth.getYear();
- }
-
- public int getYear() {
- return year;
- }
-
- @Override
- public String toString() {
- return Integer.toString(year);
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + year;
- return result;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (getClass() != obj.getClass())
- return false;
- Year other = (Year) obj;
- return (year == other.year);
- }
-
-}
diff --git a/src/main/java/au/com/miskinhill/rdftemplate/datatype/YearMonth.java b/src/main/java/au/com/miskinhill/rdftemplate/datatype/YearMonth.java
@@ -1,58 +0,0 @@
-package au.com.miskinhill.rdftemplate.datatype;
-
-import org.joda.time.LocalDate;
-
-public class YearMonth {
-
- private final int year;
- private final int month;
-
- public YearMonth(int year, int month) {
- this.year = year;
- this.month = month;
- }
-
- public YearMonth(LocalDate date) {
- this.year = date.getYear();
- this.month = date.getMonthOfYear();
- }
-
- public int getYear() {
- return year;
- }
-
- public int getMonth() {
- return month;
- }
-
- @Override
- public String toString() {
- return String.format("%04d-%02d", year, month);
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + month;
- result = prime * result + year;
- return result;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (getClass() != obj.getClass())
- return false;
- YearMonth other = (YearMonth) obj;
- if (month != other.month)
- return false;
- if (year != other.year)
- return false;
- return true;
- }
-
-}
diff --git a/src/main/java/au/com/miskinhill/rdftemplate/selector/AbstractAdaptation.java b/src/main/java/au/com/miskinhill/rdftemplate/selector/AbstractAdaptation.java
@@ -1,58 +0,0 @@
-package au.com.miskinhill.rdftemplate.selector;
-
-import java.util.Arrays;
-
-import com.hp.hpl.jena.rdf.model.RDFNode;
-
-public abstract class AbstractAdaptation<DestType, NodeType extends RDFNode> implements Adaptation<DestType> {
-
- private final Class<DestType> destinationType;
- private final Class<?>[] argTypes;
- private final Class<NodeType> nodeType;
-
- protected AbstractAdaptation(Class<DestType> destinationType, Class<?>[] argTypes, Class<NodeType> nodeType) {
- this.destinationType = destinationType;
- this.argTypes = argTypes;
- this.nodeType = nodeType;
- }
-
- @Override
- public Class<DestType> getDestinationType() {
- return destinationType;
- }
-
- @Override
- public Class<?>[] getArgTypes() {
- return argTypes;
- }
-
- @Override
- public void setArgs(Object[] args) {
- if (args.length != argTypes.length)
- throw new SelectorEvaluationException("Expected args of types " + Arrays.toString(argTypes) +
- " but invoked with " + Arrays.toString(args));
- for (int i = 0; i < args.length; i ++) {
- if (!argTypes[i].isAssignableFrom(args[i].getClass()))
- throw new SelectorEvaluationException("Arg " + i + ": expected type " + argTypes[i] +
- " but was " + args[i].getClass());
- }
- setCheckedArgs(args);
- }
-
- protected void setCheckedArgs(Object[] args) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public DestType adapt(RDFNode node) {
- if (!nodeType.equals(RDFNode.class)) {
- if (!node.canAs(nodeType))
- throw new SelectorEvaluationException("Adaptation can only be applied to " + nodeType +
- " but was applied to " + node);
- }
- return doAdapt(node.as(nodeType));
- }
-
- protected abstract DestType doAdapt(NodeType node);
-
-}
diff --git a/src/main/java/au/com/miskinhill/rdftemplate/selector/AbstractSelector.java b/src/main/java/au/com/miskinhill/rdftemplate/selector/AbstractSelector.java
@@ -1,40 +0,0 @@
-package au.com.miskinhill.rdftemplate.selector;
-
-import java.util.List;
-
-import com.hp.hpl.jena.rdf.model.RDFNode;
-
-public abstract class AbstractSelector<T> implements Selector<T> {
-
- private final Class<T> resultType;
-
- protected AbstractSelector(Class<T> resultType) {
- this.resultType = resultType;
- }
-
- @Override
- public abstract List<T> result(RDFNode node);
-
- @Override
- public T singleResult(RDFNode node) {
- List<T> results = result(node);
- if (results.size() != 1) {
- throw new SelectorEvaluationException("Expected exactly one result but got " + results);
- }
- return results.get(0);
- }
-
- @Override
- public Class<T> getResultType() {
- return resultType;
- }
-
- @Override
- public <Other> Selector<Other> withResultType(Class<Other> otherType) {
- if (!otherType.isAssignableFrom(resultType)) {
- throw new ClassCastException("Result type " + resultType + " incompatible with requested type " + otherType);
- }
- return (Selector<Other>) this;
- }
-
-}
-\ No newline at end of file
diff --git a/src/main/java/au/com/miskinhill/rdftemplate/selector/Adaptation.java b/src/main/java/au/com/miskinhill/rdftemplate/selector/Adaptation.java
@@ -1,15 +0,0 @@
-package au.com.miskinhill.rdftemplate.selector;
-
-import com.hp.hpl.jena.rdf.model.RDFNode;
-
-public interface Adaptation<T> {
-
- Class<T> getDestinationType();
-
- Class<?>[] getArgTypes();
-
- void setArgs(Object[] args);
-
- T adapt(RDFNode node);
-
-}
diff --git a/src/main/java/au/com/miskinhill/rdftemplate/selector/AdaptationFactory.java b/src/main/java/au/com/miskinhill/rdftemplate/selector/AdaptationFactory.java
@@ -1,9 +0,0 @@
-package au.com.miskinhill.rdftemplate.selector;
-
-public interface AdaptationFactory {
-
- boolean hasName(String name);
-
- Adaptation<?> getByName(String name);
-
-}
diff --git a/src/main/java/au/com/miskinhill/rdftemplate/selector/AntlrSelectorFactory.java b/src/main/java/au/com/miskinhill/rdftemplate/selector/AntlrSelectorFactory.java
@@ -1,48 +0,0 @@
-package au.com.miskinhill.rdftemplate.selector;
-
-import java.util.Collections;
-import java.util.Map;
-
-import org.antlr.runtime.ANTLRStringStream;
-import org.antlr.runtime.CharStream;
-import org.antlr.runtime.CommonTokenStream;
-import org.antlr.runtime.RecognitionException;
-
-public class AntlrSelectorFactory implements SelectorFactory {
-
- private AdaptationFactory adaptationFactory = new DefaultAdaptationFactory();
- private PredicateResolver predicateResolver = new DefaultPredicateResolver();
- private Map<String, String> namespacePrefixMap = Collections.emptyMap();
-
- public AntlrSelectorFactory() {
- }
-
- public void setAdaptationFactory(AdaptationFactory adaptationFactory) {
- this.adaptationFactory = adaptationFactory;
- }
-
- public void setPredicateResolver(PredicateResolver predicateResolver) {
- this.predicateResolver = predicateResolver;
- }
-
- public void setNamespacePrefixMap(Map<String, String> namespacePrefixMap) {
- this.namespacePrefixMap = namespacePrefixMap;
- }
-
- @Override
- public Selector<?> get(String expression) {
- CharStream stream = new ANTLRStringStream(expression);
- SelectorLexer lexer = new SelectorLexer(stream);
- CommonTokenStream tokens = new CommonTokenStream(lexer);
- SelectorParser parser = new SelectorParser(tokens);
- parser.setAdaptationFactory(adaptationFactory);
- parser.setPredicateResolver(predicateResolver);
- parser.setNamespacePrefixMap(namespacePrefixMap);
- try {
- return parser.unionSelector();
- } catch (RecognitionException e) {
- throw new InvalidSelectorSyntaxException(e);
- }
- }
-
-}
diff --git a/src/main/java/au/com/miskinhill/rdftemplate/selector/BooleanAndPredicate.java b/src/main/java/au/com/miskinhill/rdftemplate/selector/BooleanAndPredicate.java
@@ -1,34 +0,0 @@
-package au.com.miskinhill.rdftemplate.selector;
-
-import com.hp.hpl.jena.rdf.model.RDFNode;
-import org.apache.commons.lang.builder.ToStringBuilder;
-
-public class BooleanAndPredicate implements Predicate {
-
- private final Predicate left;
- private final Predicate right;
-
- public BooleanAndPredicate(Predicate left, Predicate right) {
- this.left = left;
- this.right = right;
- }
-
- public Predicate getLeft() {
- return left;
- }
-
- public Predicate getRight() {
- return right;
- }
-
- @Override
- public boolean evaluate(RDFNode node) {
- return left.evaluate(node) && right.evaluate(node);
- }
-
- @Override
- public String toString() {
- return new ToStringBuilder(this).append(left).append(right).toString();
- }
-
-}
diff --git a/src/main/java/au/com/miskinhill/rdftemplate/selector/ComparableLiteralValueAdaptation.java b/src/main/java/au/com/miskinhill/rdftemplate/selector/ComparableLiteralValueAdaptation.java
@@ -1,22 +0,0 @@
-package au.com.miskinhill.rdftemplate.selector;
-
-import com.hp.hpl.jena.rdf.model.Literal;
-
-@SuppressWarnings("unchecked")
-public class ComparableLiteralValueAdaptation extends AbstractAdaptation<Comparable, Literal> {
-
- public ComparableLiteralValueAdaptation() {
- super(Comparable.class, new Class<?>[] { }, Literal.class);
- }
-
- @Override
- protected Comparable<?> doAdapt(Literal node) {
- Object literalValue = node.getValue();
- if (!(literalValue instanceof Comparable<?>)) {
- throw new SelectorEvaluationException("Attempted to apply #comparable-lv to non-Comparable node " + node +
- " with literal value of type " + literalValue.getClass());
- }
- return (Comparable<?>) literalValue;
- }
-
-}
diff --git a/src/main/java/au/com/miskinhill/rdftemplate/selector/DefaultAdaptationFactory.java b/src/main/java/au/com/miskinhill/rdftemplate/selector/DefaultAdaptationFactory.java
@@ -1,35 +0,0 @@
-package au.com.miskinhill.rdftemplate.selector;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import org.springframework.beans.BeanUtils;
-
-public class DefaultAdaptationFactory implements AdaptationFactory {
-
- private static final Map<String, Class<? extends Adaptation<?>>> ADAPTATIONS = new HashMap<String, Class<? extends Adaptation<?>>>();
- static {
- ADAPTATIONS.put("uri", UriAdaptation.class);
- ADAPTATIONS.put("uri-slice", UriSliceAdaptation.class);
- ADAPTATIONS.put("uri-anchor", UriAnchorAdaptation.class);
- ADAPTATIONS.put("lv", LiteralValueAdaptation.class);
- ADAPTATIONS.put("comparable-lv", ComparableLiteralValueAdaptation.class);
- ADAPTATIONS.put("string-lv", StringLiteralValueAdaptation.class);
- ADAPTATIONS.put("formatted-dt", FormattedDateTimeAdaptation.class);
- }
-
- @Override
- public boolean hasName(String name) {
- return ADAPTATIONS.containsKey(name);
- }
-
- @Override
- public Adaptation<?> getByName(String name) {
- Class<? extends Adaptation<?>> adaptationClass = ADAPTATIONS.get(name);
- if (adaptationClass == null) {
- throw new InvalidSelectorSyntaxException("No adaptation named " + name);
- }
- return BeanUtils.instantiate(adaptationClass);
- }
-
-}
diff --git a/src/main/java/au/com/miskinhill/rdftemplate/selector/DefaultPredicateResolver.java b/src/main/java/au/com/miskinhill/rdftemplate/selector/DefaultPredicateResolver.java
@@ -1,19 +0,0 @@
-package au.com.miskinhill.rdftemplate.selector;
-
-import java.util.HashMap;
-import java.util.Map;
-
-public class DefaultPredicateResolver implements PredicateResolver {
-
- private static final Map<String, Class<? extends Predicate>> PREDICATES = new HashMap<String, Class<? extends Predicate>>();
- static {
- PREDICATES.put("type", TypePredicate.class);
- PREDICATES.put("uri-prefix", UriPrefixPredicate.class);
- }
-
- @Override
- public Class<? extends Predicate> getByName(String name) {
- return PREDICATES.get(name);
- }
-
-}
diff --git a/src/main/java/au/com/miskinhill/rdftemplate/selector/EternallyCachingSelectorFactory.java b/src/main/java/au/com/miskinhill/rdftemplate/selector/EternallyCachingSelectorFactory.java
@@ -1,35 +0,0 @@
-package au.com.miskinhill.rdftemplate.selector;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * {@link SelectorFactory} implementation which indirects to a real
- * implementation and caches its return values eternally. Do not use in
- * situations where the set of input expressions can be unbounded (e.g.
- * user-provided) as this will lead to unbounded cache growth.
- * <p>
- * A better implementation would use a LRU cache or similar, but I cbf.
- */
-public class EternallyCachingSelectorFactory implements SelectorFactory {
-
- private final SelectorFactory real;
- private final Map<String, Selector<?>> cache = new HashMap<String, Selector<?>>();
-
- public EternallyCachingSelectorFactory(SelectorFactory real) {
- this.real = real;
- }
-
- @Override
- public Selector<?> get(String expression) {
- Selector<?> cached = cache.get(expression);
- if (cached == null) {
- Selector<?> fresh = real.get(expression);
- cache.put(expression, fresh);
- return fresh;
- } else {
- return cached;
- }
- }
-
-}
diff --git a/src/main/java/au/com/miskinhill/rdftemplate/selector/FormattedDateTimeAdaptation.java b/src/main/java/au/com/miskinhill/rdftemplate/selector/FormattedDateTimeAdaptation.java
@@ -1,49 +0,0 @@
-package au.com.miskinhill.rdftemplate.selector;
-
-import org.apache.commons.lang.builder.ToStringBuilder;
-import org.joda.time.ReadableInstant;
-import org.joda.time.ReadablePartial;
-import org.joda.time.format.DateTimeFormat;
-import org.joda.time.format.DateTimeFormatter;
-
-import com.hp.hpl.jena.rdf.model.Literal;
-
-public class FormattedDateTimeAdaptation extends AbstractAdaptation<String, Literal> {
-
- private String pattern;
- private DateTimeFormatter formatter;
-
- public FormattedDateTimeAdaptation() {
- super(String.class, new Class<?>[] { String.class }, Literal.class);
- }
-
- @Override
- protected void setCheckedArgs(Object[] args) {
- this.pattern = (String) args[0];
- this.formatter = DateTimeFormat.forPattern(pattern.replace("\"", "'")); // for convenience in XML
- }
-
- public String getPattern() {
- return pattern;
- }
-
- @Override
- protected String doAdapt(Literal node) {
- Object lv = node.getValue();
- if (lv instanceof ReadableInstant) {
- ReadableInstant instant = (ReadableInstant) lv;
- return formatter.print(instant);
- } else if (lv instanceof ReadablePartial) {
- ReadablePartial instant = (ReadablePartial) lv;
- return formatter.print(instant);
- } else {
- throw new SelectorEvaluationException("Attempted to apply #formatted-dt to non-datetime literal " + lv);
- }
- }
-
- @Override
- public String toString() {
- return new ToStringBuilder(this).append("pattern", pattern).toString();
- }
-
-}
diff --git a/src/main/java/au/com/miskinhill/rdftemplate/selector/InvalidSelectorSyntaxException.java b/src/main/java/au/com/miskinhill/rdftemplate/selector/InvalidSelectorSyntaxException.java
@@ -1,15 +0,0 @@
-package au.com.miskinhill.rdftemplate.selector;
-
-public class InvalidSelectorSyntaxException extends RuntimeException {
-
- private static final long serialVersionUID = 5805546105865617336L;
-
- public InvalidSelectorSyntaxException(Throwable cause) {
- super(cause);
- }
-
- public InvalidSelectorSyntaxException(String message) {
- super(message);
- }
-
-}
diff --git a/src/main/java/au/com/miskinhill/rdftemplate/selector/LiteralValueAdaptation.java b/src/main/java/au/com/miskinhill/rdftemplate/selector/LiteralValueAdaptation.java
@@ -1,16 +0,0 @@
-package au.com.miskinhill.rdftemplate.selector;
-
-import com.hp.hpl.jena.rdf.model.Literal;
-
-public class LiteralValueAdaptation extends AbstractAdaptation<Object, Literal> {
-
- public LiteralValueAdaptation() {
- super(Object.class, new Class<?>[] { }, Literal.class);
- }
-
- @Override
- protected Object doAdapt(Literal node) {
- return node.getValue();
- }
-
-}
diff --git a/src/main/java/au/com/miskinhill/rdftemplate/selector/NoopSelector.java b/src/main/java/au/com/miskinhill/rdftemplate/selector/NoopSelector.java
@@ -1,19 +0,0 @@
-package au.com.miskinhill.rdftemplate.selector;
-
-import java.util.Collections;
-import java.util.List;
-
-import com.hp.hpl.jena.rdf.model.RDFNode;
-
-public class NoopSelector extends AbstractSelector<RDFNode> {
-
- public NoopSelector() {
- super(RDFNode.class);
- }
-
- @Override
- public List<RDFNode> result(RDFNode node) {
- return Collections.singletonList(node);
- }
-
-}
diff --git a/src/main/java/au/com/miskinhill/rdftemplate/selector/Predicate.java b/src/main/java/au/com/miskinhill/rdftemplate/selector/Predicate.java
@@ -1,7 +0,0 @@
-package au.com.miskinhill.rdftemplate.selector;
-
-import com.hp.hpl.jena.rdf.model.RDFNode;
-
-public interface Predicate extends org.apache.commons.collections15.Predicate<RDFNode> {
-
-}
diff --git a/src/main/java/au/com/miskinhill/rdftemplate/selector/PredicateResolver.java b/src/main/java/au/com/miskinhill/rdftemplate/selector/PredicateResolver.java
@@ -1,7 +0,0 @@
-package au.com.miskinhill.rdftemplate.selector;
-
-public interface PredicateResolver {
-
- Class<? extends Predicate> getByName(String name);
-
-}
diff --git a/src/main/java/au/com/miskinhill/rdftemplate/selector/Selector.java b/src/main/java/au/com/miskinhill/rdftemplate/selector/Selector.java
@@ -1,17 +0,0 @@
-package au.com.miskinhill.rdftemplate.selector;
-
-import java.util.List;
-
-import com.hp.hpl.jena.rdf.model.RDFNode;
-
-public interface Selector<T> {
-
- List<T> result(RDFNode node);
-
- T singleResult(RDFNode node);
-
- Class<T> getResultType();
-
- <Other> Selector<Other> withResultType(Class<Other> otherType);
-
-}
diff --git a/src/main/java/au/com/miskinhill/rdftemplate/selector/SelectorComparator.java b/src/main/java/au/com/miskinhill/rdftemplate/selector/SelectorComparator.java
@@ -1,58 +0,0 @@
-/**
- *
- */
-package au.com.miskinhill.rdftemplate.selector;
-
-import java.util.Comparator;
-
-import org.apache.commons.lang.builder.ToStringBuilder;
-
-import com.hp.hpl.jena.rdf.model.RDFNode;
-
-public class SelectorComparator<T extends Comparable<T>> implements Comparator<RDFNode> {
-
- private Selector<T> selector;
- private boolean reversed = false;
-
- public Selector<T> getSelector() {
- return selector;
- }
-
- public void setSelector(Selector<T> selector) {
- this.selector = selector;
- }
-
- public boolean isReversed() {
- return reversed;
- }
-
- public void setReversed(boolean reversed) {
- this.reversed = reversed;
- }
-
- @Override
- public String toString() {
- return new ToStringBuilder(this).append(selector).append("reversed", reversed).toString();
- }
-
- @Override
- public int compare(RDFNode left, RDFNode right) {
- T leftKey;
- try {
- leftKey = selector.singleResult(left);
- } catch (SelectorEvaluationException e) {
- throw new SelectorEvaluationException("Exception evaluating selector [" + selector + "] " +
- "with context node [" + left + "] for comparison", e);
- }
- T rightKey;
- try {
- rightKey = selector.singleResult(right);
- } catch (SelectorEvaluationException e) {
- throw new SelectorEvaluationException("Exception evaluating selector [" + selector + "] " +
- "with context node [" + right + "] for comparison", e);
- }
- int result = leftKey.compareTo(rightKey);
- return reversed ? -result : result;
- }
-
-}
-\ No newline at end of file
diff --git a/src/main/java/au/com/miskinhill/rdftemplate/selector/SelectorEvaluationException.java b/src/main/java/au/com/miskinhill/rdftemplate/selector/SelectorEvaluationException.java
@@ -1,15 +0,0 @@
-package au.com.miskinhill.rdftemplate.selector;
-
-public class SelectorEvaluationException extends RuntimeException {
-
- private static final long serialVersionUID = -398277800899471326L;
-
- public SelectorEvaluationException(String message) {
- super(message);
- }
-
- public SelectorEvaluationException(String message, Throwable cause) {
- super(message, cause);
- }
-
-}
diff --git a/src/main/java/au/com/miskinhill/rdftemplate/selector/SelectorFactory.java b/src/main/java/au/com/miskinhill/rdftemplate/selector/SelectorFactory.java
@@ -1,7 +0,0 @@
-package au.com.miskinhill.rdftemplate.selector;
-
-public interface SelectorFactory {
-
- Selector<?> get(String expression);
-
-}
diff --git a/src/main/java/au/com/miskinhill/rdftemplate/selector/SelectorWithAdaptation.java b/src/main/java/au/com/miskinhill/rdftemplate/selector/SelectorWithAdaptation.java
@@ -1,48 +0,0 @@
-package au.com.miskinhill.rdftemplate.selector;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import com.hp.hpl.jena.rdf.model.RDFNode;
-import org.apache.commons.lang.builder.ToStringBuilder;
-
-public class SelectorWithAdaptation<T> extends AbstractSelector<T> {
-
- private final Selector<RDFNode> baseSelector;
- private final Adaptation<T> adaptation;
-
- public SelectorWithAdaptation(Selector<RDFNode> baseSelector, Adaptation<T> adaptation) {
- super(adaptation.getDestinationType());
- this.baseSelector = baseSelector;
- this.adaptation = adaptation;
- }
-
- @Override
- public String toString() {
- return new ToStringBuilder(this).append(baseSelector).append(adaptation).toString();
- }
-
- @Override
- public List<T> result(RDFNode node) {
- List<RDFNode> baseResults = baseSelector.result(node);
- List<T> results = new ArrayList<T>();
- for (RDFNode resultNode: baseResults) {
- results.add(adaptation.adapt(resultNode));
- }
- return results;
- }
-
- @Override
- public T singleResult(RDFNode node) {
- return adaptation.adapt(baseSelector.singleResult(node));
- }
-
- public Selector<RDFNode> getBaseSelector() {
- return baseSelector;
- }
-
- public Adaptation<T> getAdaptation() {
- return adaptation;
- }
-
-}
-\ No newline at end of file
diff --git a/src/main/java/au/com/miskinhill/rdftemplate/selector/StringLiteralValueAdaptation.java b/src/main/java/au/com/miskinhill/rdftemplate/selector/StringLiteralValueAdaptation.java
@@ -1,45 +0,0 @@
-package au.com.miskinhill.rdftemplate.selector;
-
-import java.io.StringReader;
-
-import javax.xml.stream.XMLEventReader;
-import javax.xml.stream.XMLInputFactory;
-import javax.xml.stream.XMLStreamException;
-import javax.xml.stream.events.XMLEvent;
-
-import com.hp.hpl.jena.rdf.model.Literal;
-
-public class StringLiteralValueAdaptation extends AbstractAdaptation<String, Literal> {
-
- private static final XMLInputFactory inputFactory = XMLInputFactory.newInstance();
-
- public StringLiteralValueAdaptation() {
- super(String.class, new Class<?>[] { }, Literal.class);
- }
-
- @Override
- protected String doAdapt(Literal literal) {
- if (literal.isWellFormedXML()) {
- try {
- return stripTags(literal.getLexicalForm());
- } catch (XMLStreamException e) {
- throw new RuntimeException(e);
- }
- } else {
- return literal.getValue().toString();
- }
- }
-
- private String stripTags(String literal) throws XMLStreamException {
- StringBuilder sb = new StringBuilder();
- XMLEventReader reader = inputFactory.createXMLEventReader(new StringReader(literal));
- while (reader.hasNext()) {
- XMLEvent event = reader.nextEvent();
- if (event.isCharacters()) {
- sb.append(event.asCharacters().getData());
- }
- }
- return sb.toString();
- }
-
-}
diff --git a/src/main/java/au/com/miskinhill/rdftemplate/selector/Traversal.java b/src/main/java/au/com/miskinhill/rdftemplate/selector/Traversal.java
@@ -1,126 +0,0 @@
-package au.com.miskinhill.rdftemplate.selector;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-
-import org.apache.commons.collections15.CollectionUtils;
-
-import com.hp.hpl.jena.rdf.model.Property;
-import com.hp.hpl.jena.rdf.model.RDFNode;
-import com.hp.hpl.jena.rdf.model.ResIterator;
-import com.hp.hpl.jena.rdf.model.Resource;
-import com.hp.hpl.jena.rdf.model.StmtIterator;
-import org.apache.commons.lang.builder.ToStringBuilder;
-
-public class Traversal {
-
- private String propertyNamespace;
- private String propertyLocalName;
- private boolean inverse = false;
- private Predicate predicate;
- private List<Comparator<RDFNode>> sortOrder = new ArrayList<Comparator<RDFNode>>();
- private Integer subscript;
-
- private class SortComparator implements Comparator<RDFNode> {
- @Override
- public int compare(RDFNode left, RDFNode right) {
- for (Comparator<RDFNode> comparator: sortOrder) {
- int result = comparator.compare(left, right);
- if (result != 0)
- return result;
- }
- return 0;
- }
- }
-
- public List<RDFNode> traverse(RDFNode node) {
- if (!node.isResource()) {
- throw new SelectorEvaluationException("Attempted to traverse non-resource node " + node);
- }
- Resource resource = (Resource) node;
- Property property = resource.getModel().createProperty(propertyNamespace, propertyLocalName);
- List<RDFNode> destinations = new ArrayList<RDFNode>();
- if (!inverse) {
- for (StmtIterator it = resource.listProperties(property); it.hasNext(); ) {
- destinations.add(it.nextStatement().getObject());
- }
- } else {
- for (ResIterator it = resource.getModel().listResourcesWithProperty(property, node); it.hasNext(); ) {
- destinations.add(it.nextResource());
- }
- }
- CollectionUtils.filter(destinations, predicate);
- if (!sortOrder.isEmpty())
- Collections.sort(destinations, new SortComparator());
- if (subscript != null) {
- if (destinations.size() <= subscript) {
- throw new SelectorEvaluationException("Cannot apply subscript " + subscript + " to nodes " + destinations);
- }
- destinations = Collections.singletonList(destinations.get(subscript));
- }
- return destinations;
- }
-
- @Override
- public String toString() {
- return new ToStringBuilder(this)
- .append("propertyNamespace", propertyNamespace)
- .append("propertyLocalName", propertyLocalName)
- .append("inverse", inverse)
- .append("predicate", predicate)
- .append("sortOrder", sortOrder)
- .append("subscript", subscript)
- .toString();
- }
-
- public String getPropertyLocalName() {
- return propertyLocalName;
- }
-
- public void setPropertyLocalName(String propertyLocalName) {
- this.propertyLocalName = propertyLocalName;
- }
-
- public String getPropertyNamespace() {
- return propertyNamespace;
- }
-
- public void setPropertyNamespace(String propertyNamespace) {
- this.propertyNamespace = propertyNamespace;
- }
-
- public boolean isInverse() {
- return inverse;
- }
-
- public void setInverse(boolean inverse) {
- this.inverse = inverse;
- }
-
- public Predicate getPredicate() {
- return predicate;
- }
-
- public void setPredicate(Predicate predicate) {
- this.predicate = predicate;
- }
-
- public List<Comparator<RDFNode>> getSortOrder() {
- return sortOrder;
- }
-
- public void addSortOrderComparator(Comparator<RDFNode> selector) {
- this.sortOrder.add(selector);
- }
-
- public Integer getSubscript() {
- return subscript;
- }
-
- public void setSubscript(Integer subscript) {
- this.subscript = subscript;
- }
-
-}
diff --git a/src/main/java/au/com/miskinhill/rdftemplate/selector/TraversingSelector.java b/src/main/java/au/com/miskinhill/rdftemplate/selector/TraversingSelector.java
@@ -1,46 +0,0 @@
-package au.com.miskinhill.rdftemplate.selector;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Set;
-
-import com.hp.hpl.jena.rdf.model.RDFNode;
-import org.apache.commons.lang.builder.ToStringBuilder;
-
-public class TraversingSelector extends AbstractSelector<RDFNode> {
-
- private final List<Traversal> traversals = new ArrayList<Traversal>();
-
- public TraversingSelector() {
- super(RDFNode.class);
- }
-
- @Override
- public List<RDFNode> result(RDFNode node) {
- Set<RDFNode> current = Collections.singleton(node);
- for (Traversal traversal: traversals) {
- LinkedHashSet<RDFNode> destinationsUnion = new LinkedHashSet<RDFNode>();
- for (RDFNode start: current) {
- destinationsUnion.addAll(traversal.traverse(start));
- }
- current = destinationsUnion;
- }
- return new ArrayList<RDFNode>(current);
- }
-
- @Override
- public String toString() {
- return new ToStringBuilder(this).append(traversals).toString();
- }
-
- public List<Traversal> getTraversals() {
- return traversals;
- }
-
- public void addTraversal(Traversal traversal) {
- traversals.add(traversal);
- }
-
-}
diff --git a/src/main/java/au/com/miskinhill/rdftemplate/selector/TypePredicate.java b/src/main/java/au/com/miskinhill/rdftemplate/selector/TypePredicate.java
@@ -1,46 +0,0 @@
-package au.com.miskinhill.rdftemplate.selector;
-
-import com.hp.hpl.jena.rdf.model.RDFNode;
-import com.hp.hpl.jena.rdf.model.Resource;
-import com.hp.hpl.jena.rdf.model.Statement;
-import com.hp.hpl.jena.vocabulary.RDF;
-import org.apache.commons.lang.builder.ToStringBuilder;
-
-public class TypePredicate implements Predicate {
-
- private final String namespace;
- private final String localName;
-
- public TypePredicate(String namespace, String localName) {
- this.namespace = namespace;
- this.localName = localName;
- }
-
- public String getNamespace() {
- return namespace;
- }
-
- public String getLocalName() {
- return localName;
- }
-
- @Override
- public boolean evaluate(RDFNode node) {
- if (!node.isResource()) {
- throw new SelectorEvaluationException("Attempted to apply [type] to non-resource node " + node);
- }
- Resource resource = (Resource) node;
- Resource type = resource.getModel().createResource(namespace + localName);
- for (Statement statement: resource.listProperties(RDF.type).toSet()) {
- if (statement.getObject().equals(type))
- return true;
- }
- return false;
- }
-
- @Override
- public String toString() {
- return new ToStringBuilder(this).append(namespace).append(localName).toString();
- }
-
-}
diff --git a/src/main/java/au/com/miskinhill/rdftemplate/selector/UnionSelector.java b/src/main/java/au/com/miskinhill/rdftemplate/selector/UnionSelector.java
@@ -1,45 +0,0 @@
-package au.com.miskinhill.rdftemplate.selector;
-
-import java.util.ArrayList;
-import java.util.LinkedHashSet;
-import java.util.List;
-
-import com.hp.hpl.jena.rdf.model.RDFNode;
-import org.apache.commons.lang.builder.ToStringBuilder;
-
-public class UnionSelector<T> extends AbstractSelector<T> {
-
- private final List<Selector<? extends T>> selectors;
-
- public UnionSelector(List<Selector<? extends T>> selectors) {
- super(null);
- this.selectors = selectors;
- }
-
- @Override
- public List<T> result(RDFNode node) {
- LinkedHashSet<T> results = new LinkedHashSet<T>();
- for (Selector<? extends T> selector: selectors) {
- results.addAll(selector.result(node));
- }
- return new ArrayList<T>(results);
- }
-
- @Override
- public String toString() {
- return new ToStringBuilder(this).append(selectors).toString();
- }
-
- public List<Selector<? extends T>> getSelectors() {
- return selectors;
- }
-
- @Override
- public <Other> Selector<Other> withResultType(Class<Other> otherType) {
- for (Selector<? extends T> selector: selectors) {
- selector.withResultType(otherType); // class cast exception?
- }
- return (Selector<Other>) this;
- }
-
-}
diff --git a/src/main/java/au/com/miskinhill/rdftemplate/selector/UriAdaptation.java b/src/main/java/au/com/miskinhill/rdftemplate/selector/UriAdaptation.java
@@ -1,16 +0,0 @@
-package au.com.miskinhill.rdftemplate.selector;
-
-import com.hp.hpl.jena.rdf.model.Resource;
-
-public class UriAdaptation extends AbstractAdaptation<String, Resource> {
-
- public UriAdaptation() {
- super(String.class, new Class<?>[] { }, Resource.class);
- }
-
- @Override
- protected String doAdapt(Resource node) {
- return node.getURI();
- }
-
-}
diff --git a/src/main/java/au/com/miskinhill/rdftemplate/selector/UriAnchorAdaptation.java b/src/main/java/au/com/miskinhill/rdftemplate/selector/UriAnchorAdaptation.java
@@ -1,24 +0,0 @@
-package au.com.miskinhill.rdftemplate.selector;
-
-import com.hp.hpl.jena.rdf.model.Resource;
-
-/**
- * Returns the anchor component of the node's URI (excluding initial #), or the
- * empty string if it has no anchor component.
- */
-public class UriAnchorAdaptation extends AbstractAdaptation<String, Resource> {
-
- public UriAnchorAdaptation() {
- super(String.class, new Class<?>[] { }, Resource.class);
- }
-
- @Override
- protected String doAdapt(Resource node) {
- String uri = node.getURI();
- int hashIndex = uri.lastIndexOf('#');
- if (hashIndex < 0)
- return "";
- return uri.substring(hashIndex + 1);
- }
-
-}
diff --git a/src/main/java/au/com/miskinhill/rdftemplate/selector/UriPrefixPredicate.java b/src/main/java/au/com/miskinhill/rdftemplate/selector/UriPrefixPredicate.java
@@ -1,26 +0,0 @@
-package au.com.miskinhill.rdftemplate.selector;
-
-import com.hp.hpl.jena.rdf.model.RDFNode;
-import com.hp.hpl.jena.rdf.model.Resource;
-
-public class UriPrefixPredicate implements Predicate {
-
- private final String prefix;
-
- public UriPrefixPredicate(String prefix) {
- this.prefix = prefix;
- }
-
- public String getPrefix() {
- return prefix;
- }
-
- @Override
- public boolean evaluate(RDFNode node) {
- if (!node.isResource()) {
- throw new SelectorEvaluationException("Attempted to apply [uri-prefix] to non-resource node " + node);
- }
- return ((Resource) node).getURI().startsWith(prefix);
- }
-
-}
diff --git a/src/main/java/au/com/miskinhill/rdftemplate/selector/UriSliceAdaptation.java b/src/main/java/au/com/miskinhill/rdftemplate/selector/UriSliceAdaptation.java
@@ -1,28 +0,0 @@
-package au.com.miskinhill.rdftemplate.selector;
-
-import com.hp.hpl.jena.rdf.model.Resource;
-
-public class UriSliceAdaptation extends AbstractAdaptation<String, Resource> {
-
- private Integer startIndex;
-
- public UriSliceAdaptation() {
- super(String.class, new Class<?>[] { Integer.class }, Resource.class);
- }
-
- public Integer getStartIndex() {
- return startIndex;
- }
-
- @Override
- protected void setCheckedArgs(Object[] args) {
- this.startIndex = (Integer) args[0];
- }
-
- @Override
- protected String doAdapt(Resource node) {
- String uri = node.getURI();
- return uri.substring(startIndex);
- }
-
-}
diff --git a/src/main/java/au/com/miskinhill/rdftemplate/view/RDFTemplateView.java b/src/main/java/au/com/miskinhill/rdftemplate/view/RDFTemplateView.java
@@ -1,76 +0,0 @@
-package au.com.miskinhill.rdftemplate.view;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Locale;
-import java.util.Map;
-
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
-import org.springframework.web.servlet.view.AbstractTemplateView;
-
-import au.com.miskinhill.rdftemplate.TemplateInterpolator;
-import au.com.miskinhill.rdftemplate.selector.SelectorFactory;
-import au.id.djc.jena.util.ModelOperations;
-import au.id.djc.jena.util.ModelOperations.ModelExecutionCallbackWithoutResult;
-
-import com.hp.hpl.jena.rdf.model.Model;
-import com.hp.hpl.jena.rdf.model.Resource;
-
-public class RDFTemplateView extends AbstractTemplateView {
-
- public static final String NODE_URI_KEY = "nodeUri";
-
- private TemplateInterpolator templateInterpolator;
- private SelectorFactory selectorFactory;
- private ModelOperations modelOperations;
-
- public void setSelectorFactory(SelectorFactory selectorFactory) {
- this.selectorFactory = selectorFactory;
- }
-
- public void setModelOperations(ModelOperations modelOperations) {
- this.modelOperations = modelOperations;
- }
-
- @Override
- public void afterPropertiesSet() throws Exception {
- super.afterPropertiesSet();
- if (selectorFactory == null) {
- throw new IllegalArgumentException("Property 'selectorFactory' is required");
- }
- if (modelOperations == null) {
- throw new IllegalArgumentException("Property 'sdbTemplate' is required");
- }
- this.templateInterpolator = new TemplateInterpolator(selectorFactory);
- }
-
- @Override
- protected void renderMergedTemplateModel(final Map<String, Object> model,
- final HttpServletRequest request, final HttpServletResponse response)
- throws Exception {
- final InputStream inputStream = getApplicationContext().getResource(getUrl()).getInputStream();
- try {
- modelOperations.withModel(new ModelExecutionCallbackWithoutResult() {
- @Override
- protected void executeWithoutResult(Model rdfModel) {
- Resource node = rdfModel.getResource((String) model.get(NODE_URI_KEY));
- try {
- templateInterpolator.interpolate(inputStream, node, response.getWriter());
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
- });
- } finally {
- inputStream.close();
- }
- }
-
- @Override
- public boolean checkResource(Locale locale) throws Exception {
- return getApplicationContext().getResource(getUrl()).exists();
- }
-
-}
diff --git a/src/main/java/au/com/miskinhill/rdftemplate/view/RDFTemplateViewResolver.java b/src/main/java/au/com/miskinhill/rdftemplate/view/RDFTemplateViewResolver.java
@@ -1,54 +0,0 @@
-package au.com.miskinhill.rdftemplate.view;
-
-import org.springframework.beans.factory.InitializingBean;
-import org.springframework.web.servlet.view.AbstractTemplateView;
-import org.springframework.web.servlet.view.AbstractTemplateViewResolver;
-
-import au.com.miskinhill.rdftemplate.selector.SelectorFactory;
-import au.id.djc.jena.util.ModelOperations;
-
-public class RDFTemplateViewResolver extends AbstractTemplateViewResolver implements InitializingBean {
-
- private SelectorFactory selectorFactory;
- private ModelOperations modelOperations;
-
- public RDFTemplateViewResolver() {
- super();
- setViewClass(requiredViewClass());
- setExposeRequestAttributes(false);
- setExposeSessionAttributes(false);
- setExposeSpringMacroHelpers(false);
- }
-
- public void setSelectorFactory(SelectorFactory selectorFactory) {
- this.selectorFactory = selectorFactory;
- }
-
- public void setModelOperations(ModelOperations modelOperations) {
- this.modelOperations = modelOperations;
- }
-
- @Override
- public void afterPropertiesSet() throws Exception {
- if (selectorFactory == null) {
- throw new IllegalArgumentException("Property 'selectorFactory' is required");
- }
- if (modelOperations == null) {
- throw new IllegalArgumentException("Property 'modelOperations' is required");
- }
- }
-
- @Override
- protected Class<? extends AbstractTemplateView> requiredViewClass() {
- return RDFTemplateView.class;
- }
-
- @Override
- protected RDFTemplateView buildView(String viewName) throws Exception {
- RDFTemplateView view = (RDFTemplateView) super.buildView(viewName);
- view.setSelectorFactory(selectorFactory);
- view.setModelOperations(modelOperations);
- return view;
- }
-
-}
diff --git a/src/main/java/au/id/djc/rdftemplate/ContentAction.java b/src/main/java/au/id/djc/rdftemplate/ContentAction.java
@@ -0,0 +1,68 @@
+package au.id.djc.rdftemplate;
+
+import java.util.Set;
+
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import javax.xml.stream.XMLEventFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.events.Attribute;
+import javax.xml.stream.events.StartElement;
+import javax.xml.stream.util.XMLEventConsumer;
+
+import com.hp.hpl.jena.rdf.model.Literal;
+import com.hp.hpl.jena.rdf.model.RDFNode;
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang.builder.ToStringBuilder;
+
+import au.id.djc.rdftemplate.selector.Selector;
+
+public class ContentAction extends TemplateAction {
+
+ public static final String ACTION_NAME = "content";
+ public static final QName ACTION_QNAME = new QName(TemplateInterpolator.NS, ACTION_NAME);
+ private static final QName XML_LANG_QNAME = new QName(XMLConstants.XML_NS_URI, "lang", XMLConstants.XML_NS_PREFIX);
+ private static final String XHTML_NS_URI = "http://www.w3.org/1999/xhtml";
+
+ private final StartElement start;
+ private final Selector<?> selector;
+
+ public ContentAction(StartElement start, Selector<?> selector) {
+ this.start = start;
+ this.selector = selector;
+ }
+
+ public void evaluate(TemplateInterpolator interpolator, RDFNode node, XMLEventConsumer writer, XMLEventFactory eventFactory)
+ throws XMLStreamException {
+ Object replacement = selector.singleResult(node);
+ StartElement start = interpolator.interpolateAttributes(this.start, node);
+ Set<Attribute> attributes = interpolator.cloneAttributesWithout(start, ACTION_QNAME);
+ if (replacement instanceof Literal) {
+ Literal literal = (Literal) replacement;
+ if (!StringUtils.isEmpty(literal.getLanguage())) {
+ attributes.add(eventFactory.createAttribute(XML_LANG_QNAME, ((Literal) replacement).getLanguage()));
+ if (start.getName().getNamespaceURI().equals(XHTML_NS_URI)) {
+ String xhtmlPrefixInContext = start.getNamespaceContext().getPrefix(XHTML_NS_URI);
+ QName xhtmlLangQNameForContext; // ugh
+ if (xhtmlPrefixInContext.isEmpty())
+ xhtmlLangQNameForContext = new QName("lang");
+ else
+ xhtmlLangQNameForContext = new QName(XHTML_NS_URI, "lang", xhtmlPrefixInContext);
+ attributes.add(eventFactory.createAttribute(xhtmlLangQNameForContext, literal.getLanguage()));
+ }
+ }
+ }
+ writer.add(eventFactory.createStartElement(start.getName(), attributes.iterator(), start.getNamespaces()));
+ interpolator.writeTreeForContent(writer, replacement);
+ writer.add(eventFactory.createEndElement(start.getName(), start.getNamespaces()));
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this)
+ .append("start", start)
+ .append("selector", selector)
+ .toString();
+ }
+
+}
diff --git a/src/main/java/au/id/djc/rdftemplate/ForAction.java b/src/main/java/au/id/djc/rdftemplate/ForAction.java
@@ -0,0 +1,55 @@
+package au.id.djc.rdftemplate;
+
+import java.util.List;
+import java.util.logging.Logger;
+
+import javax.xml.namespace.QName;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.events.XMLEvent;
+import javax.xml.stream.util.XMLEventConsumer;
+
+import com.hp.hpl.jena.rdf.model.RDFNode;
+import com.hp.hpl.jena.rdf.model.Resource;
+import com.hp.hpl.jena.rdf.model.Seq;
+import com.hp.hpl.jena.vocabulary.RDF;
+import org.apache.commons.lang.builder.ToStringBuilder;
+
+import au.id.djc.rdftemplate.selector.Selector;
+
+public class ForAction extends TemplateAction {
+
+ public static final String ACTION_NAME = "for";
+ public static final QName ACTION_QNAME = new QName(TemplateInterpolator.NS, ACTION_NAME);
+ private static final Logger LOG = Logger.getLogger(ForAction.class.getName());
+
+ private final List<XMLEvent> tree;
+ private final Selector<RDFNode> selector;
+
+ public ForAction(List<XMLEvent> tree, Selector<RDFNode> selector) {
+ this.tree = tree;
+ this.selector = selector;
+ }
+
+ public void evaluate(TemplateInterpolator interpolator, RDFNode node, XMLEventConsumer writer)
+ throws XMLStreamException {
+ List<RDFNode> result = selector.result(node);
+ if (result.size() == 1 && result.get(0).canAs(Resource.class)) {
+ if (result.get(0).as(Resource.class).hasProperty(RDF.type, RDF.Seq)) {
+ LOG.fine("Apply rdf:Seq special case for " + result.get(0));
+ result = result.get(0).as(Seq.class).iterator().toList();
+ LOG.fine("Resulting sequence is " + result);
+ }
+ }
+ for (RDFNode eachNode: result) {
+ interpolator.interpolate(tree.iterator(), eachNode, writer);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this)
+ .append("selector", selector)
+ .toString();
+ }
+
+}
diff --git a/src/main/java/au/id/djc/rdftemplate/IfAction.java b/src/main/java/au/id/djc/rdftemplate/IfAction.java
@@ -0,0 +1,46 @@
+package au.id.djc.rdftemplate;
+
+import java.util.List;
+
+import javax.xml.namespace.QName;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.events.XMLEvent;
+import javax.xml.stream.util.XMLEventConsumer;
+
+import com.hp.hpl.jena.rdf.model.RDFNode;
+import org.apache.commons.lang.builder.ToStringBuilder;
+
+import au.id.djc.rdftemplate.selector.Selector;
+
+public class IfAction extends TemplateAction {
+
+ public static final String ACTION_NAME = "if";
+ public static final QName ACTION_QNAME = new QName(TemplateInterpolator.NS, ACTION_NAME);
+
+ private final List<XMLEvent> tree;
+ private final Selector<?> condition;
+ private final boolean negate;
+
+ public IfAction(List<XMLEvent> tree, Selector<?> condition, boolean negate) {
+ this.tree = tree;
+ this.condition = condition;
+ this.negate = negate;
+ }
+
+ public void evaluate(TemplateInterpolator interpolator, RDFNode node, XMLEventConsumer writer)
+ throws XMLStreamException {
+ List<?> selectorResult = condition.result(node);
+ if (negate ? selectorResult.isEmpty() : !selectorResult.isEmpty()) {
+ interpolator.interpolate(tree.iterator(), node, writer);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this)
+ .append("condition", condition)
+ .append("negate", negate)
+ .toString();
+ }
+
+}
diff --git a/src/main/java/au/id/djc/rdftemplate/JoinAction.java b/src/main/java/au/id/djc/rdftemplate/JoinAction.java
@@ -0,0 +1,64 @@
+package au.id.djc.rdftemplate;
+
+import java.util.List;
+import java.util.logging.Logger;
+
+import javax.xml.namespace.QName;
+import javax.xml.stream.XMLEventFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.events.XMLEvent;
+import javax.xml.stream.util.XMLEventConsumer;
+
+import com.hp.hpl.jena.rdf.model.RDFNode;
+import com.hp.hpl.jena.rdf.model.Resource;
+import com.hp.hpl.jena.rdf.model.Seq;
+import com.hp.hpl.jena.vocabulary.RDF;
+import org.apache.commons.lang.builder.ToStringBuilder;
+
+import au.id.djc.rdftemplate.selector.Selector;
+
+public class JoinAction extends TemplateAction {
+
+ public static final String ACTION_NAME = "join";
+ public static final QName ACTION_QNAME = new QName(TemplateInterpolator.NS, ACTION_NAME);
+ private static final Logger LOG = Logger.getLogger(JoinAction.class.getName());
+
+ private final List<XMLEvent> tree;
+ private final Selector<RDFNode> selector;
+ private final String separator;
+
+ public JoinAction(List<XMLEvent> tree, Selector<RDFNode> selector, String separator) {
+ this.tree = tree;
+ this.selector = selector;
+ this.separator = separator;
+ }
+
+ public void evaluate(TemplateInterpolator interpolator, RDFNode node, XMLEventConsumer writer, XMLEventFactory eventFactory)
+ throws XMLStreamException {
+ List<RDFNode> result = selector.result(node);
+ if (result.size() == 1 && result.get(0).canAs(Resource.class)) {
+ if (result.get(0).as(Resource.class).hasProperty(RDF.type, RDF.Seq)) {
+ LOG.fine("Apply rdf:Seq special case for " + result.get(0));
+ result = result.get(0).as(Seq.class).iterator().toList();
+ LOG.fine("Resulting sequence is " + result);
+ }
+ }
+ boolean first = true;
+ for (RDFNode eachNode: result) {
+ if (!first) {
+ writer.add(eventFactory.createCharacters(separator));
+ }
+ interpolator.interpolate(tree.iterator(), eachNode, writer);
+ first = false;
+ }
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this)
+ .append("selector", selector)
+ .append("separator", separator)
+ .toString();
+ }
+
+}
diff --git a/src/main/java/au/id/djc/rdftemplate/TemplateAction.java b/src/main/java/au/id/djc/rdftemplate/TemplateAction.java
@@ -0,0 +1,5 @@
+package au.id.djc.rdftemplate;
+
+public abstract class TemplateAction {
+
+}
diff --git a/src/main/java/au/id/djc/rdftemplate/TemplateInterpolationException.java b/src/main/java/au/id/djc/rdftemplate/TemplateInterpolationException.java
@@ -0,0 +1,23 @@
+package au.id.djc.rdftemplate;
+
+import javax.xml.stream.Location;
+
+import com.hp.hpl.jena.rdf.model.RDFNode;
+
+public class TemplateInterpolationException extends RuntimeException {
+
+ private static final long serialVersionUID = -1472104970210074672L;
+
+ public TemplateInterpolationException(Location location, TemplateAction action, RDFNode node, Throwable cause) {
+ super("Exception evaluating action [" + action + "] " +
+ "at location [" + location.getLineNumber() + "," + location.getColumnNumber() + "] " +
+ "with context node " + node, cause);
+ }
+
+ public TemplateInterpolationException(Location location, String selectorExpression, RDFNode node, Throwable cause) {
+ super("Exception evaluating selector expression [" + selectorExpression + "] " +
+ "at location [" + location.getLineNumber() + "," + location.getColumnNumber() + "] " +
+ "with context node " + node, cause);
+ }
+
+}
diff --git a/src/main/java/au/id/djc/rdftemplate/TemplateInterpolator.java b/src/main/java/au/id/djc/rdftemplate/TemplateInterpolator.java
@@ -0,0 +1,431 @@
+package au.id.djc.rdftemplate;
+
+import java.io.InputStream;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Deque;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.xml.namespace.QName;
+import javax.xml.stream.XMLEventFactory;
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.XMLEventWriter;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamConstants;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.events.Attribute;
+import javax.xml.stream.events.Characters;
+import javax.xml.stream.events.EndElement;
+import javax.xml.stream.events.Namespace;
+import javax.xml.stream.events.StartElement;
+import javax.xml.stream.events.XMLEvent;
+import javax.xml.stream.util.XMLEventConsumer;
+
+import com.hp.hpl.jena.rdf.model.Literal;
+import com.hp.hpl.jena.rdf.model.RDFNode;
+
+import au.id.djc.rdftemplate.selector.InvalidSelectorSyntaxException;
+import au.id.djc.rdftemplate.selector.Selector;
+import au.id.djc.rdftemplate.selector.SelectorFactory;
+
+public class TemplateInterpolator {
+
+ public static final String NS = "http://code.miskinhill.com.au/rdftemplate/";
+
+ private final XMLInputFactory inputFactory = XMLInputFactory.newInstance();
+ private final XMLOutputFactory outputFactory = XMLOutputFactory.newInstance();
+ private final XMLEventFactory eventFactory = XMLEventFactory.newInstance();
+
+ private final SelectorFactory selectorFactory;
+
+ public TemplateInterpolator(SelectorFactory selectorFactory) {
+ this.selectorFactory = selectorFactory;
+ inputFactory.setProperty(XMLInputFactory.IS_COALESCING, true);
+ outputFactory.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, true);
+ }
+
+ public String interpolate(Reader reader, RDFNode node) {
+ try {
+ StringWriter writer = new StringWriter();
+ final XMLEventWriter eventWriter = outputFactory.createXMLEventWriter(writer);
+ XMLEventConsumer destination = new XMLEventConsumer() {
+ @Override
+ public void add(XMLEvent event) throws XMLStreamException {
+ eventWriter.add(event);
+ }
+ };
+ interpolate(reader, node, destination);
+ return writer.toString();
+ } catch (XMLStreamException e) {
+ throw new TemplateSyntaxException(e);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public void interpolate(Reader reader, RDFNode node, XMLEventConsumer writer) {
+ try {
+ interpolate(inputFactory.createXMLEventReader(reader), node, writer);
+ } catch (XMLStreamException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public void interpolate(InputStream inputStream, RDFNode node, Writer writer) {
+ try {
+ final XMLEventWriter eventWriter = outputFactory.createXMLEventWriter(writer);
+ XMLEventConsumer destination = new XMLEventConsumer() {
+ @Override
+ public void add(XMLEvent event) throws XMLStreamException {
+ eventWriter.add(event);
+ }
+ };
+ interpolate(inputFactory.createXMLEventReader(inputStream), node, destination);
+ } catch (XMLStreamException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public void interpolate(Reader reader, RDFNode node, final Collection<XMLEvent> destination) {
+ interpolate(reader, node, new XMLEventConsumer() {
+ @Override
+ public void add(XMLEvent event) {
+ destination.add(event);
+ }
+ });
+ }
+
+ public void interpolate(Iterator<XMLEvent> reader, RDFNode node, XMLEventConsumer writer)
+ throws XMLStreamException {
+ while (reader.hasNext()) {
+ XMLEvent event = reader.next();
+ switch (event.getEventType()) {
+ case XMLStreamConstants.START_ELEMENT: {
+ StartElement start = (StartElement) event;
+ if (start.getName().equals(IfAction.ACTION_QNAME)) {
+ Attribute testAttribute = start.getAttributeByName(new QName("test"));
+ Attribute notAttribute = start.getAttributeByName(new QName("not"));
+ String condition;
+ boolean negate = false;
+ if (testAttribute != null && notAttribute != null)
+ throw new TemplateSyntaxException(start.getLocation(), "test and not attribute on rdf:if are mutually exclusive");
+ else if (testAttribute != null)
+ condition = testAttribute.getValue();
+ else if (notAttribute != null) {
+ condition = notAttribute.getValue();
+ negate = true;
+ } else
+ throw new TemplateSyntaxException(start.getLocation(), "rdf:if must have a test attribute or a not attribute");
+ Selector<?> conditionSelector;
+ try {
+ conditionSelector = selectorFactory.get(condition);
+ } catch (InvalidSelectorSyntaxException e) {
+ throw new TemplateSyntaxException(start.getLocation(), e);
+ }
+ List<XMLEvent> tree = consumeTree(start, reader);
+ // discard enclosing rdf:if
+ tree.remove(tree.size() - 1);
+ tree.remove(0);
+ IfAction action = new IfAction(tree, conditionSelector, negate);
+ try {
+ action.evaluate(this, node, writer);
+ } catch (Exception e) {
+ throw new TemplateInterpolationException(start.getLocation(), action, node, e);
+ }
+ } else if (start.getName().equals(JoinAction.ACTION_QNAME)) {
+ Attribute eachAttribute = start.getAttributeByName(new QName("each"));
+ if (eachAttribute == null)
+ throw new TemplateSyntaxException(start.getLocation(), "rdf:join must have an each attribute");
+ String separator = "";
+ Attribute separatorAttribute = start.getAttributeByName(new QName("separator"));
+ if (separatorAttribute != null)
+ separator = separatorAttribute.getValue();
+ Selector<RDFNode> selector;
+ try {
+ selector = selectorFactory.get(eachAttribute.getValue()).withResultType(RDFNode.class);
+ } catch (InvalidSelectorSyntaxException e) {
+ throw new TemplateSyntaxException(start.getLocation(), e);
+ }
+ List<XMLEvent> events = consumeTree(start, reader);
+ // discard enclosing rdf:join
+ events.remove(events.size() - 1);
+ events.remove(0);
+ JoinAction action = new JoinAction(events, selector, separator);
+ try {
+ action.evaluate(this, node, writer, eventFactory);
+ } catch (Exception e) {
+ throw new TemplateInterpolationException(start.getLocation(), action, node, e);
+ }
+ } else if (start.getName().equals(ForAction.ACTION_QNAME)) {
+ Attribute eachAttribute = start.getAttributeByName(new QName("each"));
+ if (eachAttribute == null)
+ throw new TemplateSyntaxException(start.getLocation(), "rdf:for must have an each attribute");
+ Selector<RDFNode> selector;
+ try {
+ selector = selectorFactory.get(eachAttribute.getValue()).withResultType(RDFNode.class);
+ } catch (InvalidSelectorSyntaxException e) {
+ throw new TemplateSyntaxException(start.getLocation(), e);
+ }
+ List<XMLEvent> events = consumeTree(start, reader);
+ // discard enclosing rdf:for
+ events.remove(events.size() - 1);
+ events.remove(0);
+ ForAction action = new ForAction(events, selector);
+ try {
+ action.evaluate(this, node, writer);
+ } catch (Exception e) {
+ throw new TemplateInterpolationException(start.getLocation(), action, node, e);
+ }
+ } else {
+ Attribute ifAttribute = start.getAttributeByName(IfAction.ACTION_QNAME);
+ Attribute contentAttribute = start.getAttributeByName(ContentAction.ACTION_QNAME);
+ Attribute forAttribute = start.getAttributeByName(ForAction.ACTION_QNAME);
+ if (ifAttribute != null) {
+ Selector<?> selector;
+ try {
+ selector = selectorFactory.get(ifAttribute.getValue());
+ } catch (InvalidSelectorSyntaxException e) {
+ throw new TemplateSyntaxException(ifAttribute.getLocation(), e);
+ }
+ start = cloneStart(start, cloneAttributesWithout(start, IfAction.ACTION_QNAME), cloneNamespacesWithoutRdf(start));
+ IfAction action = new IfAction(consumeTree(start, reader), selector, false);
+ action.evaluate(this, node, writer);
+ } else if (contentAttribute != null && forAttribute != null) {
+ throw new TemplateSyntaxException(start.getLocation(), "rdf:for and rdf:content cannot both be present on an element");
+ } else if (contentAttribute != null) {
+ consumeTree(start, reader); // discard
+ Selector<?> selector;
+ try {
+ selector = selectorFactory.get(contentAttribute.getValue());
+ } catch (InvalidSelectorSyntaxException e) {
+ throw new TemplateSyntaxException(contentAttribute.getLocation(), e);
+ }
+ ContentAction action = new ContentAction(start, selector);
+ try {
+ action.evaluate(this, node, writer, eventFactory);
+ } catch (Exception e) {
+ throw new TemplateInterpolationException(contentAttribute.getLocation(), action, node, e);
+ }
+ } else if (forAttribute != null) {
+ Selector<RDFNode> selector;
+ try {
+ selector = selectorFactory.get(forAttribute.getValue()).withResultType(RDFNode.class);
+ } catch (InvalidSelectorSyntaxException e) {
+ throw new TemplateSyntaxException(forAttribute.getLocation(), e);
+ }
+ start = cloneStart(start, cloneAttributesWithout(start, ForAction.ACTION_QNAME), cloneNamespacesWithoutRdf(start));
+ List<XMLEvent> tree = consumeTree(start, reader);
+ ForAction action = new ForAction(tree, selector);
+ try {
+ action.evaluate(this, node, writer);
+ } catch (Exception e) {
+ throw new TemplateInterpolationException(forAttribute.getLocation(), action, node, e);
+ }
+ } else {
+ start = interpolateAttributes(start, node);
+ writer.add(start);
+ }
+ }
+ break;
+ }
+ case XMLStreamConstants.CHARACTERS: {
+ Characters characters = (Characters) event;
+ interpolateCharacters(writer, characters, node);
+ break;
+ }
+ case XMLStreamConstants.CDATA: {
+ Characters characters = (Characters) event;
+ interpolateCharacters(writer, characters, node);
+ break;
+ }
+ default:
+ writer.add(event);
+ }
+ }
+ }
+
+ private List<XMLEvent> consumeTree(StartElement start, Iterator<XMLEvent> reader) throws XMLStreamException {
+ List<XMLEvent> events = new ArrayList<XMLEvent>();
+ events.add(start);
+ Deque<QName> elementStack = new LinkedList<QName>();
+ while (reader.hasNext()) {
+ XMLEvent event = reader.next();
+ events.add(event);
+ switch (event.getEventType()) {
+ case XMLStreamConstants.START_ELEMENT:
+ elementStack.addLast(((StartElement) event).getName());
+ break;
+ case XMLStreamConstants.END_ELEMENT:
+ if (elementStack.isEmpty()) {
+ return events;
+ } else {
+ if (!elementStack.removeLast().equals(((EndElement) event).getName()))
+ throw new IllegalStateException("End element mismatch");
+ }
+ break;
+ default:
+ }
+ }
+ throw new IllegalStateException("Reader exhausted before end element found");
+ }
+
+ @SuppressWarnings("unchecked")
+ protected StartElement interpolateAttributes(StartElement start, RDFNode node) {
+ Set<Attribute> replacementAttributes = new LinkedHashSet<Attribute>();
+ for (Iterator<Attribute> it = start.getAttributes(); it.hasNext(); ) {
+ Attribute attribute = it.next();
+ String replacementValue = attribute.getValue();
+ if (!attribute.getName().getNamespaceURI().equals(NS)) { // skip rdf: attributes
+ try {
+ replacementValue = interpolateString(attribute.getValue(), node);
+ } catch (Exception e) {
+ throw new TemplateInterpolationException(attribute.getLocation(), attribute.getValue(), node, e);
+ }
+ }
+ replacementAttributes.add(eventFactory.createAttribute(attribute.getName(),
+ replacementValue));
+ }
+ return cloneStart(start, replacementAttributes, cloneNamespacesWithoutRdf(start));
+ }
+
+ private StartElement cloneStart(StartElement start, Iterable<Attribute> attributes, Iterable<Namespace> namespaces) {
+ return eventFactory.createStartElement(
+ start.getName().getPrefix(),
+ start.getName().getNamespaceURI(),
+ start.getName().getLocalPart(),
+ attributes.iterator(),
+ namespaces.iterator(),
+ start.getNamespaceContext());
+ }
+
+ @SuppressWarnings("unchecked")
+ private Set<Namespace> cloneNamespacesWithoutRdf(StartElement start) {
+ Set<Namespace> clonedNamespaces = new LinkedHashSet<Namespace>();
+ for (Iterator<Namespace> it = start.getNamespaces(); it.hasNext(); ) {
+ Namespace namespace = it.next();
+ if (!namespace.getNamespaceURI().equals(NS))
+ clonedNamespaces.add(namespace);
+ }
+ return clonedNamespaces;
+ }
+
+ private static final Pattern SUBSTITUTION_PATTERN = Pattern.compile("\\$\\{([^}]*)\\}");
+ public String interpolateString(String template, RDFNode node) {
+ if (!SUBSTITUTION_PATTERN.matcher(template).find()) {
+ return template; // fast path
+ }
+ StringBuffer substituted = new StringBuffer();
+ Matcher matcher = SUBSTITUTION_PATTERN.matcher(template);
+ while (matcher.find()) {
+ String expression = matcher.group(1);
+ Object replacement = selectorFactory.get(expression).singleResult(node);
+
+ String replacementValue;
+ if (replacement instanceof RDFNode) {
+ RDFNode replacementNode = (RDFNode) replacement;
+ if (replacementNode.isLiteral()) {
+ Literal replacementLiteral = (Literal) replacementNode;
+ replacementValue = replacementLiteral.getValue().toString();
+ } else {
+ throw new UnsupportedOperationException("Not a literal: " + replacementNode);
+ }
+ } else {
+ replacementValue = replacement.toString();
+ }
+
+ matcher.appendReplacement(substituted, replacementValue.replace("$", "\\$"));
+ }
+ matcher.appendTail(substituted);
+ return substituted.toString();
+ }
+
+ private void interpolateCharacters(XMLEventConsumer writer, Characters characters, RDFNode node) throws XMLStreamException {
+ String template = characters.getData();
+ if (!SUBSTITUTION_PATTERN.matcher(template).find()) {
+ writer.add(characters); // fast path
+ return;
+ }
+ Matcher matcher = SUBSTITUTION_PATTERN.matcher(template);
+ int lastAppendedPos = 0;
+ while (matcher.find()) {
+ writer.add(eventFactory.createCharacters(template.substring(lastAppendedPos, matcher.start())));
+ lastAppendedPos = matcher.end();
+ String expression = matcher.group(1);
+ Selector<?> selector;
+ try {
+ selector = selectorFactory.get(expression);
+ } catch (InvalidSelectorSyntaxException e) {
+ throw new TemplateSyntaxException(characters.getLocation(), e);
+ }
+ try {
+ Object replacement = selector.singleResult(node);
+ writeTreeForContent(writer, replacement);
+ } catch (Exception e) {
+ throw new TemplateInterpolationException(characters.getLocation(), expression, node, e);
+ }
+ }
+ writer.add(eventFactory.createCharacters(template.substring(lastAppendedPos)));
+ }
+
+ protected void writeTreeForContent(XMLEventConsumer writer, Object replacement)
+ throws XMLStreamException {
+ if (replacement instanceof RDFNode) {
+ RDFNode replacementNode = (RDFNode) replacement;
+ if (replacementNode.isLiteral()) {
+ Literal literal = (Literal) replacementNode;
+ if (literal.isWellFormedXML()) {
+ writeXMLLiteral(literal.getLexicalForm(), writer);
+ } else {
+ writer.add(eventFactory.createCharacters(literal.getValue().toString()));
+ }
+ } else {
+ throw new UnsupportedOperationException("Not a literal: " + replacementNode);
+ }
+ } else if (replacement instanceof XMLStream) {
+ for (XMLEvent event: (XMLStream) replacement) {
+ writer.add(event);
+ }
+ } else {
+ writer.add(eventFactory.createCharacters(replacement.toString()));
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ protected Set<Attribute> cloneAttributesWithout(StartElement start, QName omit) {
+ // clone attributes, but without rdf:content
+ Set<Attribute> attributes = new LinkedHashSet<Attribute>();
+ for (Iterator<Attribute> it = start.getAttributes(); it.hasNext(); ) {
+ Attribute attribute = it.next();
+ if (!attribute.getName().equals(omit))
+ attributes.add(attribute);
+ }
+ return attributes;
+ }
+
+ private void writeXMLLiteral(String literal, XMLEventConsumer writer)
+ throws XMLStreamException {
+ XMLEventReader reader = inputFactory.createXMLEventReader(new StringReader(literal));
+ while (reader.hasNext()) {
+ XMLEvent event = reader.nextEvent();
+ switch (event.getEventType()) {
+ case XMLStreamConstants.START_DOCUMENT:
+ case XMLStreamConstants.END_DOCUMENT:
+ break; // discard
+ default:
+ writer.add(event);
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/au/id/djc/rdftemplate/TemplateSyntaxException.java b/src/main/java/au/id/djc/rdftemplate/TemplateSyntaxException.java
@@ -0,0 +1,22 @@
+package au.id.djc.rdftemplate;
+
+import javax.xml.stream.Location;
+import javax.xml.stream.XMLStreamException;
+
+public class TemplateSyntaxException extends RuntimeException {
+
+ private static final long serialVersionUID = 6518982504570154030L;
+
+ public TemplateSyntaxException(Location location, String message) {
+ super("[location " + location.getLineNumber() + "," + location.getColumnNumber() + "] " + message);
+ }
+
+ public TemplateSyntaxException(Location location, Throwable cause) {
+ super("[location " + location.getLineNumber() + "," + location.getColumnNumber() + "]", cause);
+ }
+
+ public TemplateSyntaxException(XMLStreamException e) {
+ super(e);
+ }
+
+}
diff --git a/src/main/java/au/id/djc/rdftemplate/XMLStream.java b/src/main/java/au/id/djc/rdftemplate/XMLStream.java
@@ -0,0 +1,43 @@
+package au.id.djc.rdftemplate;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
+import javax.xml.stream.XMLStreamConstants;
+import javax.xml.stream.events.XMLEvent;
+
+public class XMLStream implements Iterable<XMLEvent> {
+
+ public static XMLStream collect(Iterator<XMLEvent> it) {
+ List<XMLEvent> events = new ArrayList<XMLEvent>();
+ while (it.hasNext()) {
+ XMLEvent event = it.next();
+ switch (event.getEventType()) {
+ case XMLStreamConstants.START_DOCUMENT:
+ case XMLStreamConstants.END_DOCUMENT:
+ break; // discard
+ default:
+ events.add(event);
+ }
+ }
+ return new XMLStream(events);
+ }
+
+ private final List<XMLEvent> events;
+
+ public XMLStream(XMLEvent... events) {
+ this.events = Arrays.asList(events);
+ }
+
+ public XMLStream(List<XMLEvent> events) {
+ this.events = events;
+ }
+
+ @Override
+ public Iterator<XMLEvent> iterator() {
+ return events.iterator();
+ }
+
+}
diff --git a/src/main/java/au/id/djc/rdftemplate/datatype/DateDataType.java b/src/main/java/au/id/djc/rdftemplate/datatype/DateDataType.java
@@ -0,0 +1,112 @@
+package au.id.djc.rdftemplate.datatype;
+
+import org.springframework.stereotype.Component;
+
+import com.hp.hpl.jena.datatypes.DatatypeFormatException;
+import com.hp.hpl.jena.datatypes.RDFDatatype;
+import com.hp.hpl.jena.datatypes.TypeMapper;
+import com.hp.hpl.jena.graph.impl.LiteralLabel;
+import org.joda.time.LocalDate;
+import org.joda.time.format.DateTimeFormat;
+import org.joda.time.format.DateTimeFormatter;
+
+@Component
+public class DateDataType implements RDFDatatype {
+
+ public static final String URI = "http://www.w3.org/TR/xmlschema-2/#date";
+
+ @SuppressWarnings("unused")
+ private static DateDataType instance;
+ public static void registerStaticInstance() {
+ instance = new DateDataType();
+ }
+
+ private final DateTimeFormatter yearParser = DateTimeFormat.forPattern("yyyy");
+ private final DateTimeFormatter yearMonthParser = DateTimeFormat.forPattern("yyyy-MM");
+ private final DateTimeFormatter dateParser = DateTimeFormat.forPattern("yyyy-MM-dd");
+
+ public DateDataType() {
+ TypeMapper.getInstance().registerDatatype(this);
+ }
+
+ @Override
+ public String getURI() {
+ return URI;
+ }
+
+ @Override
+ public Class<LocalDate> getJavaClass() {
+ return null;
+ }
+
+ @Override
+ public String unparse(Object value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Object cannonicalise(Object value) {
+ return value;
+ }
+
+ @Override
+ public Object extendedTypeDefinition() {
+ return null;
+ }
+
+ @Override
+ public int getHashCode(LiteralLabel lit) {
+ return lit.getValue().hashCode();
+ }
+
+ @Override
+ public boolean isEqual(LiteralLabel left, LiteralLabel right) {
+ return left.getValue().equals(right.getValue());
+ }
+
+ @Override
+ public Object parse(String lexicalForm) throws DatatypeFormatException {
+ try {
+ return dateParser.parseDateTime(lexicalForm).toLocalDate();
+ } catch (IllegalArgumentException e) {
+ // pass
+ }
+ try {
+ return new YearMonth(yearMonthParser.parseDateTime(lexicalForm).toLocalDate());
+ } catch (IllegalArgumentException e) {
+ // pass
+ }
+ try {
+ return new Year(yearParser.parseDateTime(lexicalForm).toLocalDate());
+ } catch (IllegalArgumentException e) {
+ // pass
+ }
+ throw new DatatypeFormatException(lexicalForm, this, "No matching parsers found");
+ }
+
+ @Override
+ public boolean isValid(String lexicalForm) {
+ try {
+ parse(lexicalForm);
+ return true;
+ } catch (DatatypeFormatException e) {
+ return false;
+ }
+ }
+
+ @Override
+ public boolean isValidLiteral(LiteralLabel lit) {
+ return lit.getDatatypeURI().equals(URI) && isValid(lit.getLexicalForm());
+ }
+
+ @Override
+ public boolean isValidValue(Object valueForm) {
+ return (valueForm instanceof LocalDate);
+ }
+
+ @Override
+ public RDFDatatype normalizeSubType(Object value, RDFDatatype dt) {
+ return dt;
+ }
+
+}
+\ No newline at end of file
diff --git a/src/main/java/au/id/djc/rdftemplate/datatype/DateTimeDataType.java b/src/main/java/au/id/djc/rdftemplate/datatype/DateTimeDataType.java
@@ -0,0 +1,98 @@
+package au.id.djc.rdftemplate.datatype;
+
+import com.hp.hpl.jena.datatypes.DatatypeFormatException;
+import com.hp.hpl.jena.datatypes.RDFDatatype;
+import com.hp.hpl.jena.datatypes.TypeMapper;
+import com.hp.hpl.jena.graph.impl.LiteralLabel;
+import org.joda.time.DateTime;
+import org.joda.time.format.DateTimeFormatter;
+import org.joda.time.format.ISODateTimeFormat;
+import org.springframework.stereotype.Component;
+
+@Component
+public class DateTimeDataType implements RDFDatatype {
+
+ public static final String URI = "http://www.w3.org/TR/xmlschema-2/#datetime";
+
+ @SuppressWarnings("unused")
+ private static DateTimeDataType instance;
+ public static void registerStaticInstance() {
+ instance = new DateTimeDataType();
+ }
+
+ private final DateTimeFormatter format = ISODateTimeFormat.dateTimeNoMillis().withOffsetParsed();
+
+ public DateTimeDataType() {
+ TypeMapper.getInstance().registerDatatype(this);
+ }
+
+ @Override
+ public String getURI() {
+ return URI;
+ }
+
+ @Override
+ public Class<DateTime> getJavaClass() {
+ return DateTime.class;
+ }
+
+ @Override
+ public String unparse(Object value) {
+ return ((DateTime) value).toString(format);
+ }
+
+ @Override
+ public Object cannonicalise(Object value) {
+ return value;
+ }
+
+ @Override
+ public Object extendedTypeDefinition() {
+ return null;
+ }
+
+ @Override
+ public int getHashCode(LiteralLabel lit) {
+ return lit.getValue().hashCode();
+ }
+
+ @Override
+ public boolean isEqual(LiteralLabel left, LiteralLabel right) {
+ return left.getValue().equals(right.getValue());
+ }
+
+ @Override
+ public DateTime parse(String lexicalForm) throws DatatypeFormatException {
+ try {
+ return format.parseDateTime(lexicalForm);
+ } catch (IllegalArgumentException e) {
+ throw new DatatypeFormatException(lexicalForm, this, "Parser barfed");
+ }
+ }
+
+ @Override
+ public boolean isValid(String lexicalForm) {
+ try {
+ parse(lexicalForm);
+ return true;
+ } catch (DatatypeFormatException e) {
+ return false;
+ }
+ }
+
+ @Override
+ public boolean isValidLiteral(LiteralLabel lit) {
+ return lit.getDatatypeURI().equals(URI) && isValid(lit.getLexicalForm());
+ }
+
+ @Override
+ public boolean isValidValue(Object valueForm) {
+ return (valueForm instanceof DateTime);
+ }
+
+ @Override
+ public RDFDatatype normalizeSubType(Object value, RDFDatatype dt) {
+ return dt;
+ }
+
+}
+\ No newline at end of file
diff --git a/src/main/java/au/id/djc/rdftemplate/datatype/Year.java b/src/main/java/au/id/djc/rdftemplate/datatype/Year.java
@@ -0,0 +1,50 @@
+package au.id.djc.rdftemplate.datatype;
+
+import org.joda.time.LocalDate;
+
+public class Year {
+
+ private final int year;
+
+ public Year(int value) {
+ this.year = value;
+ }
+
+ public Year(LocalDate date) {
+ this.year = date.getYear();
+ }
+
+ public Year(YearMonth yearMonth) {
+ this.year = yearMonth.getYear();
+ }
+
+ public int getYear() {
+ return year;
+ }
+
+ @Override
+ public String toString() {
+ return Integer.toString(year);
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + year;
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ Year other = (Year) obj;
+ return (year == other.year);
+ }
+
+}
diff --git a/src/main/java/au/id/djc/rdftemplate/datatype/YearMonth.java b/src/main/java/au/id/djc/rdftemplate/datatype/YearMonth.java
@@ -0,0 +1,58 @@
+package au.id.djc.rdftemplate.datatype;
+
+import org.joda.time.LocalDate;
+
+public class YearMonth {
+
+ private final int year;
+ private final int month;
+
+ public YearMonth(int year, int month) {
+ this.year = year;
+ this.month = month;
+ }
+
+ public YearMonth(LocalDate date) {
+ this.year = date.getYear();
+ this.month = date.getMonthOfYear();
+ }
+
+ public int getYear() {
+ return year;
+ }
+
+ public int getMonth() {
+ return month;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%04d-%02d", year, month);
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + month;
+ result = prime * result + year;
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ YearMonth other = (YearMonth) obj;
+ if (month != other.month)
+ return false;
+ if (year != other.year)
+ return false;
+ return true;
+ }
+
+}
diff --git a/src/main/java/au/id/djc/rdftemplate/selector/AbstractAdaptation.java b/src/main/java/au/id/djc/rdftemplate/selector/AbstractAdaptation.java
@@ -0,0 +1,58 @@
+package au.id.djc.rdftemplate.selector;
+
+import java.util.Arrays;
+
+import com.hp.hpl.jena.rdf.model.RDFNode;
+
+public abstract class AbstractAdaptation<DestType, NodeType extends RDFNode> implements Adaptation<DestType> {
+
+ private final Class<DestType> destinationType;
+ private final Class<?>[] argTypes;
+ private final Class<NodeType> nodeType;
+
+ protected AbstractAdaptation(Class<DestType> destinationType, Class<?>[] argTypes, Class<NodeType> nodeType) {
+ this.destinationType = destinationType;
+ this.argTypes = argTypes;
+ this.nodeType = nodeType;
+ }
+
+ @Override
+ public Class<DestType> getDestinationType() {
+ return destinationType;
+ }
+
+ @Override
+ public Class<?>[] getArgTypes() {
+ return argTypes;
+ }
+
+ @Override
+ public void setArgs(Object[] args) {
+ if (args.length != argTypes.length)
+ throw new SelectorEvaluationException("Expected args of types " + Arrays.toString(argTypes) +
+ " but invoked with " + Arrays.toString(args));
+ for (int i = 0; i < args.length; i ++) {
+ if (!argTypes[i].isAssignableFrom(args[i].getClass()))
+ throw new SelectorEvaluationException("Arg " + i + ": expected type " + argTypes[i] +
+ " but was " + args[i].getClass());
+ }
+ setCheckedArgs(args);
+ }
+
+ protected void setCheckedArgs(Object[] args) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public DestType adapt(RDFNode node) {
+ if (!nodeType.equals(RDFNode.class)) {
+ if (!node.canAs(nodeType))
+ throw new SelectorEvaluationException("Adaptation can only be applied to " + nodeType +
+ " but was applied to " + node);
+ }
+ return doAdapt(node.as(nodeType));
+ }
+
+ protected abstract DestType doAdapt(NodeType node);
+
+}
diff --git a/src/main/java/au/id/djc/rdftemplate/selector/AbstractSelector.java b/src/main/java/au/id/djc/rdftemplate/selector/AbstractSelector.java
@@ -0,0 +1,40 @@
+package au.id.djc.rdftemplate.selector;
+
+import java.util.List;
+
+import com.hp.hpl.jena.rdf.model.RDFNode;
+
+public abstract class AbstractSelector<T> implements Selector<T> {
+
+ private final Class<T> resultType;
+
+ protected AbstractSelector(Class<T> resultType) {
+ this.resultType = resultType;
+ }
+
+ @Override
+ public abstract List<T> result(RDFNode node);
+
+ @Override
+ public T singleResult(RDFNode node) {
+ List<T> results = result(node);
+ if (results.size() != 1) {
+ throw new SelectorEvaluationException("Expected exactly one result but got " + results);
+ }
+ return results.get(0);
+ }
+
+ @Override
+ public Class<T> getResultType() {
+ return resultType;
+ }
+
+ @Override
+ public <Other> Selector<Other> withResultType(Class<Other> otherType) {
+ if (!otherType.isAssignableFrom(resultType)) {
+ throw new ClassCastException("Result type " + resultType + " incompatible with requested type " + otherType);
+ }
+ return (Selector<Other>) this;
+ }
+
+}
+\ No newline at end of file
diff --git a/src/main/java/au/id/djc/rdftemplate/selector/Adaptation.java b/src/main/java/au/id/djc/rdftemplate/selector/Adaptation.java
@@ -0,0 +1,15 @@
+package au.id.djc.rdftemplate.selector;
+
+import com.hp.hpl.jena.rdf.model.RDFNode;
+
+public interface Adaptation<T> {
+
+ Class<T> getDestinationType();
+
+ Class<?>[] getArgTypes();
+
+ void setArgs(Object[] args);
+
+ T adapt(RDFNode node);
+
+}
diff --git a/src/main/java/au/id/djc/rdftemplate/selector/AdaptationFactory.java b/src/main/java/au/id/djc/rdftemplate/selector/AdaptationFactory.java
@@ -0,0 +1,9 @@
+package au.id.djc.rdftemplate.selector;
+
+public interface AdaptationFactory {
+
+ boolean hasName(String name);
+
+ Adaptation<?> getByName(String name);
+
+}
diff --git a/src/main/java/au/id/djc/rdftemplate/selector/AntlrSelectorFactory.java b/src/main/java/au/id/djc/rdftemplate/selector/AntlrSelectorFactory.java
@@ -0,0 +1,48 @@
+package au.id.djc.rdftemplate.selector;
+
+import java.util.Collections;
+import java.util.Map;
+
+import org.antlr.runtime.ANTLRStringStream;
+import org.antlr.runtime.CharStream;
+import org.antlr.runtime.CommonTokenStream;
+import org.antlr.runtime.RecognitionException;
+
+public class AntlrSelectorFactory implements SelectorFactory {
+
+ private AdaptationFactory adaptationFactory = new DefaultAdaptationFactory();
+ private PredicateResolver predicateResolver = new DefaultPredicateResolver();
+ private Map<String, String> namespacePrefixMap = Collections.emptyMap();
+
+ public AntlrSelectorFactory() {
+ }
+
+ public void setAdaptationFactory(AdaptationFactory adaptationFactory) {
+ this.adaptationFactory = adaptationFactory;
+ }
+
+ public void setPredicateResolver(PredicateResolver predicateResolver) {
+ this.predicateResolver = predicateResolver;
+ }
+
+ public void setNamespacePrefixMap(Map<String, String> namespacePrefixMap) {
+ this.namespacePrefixMap = namespacePrefixMap;
+ }
+
+ @Override
+ public Selector<?> get(String expression) {
+ CharStream stream = new ANTLRStringStream(expression);
+ SelectorLexer lexer = new SelectorLexer(stream);
+ CommonTokenStream tokens = new CommonTokenStream(lexer);
+ SelectorParser parser = new SelectorParser(tokens);
+ parser.setAdaptationFactory(adaptationFactory);
+ parser.setPredicateResolver(predicateResolver);
+ parser.setNamespacePrefixMap(namespacePrefixMap);
+ try {
+ return parser.unionSelector();
+ } catch (RecognitionException e) {
+ throw new InvalidSelectorSyntaxException(e);
+ }
+ }
+
+}
diff --git a/src/main/java/au/id/djc/rdftemplate/selector/BooleanAndPredicate.java b/src/main/java/au/id/djc/rdftemplate/selector/BooleanAndPredicate.java
@@ -0,0 +1,34 @@
+package au.id.djc.rdftemplate.selector;
+
+import com.hp.hpl.jena.rdf.model.RDFNode;
+import org.apache.commons.lang.builder.ToStringBuilder;
+
+public class BooleanAndPredicate implements Predicate {
+
+ private final Predicate left;
+ private final Predicate right;
+
+ public BooleanAndPredicate(Predicate left, Predicate right) {
+ this.left = left;
+ this.right = right;
+ }
+
+ public Predicate getLeft() {
+ return left;
+ }
+
+ public Predicate getRight() {
+ return right;
+ }
+
+ @Override
+ public boolean evaluate(RDFNode node) {
+ return left.evaluate(node) && right.evaluate(node);
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this).append(left).append(right).toString();
+ }
+
+}
diff --git a/src/main/java/au/id/djc/rdftemplate/selector/ComparableLiteralValueAdaptation.java b/src/main/java/au/id/djc/rdftemplate/selector/ComparableLiteralValueAdaptation.java
@@ -0,0 +1,22 @@
+package au.id.djc.rdftemplate.selector;
+
+import com.hp.hpl.jena.rdf.model.Literal;
+
+@SuppressWarnings("unchecked")
+public class ComparableLiteralValueAdaptation extends AbstractAdaptation<Comparable, Literal> {
+
+ public ComparableLiteralValueAdaptation() {
+ super(Comparable.class, new Class<?>[] { }, Literal.class);
+ }
+
+ @Override
+ protected Comparable<?> doAdapt(Literal node) {
+ Object literalValue = node.getValue();
+ if (!(literalValue instanceof Comparable<?>)) {
+ throw new SelectorEvaluationException("Attempted to apply #comparable-lv to non-Comparable node " + node +
+ " with literal value of type " + literalValue.getClass());
+ }
+ return (Comparable<?>) literalValue;
+ }
+
+}
diff --git a/src/main/java/au/id/djc/rdftemplate/selector/DefaultAdaptationFactory.java b/src/main/java/au/id/djc/rdftemplate/selector/DefaultAdaptationFactory.java
@@ -0,0 +1,35 @@
+package au.id.djc.rdftemplate.selector;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.springframework.beans.BeanUtils;
+
+public class DefaultAdaptationFactory implements AdaptationFactory {
+
+ private static final Map<String, Class<? extends Adaptation<?>>> ADAPTATIONS = new HashMap<String, Class<? extends Adaptation<?>>>();
+ static {
+ ADAPTATIONS.put("uri", UriAdaptation.class);
+ ADAPTATIONS.put("uri-slice", UriSliceAdaptation.class);
+ ADAPTATIONS.put("uri-anchor", UriAnchorAdaptation.class);
+ ADAPTATIONS.put("lv", LiteralValueAdaptation.class);
+ ADAPTATIONS.put("comparable-lv", ComparableLiteralValueAdaptation.class);
+ ADAPTATIONS.put("string-lv", StringLiteralValueAdaptation.class);
+ ADAPTATIONS.put("formatted-dt", FormattedDateTimeAdaptation.class);
+ }
+
+ @Override
+ public boolean hasName(String name) {
+ return ADAPTATIONS.containsKey(name);
+ }
+
+ @Override
+ public Adaptation<?> getByName(String name) {
+ Class<? extends Adaptation<?>> adaptationClass = ADAPTATIONS.get(name);
+ if (adaptationClass == null) {
+ throw new InvalidSelectorSyntaxException("No adaptation named " + name);
+ }
+ return BeanUtils.instantiate(adaptationClass);
+ }
+
+}
diff --git a/src/main/java/au/id/djc/rdftemplate/selector/DefaultPredicateResolver.java b/src/main/java/au/id/djc/rdftemplate/selector/DefaultPredicateResolver.java
@@ -0,0 +1,19 @@
+package au.id.djc.rdftemplate.selector;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class DefaultPredicateResolver implements PredicateResolver {
+
+ private static final Map<String, Class<? extends Predicate>> PREDICATES = new HashMap<String, Class<? extends Predicate>>();
+ static {
+ PREDICATES.put("type", TypePredicate.class);
+ PREDICATES.put("uri-prefix", UriPrefixPredicate.class);
+ }
+
+ @Override
+ public Class<? extends Predicate> getByName(String name) {
+ return PREDICATES.get(name);
+ }
+
+}
diff --git a/src/main/java/au/id/djc/rdftemplate/selector/EternallyCachingSelectorFactory.java b/src/main/java/au/id/djc/rdftemplate/selector/EternallyCachingSelectorFactory.java
@@ -0,0 +1,35 @@
+package au.id.djc.rdftemplate.selector;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * {@link SelectorFactory} implementation which indirects to a real
+ * implementation and caches its return values eternally. Do not use in
+ * situations where the set of input expressions can be unbounded (e.g.
+ * user-provided) as this will lead to unbounded cache growth.
+ * <p>
+ * A better implementation would use a LRU cache or similar, but I cbf.
+ */
+public class EternallyCachingSelectorFactory implements SelectorFactory {
+
+ private final SelectorFactory real;
+ private final Map<String, Selector<?>> cache = new HashMap<String, Selector<?>>();
+
+ public EternallyCachingSelectorFactory(SelectorFactory real) {
+ this.real = real;
+ }
+
+ @Override
+ public Selector<?> get(String expression) {
+ Selector<?> cached = cache.get(expression);
+ if (cached == null) {
+ Selector<?> fresh = real.get(expression);
+ cache.put(expression, fresh);
+ return fresh;
+ } else {
+ return cached;
+ }
+ }
+
+}
diff --git a/src/main/java/au/id/djc/rdftemplate/selector/FormattedDateTimeAdaptation.java b/src/main/java/au/id/djc/rdftemplate/selector/FormattedDateTimeAdaptation.java
@@ -0,0 +1,49 @@
+package au.id.djc.rdftemplate.selector;
+
+import org.apache.commons.lang.builder.ToStringBuilder;
+import org.joda.time.ReadableInstant;
+import org.joda.time.ReadablePartial;
+import org.joda.time.format.DateTimeFormat;
+import org.joda.time.format.DateTimeFormatter;
+
+import com.hp.hpl.jena.rdf.model.Literal;
+
+public class FormattedDateTimeAdaptation extends AbstractAdaptation<String, Literal> {
+
+ private String pattern;
+ private DateTimeFormatter formatter;
+
+ public FormattedDateTimeAdaptation() {
+ super(String.class, new Class<?>[] { String.class }, Literal.class);
+ }
+
+ @Override
+ protected void setCheckedArgs(Object[] args) {
+ this.pattern = (String) args[0];
+ this.formatter = DateTimeFormat.forPattern(pattern.replace("\"", "'")); // for convenience in XML
+ }
+
+ public String getPattern() {
+ return pattern;
+ }
+
+ @Override
+ protected String doAdapt(Literal node) {
+ Object lv = node.getValue();
+ if (lv instanceof ReadableInstant) {
+ ReadableInstant instant = (ReadableInstant) lv;
+ return formatter.print(instant);
+ } else if (lv instanceof ReadablePartial) {
+ ReadablePartial instant = (ReadablePartial) lv;
+ return formatter.print(instant);
+ } else {
+ throw new SelectorEvaluationException("Attempted to apply #formatted-dt to non-datetime literal " + lv);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this).append("pattern", pattern).toString();
+ }
+
+}
diff --git a/src/main/java/au/id/djc/rdftemplate/selector/InvalidSelectorSyntaxException.java b/src/main/java/au/id/djc/rdftemplate/selector/InvalidSelectorSyntaxException.java
@@ -0,0 +1,15 @@
+package au.id.djc.rdftemplate.selector;
+
+public class InvalidSelectorSyntaxException extends RuntimeException {
+
+ private static final long serialVersionUID = 5805546105865617336L;
+
+ public InvalidSelectorSyntaxException(Throwable cause) {
+ super(cause);
+ }
+
+ public InvalidSelectorSyntaxException(String message) {
+ super(message);
+ }
+
+}
diff --git a/src/main/java/au/id/djc/rdftemplate/selector/LiteralValueAdaptation.java b/src/main/java/au/id/djc/rdftemplate/selector/LiteralValueAdaptation.java
@@ -0,0 +1,16 @@
+package au.id.djc.rdftemplate.selector;
+
+import com.hp.hpl.jena.rdf.model.Literal;
+
+public class LiteralValueAdaptation extends AbstractAdaptation<Object, Literal> {
+
+ public LiteralValueAdaptation() {
+ super(Object.class, new Class<?>[] { }, Literal.class);
+ }
+
+ @Override
+ protected Object doAdapt(Literal node) {
+ return node.getValue();
+ }
+
+}
diff --git a/src/main/java/au/id/djc/rdftemplate/selector/NoopSelector.java b/src/main/java/au/id/djc/rdftemplate/selector/NoopSelector.java
@@ -0,0 +1,19 @@
+package au.id.djc.rdftemplate.selector;
+
+import java.util.Collections;
+import java.util.List;
+
+import com.hp.hpl.jena.rdf.model.RDFNode;
+
+public class NoopSelector extends AbstractSelector<RDFNode> {
+
+ public NoopSelector() {
+ super(RDFNode.class);
+ }
+
+ @Override
+ public List<RDFNode> result(RDFNode node) {
+ return Collections.singletonList(node);
+ }
+
+}
diff --git a/src/main/java/au/id/djc/rdftemplate/selector/Predicate.java b/src/main/java/au/id/djc/rdftemplate/selector/Predicate.java
@@ -0,0 +1,7 @@
+package au.id.djc.rdftemplate.selector;
+
+import com.hp.hpl.jena.rdf.model.RDFNode;
+
+public interface Predicate extends org.apache.commons.collections15.Predicate<RDFNode> {
+
+}
diff --git a/src/main/java/au/id/djc/rdftemplate/selector/PredicateResolver.java b/src/main/java/au/id/djc/rdftemplate/selector/PredicateResolver.java
@@ -0,0 +1,7 @@
+package au.id.djc.rdftemplate.selector;
+
+public interface PredicateResolver {
+
+ Class<? extends Predicate> getByName(String name);
+
+}
diff --git a/src/main/java/au/id/djc/rdftemplate/selector/Selector.java b/src/main/java/au/id/djc/rdftemplate/selector/Selector.java
@@ -0,0 +1,17 @@
+package au.id.djc.rdftemplate.selector;
+
+import java.util.List;
+
+import com.hp.hpl.jena.rdf.model.RDFNode;
+
+public interface Selector<T> {
+
+ List<T> result(RDFNode node);
+
+ T singleResult(RDFNode node);
+
+ Class<T> getResultType();
+
+ <Other> Selector<Other> withResultType(Class<Other> otherType);
+
+}
diff --git a/src/main/java/au/id/djc/rdftemplate/selector/SelectorComparator.java b/src/main/java/au/id/djc/rdftemplate/selector/SelectorComparator.java
@@ -0,0 +1,58 @@
+/**
+ *
+ */
+package au.id.djc.rdftemplate.selector;
+
+import java.util.Comparator;
+
+import org.apache.commons.lang.builder.ToStringBuilder;
+
+import com.hp.hpl.jena.rdf.model.RDFNode;
+
+public class SelectorComparator<T extends Comparable<T>> implements Comparator<RDFNode> {
+
+ private Selector<T> selector;
+ private boolean reversed = false;
+
+ public Selector<T> getSelector() {
+ return selector;
+ }
+
+ public void setSelector(Selector<T> selector) {
+ this.selector = selector;
+ }
+
+ public boolean isReversed() {
+ return reversed;
+ }
+
+ public void setReversed(boolean reversed) {
+ this.reversed = reversed;
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this).append(selector).append("reversed", reversed).toString();
+ }
+
+ @Override
+ public int compare(RDFNode left, RDFNode right) {
+ T leftKey;
+ try {
+ leftKey = selector.singleResult(left);
+ } catch (SelectorEvaluationException e) {
+ throw new SelectorEvaluationException("Exception evaluating selector [" + selector + "] " +
+ "with context node [" + left + "] for comparison", e);
+ }
+ T rightKey;
+ try {
+ rightKey = selector.singleResult(right);
+ } catch (SelectorEvaluationException e) {
+ throw new SelectorEvaluationException("Exception evaluating selector [" + selector + "] " +
+ "with context node [" + right + "] for comparison", e);
+ }
+ int result = leftKey.compareTo(rightKey);
+ return reversed ? -result : result;
+ }
+
+}
+\ No newline at end of file
diff --git a/src/main/java/au/id/djc/rdftemplate/selector/SelectorEvaluationException.java b/src/main/java/au/id/djc/rdftemplate/selector/SelectorEvaluationException.java
@@ -0,0 +1,15 @@
+package au.id.djc.rdftemplate.selector;
+
+public class SelectorEvaluationException extends RuntimeException {
+
+ private static final long serialVersionUID = -398277800899471326L;
+
+ public SelectorEvaluationException(String message) {
+ super(message);
+ }
+
+ public SelectorEvaluationException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+}
diff --git a/src/main/java/au/id/djc/rdftemplate/selector/SelectorFactory.java b/src/main/java/au/id/djc/rdftemplate/selector/SelectorFactory.java
@@ -0,0 +1,7 @@
+package au.id.djc.rdftemplate.selector;
+
+public interface SelectorFactory {
+
+ Selector<?> get(String expression);
+
+}
diff --git a/src/main/java/au/id/djc/rdftemplate/selector/SelectorWithAdaptation.java b/src/main/java/au/id/djc/rdftemplate/selector/SelectorWithAdaptation.java
@@ -0,0 +1,48 @@
+package au.id.djc.rdftemplate.selector;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.hp.hpl.jena.rdf.model.RDFNode;
+import org.apache.commons.lang.builder.ToStringBuilder;
+
+public class SelectorWithAdaptation<T> extends AbstractSelector<T> {
+
+ private final Selector<RDFNode> baseSelector;
+ private final Adaptation<T> adaptation;
+
+ public SelectorWithAdaptation(Selector<RDFNode> baseSelector, Adaptation<T> adaptation) {
+ super(adaptation.getDestinationType());
+ this.baseSelector = baseSelector;
+ this.adaptation = adaptation;
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this).append(baseSelector).append(adaptation).toString();
+ }
+
+ @Override
+ public List<T> result(RDFNode node) {
+ List<RDFNode> baseResults = baseSelector.result(node);
+ List<T> results = new ArrayList<T>();
+ for (RDFNode resultNode: baseResults) {
+ results.add(adaptation.adapt(resultNode));
+ }
+ return results;
+ }
+
+ @Override
+ public T singleResult(RDFNode node) {
+ return adaptation.adapt(baseSelector.singleResult(node));
+ }
+
+ public Selector<RDFNode> getBaseSelector() {
+ return baseSelector;
+ }
+
+ public Adaptation<T> getAdaptation() {
+ return adaptation;
+ }
+
+}
+\ No newline at end of file
diff --git a/src/main/java/au/id/djc/rdftemplate/selector/StringLiteralValueAdaptation.java b/src/main/java/au/id/djc/rdftemplate/selector/StringLiteralValueAdaptation.java
@@ -0,0 +1,45 @@
+package au.id.djc.rdftemplate.selector;
+
+import java.io.StringReader;
+
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.events.XMLEvent;
+
+import com.hp.hpl.jena.rdf.model.Literal;
+
+public class StringLiteralValueAdaptation extends AbstractAdaptation<String, Literal> {
+
+ private static final XMLInputFactory inputFactory = XMLInputFactory.newInstance();
+
+ public StringLiteralValueAdaptation() {
+ super(String.class, new Class<?>[] { }, Literal.class);
+ }
+
+ @Override
+ protected String doAdapt(Literal literal) {
+ if (literal.isWellFormedXML()) {
+ try {
+ return stripTags(literal.getLexicalForm());
+ } catch (XMLStreamException e) {
+ throw new RuntimeException(e);
+ }
+ } else {
+ return literal.getValue().toString();
+ }
+ }
+
+ private String stripTags(String literal) throws XMLStreamException {
+ StringBuilder sb = new StringBuilder();
+ XMLEventReader reader = inputFactory.createXMLEventReader(new StringReader(literal));
+ while (reader.hasNext()) {
+ XMLEvent event = reader.nextEvent();
+ if (event.isCharacters()) {
+ sb.append(event.asCharacters().getData());
+ }
+ }
+ return sb.toString();
+ }
+
+}
diff --git a/src/main/java/au/id/djc/rdftemplate/selector/Traversal.java b/src/main/java/au/id/djc/rdftemplate/selector/Traversal.java
@@ -0,0 +1,126 @@
+package au.id.djc.rdftemplate.selector;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import org.apache.commons.collections15.CollectionUtils;
+
+import com.hp.hpl.jena.rdf.model.Property;
+import com.hp.hpl.jena.rdf.model.RDFNode;
+import com.hp.hpl.jena.rdf.model.ResIterator;
+import com.hp.hpl.jena.rdf.model.Resource;
+import com.hp.hpl.jena.rdf.model.StmtIterator;
+import org.apache.commons.lang.builder.ToStringBuilder;
+
+public class Traversal {
+
+ private String propertyNamespace;
+ private String propertyLocalName;
+ private boolean inverse = false;
+ private Predicate predicate;
+ private List<Comparator<RDFNode>> sortOrder = new ArrayList<Comparator<RDFNode>>();
+ private Integer subscript;
+
+ private class SortComparator implements Comparator<RDFNode> {
+ @Override
+ public int compare(RDFNode left, RDFNode right) {
+ for (Comparator<RDFNode> comparator: sortOrder) {
+ int result = comparator.compare(left, right);
+ if (result != 0)
+ return result;
+ }
+ return 0;
+ }
+ }
+
+ public List<RDFNode> traverse(RDFNode node) {
+ if (!node.isResource()) {
+ throw new SelectorEvaluationException("Attempted to traverse non-resource node " + node);
+ }
+ Resource resource = (Resource) node;
+ Property property = resource.getModel().createProperty(propertyNamespace, propertyLocalName);
+ List<RDFNode> destinations = new ArrayList<RDFNode>();
+ if (!inverse) {
+ for (StmtIterator it = resource.listProperties(property); it.hasNext(); ) {
+ destinations.add(it.nextStatement().getObject());
+ }
+ } else {
+ for (ResIterator it = resource.getModel().listResourcesWithProperty(property, node); it.hasNext(); ) {
+ destinations.add(it.nextResource());
+ }
+ }
+ CollectionUtils.filter(destinations, predicate);
+ if (!sortOrder.isEmpty())
+ Collections.sort(destinations, new SortComparator());
+ if (subscript != null) {
+ if (destinations.size() <= subscript) {
+ throw new SelectorEvaluationException("Cannot apply subscript " + subscript + " to nodes " + destinations);
+ }
+ destinations = Collections.singletonList(destinations.get(subscript));
+ }
+ return destinations;
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this)
+ .append("propertyNamespace", propertyNamespace)
+ .append("propertyLocalName", propertyLocalName)
+ .append("inverse", inverse)
+ .append("predicate", predicate)
+ .append("sortOrder", sortOrder)
+ .append("subscript", subscript)
+ .toString();
+ }
+
+ public String getPropertyLocalName() {
+ return propertyLocalName;
+ }
+
+ public void setPropertyLocalName(String propertyLocalName) {
+ this.propertyLocalName = propertyLocalName;
+ }
+
+ public String getPropertyNamespace() {
+ return propertyNamespace;
+ }
+
+ public void setPropertyNamespace(String propertyNamespace) {
+ this.propertyNamespace = propertyNamespace;
+ }
+
+ public boolean isInverse() {
+ return inverse;
+ }
+
+ public void setInverse(boolean inverse) {
+ this.inverse = inverse;
+ }
+
+ public Predicate getPredicate() {
+ return predicate;
+ }
+
+ public void setPredicate(Predicate predicate) {
+ this.predicate = predicate;
+ }
+
+ public List<Comparator<RDFNode>> getSortOrder() {
+ return sortOrder;
+ }
+
+ public void addSortOrderComparator(Comparator<RDFNode> selector) {
+ this.sortOrder.add(selector);
+ }
+
+ public Integer getSubscript() {
+ return subscript;
+ }
+
+ public void setSubscript(Integer subscript) {
+ this.subscript = subscript;
+ }
+
+}
diff --git a/src/main/java/au/id/djc/rdftemplate/selector/TraversingSelector.java b/src/main/java/au/id/djc/rdftemplate/selector/TraversingSelector.java
@@ -0,0 +1,46 @@
+package au.id.djc.rdftemplate.selector;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+import com.hp.hpl.jena.rdf.model.RDFNode;
+import org.apache.commons.lang.builder.ToStringBuilder;
+
+public class TraversingSelector extends AbstractSelector<RDFNode> {
+
+ private final List<Traversal> traversals = new ArrayList<Traversal>();
+
+ public TraversingSelector() {
+ super(RDFNode.class);
+ }
+
+ @Override
+ public List<RDFNode> result(RDFNode node) {
+ Set<RDFNode> current = Collections.singleton(node);
+ for (Traversal traversal: traversals) {
+ LinkedHashSet<RDFNode> destinationsUnion = new LinkedHashSet<RDFNode>();
+ for (RDFNode start: current) {
+ destinationsUnion.addAll(traversal.traverse(start));
+ }
+ current = destinationsUnion;
+ }
+ return new ArrayList<RDFNode>(current);
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this).append(traversals).toString();
+ }
+
+ public List<Traversal> getTraversals() {
+ return traversals;
+ }
+
+ public void addTraversal(Traversal traversal) {
+ traversals.add(traversal);
+ }
+
+}
diff --git a/src/main/java/au/id/djc/rdftemplate/selector/TypePredicate.java b/src/main/java/au/id/djc/rdftemplate/selector/TypePredicate.java
@@ -0,0 +1,46 @@
+package au.id.djc.rdftemplate.selector;
+
+import com.hp.hpl.jena.rdf.model.RDFNode;
+import com.hp.hpl.jena.rdf.model.Resource;
+import com.hp.hpl.jena.rdf.model.Statement;
+import com.hp.hpl.jena.vocabulary.RDF;
+import org.apache.commons.lang.builder.ToStringBuilder;
+
+public class TypePredicate implements Predicate {
+
+ private final String namespace;
+ private final String localName;
+
+ public TypePredicate(String namespace, String localName) {
+ this.namespace = namespace;
+ this.localName = localName;
+ }
+
+ public String getNamespace() {
+ return namespace;
+ }
+
+ public String getLocalName() {
+ return localName;
+ }
+
+ @Override
+ public boolean evaluate(RDFNode node) {
+ if (!node.isResource()) {
+ throw new SelectorEvaluationException("Attempted to apply [type] to non-resource node " + node);
+ }
+ Resource resource = (Resource) node;
+ Resource type = resource.getModel().createResource(namespace + localName);
+ for (Statement statement: resource.listProperties(RDF.type).toSet()) {
+ if (statement.getObject().equals(type))
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this).append(namespace).append(localName).toString();
+ }
+
+}
diff --git a/src/main/java/au/id/djc/rdftemplate/selector/UnionSelector.java b/src/main/java/au/id/djc/rdftemplate/selector/UnionSelector.java
@@ -0,0 +1,45 @@
+package au.id.djc.rdftemplate.selector;
+
+import java.util.ArrayList;
+import java.util.LinkedHashSet;
+import java.util.List;
+
+import com.hp.hpl.jena.rdf.model.RDFNode;
+import org.apache.commons.lang.builder.ToStringBuilder;
+
+public class UnionSelector<T> extends AbstractSelector<T> {
+
+ private final List<Selector<? extends T>> selectors;
+
+ public UnionSelector(List<Selector<? extends T>> selectors) {
+ super(null);
+ this.selectors = selectors;
+ }
+
+ @Override
+ public List<T> result(RDFNode node) {
+ LinkedHashSet<T> results = new LinkedHashSet<T>();
+ for (Selector<? extends T> selector: selectors) {
+ results.addAll(selector.result(node));
+ }
+ return new ArrayList<T>(results);
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this).append(selectors).toString();
+ }
+
+ public List<Selector<? extends T>> getSelectors() {
+ return selectors;
+ }
+
+ @Override
+ public <Other> Selector<Other> withResultType(Class<Other> otherType) {
+ for (Selector<? extends T> selector: selectors) {
+ selector.withResultType(otherType); // class cast exception?
+ }
+ return (Selector<Other>) this;
+ }
+
+}
diff --git a/src/main/java/au/id/djc/rdftemplate/selector/UriAdaptation.java b/src/main/java/au/id/djc/rdftemplate/selector/UriAdaptation.java
@@ -0,0 +1,16 @@
+package au.id.djc.rdftemplate.selector;
+
+import com.hp.hpl.jena.rdf.model.Resource;
+
+public class UriAdaptation extends AbstractAdaptation<String, Resource> {
+
+ public UriAdaptation() {
+ super(String.class, new Class<?>[] { }, Resource.class);
+ }
+
+ @Override
+ protected String doAdapt(Resource node) {
+ return node.getURI();
+ }
+
+}
diff --git a/src/main/java/au/id/djc/rdftemplate/selector/UriAnchorAdaptation.java b/src/main/java/au/id/djc/rdftemplate/selector/UriAnchorAdaptation.java
@@ -0,0 +1,24 @@
+package au.id.djc.rdftemplate.selector;
+
+import com.hp.hpl.jena.rdf.model.Resource;
+
+/**
+ * Returns the anchor component of the node's URI (excluding initial #), or the
+ * empty string if it has no anchor component.
+ */
+public class UriAnchorAdaptation extends AbstractAdaptation<String, Resource> {
+
+ public UriAnchorAdaptation() {
+ super(String.class, new Class<?>[] { }, Resource.class);
+ }
+
+ @Override
+ protected String doAdapt(Resource node) {
+ String uri = node.getURI();
+ int hashIndex = uri.lastIndexOf('#');
+ if (hashIndex < 0)
+ return "";
+ return uri.substring(hashIndex + 1);
+ }
+
+}
diff --git a/src/main/java/au/id/djc/rdftemplate/selector/UriPrefixPredicate.java b/src/main/java/au/id/djc/rdftemplate/selector/UriPrefixPredicate.java
@@ -0,0 +1,26 @@
+package au.id.djc.rdftemplate.selector;
+
+import com.hp.hpl.jena.rdf.model.RDFNode;
+import com.hp.hpl.jena.rdf.model.Resource;
+
+public class UriPrefixPredicate implements Predicate {
+
+ private final String prefix;
+
+ public UriPrefixPredicate(String prefix) {
+ this.prefix = prefix;
+ }
+
+ public String getPrefix() {
+ return prefix;
+ }
+
+ @Override
+ public boolean evaluate(RDFNode node) {
+ if (!node.isResource()) {
+ throw new SelectorEvaluationException("Attempted to apply [uri-prefix] to non-resource node " + node);
+ }
+ return ((Resource) node).getURI().startsWith(prefix);
+ }
+
+}
diff --git a/src/main/java/au/id/djc/rdftemplate/selector/UriSliceAdaptation.java b/src/main/java/au/id/djc/rdftemplate/selector/UriSliceAdaptation.java
@@ -0,0 +1,28 @@
+package au.id.djc.rdftemplate.selector;
+
+import com.hp.hpl.jena.rdf.model.Resource;
+
+public class UriSliceAdaptation extends AbstractAdaptation<String, Resource> {
+
+ private Integer startIndex;
+
+ public UriSliceAdaptation() {
+ super(String.class, new Class<?>[] { Integer.class }, Resource.class);
+ }
+
+ public Integer getStartIndex() {
+ return startIndex;
+ }
+
+ @Override
+ protected void setCheckedArgs(Object[] args) {
+ this.startIndex = (Integer) args[0];
+ }
+
+ @Override
+ protected String doAdapt(Resource node) {
+ String uri = node.getURI();
+ return uri.substring(startIndex);
+ }
+
+}
diff --git a/src/main/java/au/id/djc/rdftemplate/view/RDFTemplateView.java b/src/main/java/au/id/djc/rdftemplate/view/RDFTemplateView.java
@@ -0,0 +1,76 @@
+package au.id.djc.rdftemplate.view;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.web.servlet.view.AbstractTemplateView;
+
+import au.id.djc.rdftemplate.TemplateInterpolator;
+import au.id.djc.rdftemplate.selector.SelectorFactory;
+import au.id.djc.jena.util.ModelOperations;
+import au.id.djc.jena.util.ModelOperations.ModelExecutionCallbackWithoutResult;
+
+import com.hp.hpl.jena.rdf.model.Model;
+import com.hp.hpl.jena.rdf.model.Resource;
+
+public class RDFTemplateView extends AbstractTemplateView {
+
+ public static final String NODE_URI_KEY = "nodeUri";
+
+ private TemplateInterpolator templateInterpolator;
+ private SelectorFactory selectorFactory;
+ private ModelOperations modelOperations;
+
+ public void setSelectorFactory(SelectorFactory selectorFactory) {
+ this.selectorFactory = selectorFactory;
+ }
+
+ public void setModelOperations(ModelOperations modelOperations) {
+ this.modelOperations = modelOperations;
+ }
+
+ @Override
+ public void afterPropertiesSet() throws Exception {
+ super.afterPropertiesSet();
+ if (selectorFactory == null) {
+ throw new IllegalArgumentException("Property 'selectorFactory' is required");
+ }
+ if (modelOperations == null) {
+ throw new IllegalArgumentException("Property 'sdbTemplate' is required");
+ }
+ this.templateInterpolator = new TemplateInterpolator(selectorFactory);
+ }
+
+ @Override
+ protected void renderMergedTemplateModel(final Map<String, Object> model,
+ final HttpServletRequest request, final HttpServletResponse response)
+ throws Exception {
+ final InputStream inputStream = getApplicationContext().getResource(getUrl()).getInputStream();
+ try {
+ modelOperations.withModel(new ModelExecutionCallbackWithoutResult() {
+ @Override
+ protected void executeWithoutResult(Model rdfModel) {
+ Resource node = rdfModel.getResource((String) model.get(NODE_URI_KEY));
+ try {
+ templateInterpolator.interpolate(inputStream, node, response.getWriter());
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ });
+ } finally {
+ inputStream.close();
+ }
+ }
+
+ @Override
+ public boolean checkResource(Locale locale) throws Exception {
+ return getApplicationContext().getResource(getUrl()).exists();
+ }
+
+}
diff --git a/src/main/java/au/id/djc/rdftemplate/view/RDFTemplateViewResolver.java b/src/main/java/au/id/djc/rdftemplate/view/RDFTemplateViewResolver.java
@@ -0,0 +1,54 @@
+package au.id.djc.rdftemplate.view;
+
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.web.servlet.view.AbstractTemplateView;
+import org.springframework.web.servlet.view.AbstractTemplateViewResolver;
+
+import au.id.djc.rdftemplate.selector.SelectorFactory;
+import au.id.djc.jena.util.ModelOperations;
+
+public class RDFTemplateViewResolver extends AbstractTemplateViewResolver implements InitializingBean {
+
+ private SelectorFactory selectorFactory;
+ private ModelOperations modelOperations;
+
+ public RDFTemplateViewResolver() {
+ super();
+ setViewClass(requiredViewClass());
+ setExposeRequestAttributes(false);
+ setExposeSessionAttributes(false);
+ setExposeSpringMacroHelpers(false);
+ }
+
+ public void setSelectorFactory(SelectorFactory selectorFactory) {
+ this.selectorFactory = selectorFactory;
+ }
+
+ public void setModelOperations(ModelOperations modelOperations) {
+ this.modelOperations = modelOperations;
+ }
+
+ @Override
+ public void afterPropertiesSet() throws Exception {
+ if (selectorFactory == null) {
+ throw new IllegalArgumentException("Property 'selectorFactory' is required");
+ }
+ if (modelOperations == null) {
+ throw new IllegalArgumentException("Property 'modelOperations' is required");
+ }
+ }
+
+ @Override
+ protected Class<? extends AbstractTemplateView> requiredViewClass() {
+ return RDFTemplateView.class;
+ }
+
+ @Override
+ protected RDFTemplateView buildView(String viewName) throws Exception {
+ RDFTemplateView view = (RDFTemplateView) super.buildView(viewName);
+ view.setSelectorFactory(selectorFactory);
+ view.setModelOperations(modelOperations);
+ return view;
+ }
+
+}
diff --git a/src/test/java/au/com/miskinhill/rdftemplate/TemplateInterpolatorUnitTest.java b/src/test/java/au/com/miskinhill/rdftemplate/TemplateInterpolatorUnitTest.java
@@ -1,140 +0,0 @@
-package au.com.miskinhill.rdftemplate;
-
-import static org.hamcrest.CoreMatchers.*;
-import static org.junit.Assert.*;
-import static org.junit.matchers.JUnitMatchers.*;
-
-import java.io.InputStream;
-import java.io.InputStreamReader;
-
-import com.hp.hpl.jena.rdf.model.Model;
-import com.hp.hpl.jena.rdf.model.ModelFactory;
-import com.hp.hpl.jena.rdf.model.Resource;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
-
-import au.com.miskinhill.rdftemplate.datatype.DateDataType;
-import au.com.miskinhill.rdftemplate.selector.AntlrSelectorFactory;
-
-public class TemplateInterpolatorUnitTest {
-
- @BeforeClass
- public static void ensureDatatypesRegistered() {
- DateDataType.registerStaticInstance();
- }
-
- private Model model;
- private TemplateInterpolator templateInterpolator;
-
- @Before
- public void setUp() {
- model = ModelFactory.createDefaultModel();
- InputStream stream = this.getClass().getResourceAsStream(
- "/au/com/miskinhill/rdftemplate/test-data.xml");
- model.read(stream, "");
- AntlrSelectorFactory selectorFactory = new AntlrSelectorFactory();
- selectorFactory.setNamespacePrefixMap(TestNamespacePrefixMap.getInstance());
- templateInterpolator = new TemplateInterpolator(selectorFactory);
- }
-
- @Test
- public void shouldReplaceSubtreesWithContent() throws Exception {
- Resource journal = model.getResource("http://miskinhill.com.au/journals/test/");
- String result = templateInterpolator.interpolate(
- new InputStreamReader(this.getClass().getResourceAsStream("replace-subtree.xml")), journal);
- assertThat(result, containsString("<div xml:lang=\"en\" lang=\"en\">Test Journal of Good Stuff</div>"));
- assertThat(result, not(containsString("<p>This should all go <em>away</em>!</p>")));
- }
-
- @Test
- public void shouldHandleXMLLiterals() throws Exception {
- Resource journal = model.getResource("http://miskinhill.com.au/journals/test/");
- String result = templateInterpolator.interpolate(
- new InputStreamReader(this.getClass().getResourceAsStream("replace-xml.xml")), journal);
- assertThat(result, containsString(
- "<div lang=\"en\"><p><em>Test Journal</em> is a journal.</p></div>"));
- }
-
- @Test
- public void shouldHandleIfs() throws Exception {
- Resource author = model.getResource("http://miskinhill.com.au/authors/test-author");
- String result = templateInterpolator.interpolate(
- new InputStreamReader(this.getClass().getResourceAsStream("conditional.xml")), author);
- assertThat(result, containsString("attribute test"));
- assertThat(result, containsString("element test"));
- assertThat(result, not(containsString("rdf:if")));
- assertThat(result, not(containsString("negated test")));
-
- Resource authorWithoutNotes = model.getResource("http://miskinhill.com.au/authors/another-author");
- result = templateInterpolator.interpolate(
- new InputStreamReader(this.getClass().getResourceAsStream("conditional.xml")), authorWithoutNotes);
- assertThat(result, not(containsString("attribute test")));
- assertThat(result, not(containsString("element test")));
- assertThat(result, containsString("negated test"));
- }
-
- @Test
- public void shouldHandleJoins() throws Exception {
- Resource citedArticle = model.getResource("http://miskinhill.com.au/cited/journals/asdf/1:1/article");
- String result = templateInterpolator.interpolate(
- new InputStreamReader(this.getClass().getResourceAsStream("join.xml")), citedArticle);
- assertThat(result, containsString("<p><a href=\"http://miskinhill.com.au/authors/another-author\">Another Author</a>, " +
- "<a href=\"http://miskinhill.com.au/authors/test-author\">Test Author</a></p>"));
- }
-
- @Test
- public void shouldHandleFor() throws Exception {
- Resource journal = model.getResource("http://miskinhill.com.au/journals/test/");
- String result = templateInterpolator.interpolate(
- new InputStreamReader(this.getClass().getResourceAsStream("for.xml")), journal);
- assertThat(result, containsString("<span>http://miskinhill.com.au/journals/test/1:1/</span>"));
- assertThat(result, containsString("<span>http://miskinhill.com.au/journals/test/2:1/</span>"));
- assertThat(result, containsString("<p>http://miskinhill.com.au/journals/test/1:1/</p>"));
- assertThat(result, containsString("<p>http://miskinhill.com.au/journals/test/2:1/</p>"));
- }
-
- @Test
- public void shouldStripRdfNamespaceDeclarations() throws Exception {
- Resource author = model.getResource("http://miskinhill.com.au/authors/test-author");
- String result = templateInterpolator.interpolate(
- new InputStreamReader(this.getClass().getResourceAsStream("namespaces.xml")), author);
- assertThat(result, not(containsString("xmlns:rdf=\"http://code.miskinhill.com.au/rdftemplate/\"")));
- assertThat(result, not(containsString("rdf:")));
- }
-
- @Test
- public void forShouldIterateRdfSeqsInOrder() throws Exception {
- Resource article = model.getResource("http://miskinhill.com.au/journals/test/1:1/multi-author-article");
- String result = templateInterpolator.interpolate(
- new InputStreamReader(this.getClass().getResourceAsStream("for-seq.xml")), article);
- assertThat(result, containsString("Another Author\n\nTest Author"));
- }
-
- @Test
- public void joinShouldIterateRdfSeqsInOrder() throws Exception {
- Resource article = model.getResource("http://miskinhill.com.au/journals/test/1:1/multi-author-article");
- String result = templateInterpolator.interpolate(
- new InputStreamReader(this.getClass().getResourceAsStream("join-seq.xml")), article);
- assertThat(result, containsString("<p><a href=\"http://miskinhill.com.au/authors/another-author\">Another Author</a>, " +
- "<a href=\"http://miskinhill.com.au/authors/test-author\">Test Author</a></p>"));
- }
-
- @Test
- public void forShouldWorkForSingleResult() throws Exception {
- Resource journal = model.getResource("http://miskinhill.com.au/cited/journals/asdf/");
- String result = templateInterpolator.interpolate(
- new InputStreamReader(this.getClass().getResourceAsStream("for.xml")), journal);
- assertThat(result, containsString("<span>http://miskinhill.com.au/cited/journals/asdf/1:1/</span>"));
- assertThat(result, containsString("<p>http://miskinhill.com.au/cited/journals/asdf/1:1/</p>"));
- }
-
- @Test
- public void joinShouldWorkForSingleResult() throws Exception {
- Resource review = model.getResource("http://miskinhill.com.au/journals/test/1:1/reviews/review");
- String result = templateInterpolator.interpolate(
- new InputStreamReader(this.getClass().getResourceAsStream("join.xml")), review);
- assertThat(result, containsString("<p><a href=\"http://miskinhill.com.au/authors/test-author\">Test Author</a></p>"));
- }
-
-}
diff --git a/src/test/java/au/com/miskinhill/rdftemplate/TestNamespacePrefixMap.java b/src/test/java/au/com/miskinhill/rdftemplate/TestNamespacePrefixMap.java
@@ -1,32 +0,0 @@
-package au.com.miskinhill.rdftemplate;
-
-import java.util.HashMap;
-
-import com.hp.hpl.jena.vocabulary.DCTerms;
-import com.hp.hpl.jena.vocabulary.RDF;
-import org.junit.Ignore;
-
-@Ignore // why does JUnit think this is a test?
-public final class TestNamespacePrefixMap extends HashMap<String, String> {
-
- public static final String MHS_NS = "http://miskinhill.com.au/rdfschema/1.0/";
- public static final String FOAF_NS = "http://xmlns.com/foaf/0.1/";
-
- private static final long serialVersionUID = 2119318190108418683L;
-
- private static final TestNamespacePrefixMap instance = new TestNamespacePrefixMap();
- public static TestNamespacePrefixMap getInstance() {
- return instance;
- }
-
- private TestNamespacePrefixMap() {
- put("mhs", MHS_NS);
- put("dc", DCTerms.NS);
- put("foaf", FOAF_NS);
- put("rdf", RDF.getURI());
- put("sioc", "http://rdfs.org/sioc/ns#");
- put("awol", "http://bblfish.net/work/atom-owl/2006-06-06/#");
- put("lingvoj", "http://www.lingvoj.org/ontology#");
- }
-
-}
diff --git a/src/test/java/au/com/miskinhill/rdftemplate/datatype/DateDataTypeUnitTest.java b/src/test/java/au/com/miskinhill/rdftemplate/datatype/DateDataTypeUnitTest.java
@@ -1,35 +0,0 @@
-package au.com.miskinhill.rdftemplate.datatype;
-
-import static org.hamcrest.CoreMatchers.equalTo;
-import static org.junit.Assert.assertThat;
-
-import com.hp.hpl.jena.datatypes.RDFDatatype;
-import org.joda.time.LocalDate;
-import org.junit.Before;
-import org.junit.Test;
-
-public class DateDataTypeUnitTest {
-
- private RDFDatatype type;
-
- @Before
- public void setUp() {
- type = new DateDataType();
- }
-
- @Test
- public void shouldParseYear() {
- assertThat((Year) type.parse("2003"), equalTo(new Year(2003)));
- }
-
- @Test
- public void shouldParseYearMonth() {
- assertThat((YearMonth) type.parse("2003-05"), equalTo(new YearMonth(2003, 5)));
- }
-
- @Test
- public void shouldParseDate() {
- assertThat((LocalDate) type.parse("2003-05-25"), equalTo(new LocalDate(2003, 5, 25)));
- }
-
-}
diff --git a/src/test/java/au/com/miskinhill/rdftemplate/datatype/DateTimeDataTypeUnitTest.java b/src/test/java/au/com/miskinhill/rdftemplate/datatype/DateTimeDataTypeUnitTest.java
@@ -1,34 +0,0 @@
-package au.com.miskinhill.rdftemplate.datatype;
-
-import static org.hamcrest.CoreMatchers.*;
-import static org.junit.Assert.*;
-
-import org.joda.time.DateTime;
-import org.joda.time.DateTimeZone;
-import org.junit.Before;
-import org.junit.Test;
-
-import com.hp.hpl.jena.datatypes.RDFDatatype;
-
-public class DateTimeDataTypeUnitTest {
-
- private RDFDatatype type;
-
- @Before
- public void setUp() {
- type = new DateTimeDataType();
- }
-
- @Test
- public void shouldParseDate() {
- assertThat((DateTime) type.parse("2003-05-25T10:11:12+05:00"),
- equalTo(new DateTime(2003, 5, 25, 10, 11, 12, 0, DateTimeZone.forOffsetHours(5))));
- }
-
- @Test
- public void shouldUnparseDate() {
- assertThat(type.unparse(new DateTime(2003, 5, 25, 10, 11, 12, 0, DateTimeZone.forOffsetHours(5))),
- equalTo("2003-05-25T10:11:12+05:00"));
- }
-
-}
diff --git a/src/test/java/au/com/miskinhill/rdftemplate/datatype/YearMonthUnitTest.java b/src/test/java/au/com/miskinhill/rdftemplate/datatype/YearMonthUnitTest.java
@@ -1,24 +0,0 @@
-package au.com.miskinhill.rdftemplate.datatype;
-
-import static org.hamcrest.CoreMatchers.equalTo;
-import static org.junit.Assert.assertThat;
-
-import org.joda.time.LocalDate;
-import org.junit.Test;
-
-public class YearMonthUnitTest {
-
- @Test
- public void testToString() {
- assertThat(new YearMonth(new LocalDate(2001, 5, 1)).toString(), equalTo("2001-05"));
- }
-
- @Test
- public void testEqualsHashCode() {
- YearMonth yearMonth1 = new YearMonth(new LocalDate(2001, 5, 1));
- YearMonth yearMonth2 = new YearMonth(new LocalDate(2001, 5, 1));
- assertThat(yearMonth1, equalTo(yearMonth2));
- assertThat(yearMonth1.hashCode(), equalTo(yearMonth2.hashCode()));
- }
-
-}
diff --git a/src/test/java/au/com/miskinhill/rdftemplate/datatype/YearUnitTest.java b/src/test/java/au/com/miskinhill/rdftemplate/datatype/YearUnitTest.java
@@ -1,24 +0,0 @@
-package au.com.miskinhill.rdftemplate.datatype;
-
-import static org.hamcrest.CoreMatchers.equalTo;
-import static org.junit.Assert.assertThat;
-
-import org.joda.time.LocalDate;
-import org.junit.Test;
-
-public class YearUnitTest {
-
- @Test
- public void testToString() {
- assertThat(new Year(new LocalDate(2001, 1, 1)).toString(), equalTo("2001"));
- }
-
- @Test
- public void testEqualsHashCode() {
- Year year1 = new Year(new LocalDate(2001, 1, 1));
- Year year2 = new Year(new LocalDate(2001, 1, 1));
- assertThat(year1, equalTo(year2));
- assertThat(year1.hashCode(), equalTo(year2.hashCode()));
- }
-
-}
diff --git a/src/test/java/au/com/miskinhill/rdftemplate/selector/AdaptationMatcher.java b/src/test/java/au/com/miskinhill/rdftemplate/selector/AdaptationMatcher.java
@@ -1,36 +0,0 @@
-package au.com.miskinhill.rdftemplate.selector;
-
-
-import static org.hamcrest.CoreMatchers.equalTo;
-
-public class AdaptationMatcher<T extends Adaptation<?>> extends BeanPropertyMatcher<T> {
-
- private AdaptationMatcher(Class<T> type) {
- super(type);
- }
-
- public static AdaptationMatcher<UriAdaptation> uriAdaptation() {
- return new AdaptationMatcher<UriAdaptation>(UriAdaptation.class);
- }
-
- public static AdaptationMatcher<UriSliceAdaptation> uriSliceAdaptation(Integer startIndex) {
- AdaptationMatcher<UriSliceAdaptation> m = new AdaptationMatcher<UriSliceAdaptation>(UriSliceAdaptation.class);
- m.addRequiredProperty("startIndex", equalTo(startIndex));
- return m;
- }
-
- public static AdaptationMatcher<LiteralValueAdaptation> lvAdaptation() {
- return new AdaptationMatcher<LiteralValueAdaptation>(LiteralValueAdaptation.class);
- }
-
- public static AdaptationMatcher<ComparableLiteralValueAdaptation> comparableLVAdaptation() {
- return new AdaptationMatcher<ComparableLiteralValueAdaptation>(ComparableLiteralValueAdaptation.class);
- }
-
- public static AdaptationMatcher<FormattedDateTimeAdaptation> formattedDTAdaptation(String pattern) {
- AdaptationMatcher<FormattedDateTimeAdaptation> m = new AdaptationMatcher<FormattedDateTimeAdaptation>(FormattedDateTimeAdaptation.class);
- m.addRequiredProperty("pattern", equalTo(pattern));
- return m;
- }
-
-}
diff --git a/src/test/java/au/com/miskinhill/rdftemplate/selector/BeanPropertyMatcher.java b/src/test/java/au/com/miskinhill/rdftemplate/selector/BeanPropertyMatcher.java
@@ -1,56 +0,0 @@
-package au.com.miskinhill.rdftemplate.selector;
-
-import java.util.LinkedHashMap;
-import java.util.Map;
-
-import org.apache.commons.beanutils.PropertyUtils;
-import org.hamcrest.BaseMatcher;
-import org.hamcrest.Description;
-import org.hamcrest.Matcher;
-
-public class BeanPropertyMatcher<T> extends BaseMatcher<T> {
-
- private final Class<? extends T> matchedType;
- private final Map<String, Matcher<?>> requiredProperties = new LinkedHashMap<String, Matcher<?>>();
-
- public BeanPropertyMatcher(Class<? extends T> type) {
- this.matchedType = type;
- }
-
- public void addRequiredProperty(String name, Matcher<?> matcher) {
- requiredProperties.put(name, matcher);
- }
-
- @Override
- public boolean matches(Object arg0) {
- if (!matchedType.isInstance(arg0))
- return false;
- for (Map.Entry<String, Matcher<?>> property: requiredProperties.entrySet()) {
- try {
- Object beanProperty = PropertyUtils.getProperty(arg0, property.getKey());
- if (!property.getValue().matches(beanProperty))
- return false;
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
- return true;
- }
-
- @Override
- public void describeTo(Description desc) {
- desc.appendText(matchedType.getName());
- desc.appendText("[");
- boolean first = true;
- for (Map.Entry<String, Matcher<?>> property: requiredProperties.entrySet()) {
- if (!first)
- desc.appendText(",");
- desc.appendText(property.getKey());
- desc.appendText("=");
- property.getValue().describeTo(desc);
- first = false;
- }
- desc.appendText("]");
- }
-
-}
diff --git a/src/test/java/au/com/miskinhill/rdftemplate/selector/EternallyCachingSelectorFactoryUnitTest.java b/src/test/java/au/com/miskinhill/rdftemplate/selector/EternallyCachingSelectorFactoryUnitTest.java
@@ -1,22 +0,0 @@
-package au.com.miskinhill.rdftemplate.selector;
-
-import static org.hamcrest.CoreMatchers.sameInstance;
-import static org.junit.Assert.assertThat;
-
-import org.junit.Test;
-
-import au.com.miskinhill.rdftemplate.TestNamespacePrefixMap;
-
-public class EternallyCachingSelectorFactoryUnitTest {
-
- @Test
- public void shouldCacheSelectors() {
- AntlrSelectorFactory wrappedFactory = new AntlrSelectorFactory();
- wrappedFactory.setNamespacePrefixMap(TestNamespacePrefixMap.getInstance());
- EternallyCachingSelectorFactory factory = new EternallyCachingSelectorFactory(wrappedFactory);
- Selector<?> first = factory.get("dc:creator/foaf:name");
- Selector<?> second = factory.get("dc:creator/foaf:name");
- assertThat((Selector) first, sameInstance((Selector) second));
- }
-
-}
diff --git a/src/test/java/au/com/miskinhill/rdftemplate/selector/PredicateMatcher.java b/src/test/java/au/com/miskinhill/rdftemplate/selector/PredicateMatcher.java
@@ -1,34 +0,0 @@
-package au.com.miskinhill.rdftemplate.selector;
-
-import static org.hamcrest.CoreMatchers.equalTo;
-
-import org.hamcrest.Matcher;
-
-public class PredicateMatcher<T extends Predicate> extends BeanPropertyMatcher<T> {
-
- private PredicateMatcher(Class<T> type) {
- super(type);
- }
-
- public static PredicateMatcher<UriPrefixPredicate> uriPrefixPredicate(String prefix) {
- PredicateMatcher<UriPrefixPredicate> m = new PredicateMatcher<UriPrefixPredicate>(UriPrefixPredicate.class);
- m.addRequiredProperty("prefix", equalTo(prefix));
- return m;
- }
-
- public static PredicateMatcher<TypePredicate> typePredicate(String namespace, String localName) {
- PredicateMatcher<TypePredicate> m = new PredicateMatcher<TypePredicate>(TypePredicate.class);
- m.addRequiredProperty("namespace", equalTo(namespace));
- m.addRequiredProperty("localName", equalTo(localName));
- return m;
- }
-
- public static PredicateMatcher<BooleanAndPredicate> booleanAndPredicate(
- Matcher<? extends Predicate> left, Matcher<? extends Predicate> right) {
- PredicateMatcher<BooleanAndPredicate> m = new PredicateMatcher<BooleanAndPredicate>(BooleanAndPredicate.class);
- m.addRequiredProperty("left", left);
- m.addRequiredProperty("right", right);
- return m;
- }
-
-}
diff --git a/src/test/java/au/com/miskinhill/rdftemplate/selector/SelectorComparatorMatcher.java b/src/test/java/au/com/miskinhill/rdftemplate/selector/SelectorComparatorMatcher.java
@@ -1,25 +0,0 @@
-package au.com.miskinhill.rdftemplate.selector;
-
-import static org.hamcrest.CoreMatchers.equalTo;
-
-import org.hamcrest.Matcher;
-
-public class SelectorComparatorMatcher<T extends Comparable<T>> extends BeanPropertyMatcher<SelectorComparator<T>> {
-
- @SuppressWarnings("unchecked")
- public SelectorComparatorMatcher() {
- super((Class) SelectorComparator.class);
- }
-
- public static SelectorComparatorMatcher<?> selectorComparator(Matcher<? extends Selector<?>> selector) {
- SelectorComparatorMatcher<?> m = new SelectorComparatorMatcher();
- m.addRequiredProperty("selector", selector);
- return m;
- }
-
- public SelectorComparatorMatcher<T> reversed() {
- addRequiredProperty("reversed", equalTo(true));
- return this;
- }
-
-}
diff --git a/src/test/java/au/com/miskinhill/rdftemplate/selector/SelectorEvaluationUnitTest.java b/src/test/java/au/com/miskinhill/rdftemplate/selector/SelectorEvaluationUnitTest.java
@@ -1,224 +0,0 @@
-package au.com.miskinhill.rdftemplate.selector;
-
-import static org.hamcrest.CoreMatchers.*;
-import static org.junit.Assert.*;
-import static org.junit.matchers.JUnitMatchers.*;
-
-import java.io.InputStream;
-import java.util.List;
-
-import com.hp.hpl.jena.rdf.model.Literal;
-import com.hp.hpl.jena.rdf.model.Model;
-import com.hp.hpl.jena.rdf.model.ModelFactory;
-import com.hp.hpl.jena.rdf.model.RDFNode;
-import com.hp.hpl.jena.rdf.model.Resource;
-import org.junit.Before;
-import org.junit.BeforeClass;
-import org.junit.Test;
-
-import au.com.miskinhill.rdftemplate.TestNamespacePrefixMap;
-import au.com.miskinhill.rdftemplate.datatype.DateDataType;
-import au.com.miskinhill.rdftemplate.datatype.DateTimeDataType;
-
-public class SelectorEvaluationUnitTest {
-
- private Model m;
- private Resource journal, issue, article, multiAuthorArticle, citedArticle, author, anotherAuthor, book, review, anotherReview, obituary, en, ru, forum;
- private AntlrSelectorFactory selectorFactory;
-
- @BeforeClass
- public static void ensureDatatypesRegistered() {
- DateDataType.registerStaticInstance();
- DateTimeDataType.registerStaticInstance();
- }
-
- @Before
- public void setUp() {
- m = ModelFactory.createDefaultModel();
- InputStream stream = this.getClass().getResourceAsStream("/au/com/miskinhill/rdftemplate/test-data.xml");
- m.read(stream, "");
- journal = m.createResource("http://miskinhill.com.au/journals/test/");
- issue = m.createResource("http://miskinhill.com.au/journals/test/1:1/");
- article = m.createResource("http://miskinhill.com.au/journals/test/1:1/article");
- multiAuthorArticle = m.createResource("http://miskinhill.com.au/journals/test/1:1/multi-author-article");
- citedArticle = m.createResource("http://miskinhill.com.au/cited/journals/asdf/1:1/article");
- author = m.createResource("http://miskinhill.com.au/authors/test-author");
- anotherAuthor = m.createResource("http://miskinhill.com.au/authors/another-author");
- book = m.createResource("http://miskinhill.com.au/cited/books/test");
- review = m.createResource("http://miskinhill.com.au/journals/test/1:1/reviews/review");
- anotherReview = m.createResource("http://miskinhill.com.au/journals/test/2:1/reviews/another-review");
- obituary = m.createResource("http://miskinhill.com.au/journals/test/1:1/in-memoriam-john-doe");
- en = m.createResource("http://www.lingvoj.org/lang/en");
- ru = m.createResource("http://www.lingvoj.org/lang/ru");
- forum = m.createResource("http://miskinhill.com.au/");
- selectorFactory = new AntlrSelectorFactory();
- selectorFactory.setNamespacePrefixMap(TestNamespacePrefixMap.getInstance());
- }
-
- @Test
- public void shouldEvaluateTraversal() {
- RDFNode result = selectorFactory.get("dc:creator").withResultType(RDFNode.class).singleResult(article);
- assertThat(result, equalTo((RDFNode) author));
- }
-
- @Test
- public void shouldEvaluateMultipleTraversals() throws Exception {
- RDFNode result = selectorFactory.get("dc:creator/foaf:name")
- .withResultType(RDFNode.class).singleResult(article);
- assertThat(((Literal) result).getString(), equalTo("Test Author"));
- }
-
- @Test
- public void shouldEvaluateInverseTraversal() throws Exception {
- List<RDFNode> results = selectorFactory.get("!dc:isPartOf")
- .withResultType(RDFNode.class).result(issue);
- assertThat(results.size(), equalTo(4));
- assertThat(results, hasItems((RDFNode) article, (RDFNode) multiAuthorArticle, (RDFNode) review, (RDFNode) obituary));
- }
-
- @Test
- public void shouldEvaluateSortOrder() throws Exception {
- List<RDFNode> results = selectorFactory.get("dc:language(lingvoj:iso1#comparable-lv)")
- .withResultType(RDFNode.class).result(journal);
- assertThat(results.size(), equalTo(2));
- assertThat(results.get(0), equalTo((RDFNode) en));
- assertThat(results.get(1), equalTo((RDFNode) ru));
- }
-
- @Test
- public void shouldEvaluateReverseSortOrder() throws Exception {
- List<RDFNode> results = selectorFactory.get("dc:language(~lingvoj:iso1#comparable-lv)")
- .withResultType(RDFNode.class).result(journal);
- assertThat(results.size(), equalTo(2));
- assertThat(results.get(0), equalTo((RDFNode) ru));
- assertThat(results.get(1), equalTo((RDFNode) en));
- }
-
- @Test
- public void shouldEvaluateComplexSortOrder() throws Exception {
- List<RDFNode> results = selectorFactory.get("!mhs:reviews(dc:isPartOf/mhs:publicationDate#comparable-lv)")
- .withResultType(RDFNode.class).result(book);
- assertThat(results.size(), equalTo(2));
- assertThat(results.get(0), equalTo((RDFNode) review));
- assertThat(results.get(1), equalTo((RDFNode) anotherReview));
- }
-
- @Test
- public void shouldEvaluateUriAdaptation() throws Exception {
- String result = selectorFactory.get("mhs:coverThumbnail#uri")
- .withResultType(String.class).singleResult(issue);
- assertThat(result, equalTo("http://miskinhill.com.au/journals/test/1:1/cover.thumb.jpg"));
- }
-
- @Test
- public void shouldEvaluateBareUriAdaptation() throws Exception {
- String result = selectorFactory.get("#uri").withResultType(String.class).singleResult(journal);
- assertThat(result, equalTo("http://miskinhill.com.au/journals/test/"));
- }
-
- @Test
- public void shouldEvaluateUriSliceAdaptation() throws Exception {
- String result = selectorFactory.get("dc:identifier[uri-prefix='urn:issn:']#uri-slice(9)")
- .withResultType(String.class).singleResult(journal);
- assertThat(result, equalTo("12345678"));
- }
-
- @Test
- public void shouldEvaluateUriAnchorAdaptation() throws Exception {
- String result = selectorFactory.get("mhs:inSection#uri-anchor")
- .withResultType(String.class).singleResult(anotherReview);
- assertThat(result, equalTo("stuff"));
- }
-
- @Test
- public void shouldEvaluateSubscript() throws Exception {
- String result = selectorFactory.get(
- "!mhs:isIssueOf(~mhs:publicationDate#comparable-lv)[0]/mhs:coverThumbnail#uri")
- .withResultType(String.class).singleResult(journal);
- assertThat(result, equalTo("http://miskinhill.com.au/journals/test/2:1/cover.thumb.jpg"));
- result = selectorFactory.get(
- "!mhs:isIssueOf(mhs:publicationDate#comparable-lv)[0]/mhs:coverThumbnail#uri")
- .withResultType(String.class).singleResult(journal);
- assertThat(result, equalTo("http://miskinhill.com.au/journals/test/1:1/cover.thumb.jpg"));
- }
-
- @Test
- public void shouldEvaluateLVAdaptation() throws Exception {
- List<Object> results = selectorFactory.get("dc:language/lingvoj:iso1#lv")
- .withResultType(Object.class).result(journal);
- assertThat(results.size(), equalTo(2));
- assertThat(results, hasItems((Object) "en", (Object) "ru"));
- }
-
- @Test
- public void shouldEvaluateTypePredicate() throws Exception {
- List<RDFNode> results = selectorFactory.get("!dc:creator[type=mhs:Review]")
- .withResultType(RDFNode.class).result(author);
- assertThat(results.size(), equalTo(1));
- assertThat(results, hasItems((RDFNode) review));
- }
-
- @Test
- public void shouldEvaluateAndCombinationOfPredicates() throws Exception {
- List<RDFNode> results = selectorFactory.get("!dc:creator[type=mhs:Article and uri-prefix='http://miskinhill.com.au/journals/']")
- .withResultType(RDFNode.class).result(author);
- assertThat(results.size(), equalTo(2));
- assertThat(results, hasItems((RDFNode) article, (RDFNode) multiAuthorArticle));
- }
-
- @Test
- public void shouldEvaluateUnion() throws Exception {
- List<RDFNode> results = selectorFactory.get("!dc:creator | !mhs:translator")
- .withResultType(RDFNode.class).result(anotherAuthor);
- assertThat(results.size(), equalTo(4));
- assertThat(results, hasItems((RDFNode) article, (RDFNode) multiAuthorArticle, (RDFNode) citedArticle, (RDFNode) anotherReview));
- }
-
- @Test
- public void shouldEvaluateMultipleSortSelectors() throws Exception {
- List<RDFNode> results = selectorFactory.get("!dc:creator[uri-prefix='http://miskinhill.com.au/journals/']" +
- "(~dc:isPartOf/mhs:publicationDate#comparable-lv,mhs:startPage#comparable-lv)")
- .withResultType(RDFNode.class).result(author);
- assertThat(results.size(), equalTo(4));
- assertThat(results.get(0), equalTo((RDFNode) obituary));
- assertThat(results.get(1), equalTo((RDFNode) article));
- assertThat(results.get(2), equalTo((RDFNode) multiAuthorArticle));
- assertThat(results.get(3), equalTo((RDFNode) review));
- }
-
- @Test
- public void shouldEvaluateFormattedDTAdaptation() throws Exception {
- String result = selectorFactory.get("!sioc:has_container/dc:created#formatted-dt('d MMMM yyyy')")
- .withResultType(String.class).singleResult(forum);
- assertThat(result, equalTo("15 June 2009"));
- }
-
- @Test
- public void shouldEvaluateFormattedDTAdaptationWithDoubleQuotes() throws Exception {
- String result = selectorFactory.get("!sioc:has_container/dc:created#formatted-dt('yyyy-MM-dd\"T\"HH:mm:ssZZ')")
- .withResultType(String.class).singleResult(forum);
- assertThat(result, equalTo("2009-06-15T18:21:32+10:00"));
- }
-
- @Test
- public void shouldEvaluateStringLVAdaptation() throws Exception {
- List<String> results = selectorFactory.get("dc:language/lingvoj:iso1#string-lv")
- .withResultType(String.class).result(journal);
- assertThat(results.size(), equalTo(2));
- assertThat(results, hasItems("en", "ru"));
- }
-
- @Test
- public void stringLVAdaptationShouldStripTagsFromXMLLiteral() throws Exception {
- String result = selectorFactory.get("!sioc:has_container/sioc:content/awol:body#string-lv")
- .withResultType(String.class).singleResult(forum);
- assertEquals("To coincide with the publication of our second issue, " +
- "the 2008 volume of Australian Slavonic and East European Studies, " +
- "we are making available two new data feeds: an Atom feed of all " +
- "journal issues published on this site, and the complete RDF dataset " +
- "underlying the site. We hope this helps our users and aggregators " +
- "to discover new content as it is published.",
- result.trim().replaceAll("\\s+", " "));
- }
-
-}
diff --git a/src/test/java/au/com/miskinhill/rdftemplate/selector/SelectorMatcher.java b/src/test/java/au/com/miskinhill/rdftemplate/selector/SelectorMatcher.java
@@ -1,36 +0,0 @@
-package au.com.miskinhill.rdftemplate.selector;
-
-import static org.junit.matchers.JUnitMatchers.hasItems;
-
-import com.hp.hpl.jena.rdf.model.RDFNode;
-import org.hamcrest.Matcher;
-
-public class SelectorMatcher<T extends Selector<?>> extends BeanPropertyMatcher<T> {
-
- private SelectorMatcher(Class<? extends T> type) {
- super(type);
- }
-
- public static SelectorMatcher<Selector<RDFNode>> selector(Matcher<Traversal>... traversals) {
- if (traversals.length == 0) {
- return new SelectorMatcher<Selector<RDFNode>>(NoopSelector.class);
- }
- SelectorMatcher<Selector<RDFNode>> m = new SelectorMatcher<Selector<RDFNode>>(TraversingSelector.class);
- m.addRequiredProperty("traversals", hasItems(traversals));
- return m;
- }
-
- public static <R> SelectorMatcher<UnionSelector<R>> unionSelector(Matcher<Selector<R>>... selectors) {
- SelectorMatcher<UnionSelector<R>> m = new SelectorMatcher(UnionSelector.class);
- m.addRequiredProperty("selectors", hasItems(selectors));
- return m;
- }
-
- public <A> SelectorMatcher<Selector<?>> withAdaptation(Matcher<? extends Adaptation<A>> adaptation) {
- SelectorMatcher<Selector<?>> m = new SelectorMatcher(SelectorWithAdaptation.class);
- m.addRequiredProperty("baseSelector", this);
- m.addRequiredProperty("adaptation", adaptation);
- return m;
- }
-
-}
diff --git a/src/test/java/au/com/miskinhill/rdftemplate/selector/SelectorParserUnitTest.java b/src/test/java/au/com/miskinhill/rdftemplate/selector/SelectorParserUnitTest.java
@@ -1,206 +0,0 @@
-package au.com.miskinhill.rdftemplate.selector;
-
-import static au.com.miskinhill.rdftemplate.TestNamespacePrefixMap.*;
-import static au.com.miskinhill.rdftemplate.selector.AdaptationMatcher.*;
-import static au.com.miskinhill.rdftemplate.selector.PredicateMatcher.*;
-import static au.com.miskinhill.rdftemplate.selector.SelectorComparatorMatcher.*;
-import static au.com.miskinhill.rdftemplate.selector.SelectorMatcher.*;
-import static au.com.miskinhill.rdftemplate.selector.TraversalMatcher.*;
-import static org.junit.Assert.*;
-
-import com.hp.hpl.jena.rdf.model.RDFNode;
-import com.hp.hpl.jena.vocabulary.DCTerms;
-import com.hp.hpl.jena.vocabulary.RDF;
-import org.junit.Before;
-import org.junit.Test;
-
-import au.com.miskinhill.rdftemplate.TestNamespacePrefixMap;
-
-public class SelectorParserUnitTest {
-
- private AntlrSelectorFactory factory;
-
- @Before
- public void setUp() {
- factory = new AntlrSelectorFactory();
- factory.setNamespacePrefixMap(TestNamespacePrefixMap.getInstance());
- }
-
- @Test
- public void shouldRecogniseSingleTraversal() throws Exception {
- Selector<RDFNode> selector = factory.get("dc:creator").withResultType(RDFNode.class);
- assertThat(selector, selector(traversal(DCTerms.NS, "creator")));
- }
-
- @Test
- public void shouldRecogniseMultipleTraversals() throws Exception {
- Selector<RDFNode> selector = factory.get("dc:creator/foaf:name").withResultType(RDFNode.class);
- assertThat(selector, selector(
- traversal(DCTerms.NS, "creator"),
- traversal(FOAF_NS, "name")));
- }
-
- @Test
- public void shouldRecogniseMultipleTraversalsWithWhitespace() throws Exception {
- Selector<RDFNode> selector = factory.get("dc:creator / foaf:name").withResultType(RDFNode.class);
- assertThat(selector, selector(
- traversal(DCTerms.NS, "creator"),
- traversal(FOAF_NS, "name")));
- }
-
- @Test
- public void shouldRecogniseInverseTraversal() throws Exception {
- Selector<RDFNode> selector = factory.get("!dc:isPartOf/!dc:isPartOf").withResultType(RDFNode.class);
- assertThat(selector, selector(
- traversal(DCTerms.NS, "isPartOf").inverse(),
- traversal(DCTerms.NS, "isPartOf").inverse()));
- }
-
- @Test
- public void shouldRecogniseSortOrder() throws Exception {
- Selector<RDFNode> selector = factory.get("!mhs:isIssueOf(mhs:publicationDate#comparable-lv)").withResultType(RDFNode.class);
- assertThat(selector, selector(
- traversal(MHS_NS, "isIssueOf").inverse()
- .withSortOrder(selectorComparator(selector(traversal(MHS_NS, "publicationDate"))
- .withAdaptation(comparableLVAdaptation())))));
- }
-
- @Test
- public void shouldRecogniseReverseSortOrder() throws Exception {
- Selector<RDFNode> selector = factory.get("!mhs:isIssueOf(~mhs:publicationDate#comparable-lv)").withResultType(RDFNode.class);
- assertThat(selector, selector(
- traversal(MHS_NS, "isIssueOf").inverse()
- .withSortOrder(selectorComparator(selector(traversal(MHS_NS, "publicationDate"))
- .withAdaptation(comparableLVAdaptation())).reversed())));
- }
-
- @Test
- public void shouldRecogniseComplexSortOrder() throws Exception {
- Selector<RDFNode> selector = factory.get("!mhs:reviews(dc:isPartOf/mhs:publicationDate#comparable-lv)").withResultType(RDFNode.class);
- assertThat(selector, selector(
- traversal(MHS_NS, "reviews")
- .withSortOrder(selectorComparator(selector(traversal(DCTerms.NS, "isPartOf"), traversal(MHS_NS, "publicationDate"))
- .withAdaptation(comparableLVAdaptation())))));
- }
-
- @Test
- public void shouldRecogniseUriAdaptation() throws Exception {
- Selector<?> selector = factory.get("mhs:coverThumbnail#uri");
- assertThat(selector, selector(
- traversal(MHS_NS, "coverThumbnail"))
- .withAdaptation(uriAdaptation()));
- }
-
- @Test
- public void shouldRecogniseBareUriAdaptation() throws Exception {
- Selector<?> selector = factory.get("#uri");
- assertThat(selector, selector().withAdaptation(uriAdaptation()));
- }
-
- @Test
- public void shouldRecogniseUriSliceAdaptation() throws Exception {
- Selector<?> selector = factory.get("dc:identifier[uri-prefix='urn:issn:']#uri-slice(9)");
- assertThat(selector, selector(
- traversal(DCTerms.NS, "identifier")
- .withPredicate(uriPrefixPredicate("urn:issn:")))
- .withAdaptation(uriSliceAdaptation(9)));
- }
-
- @Test
- public void shouldRecogniseUriPrefixPredicate() throws Exception {
- Selector<RDFNode> selector = factory.get(
- "!mhs:isIssueOf[uri-prefix='http://miskinhill.com.au/journals/'](~mhs:publicationDate#comparable-lv)")
- .withResultType(RDFNode.class);
- assertThat(selector, selector(
- traversal(MHS_NS, "isIssueOf")
- .inverse()
- .withPredicate(uriPrefixPredicate("http://miskinhill.com.au/journals/"))
- .withSortOrder(selectorComparator(selector(traversal(MHS_NS, "publicationDate"))
- .withAdaptation(comparableLVAdaptation())).reversed())));
- }
-
- @Test
- public void shouldRecogniseSubscript() throws Exception {
- Selector<String> selector = factory.get(
- "!mhs:isIssueOf(~mhs:publicationDate#comparable-lv)[0]/mhs:coverThumbnail#uri")
- .withResultType(String.class);
- assertThat(selector, selector(
- traversal(MHS_NS, "isIssueOf")
- .inverse()
- .withSortOrder(selectorComparator(selector(traversal(MHS_NS, "publicationDate"))
- .withAdaptation(comparableLVAdaptation())).reversed())
- .withSubscript(0),
- traversal(MHS_NS, "coverThumbnail"))
- .withAdaptation(uriAdaptation()));
- }
-
- @Test
- public void shouldRecogniseLVAdaptation() throws Exception {
- Selector<Object> selector = factory.get("dc:language/lingvoj:iso1#lv").withResultType(Object.class);
- assertThat(selector, selector(
- traversal(DCTerms.NS, "language"),
- traversal("http://www.lingvoj.org/ontology#", "iso1"))
- .withAdaptation(lvAdaptation()));
- }
-
- @Test
- public void shouldRecogniseTypePredicate() throws Exception {
- Selector<RDFNode> selector = factory.get("!dc:creator[type=mhs:Review]").withResultType(RDFNode.class);
- assertThat(selector, selector(
- traversal(DCTerms.NS, "creator").inverse().withPredicate(typePredicate(MHS_NS, "Review"))));
- }
-
- @Test
- public void shouldRecogniseAndCombinationOfPredicates() throws Exception {
- Selector<RDFNode> selector = factory.get("!dc:creator[type=mhs:Review and uri-prefix='http://miskinhill.com.au/journals/']").withResultType(RDFNode.class);
- assertThat(selector, selector(
- traversal(DCTerms.NS, "creator").inverse()
- .withPredicate(booleanAndPredicate(
- typePredicate(MHS_NS, "Review"),
- uriPrefixPredicate("http://miskinhill.com.au/journals/")))));
- }
-
- @Test
- public void shouldRecogniseUnion() throws Exception {
- Selector<RDFNode> selector = factory.get("!dc:creator | !mhs:translator").withResultType(RDFNode.class);
- assertThat((UnionSelector<RDFNode>) selector, unionSelector(
- selector(traversal(DCTerms.NS, "creator").inverse()),
- selector(traversal(MHS_NS, "translator").inverse())));
- }
-
- @Test
- public void shouldRecogniseMultipleSortSelectors() throws Exception {
- Selector<RDFNode> selector = factory.get("!dc:creator(~dc:isPartOf/mhs:publicationDate#comparable-lv,mhs:startPage#comparable-lv)").withResultType(RDFNode.class);
- assertThat(selector, selector(
- traversal(DCTerms.NS, "creator").inverse()
- .withSortOrder(
- selectorComparator(selector(traversal(DCTerms.NS, "isPartOf"), traversal(MHS_NS, "publicationDate"))
- .withAdaptation(comparableLVAdaptation())).reversed(),
- selectorComparator(selector(traversal(MHS_NS, "startPage")).withAdaptation(comparableLVAdaptation())))));
- }
-
- @Test
- public void shouldRecogniseFormattedDTAdaptation() throws Exception {
- Selector<?> selector = factory.get("dc:created#formatted-dt('d MMMM yyyy')");
- assertThat(selector, selector(traversal(DCTerms.NS, "created"))
- .withAdaptation(formattedDTAdaptation("d MMMM yyyy")));
- }
-
- @Test
- public void shouldRecogniseRdfType() throws Exception {
- // was broken due to ANTLR being confused about the literal string "type" which was hardcoded to be a predicate
- Selector<RDFNode> selector = factory.get("rdf:type").withResultType(RDFNode.class);
- assertThat(selector, selector(traversal(RDF.getURI(), "type")));
- }
-
- @Test(expected = InvalidSelectorSyntaxException.class)
- public void shouldThrowForInvalidSyntax() throws Exception {
- factory.get("dc:creator]["); // this is a parser error
- }
-
- @Test(expected = InvalidSelectorSyntaxException.class)
- public void shouldThrowForUnrecognisedCharacter() throws Exception {
- factory.get("dc:cre&ator"); // ... and this is a lexer error
- }
-
-}
diff --git a/src/test/java/au/com/miskinhill/rdftemplate/selector/TraversalMatcher.java b/src/test/java/au/com/miskinhill/rdftemplate/selector/TraversalMatcher.java
@@ -1,44 +0,0 @@
-package au.com.miskinhill.rdftemplate.selector;
-
-import static org.hamcrest.CoreMatchers.equalTo;
-import static org.junit.matchers.JUnitMatchers.hasItems;
-
-import java.util.Comparator;
-
-import com.hp.hpl.jena.rdf.model.RDFNode;
-import org.hamcrest.Matcher;
-
-public class TraversalMatcher extends BeanPropertyMatcher<Traversal> {
-
- private TraversalMatcher() {
- super(Traversal.class);
- }
-
- public static TraversalMatcher traversal(String propertyNamespace, String propertyLocalName) {
- TraversalMatcher m = new TraversalMatcher();
- m.addRequiredProperty("propertyNamespace", equalTo(propertyNamespace));
- m.addRequiredProperty("propertyLocalName", equalTo(propertyLocalName));
- return m;
- }
-
- public TraversalMatcher inverse() {
- addRequiredProperty("inverse", equalTo(true));
- return this;
- }
-
- public TraversalMatcher withPredicate(Matcher<? extends Predicate> predicate) {
- addRequiredProperty("predicate", predicate);
- return this;
- }
-
- public TraversalMatcher withSortOrder(Matcher<? extends Comparator<RDFNode>>... sortOrder) {
- addRequiredProperty("sortOrder", hasItems(sortOrder));
- return this;
- }
-
- public TraversalMatcher withSubscript(int subscript) {
- addRequiredProperty("subscript", equalTo(subscript));
- return this;
- }
-
-}
diff --git a/src/test/java/au/com/miskinhill/rdftemplate/selector/UriAnchorAdaptationUnitTest.java b/src/test/java/au/com/miskinhill/rdftemplate/selector/UriAnchorAdaptationUnitTest.java
@@ -1,23 +0,0 @@
-package au.com.miskinhill.rdftemplate.selector;
-
-import static org.hamcrest.CoreMatchers.*;
-import static org.junit.Assert.*;
-
-import com.hp.hpl.jena.rdf.model.ResourceFactory;
-import org.junit.Test;
-
-public class UriAnchorAdaptationUnitTest {
-
- @Test
- public void shouldReturnAnchor() {
- String result = new UriAnchorAdaptation().adapt(ResourceFactory.createResource("http://example.com/#asdf"));
- assertThat(result, equalTo("asdf"));
- }
-
- @Test
- public void shouldReturnEmptyStringForUriWithoutAnchor() {
- String result = new UriAnchorAdaptation().adapt(ResourceFactory.createResource("http://example.com/"));
- assertThat(result, equalTo(""));
- }
-
-}
diff --git a/src/test/java/au/id/djc/rdftemplate/TemplateInterpolatorUnitTest.java b/src/test/java/au/id/djc/rdftemplate/TemplateInterpolatorUnitTest.java
@@ -0,0 +1,140 @@
+package au.id.djc.rdftemplate;
+
+import static org.hamcrest.CoreMatchers.*;
+import static org.junit.Assert.*;
+import static org.junit.matchers.JUnitMatchers.*;
+
+import java.io.InputStream;
+import java.io.InputStreamReader;
+
+import com.hp.hpl.jena.rdf.model.Model;
+import com.hp.hpl.jena.rdf.model.ModelFactory;
+import com.hp.hpl.jena.rdf.model.Resource;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import au.id.djc.rdftemplate.datatype.DateDataType;
+import au.id.djc.rdftemplate.selector.AntlrSelectorFactory;
+
+public class TemplateInterpolatorUnitTest {
+
+ @BeforeClass
+ public static void ensureDatatypesRegistered() {
+ DateDataType.registerStaticInstance();
+ }
+
+ private Model model;
+ private TemplateInterpolator templateInterpolator;
+
+ @Before
+ public void setUp() {
+ model = ModelFactory.createDefaultModel();
+ InputStream stream = this.getClass().getResourceAsStream(
+ "/au/id/djc/rdftemplate/test-data.xml");
+ model.read(stream, "");
+ AntlrSelectorFactory selectorFactory = new AntlrSelectorFactory();
+ selectorFactory.setNamespacePrefixMap(TestNamespacePrefixMap.getInstance());
+ templateInterpolator = new TemplateInterpolator(selectorFactory);
+ }
+
+ @Test
+ public void shouldReplaceSubtreesWithContent() throws Exception {
+ Resource journal = model.getResource("http://miskinhill.com.au/journals/test/");
+ String result = templateInterpolator.interpolate(
+ new InputStreamReader(this.getClass().getResourceAsStream("replace-subtree.xml")), journal);
+ assertThat(result, containsString("<div xml:lang=\"en\" lang=\"en\">Test Journal of Good Stuff</div>"));
+ assertThat(result, not(containsString("<p>This should all go <em>away</em>!</p>")));
+ }
+
+ @Test
+ public void shouldHandleXMLLiterals() throws Exception {
+ Resource journal = model.getResource("http://miskinhill.com.au/journals/test/");
+ String result = templateInterpolator.interpolate(
+ new InputStreamReader(this.getClass().getResourceAsStream("replace-xml.xml")), journal);
+ assertThat(result, containsString(
+ "<div lang=\"en\"><p><em>Test Journal</em> is a journal.</p></div>"));
+ }
+
+ @Test
+ public void shouldHandleIfs() throws Exception {
+ Resource author = model.getResource("http://miskinhill.com.au/authors/test-author");
+ String result = templateInterpolator.interpolate(
+ new InputStreamReader(this.getClass().getResourceAsStream("conditional.xml")), author);
+ assertThat(result, containsString("attribute test"));
+ assertThat(result, containsString("element test"));
+ assertThat(result, not(containsString("rdf:if")));
+ assertThat(result, not(containsString("negated test")));
+
+ Resource authorWithoutNotes = model.getResource("http://miskinhill.com.au/authors/another-author");
+ result = templateInterpolator.interpolate(
+ new InputStreamReader(this.getClass().getResourceAsStream("conditional.xml")), authorWithoutNotes);
+ assertThat(result, not(containsString("attribute test")));
+ assertThat(result, not(containsString("element test")));
+ assertThat(result, containsString("negated test"));
+ }
+
+ @Test
+ public void shouldHandleJoins() throws Exception {
+ Resource citedArticle = model.getResource("http://miskinhill.com.au/cited/journals/asdf/1:1/article");
+ String result = templateInterpolator.interpolate(
+ new InputStreamReader(this.getClass().getResourceAsStream("join.xml")), citedArticle);
+ assertThat(result, containsString("<p><a href=\"http://miskinhill.com.au/authors/another-author\">Another Author</a>, " +
+ "<a href=\"http://miskinhill.com.au/authors/test-author\">Test Author</a></p>"));
+ }
+
+ @Test
+ public void shouldHandleFor() throws Exception {
+ Resource journal = model.getResource("http://miskinhill.com.au/journals/test/");
+ String result = templateInterpolator.interpolate(
+ new InputStreamReader(this.getClass().getResourceAsStream("for.xml")), journal);
+ assertThat(result, containsString("<span>http://miskinhill.com.au/journals/test/1:1/</span>"));
+ assertThat(result, containsString("<span>http://miskinhill.com.au/journals/test/2:1/</span>"));
+ assertThat(result, containsString("<p>http://miskinhill.com.au/journals/test/1:1/</p>"));
+ assertThat(result, containsString("<p>http://miskinhill.com.au/journals/test/2:1/</p>"));
+ }
+
+ @Test
+ public void shouldStripRdfNamespaceDeclarations() throws Exception {
+ Resource author = model.getResource("http://miskinhill.com.au/authors/test-author");
+ String result = templateInterpolator.interpolate(
+ new InputStreamReader(this.getClass().getResourceAsStream("namespaces.xml")), author);
+ assertThat(result, not(containsString("xmlns:rdf=\"http://code.miskinhill.com.au/rdftemplate/\"")));
+ assertThat(result, not(containsString("rdf:")));
+ }
+
+ @Test
+ public void forShouldIterateRdfSeqsInOrder() throws Exception {
+ Resource article = model.getResource("http://miskinhill.com.au/journals/test/1:1/multi-author-article");
+ String result = templateInterpolator.interpolate(
+ new InputStreamReader(this.getClass().getResourceAsStream("for-seq.xml")), article);
+ assertThat(result, containsString("Another Author\n\nTest Author"));
+ }
+
+ @Test
+ public void joinShouldIterateRdfSeqsInOrder() throws Exception {
+ Resource article = model.getResource("http://miskinhill.com.au/journals/test/1:1/multi-author-article");
+ String result = templateInterpolator.interpolate(
+ new InputStreamReader(this.getClass().getResourceAsStream("join-seq.xml")), article);
+ assertThat(result, containsString("<p><a href=\"http://miskinhill.com.au/authors/another-author\">Another Author</a>, " +
+ "<a href=\"http://miskinhill.com.au/authors/test-author\">Test Author</a></p>"));
+ }
+
+ @Test
+ public void forShouldWorkForSingleResult() throws Exception {
+ Resource journal = model.getResource("http://miskinhill.com.au/cited/journals/asdf/");
+ String result = templateInterpolator.interpolate(
+ new InputStreamReader(this.getClass().getResourceAsStream("for.xml")), journal);
+ assertThat(result, containsString("<span>http://miskinhill.com.au/cited/journals/asdf/1:1/</span>"));
+ assertThat(result, containsString("<p>http://miskinhill.com.au/cited/journals/asdf/1:1/</p>"));
+ }
+
+ @Test
+ public void joinShouldWorkForSingleResult() throws Exception {
+ Resource review = model.getResource("http://miskinhill.com.au/journals/test/1:1/reviews/review");
+ String result = templateInterpolator.interpolate(
+ new InputStreamReader(this.getClass().getResourceAsStream("join.xml")), review);
+ assertThat(result, containsString("<p><a href=\"http://miskinhill.com.au/authors/test-author\">Test Author</a></p>"));
+ }
+
+}
diff --git a/src/test/java/au/id/djc/rdftemplate/TestNamespacePrefixMap.java b/src/test/java/au/id/djc/rdftemplate/TestNamespacePrefixMap.java
@@ -0,0 +1,32 @@
+package au.id.djc.rdftemplate;
+
+import java.util.HashMap;
+
+import com.hp.hpl.jena.vocabulary.DCTerms;
+import com.hp.hpl.jena.vocabulary.RDF;
+import org.junit.Ignore;
+
+@Ignore // why does JUnit think this is a test?
+public final class TestNamespacePrefixMap extends HashMap<String, String> {
+
+ public static final String MHS_NS = "http://miskinhill.com.au/rdfschema/1.0/";
+ public static final String FOAF_NS = "http://xmlns.com/foaf/0.1/";
+
+ private static final long serialVersionUID = 2119318190108418683L;
+
+ private static final TestNamespacePrefixMap instance = new TestNamespacePrefixMap();
+ public static TestNamespacePrefixMap getInstance() {
+ return instance;
+ }
+
+ private TestNamespacePrefixMap() {
+ put("mhs", MHS_NS);
+ put("dc", DCTerms.NS);
+ put("foaf", FOAF_NS);
+ put("rdf", RDF.getURI());
+ put("sioc", "http://rdfs.org/sioc/ns#");
+ put("awol", "http://bblfish.net/work/atom-owl/2006-06-06/#");
+ put("lingvoj", "http://www.lingvoj.org/ontology#");
+ }
+
+}
diff --git a/src/test/java/au/id/djc/rdftemplate/datatype/DateDataTypeUnitTest.java b/src/test/java/au/id/djc/rdftemplate/datatype/DateDataTypeUnitTest.java
@@ -0,0 +1,35 @@
+package au.id.djc.rdftemplate.datatype;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.junit.Assert.assertThat;
+
+import com.hp.hpl.jena.datatypes.RDFDatatype;
+import org.joda.time.LocalDate;
+import org.junit.Before;
+import org.junit.Test;
+
+public class DateDataTypeUnitTest {
+
+ private RDFDatatype type;
+
+ @Before
+ public void setUp() {
+ type = new DateDataType();
+ }
+
+ @Test
+ public void shouldParseYear() {
+ assertThat((Year) type.parse("2003"), equalTo(new Year(2003)));
+ }
+
+ @Test
+ public void shouldParseYearMonth() {
+ assertThat((YearMonth) type.parse("2003-05"), equalTo(new YearMonth(2003, 5)));
+ }
+
+ @Test
+ public void shouldParseDate() {
+ assertThat((LocalDate) type.parse("2003-05-25"), equalTo(new LocalDate(2003, 5, 25)));
+ }
+
+}
diff --git a/src/test/java/au/id/djc/rdftemplate/datatype/DateTimeDataTypeUnitTest.java b/src/test/java/au/id/djc/rdftemplate/datatype/DateTimeDataTypeUnitTest.java
@@ -0,0 +1,34 @@
+package au.id.djc.rdftemplate.datatype;
+
+import static org.hamcrest.CoreMatchers.*;
+import static org.junit.Assert.*;
+
+import org.joda.time.DateTime;
+import org.joda.time.DateTimeZone;
+import org.junit.Before;
+import org.junit.Test;
+
+import com.hp.hpl.jena.datatypes.RDFDatatype;
+
+public class DateTimeDataTypeUnitTest {
+
+ private RDFDatatype type;
+
+ @Before
+ public void setUp() {
+ type = new DateTimeDataType();
+ }
+
+ @Test
+ public void shouldParseDate() {
+ assertThat((DateTime) type.parse("2003-05-25T10:11:12+05:00"),
+ equalTo(new DateTime(2003, 5, 25, 10, 11, 12, 0, DateTimeZone.forOffsetHours(5))));
+ }
+
+ @Test
+ public void shouldUnparseDate() {
+ assertThat(type.unparse(new DateTime(2003, 5, 25, 10, 11, 12, 0, DateTimeZone.forOffsetHours(5))),
+ equalTo("2003-05-25T10:11:12+05:00"));
+ }
+
+}
diff --git a/src/test/java/au/id/djc/rdftemplate/datatype/YearMonthUnitTest.java b/src/test/java/au/id/djc/rdftemplate/datatype/YearMonthUnitTest.java
@@ -0,0 +1,24 @@
+package au.id.djc.rdftemplate.datatype;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.junit.Assert.assertThat;
+
+import org.joda.time.LocalDate;
+import org.junit.Test;
+
+public class YearMonthUnitTest {
+
+ @Test
+ public void testToString() {
+ assertThat(new YearMonth(new LocalDate(2001, 5, 1)).toString(), equalTo("2001-05"));
+ }
+
+ @Test
+ public void testEqualsHashCode() {
+ YearMonth yearMonth1 = new YearMonth(new LocalDate(2001, 5, 1));
+ YearMonth yearMonth2 = new YearMonth(new LocalDate(2001, 5, 1));
+ assertThat(yearMonth1, equalTo(yearMonth2));
+ assertThat(yearMonth1.hashCode(), equalTo(yearMonth2.hashCode()));
+ }
+
+}
diff --git a/src/test/java/au/id/djc/rdftemplate/datatype/YearUnitTest.java b/src/test/java/au/id/djc/rdftemplate/datatype/YearUnitTest.java
@@ -0,0 +1,24 @@
+package au.id.djc.rdftemplate.datatype;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.junit.Assert.assertThat;
+
+import org.joda.time.LocalDate;
+import org.junit.Test;
+
+public class YearUnitTest {
+
+ @Test
+ public void testToString() {
+ assertThat(new Year(new LocalDate(2001, 1, 1)).toString(), equalTo("2001"));
+ }
+
+ @Test
+ public void testEqualsHashCode() {
+ Year year1 = new Year(new LocalDate(2001, 1, 1));
+ Year year2 = new Year(new LocalDate(2001, 1, 1));
+ assertThat(year1, equalTo(year2));
+ assertThat(year1.hashCode(), equalTo(year2.hashCode()));
+ }
+
+}
diff --git a/src/test/java/au/id/djc/rdftemplate/selector/AdaptationMatcher.java b/src/test/java/au/id/djc/rdftemplate/selector/AdaptationMatcher.java
@@ -0,0 +1,36 @@
+package au.id.djc.rdftemplate.selector;
+
+
+import static org.hamcrest.CoreMatchers.equalTo;
+
+public class AdaptationMatcher<T extends Adaptation<?>> extends BeanPropertyMatcher<T> {
+
+ private AdaptationMatcher(Class<T> type) {
+ super(type);
+ }
+
+ public static AdaptationMatcher<UriAdaptation> uriAdaptation() {
+ return new AdaptationMatcher<UriAdaptation>(UriAdaptation.class);
+ }
+
+ public static AdaptationMatcher<UriSliceAdaptation> uriSliceAdaptation(Integer startIndex) {
+ AdaptationMatcher<UriSliceAdaptation> m = new AdaptationMatcher<UriSliceAdaptation>(UriSliceAdaptation.class);
+ m.addRequiredProperty("startIndex", equalTo(startIndex));
+ return m;
+ }
+
+ public static AdaptationMatcher<LiteralValueAdaptation> lvAdaptation() {
+ return new AdaptationMatcher<LiteralValueAdaptation>(LiteralValueAdaptation.class);
+ }
+
+ public static AdaptationMatcher<ComparableLiteralValueAdaptation> comparableLVAdaptation() {
+ return new AdaptationMatcher<ComparableLiteralValueAdaptation>(ComparableLiteralValueAdaptation.class);
+ }
+
+ public static AdaptationMatcher<FormattedDateTimeAdaptation> formattedDTAdaptation(String pattern) {
+ AdaptationMatcher<FormattedDateTimeAdaptation> m = new AdaptationMatcher<FormattedDateTimeAdaptation>(FormattedDateTimeAdaptation.class);
+ m.addRequiredProperty("pattern", equalTo(pattern));
+ return m;
+ }
+
+}
diff --git a/src/test/java/au/id/djc/rdftemplate/selector/BeanPropertyMatcher.java b/src/test/java/au/id/djc/rdftemplate/selector/BeanPropertyMatcher.java
@@ -0,0 +1,56 @@
+package au.id.djc.rdftemplate.selector;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.apache.commons.beanutils.PropertyUtils;
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+
+public class BeanPropertyMatcher<T> extends BaseMatcher<T> {
+
+ private final Class<? extends T> matchedType;
+ private final Map<String, Matcher<?>> requiredProperties = new LinkedHashMap<String, Matcher<?>>();
+
+ public BeanPropertyMatcher(Class<? extends T> type) {
+ this.matchedType = type;
+ }
+
+ public void addRequiredProperty(String name, Matcher<?> matcher) {
+ requiredProperties.put(name, matcher);
+ }
+
+ @Override
+ public boolean matches(Object arg0) {
+ if (!matchedType.isInstance(arg0))
+ return false;
+ for (Map.Entry<String, Matcher<?>> property: requiredProperties.entrySet()) {
+ try {
+ Object beanProperty = PropertyUtils.getProperty(arg0, property.getKey());
+ if (!property.getValue().matches(beanProperty))
+ return false;
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public void describeTo(Description desc) {
+ desc.appendText(matchedType.getName());
+ desc.appendText("[");
+ boolean first = true;
+ for (Map.Entry<String, Matcher<?>> property: requiredProperties.entrySet()) {
+ if (!first)
+ desc.appendText(",");
+ desc.appendText(property.getKey());
+ desc.appendText("=");
+ property.getValue().describeTo(desc);
+ first = false;
+ }
+ desc.appendText("]");
+ }
+
+}
diff --git a/src/test/java/au/id/djc/rdftemplate/selector/EternallyCachingSelectorFactoryUnitTest.java b/src/test/java/au/id/djc/rdftemplate/selector/EternallyCachingSelectorFactoryUnitTest.java
@@ -0,0 +1,22 @@
+package au.id.djc.rdftemplate.selector;
+
+import static org.hamcrest.CoreMatchers.sameInstance;
+import static org.junit.Assert.assertThat;
+
+import org.junit.Test;
+
+import au.id.djc.rdftemplate.TestNamespacePrefixMap;
+
+public class EternallyCachingSelectorFactoryUnitTest {
+
+ @Test
+ public void shouldCacheSelectors() {
+ AntlrSelectorFactory wrappedFactory = new AntlrSelectorFactory();
+ wrappedFactory.setNamespacePrefixMap(TestNamespacePrefixMap.getInstance());
+ EternallyCachingSelectorFactory factory = new EternallyCachingSelectorFactory(wrappedFactory);
+ Selector<?> first = factory.get("dc:creator/foaf:name");
+ Selector<?> second = factory.get("dc:creator/foaf:name");
+ assertThat((Selector) first, sameInstance((Selector) second));
+ }
+
+}
diff --git a/src/test/java/au/id/djc/rdftemplate/selector/PredicateMatcher.java b/src/test/java/au/id/djc/rdftemplate/selector/PredicateMatcher.java
@@ -0,0 +1,34 @@
+package au.id.djc.rdftemplate.selector;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+
+import org.hamcrest.Matcher;
+
+public class PredicateMatcher<T extends Predicate> extends BeanPropertyMatcher<T> {
+
+ private PredicateMatcher(Class<T> type) {
+ super(type);
+ }
+
+ public static PredicateMatcher<UriPrefixPredicate> uriPrefixPredicate(String prefix) {
+ PredicateMatcher<UriPrefixPredicate> m = new PredicateMatcher<UriPrefixPredicate>(UriPrefixPredicate.class);
+ m.addRequiredProperty("prefix", equalTo(prefix));
+ return m;
+ }
+
+ public static PredicateMatcher<TypePredicate> typePredicate(String namespace, String localName) {
+ PredicateMatcher<TypePredicate> m = new PredicateMatcher<TypePredicate>(TypePredicate.class);
+ m.addRequiredProperty("namespace", equalTo(namespace));
+ m.addRequiredProperty("localName", equalTo(localName));
+ return m;
+ }
+
+ public static PredicateMatcher<BooleanAndPredicate> booleanAndPredicate(
+ Matcher<? extends Predicate> left, Matcher<? extends Predicate> right) {
+ PredicateMatcher<BooleanAndPredicate> m = new PredicateMatcher<BooleanAndPredicate>(BooleanAndPredicate.class);
+ m.addRequiredProperty("left", left);
+ m.addRequiredProperty("right", right);
+ return m;
+ }
+
+}
diff --git a/src/test/java/au/id/djc/rdftemplate/selector/SelectorComparatorMatcher.java b/src/test/java/au/id/djc/rdftemplate/selector/SelectorComparatorMatcher.java
@@ -0,0 +1,25 @@
+package au.id.djc.rdftemplate.selector;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+
+import org.hamcrest.Matcher;
+
+public class SelectorComparatorMatcher<T extends Comparable<T>> extends BeanPropertyMatcher<SelectorComparator<T>> {
+
+ @SuppressWarnings("unchecked")
+ public SelectorComparatorMatcher() {
+ super((Class) SelectorComparator.class);
+ }
+
+ public static SelectorComparatorMatcher<?> selectorComparator(Matcher<? extends Selector<?>> selector) {
+ SelectorComparatorMatcher<?> m = new SelectorComparatorMatcher();
+ m.addRequiredProperty("selector", selector);
+ return m;
+ }
+
+ public SelectorComparatorMatcher<T> reversed() {
+ addRequiredProperty("reversed", equalTo(true));
+ return this;
+ }
+
+}
diff --git a/src/test/java/au/id/djc/rdftemplate/selector/SelectorEvaluationUnitTest.java b/src/test/java/au/id/djc/rdftemplate/selector/SelectorEvaluationUnitTest.java
@@ -0,0 +1,224 @@
+package au.id.djc.rdftemplate.selector;
+
+import static org.hamcrest.CoreMatchers.*;
+import static org.junit.Assert.*;
+import static org.junit.matchers.JUnitMatchers.*;
+
+import java.io.InputStream;
+import java.util.List;
+
+import com.hp.hpl.jena.rdf.model.Literal;
+import com.hp.hpl.jena.rdf.model.Model;
+import com.hp.hpl.jena.rdf.model.ModelFactory;
+import com.hp.hpl.jena.rdf.model.RDFNode;
+import com.hp.hpl.jena.rdf.model.Resource;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import au.id.djc.rdftemplate.TestNamespacePrefixMap;
+import au.id.djc.rdftemplate.datatype.DateDataType;
+import au.id.djc.rdftemplate.datatype.DateTimeDataType;
+
+public class SelectorEvaluationUnitTest {
+
+ private Model m;
+ private Resource journal, issue, article, multiAuthorArticle, citedArticle, author, anotherAuthor, book, review, anotherReview, obituary, en, ru, forum;
+ private AntlrSelectorFactory selectorFactory;
+
+ @BeforeClass
+ public static void ensureDatatypesRegistered() {
+ DateDataType.registerStaticInstance();
+ DateTimeDataType.registerStaticInstance();
+ }
+
+ @Before
+ public void setUp() {
+ m = ModelFactory.createDefaultModel();
+ InputStream stream = this.getClass().getResourceAsStream("/au/id/djc/rdftemplate/test-data.xml");
+ m.read(stream, "");
+ journal = m.createResource("http://miskinhill.com.au/journals/test/");
+ issue = m.createResource("http://miskinhill.com.au/journals/test/1:1/");
+ article = m.createResource("http://miskinhill.com.au/journals/test/1:1/article");
+ multiAuthorArticle = m.createResource("http://miskinhill.com.au/journals/test/1:1/multi-author-article");
+ citedArticle = m.createResource("http://miskinhill.com.au/cited/journals/asdf/1:1/article");
+ author = m.createResource("http://miskinhill.com.au/authors/test-author");
+ anotherAuthor = m.createResource("http://miskinhill.com.au/authors/another-author");
+ book = m.createResource("http://miskinhill.com.au/cited/books/test");
+ review = m.createResource("http://miskinhill.com.au/journals/test/1:1/reviews/review");
+ anotherReview = m.createResource("http://miskinhill.com.au/journals/test/2:1/reviews/another-review");
+ obituary = m.createResource("http://miskinhill.com.au/journals/test/1:1/in-memoriam-john-doe");
+ en = m.createResource("http://www.lingvoj.org/lang/en");
+ ru = m.createResource("http://www.lingvoj.org/lang/ru");
+ forum = m.createResource("http://miskinhill.com.au/");
+ selectorFactory = new AntlrSelectorFactory();
+ selectorFactory.setNamespacePrefixMap(TestNamespacePrefixMap.getInstance());
+ }
+
+ @Test
+ public void shouldEvaluateTraversal() {
+ RDFNode result = selectorFactory.get("dc:creator").withResultType(RDFNode.class).singleResult(article);
+ assertThat(result, equalTo((RDFNode) author));
+ }
+
+ @Test
+ public void shouldEvaluateMultipleTraversals() throws Exception {
+ RDFNode result = selectorFactory.get("dc:creator/foaf:name")
+ .withResultType(RDFNode.class).singleResult(article);
+ assertThat(((Literal) result).getString(), equalTo("Test Author"));
+ }
+
+ @Test
+ public void shouldEvaluateInverseTraversal() throws Exception {
+ List<RDFNode> results = selectorFactory.get("!dc:isPartOf")
+ .withResultType(RDFNode.class).result(issue);
+ assertThat(results.size(), equalTo(4));
+ assertThat(results, hasItems((RDFNode) article, (RDFNode) multiAuthorArticle, (RDFNode) review, (RDFNode) obituary));
+ }
+
+ @Test
+ public void shouldEvaluateSortOrder() throws Exception {
+ List<RDFNode> results = selectorFactory.get("dc:language(lingvoj:iso1#comparable-lv)")
+ .withResultType(RDFNode.class).result(journal);
+ assertThat(results.size(), equalTo(2));
+ assertThat(results.get(0), equalTo((RDFNode) en));
+ assertThat(results.get(1), equalTo((RDFNode) ru));
+ }
+
+ @Test
+ public void shouldEvaluateReverseSortOrder() throws Exception {
+ List<RDFNode> results = selectorFactory.get("dc:language(~lingvoj:iso1#comparable-lv)")
+ .withResultType(RDFNode.class).result(journal);
+ assertThat(results.size(), equalTo(2));
+ assertThat(results.get(0), equalTo((RDFNode) ru));
+ assertThat(results.get(1), equalTo((RDFNode) en));
+ }
+
+ @Test
+ public void shouldEvaluateComplexSortOrder() throws Exception {
+ List<RDFNode> results = selectorFactory.get("!mhs:reviews(dc:isPartOf/mhs:publicationDate#comparable-lv)")
+ .withResultType(RDFNode.class).result(book);
+ assertThat(results.size(), equalTo(2));
+ assertThat(results.get(0), equalTo((RDFNode) review));
+ assertThat(results.get(1), equalTo((RDFNode) anotherReview));
+ }
+
+ @Test
+ public void shouldEvaluateUriAdaptation() throws Exception {
+ String result = selectorFactory.get("mhs:coverThumbnail#uri")
+ .withResultType(String.class).singleResult(issue);
+ assertThat(result, equalTo("http://miskinhill.com.au/journals/test/1:1/cover.thumb.jpg"));
+ }
+
+ @Test
+ public void shouldEvaluateBareUriAdaptation() throws Exception {
+ String result = selectorFactory.get("#uri").withResultType(String.class).singleResult(journal);
+ assertThat(result, equalTo("http://miskinhill.com.au/journals/test/"));
+ }
+
+ @Test
+ public void shouldEvaluateUriSliceAdaptation() throws Exception {
+ String result = selectorFactory.get("dc:identifier[uri-prefix='urn:issn:']#uri-slice(9)")
+ .withResultType(String.class).singleResult(journal);
+ assertThat(result, equalTo("12345678"));
+ }
+
+ @Test
+ public void shouldEvaluateUriAnchorAdaptation() throws Exception {
+ String result = selectorFactory.get("mhs:inSection#uri-anchor")
+ .withResultType(String.class).singleResult(anotherReview);
+ assertThat(result, equalTo("stuff"));
+ }
+
+ @Test
+ public void shouldEvaluateSubscript() throws Exception {
+ String result = selectorFactory.get(
+ "!mhs:isIssueOf(~mhs:publicationDate#comparable-lv)[0]/mhs:coverThumbnail#uri")
+ .withResultType(String.class).singleResult(journal);
+ assertThat(result, equalTo("http://miskinhill.com.au/journals/test/2:1/cover.thumb.jpg"));
+ result = selectorFactory.get(
+ "!mhs:isIssueOf(mhs:publicationDate#comparable-lv)[0]/mhs:coverThumbnail#uri")
+ .withResultType(String.class).singleResult(journal);
+ assertThat(result, equalTo("http://miskinhill.com.au/journals/test/1:1/cover.thumb.jpg"));
+ }
+
+ @Test
+ public void shouldEvaluateLVAdaptation() throws Exception {
+ List<Object> results = selectorFactory.get("dc:language/lingvoj:iso1#lv")
+ .withResultType(Object.class).result(journal);
+ assertThat(results.size(), equalTo(2));
+ assertThat(results, hasItems((Object) "en", (Object) "ru"));
+ }
+
+ @Test
+ public void shouldEvaluateTypePredicate() throws Exception {
+ List<RDFNode> results = selectorFactory.get("!dc:creator[type=mhs:Review]")
+ .withResultType(RDFNode.class).result(author);
+ assertThat(results.size(), equalTo(1));
+ assertThat(results, hasItems((RDFNode) review));
+ }
+
+ @Test
+ public void shouldEvaluateAndCombinationOfPredicates() throws Exception {
+ List<RDFNode> results = selectorFactory.get("!dc:creator[type=mhs:Article and uri-prefix='http://miskinhill.com.au/journals/']")
+ .withResultType(RDFNode.class).result(author);
+ assertThat(results.size(), equalTo(2));
+ assertThat(results, hasItems((RDFNode) article, (RDFNode) multiAuthorArticle));
+ }
+
+ @Test
+ public void shouldEvaluateUnion() throws Exception {
+ List<RDFNode> results = selectorFactory.get("!dc:creator | !mhs:translator")
+ .withResultType(RDFNode.class).result(anotherAuthor);
+ assertThat(results.size(), equalTo(4));
+ assertThat(results, hasItems((RDFNode) article, (RDFNode) multiAuthorArticle, (RDFNode) citedArticle, (RDFNode) anotherReview));
+ }
+
+ @Test
+ public void shouldEvaluateMultipleSortSelectors() throws Exception {
+ List<RDFNode> results = selectorFactory.get("!dc:creator[uri-prefix='http://miskinhill.com.au/journals/']" +
+ "(~dc:isPartOf/mhs:publicationDate#comparable-lv,mhs:startPage#comparable-lv)")
+ .withResultType(RDFNode.class).result(author);
+ assertThat(results.size(), equalTo(4));
+ assertThat(results.get(0), equalTo((RDFNode) obituary));
+ assertThat(results.get(1), equalTo((RDFNode) article));
+ assertThat(results.get(2), equalTo((RDFNode) multiAuthorArticle));
+ assertThat(results.get(3), equalTo((RDFNode) review));
+ }
+
+ @Test
+ public void shouldEvaluateFormattedDTAdaptation() throws Exception {
+ String result = selectorFactory.get("!sioc:has_container/dc:created#formatted-dt('d MMMM yyyy')")
+ .withResultType(String.class).singleResult(forum);
+ assertThat(result, equalTo("15 June 2009"));
+ }
+
+ @Test
+ public void shouldEvaluateFormattedDTAdaptationWithDoubleQuotes() throws Exception {
+ String result = selectorFactory.get("!sioc:has_container/dc:created#formatted-dt('yyyy-MM-dd\"T\"HH:mm:ssZZ')")
+ .withResultType(String.class).singleResult(forum);
+ assertThat(result, equalTo("2009-06-15T18:21:32+10:00"));
+ }
+
+ @Test
+ public void shouldEvaluateStringLVAdaptation() throws Exception {
+ List<String> results = selectorFactory.get("dc:language/lingvoj:iso1#string-lv")
+ .withResultType(String.class).result(journal);
+ assertThat(results.size(), equalTo(2));
+ assertThat(results, hasItems("en", "ru"));
+ }
+
+ @Test
+ public void stringLVAdaptationShouldStripTagsFromXMLLiteral() throws Exception {
+ String result = selectorFactory.get("!sioc:has_container/sioc:content/awol:body#string-lv")
+ .withResultType(String.class).singleResult(forum);
+ assertEquals("To coincide with the publication of our second issue, " +
+ "the 2008 volume of Australian Slavonic and East European Studies, " +
+ "we are making available two new data feeds: an Atom feed of all " +
+ "journal issues published on this site, and the complete RDF dataset " +
+ "underlying the site. We hope this helps our users and aggregators " +
+ "to discover new content as it is published.",
+ result.trim().replaceAll("\\s+", " "));
+ }
+
+}
diff --git a/src/test/java/au/id/djc/rdftemplate/selector/SelectorMatcher.java b/src/test/java/au/id/djc/rdftemplate/selector/SelectorMatcher.java
@@ -0,0 +1,36 @@
+package au.id.djc.rdftemplate.selector;
+
+import static org.junit.matchers.JUnitMatchers.hasItems;
+
+import com.hp.hpl.jena.rdf.model.RDFNode;
+import org.hamcrest.Matcher;
+
+public class SelectorMatcher<T extends Selector<?>> extends BeanPropertyMatcher<T> {
+
+ private SelectorMatcher(Class<? extends T> type) {
+ super(type);
+ }
+
+ public static SelectorMatcher<Selector<RDFNode>> selector(Matcher<Traversal>... traversals) {
+ if (traversals.length == 0) {
+ return new SelectorMatcher<Selector<RDFNode>>(NoopSelector.class);
+ }
+ SelectorMatcher<Selector<RDFNode>> m = new SelectorMatcher<Selector<RDFNode>>(TraversingSelector.class);
+ m.addRequiredProperty("traversals", hasItems(traversals));
+ return m;
+ }
+
+ public static <R> SelectorMatcher<UnionSelector<R>> unionSelector(Matcher<Selector<R>>... selectors) {
+ SelectorMatcher<UnionSelector<R>> m = new SelectorMatcher(UnionSelector.class);
+ m.addRequiredProperty("selectors", hasItems(selectors));
+ return m;
+ }
+
+ public <A> SelectorMatcher<Selector<?>> withAdaptation(Matcher<? extends Adaptation<A>> adaptation) {
+ SelectorMatcher<Selector<?>> m = new SelectorMatcher(SelectorWithAdaptation.class);
+ m.addRequiredProperty("baseSelector", this);
+ m.addRequiredProperty("adaptation", adaptation);
+ return m;
+ }
+
+}
diff --git a/src/test/java/au/id/djc/rdftemplate/selector/SelectorParserUnitTest.java b/src/test/java/au/id/djc/rdftemplate/selector/SelectorParserUnitTest.java
@@ -0,0 +1,206 @@
+package au.id.djc.rdftemplate.selector;
+
+import static au.id.djc.rdftemplate.TestNamespacePrefixMap.*;
+import static au.id.djc.rdftemplate.selector.AdaptationMatcher.*;
+import static au.id.djc.rdftemplate.selector.PredicateMatcher.*;
+import static au.id.djc.rdftemplate.selector.SelectorComparatorMatcher.*;
+import static au.id.djc.rdftemplate.selector.SelectorMatcher.*;
+import static au.id.djc.rdftemplate.selector.TraversalMatcher.*;
+import static org.junit.Assert.*;
+
+import com.hp.hpl.jena.rdf.model.RDFNode;
+import com.hp.hpl.jena.vocabulary.DCTerms;
+import com.hp.hpl.jena.vocabulary.RDF;
+import org.junit.Before;
+import org.junit.Test;
+
+import au.id.djc.rdftemplate.TestNamespacePrefixMap;
+
+public class SelectorParserUnitTest {
+
+ private AntlrSelectorFactory factory;
+
+ @Before
+ public void setUp() {
+ factory = new AntlrSelectorFactory();
+ factory.setNamespacePrefixMap(TestNamespacePrefixMap.getInstance());
+ }
+
+ @Test
+ public void shouldRecogniseSingleTraversal() throws Exception {
+ Selector<RDFNode> selector = factory.get("dc:creator").withResultType(RDFNode.class);
+ assertThat(selector, selector(traversal(DCTerms.NS, "creator")));
+ }
+
+ @Test
+ public void shouldRecogniseMultipleTraversals() throws Exception {
+ Selector<RDFNode> selector = factory.get("dc:creator/foaf:name").withResultType(RDFNode.class);
+ assertThat(selector, selector(
+ traversal(DCTerms.NS, "creator"),
+ traversal(FOAF_NS, "name")));
+ }
+
+ @Test
+ public void shouldRecogniseMultipleTraversalsWithWhitespace() throws Exception {
+ Selector<RDFNode> selector = factory.get("dc:creator / foaf:name").withResultType(RDFNode.class);
+ assertThat(selector, selector(
+ traversal(DCTerms.NS, "creator"),
+ traversal(FOAF_NS, "name")));
+ }
+
+ @Test
+ public void shouldRecogniseInverseTraversal() throws Exception {
+ Selector<RDFNode> selector = factory.get("!dc:isPartOf/!dc:isPartOf").withResultType(RDFNode.class);
+ assertThat(selector, selector(
+ traversal(DCTerms.NS, "isPartOf").inverse(),
+ traversal(DCTerms.NS, "isPartOf").inverse()));
+ }
+
+ @Test
+ public void shouldRecogniseSortOrder() throws Exception {
+ Selector<RDFNode> selector = factory.get("!mhs:isIssueOf(mhs:publicationDate#comparable-lv)").withResultType(RDFNode.class);
+ assertThat(selector, selector(
+ traversal(MHS_NS, "isIssueOf").inverse()
+ .withSortOrder(selectorComparator(selector(traversal(MHS_NS, "publicationDate"))
+ .withAdaptation(comparableLVAdaptation())))));
+ }
+
+ @Test
+ public void shouldRecogniseReverseSortOrder() throws Exception {
+ Selector<RDFNode> selector = factory.get("!mhs:isIssueOf(~mhs:publicationDate#comparable-lv)").withResultType(RDFNode.class);
+ assertThat(selector, selector(
+ traversal(MHS_NS, "isIssueOf").inverse()
+ .withSortOrder(selectorComparator(selector(traversal(MHS_NS, "publicationDate"))
+ .withAdaptation(comparableLVAdaptation())).reversed())));
+ }
+
+ @Test
+ public void shouldRecogniseComplexSortOrder() throws Exception {
+ Selector<RDFNode> selector = factory.get("!mhs:reviews(dc:isPartOf/mhs:publicationDate#comparable-lv)").withResultType(RDFNode.class);
+ assertThat(selector, selector(
+ traversal(MHS_NS, "reviews")
+ .withSortOrder(selectorComparator(selector(traversal(DCTerms.NS, "isPartOf"), traversal(MHS_NS, "publicationDate"))
+ .withAdaptation(comparableLVAdaptation())))));
+ }
+
+ @Test
+ public void shouldRecogniseUriAdaptation() throws Exception {
+ Selector<?> selector = factory.get("mhs:coverThumbnail#uri");
+ assertThat(selector, selector(
+ traversal(MHS_NS, "coverThumbnail"))
+ .withAdaptation(uriAdaptation()));
+ }
+
+ @Test
+ public void shouldRecogniseBareUriAdaptation() throws Exception {
+ Selector<?> selector = factory.get("#uri");
+ assertThat(selector, selector().withAdaptation(uriAdaptation()));
+ }
+
+ @Test
+ public void shouldRecogniseUriSliceAdaptation() throws Exception {
+ Selector<?> selector = factory.get("dc:identifier[uri-prefix='urn:issn:']#uri-slice(9)");
+ assertThat(selector, selector(
+ traversal(DCTerms.NS, "identifier")
+ .withPredicate(uriPrefixPredicate("urn:issn:")))
+ .withAdaptation(uriSliceAdaptation(9)));
+ }
+
+ @Test
+ public void shouldRecogniseUriPrefixPredicate() throws Exception {
+ Selector<RDFNode> selector = factory.get(
+ "!mhs:isIssueOf[uri-prefix='http://miskinhill.com.au/journals/'](~mhs:publicationDate#comparable-lv)")
+ .withResultType(RDFNode.class);
+ assertThat(selector, selector(
+ traversal(MHS_NS, "isIssueOf")
+ .inverse()
+ .withPredicate(uriPrefixPredicate("http://miskinhill.com.au/journals/"))
+ .withSortOrder(selectorComparator(selector(traversal(MHS_NS, "publicationDate"))
+ .withAdaptation(comparableLVAdaptation())).reversed())));
+ }
+
+ @Test
+ public void shouldRecogniseSubscript() throws Exception {
+ Selector<String> selector = factory.get(
+ "!mhs:isIssueOf(~mhs:publicationDate#comparable-lv)[0]/mhs:coverThumbnail#uri")
+ .withResultType(String.class);
+ assertThat(selector, selector(
+ traversal(MHS_NS, "isIssueOf")
+ .inverse()
+ .withSortOrder(selectorComparator(selector(traversal(MHS_NS, "publicationDate"))
+ .withAdaptation(comparableLVAdaptation())).reversed())
+ .withSubscript(0),
+ traversal(MHS_NS, "coverThumbnail"))
+ .withAdaptation(uriAdaptation()));
+ }
+
+ @Test
+ public void shouldRecogniseLVAdaptation() throws Exception {
+ Selector<Object> selector = factory.get("dc:language/lingvoj:iso1#lv").withResultType(Object.class);
+ assertThat(selector, selector(
+ traversal(DCTerms.NS, "language"),
+ traversal("http://www.lingvoj.org/ontology#", "iso1"))
+ .withAdaptation(lvAdaptation()));
+ }
+
+ @Test
+ public void shouldRecogniseTypePredicate() throws Exception {
+ Selector<RDFNode> selector = factory.get("!dc:creator[type=mhs:Review]").withResultType(RDFNode.class);
+ assertThat(selector, selector(
+ traversal(DCTerms.NS, "creator").inverse().withPredicate(typePredicate(MHS_NS, "Review"))));
+ }
+
+ @Test
+ public void shouldRecogniseAndCombinationOfPredicates() throws Exception {
+ Selector<RDFNode> selector = factory.get("!dc:creator[type=mhs:Review and uri-prefix='http://miskinhill.com.au/journals/']").withResultType(RDFNode.class);
+ assertThat(selector, selector(
+ traversal(DCTerms.NS, "creator").inverse()
+ .withPredicate(booleanAndPredicate(
+ typePredicate(MHS_NS, "Review"),
+ uriPrefixPredicate("http://miskinhill.com.au/journals/")))));
+ }
+
+ @Test
+ public void shouldRecogniseUnion() throws Exception {
+ Selector<RDFNode> selector = factory.get("!dc:creator | !mhs:translator").withResultType(RDFNode.class);
+ assertThat((UnionSelector<RDFNode>) selector, unionSelector(
+ selector(traversal(DCTerms.NS, "creator").inverse()),
+ selector(traversal(MHS_NS, "translator").inverse())));
+ }
+
+ @Test
+ public void shouldRecogniseMultipleSortSelectors() throws Exception {
+ Selector<RDFNode> selector = factory.get("!dc:creator(~dc:isPartOf/mhs:publicationDate#comparable-lv,mhs:startPage#comparable-lv)").withResultType(RDFNode.class);
+ assertThat(selector, selector(
+ traversal(DCTerms.NS, "creator").inverse()
+ .withSortOrder(
+ selectorComparator(selector(traversal(DCTerms.NS, "isPartOf"), traversal(MHS_NS, "publicationDate"))
+ .withAdaptation(comparableLVAdaptation())).reversed(),
+ selectorComparator(selector(traversal(MHS_NS, "startPage")).withAdaptation(comparableLVAdaptation())))));
+ }
+
+ @Test
+ public void shouldRecogniseFormattedDTAdaptation() throws Exception {
+ Selector<?> selector = factory.get("dc:created#formatted-dt('d MMMM yyyy')");
+ assertThat(selector, selector(traversal(DCTerms.NS, "created"))
+ .withAdaptation(formattedDTAdaptation("d MMMM yyyy")));
+ }
+
+ @Test
+ public void shouldRecogniseRdfType() throws Exception {
+ // was broken due to ANTLR being confused about the literal string "type" which was hardcoded to be a predicate
+ Selector<RDFNode> selector = factory.get("rdf:type").withResultType(RDFNode.class);
+ assertThat(selector, selector(traversal(RDF.getURI(), "type")));
+ }
+
+ @Test(expected = InvalidSelectorSyntaxException.class)
+ public void shouldThrowForInvalidSyntax() throws Exception {
+ factory.get("dc:creator]["); // this is a parser error
+ }
+
+ @Test(expected = InvalidSelectorSyntaxException.class)
+ public void shouldThrowForUnrecognisedCharacter() throws Exception {
+ factory.get("dc:cre&ator"); // ... and this is a lexer error
+ }
+
+}
diff --git a/src/test/java/au/id/djc/rdftemplate/selector/TraversalMatcher.java b/src/test/java/au/id/djc/rdftemplate/selector/TraversalMatcher.java
@@ -0,0 +1,44 @@
+package au.id.djc.rdftemplate.selector;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.junit.matchers.JUnitMatchers.hasItems;
+
+import java.util.Comparator;
+
+import com.hp.hpl.jena.rdf.model.RDFNode;
+import org.hamcrest.Matcher;
+
+public class TraversalMatcher extends BeanPropertyMatcher<Traversal> {
+
+ private TraversalMatcher() {
+ super(Traversal.class);
+ }
+
+ public static TraversalMatcher traversal(String propertyNamespace, String propertyLocalName) {
+ TraversalMatcher m = new TraversalMatcher();
+ m.addRequiredProperty("propertyNamespace", equalTo(propertyNamespace));
+ m.addRequiredProperty("propertyLocalName", equalTo(propertyLocalName));
+ return m;
+ }
+
+ public TraversalMatcher inverse() {
+ addRequiredProperty("inverse", equalTo(true));
+ return this;
+ }
+
+ public TraversalMatcher withPredicate(Matcher<? extends Predicate> predicate) {
+ addRequiredProperty("predicate", predicate);
+ return this;
+ }
+
+ public TraversalMatcher withSortOrder(Matcher<? extends Comparator<RDFNode>>... sortOrder) {
+ addRequiredProperty("sortOrder", hasItems(sortOrder));
+ return this;
+ }
+
+ public TraversalMatcher withSubscript(int subscript) {
+ addRequiredProperty("subscript", equalTo(subscript));
+ return this;
+ }
+
+}
diff --git a/src/test/java/au/id/djc/rdftemplate/selector/UriAnchorAdaptationUnitTest.java b/src/test/java/au/id/djc/rdftemplate/selector/UriAnchorAdaptationUnitTest.java
@@ -0,0 +1,23 @@
+package au.id.djc.rdftemplate.selector;
+
+import static org.hamcrest.CoreMatchers.*;
+import static org.junit.Assert.*;
+
+import com.hp.hpl.jena.rdf.model.ResourceFactory;
+import org.junit.Test;
+
+public class UriAnchorAdaptationUnitTest {
+
+ @Test
+ public void shouldReturnAnchor() {
+ String result = new UriAnchorAdaptation().adapt(ResourceFactory.createResource("http://example.com/#asdf"));
+ assertThat(result, equalTo("asdf"));
+ }
+
+ @Test
+ public void shouldReturnEmptyStringForUriWithoutAnchor() {
+ String result = new UriAnchorAdaptation().adapt(ResourceFactory.createResource("http://example.com/"));
+ assertThat(result, equalTo(""));
+ }
+
+}
diff --git a/src/test/resources/au/com/miskinhill/rdftemplate/conditional.xml b/src/test/resources/au/id/djc/rdftemplate/conditional.xml
diff --git a/src/test/resources/au/com/miskinhill/rdftemplate/for-seq.xml b/src/test/resources/au/id/djc/rdftemplate/for-seq.xml
diff --git a/src/test/resources/au/com/miskinhill/rdftemplate/for.xml b/src/test/resources/au/id/djc/rdftemplate/for.xml
diff --git a/src/test/resources/au/com/miskinhill/rdftemplate/join-seq.xml b/src/test/resources/au/id/djc/rdftemplate/join-seq.xml
diff --git a/src/test/resources/au/com/miskinhill/rdftemplate/join.xml b/src/test/resources/au/id/djc/rdftemplate/join.xml
diff --git a/src/test/resources/au/com/miskinhill/rdftemplate/namespaces.xml b/src/test/resources/au/id/djc/rdftemplate/namespaces.xml
diff --git a/src/test/resources/au/com/miskinhill/rdftemplate/replace-subtree.xml b/src/test/resources/au/id/djc/rdftemplate/replace-subtree.xml
diff --git a/src/test/resources/au/com/miskinhill/rdftemplate/replace-xml.xml b/src/test/resources/au/id/djc/rdftemplate/replace-xml.xml
diff --git a/src/test/resources/au/com/miskinhill/rdftemplate/test-data.xml b/src/test/resources/au/id/djc/rdftemplate/test-data.xml