You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@marmotta.apache.org by wi...@apache.org on 2013/02/19 13:57:40 UTC
[5/11] added missing module from the previous code importation
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/32a909f7/ldpath/ldpath-core/src/main/javacc/at/newmedialab/ldpath/parser/rdfpath.jj
----------------------------------------------------------------------
diff --git a/ldpath/ldpath-core/src/main/javacc/at/newmedialab/ldpath/parser/rdfpath.jj b/ldpath/ldpath-core/src/main/javacc/at/newmedialab/ldpath/parser/rdfpath.jj
new file mode 100644
index 0000000..4e45588
--- /dev/null
+++ b/ldpath/ldpath-core/src/main/javacc/at/newmedialab/ldpath/parser/rdfpath.jj
@@ -0,0 +1,1012 @@
+options
+{
+ STATIC=false;
+// LOOKAHEAD=5;
+ CACHE_TOKENS=true;
+// FORCE_LA_CHECK=true;
+// CHOICE_AMBIGUITY_CHECK=5;
+ LOOKAHEAD=2147483647;
+// DEBUG_PARSER=true;
+// DEBUG_TOKEN_MANAGER=true;
+// DEBUG_LOOKAHEAD=true;
+}
+
+PARSER_BEGIN(RdfPathParser)
+package at.newmedialab.ldpath.parser;
+
+import at.newmedialab.ldpath.model.Constants;
+
+import at.newmedialab.ldpath.api.backend.*;
+import at.newmedialab.ldpath.api.functions.*;
+import at.newmedialab.ldpath.api.selectors.*;
+import at.newmedialab.ldpath.api.tests.*;
+import at.newmedialab.ldpath.api.transformers.*;
+
+
+import at.newmedialab.ldpath.model.fields.*;
+import at.newmedialab.ldpath.model.functions.*;
+import at.newmedialab.ldpath.model.programs.*;
+import at.newmedialab.ldpath.model.selectors.*;
+import at.newmedialab.ldpath.model.tests.*;
+import at.newmedialab.ldpath.model.transformers.*;
+
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Collections;
+
+import java.io.Reader;
+import java.io.InputStream;
+
+import java.net.URI;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+@SuppressWarnings("all")
+public class RdfPathParser<Node> {
+
+ private enum Mode { RULE, SELECTOR, TEST, PROGRAM, PREFIX };
+
+
+ private static final Logger log = LoggerFactory.getLogger(RdfPathParser.class);
+
+ /**
+ * A map mapping from namespace prefix to namespace URI
+ */
+ private Map<String,String> namespaces = new HashMap<String,String>();
+
+ private RDFBackend<Node> backend;
+
+ private Configuration config;
+
+ private Mode mode = Mode.PROGRAM;
+
+ public RdfPathParser(RDFBackend<Node> backend, Reader in) {
+ this(backend,null,in);
+ }
+
+ public RdfPathParser(RDFBackend<Node> backend, Configuration config, Reader in) {
+ this(in);
+ this.backend = backend;
+ if(config == null) {
+ this.config = new DefaultConfiguration();
+ } else {
+ this.config = config;
+ }
+
+ initialise();
+ }
+
+ public RdfPathParser(RDFBackend<Node> backend, InputStream in) {
+ this(backend,null,in);
+ }
+
+ public RdfPathParser(RDFBackend<Node> backend, Configuration config, InputStream in) {
+ this(in);
+ this.backend = backend;
+ if(config == null) {
+ this.config = new DefaultConfiguration();
+ } else {
+ this.config = config;
+ }
+
+ initialise();
+ }
+
+ public RdfPathParser(RDFBackend<Node> backend, InputStream in, String encoding) {
+ this(backend,null,in,encoding);
+ }
+
+ public RdfPathParser(RDFBackend<Node> backend, Configuration config, InputStream in, String encoding) {
+ this(in,encoding);
+ this.backend = backend;
+ if(config == null) {
+ this.config = new DefaultConfiguration();
+ } else {
+ this.config = config;
+ }
+
+ initialise();
+ }
+
+ public Program<Node> parseProgram() throws ParseException {
+ namespaces.clear();
+ namespaces.putAll(config.getNamespaces());
+
+ mode = Mode.PROGRAM;
+ try {
+ return Program();
+ } catch(TokenMgrError error){
+ throw new ParseException("Unable to parse Program: (Message: "+error.getMessage()+")");
+ }
+ }
+
+ public Entry<String, String> parsePrefix() throws ParseException {
+ namespaces.clear();
+ namespaces.putAll(config.getNamespaces());
+ mode = Mode.PREFIX;
+ try {
+ return Namespace();
+ } catch (TokenMgrError error) {
+ throw new ParseException("Unable to parse Prefix: (Message: "+ error.getMessage()+")");
+ }
+ }
+
+ public Map<String, String> parsePrefixes() throws ParseException {
+ namespaces.clear();
+ namespaces.putAll(config.getNamespaces());
+ mode = Mode.PREFIX;
+ try {
+ return Namespaces();
+ } catch (TokenMgrError error) {
+ throw new ParseException("Unable to parse Prefixes: (Message: "+ error.getMessage()+")");
+ }
+ }
+
+
+ public NodeSelector<Node> parseSelector(Map<String,String> ctxNamespaces) throws ParseException {
+ namespaces.clear();
+ namespaces.putAll(config.getNamespaces());
+ if(ctxNamespaces != null) {
+ namespaces.putAll(ctxNamespaces);
+ }
+
+ mode = Mode.SELECTOR;
+
+ try {
+ return Selector();
+ } catch(TokenMgrError error){
+ throw new ParseException("Unable to parse Selector: (Message: "+error.getMessage()+")");
+ }
+ }
+
+ public NodeTest<Node> parseTest(Map<String, String> ctxNamespaces) throws ParseException {
+ namespaces.clear();
+ namespaces.putAll(config.getNamespaces());
+ if (ctxNamespaces != null) {
+ namespaces.putAll(ctxNamespaces);
+ }
+ mode = Mode.TEST;
+ try {
+ return NodeTest();
+ } catch (TokenMgrError error) {
+ throw new ParseException("Unable to parse Test: (Message: "+ error.getMessage()+")");
+ }
+ }
+
+ public <T> FieldMapping<T,Node> parseRule(Map<String,String> ctxNamespaces) throws ParseException {
+ namespaces.clear();
+ namespaces.putAll(config.getNamespaces());
+ if(ctxNamespaces != null) {
+ namespaces.putAll(ctxNamespaces);
+ }
+
+ mode = Mode.RULE;
+
+ try {
+ return Rule();
+ } catch(TokenMgrError error){
+ throw new ParseException("Unable to parse Rule: (Message: "+error.getMessage()+")");
+ }
+ }
+
+
+ public Node resolveResource(String uri) {
+ return backend.createURI(uri);
+ }
+
+
+ public String resolveNamespace(String prefix) throws ParseException {
+ String uri = namespaces.get(prefix);
+ if(uri == null) {
+ throw new ParseException("Namespace "+prefix+" not defined!");
+ }
+ return uri;
+ }
+
+
+ public SelectorFunction<Node> getFunction(String uri) throws ParseException {
+ if(xsdNodeFunctionMap.get(uri) != null) {
+ return xsdNodeFunctionMap.get(uri);
+ } else {
+ throw new ParseException("function with URI "+uri+" does not exist");
+ }
+ }
+
+ public TestFunction<Node> getTestFunction(String uri) throws ParseException {
+ if (xsdNodeTestMap.get(uri) != null) {
+ return xsdNodeTestMap.get(uri);
+ } else {
+ throw new ParseException("test function with URI "+uri+" does not exist");
+ }
+ }
+
+ public NodeTransformer<?,Node> getTransformer(String uri) throws ParseException {
+ if(xsdNodeTransformerMap.get(uri) != null) {
+ return xsdNodeTransformerMap.get(uri);
+ } else {
+ throw new ParseException("transformer with URI "+uri+" does not exist");
+ }
+ }
+
+
+ private void initialise() {
+ initTransformerMappings();
+ initFunctionMappings();
+ }
+
+ /**
+ * Register the function passed as argument in this parser's function map.
+ */
+ public void registerFunction(SelectorFunction<Node> function) {
+ registerFunction(xsdNodeFunctionMap,function);
+ }
+
+ public void registerFunction(TestFunction<Node> test) {
+ registerTest(xsdNodeTestMap, test);
+ }
+
+ /**
+ * Register the result transformer passed as argument for the given type uri.
+ */
+ public void registerTransformer(String typeUri, NodeTransformer<?,Node> transformer) {
+ xsdNodeTransformerMap.put(typeUri,transformer);
+ }
+
+
+ /**
+ * A map mapping from XSD types to node transformers.
+ */
+ private Map<String, NodeTransformer<?,Node>> xsdNodeTransformerMap;
+ private void initTransformerMappings() {
+ Map<String, NodeTransformer<?,Node>> transformerMap = new HashMap<String, NodeTransformer<?,Node>>();
+
+ transformerMap.putAll(config.getTransformers());
+
+ xsdNodeTransformerMap = transformerMap;
+ }
+
+
+ private Map<String, SelectorFunction<Node>> xsdNodeFunctionMap;
+ private Map<String, TestFunction<Node>> xsdNodeTestMap;
+ private void initFunctionMappings() {
+ Map<String, SelectorFunction<Node>> functionMap = new HashMap<String, SelectorFunction<Node>>();
+
+ functionMap.putAll(config.getFunctions());
+
+ xsdNodeFunctionMap = functionMap;
+
+ Map<String, TestFunction<Node>> testMap = new HashMap<String, TestFunction<Node>>();
+ testMap.putAll(config.getTestFunctions());
+ xsdNodeTestMap = testMap;
+ }
+
+ private void registerFunction(Map<String, SelectorFunction<Node>> register, final SelectorFunction<Node> function) {
+ register.put(Constants.NS_LMF_FUNCS + function.getPathExpression(backend), function);
+ }
+
+ private void registerTest(Map<String, TestFunction<Node>> register, final TestFunction<Node> test) {
+ register.put(Constants.NS_LMF_FUNCS + test.getLocalName(), test);
+ }
+
+ private class Namespace implements Entry<String, String> {
+ private String key, val;
+ public Namespace(String key, String val) {
+ this.key = key;
+ this.val = val;
+ }
+ @Override
+ public String getKey() {
+ return key;
+ }
+ @Override
+ public String getValue() {
+ return val;
+ }
+ @Override
+ public String setValue(String value) {
+ String oV = val;
+ val = value;
+ return oV;
+ }
+ }
+
+}
+PARSER_END(RdfPathParser)
+
+SKIP :
+{
+ " "
+| "\r"
+| "\t"
+| "\n"
+}
+
+MORE:
+{
+ "\"" : WithinString
+}
+
+<WithinString> TOKEN:
+{
+ <STRLIT: "\""> : DEFAULT
+}
+
+<WithinString> MORE:
+{
+ <~["\n","\r"]>
+}
+
+
+TOKEN : /* OPERATORS */
+{
+ < AND: "&" > |
+ < OR: "|" > |
+ < NOT: "!" > |
+ < IS: "is" > |
+ < IS_A: "is-a" > |
+ < TYPE: "^^" > |
+ < LANG: "@" >
+}
+
+TOKEN :
+{
+ < URI: ["a"-"z","A"-"Z"](["a"-"z","A"-"Z","0"-"9","+","-","."])* "://" (["a"-"z","A"-"Z","0"-"9",";","/","?",":","@","&","=","+","$",".","-","_","!","~","*","'","%"])+ ("#" (["a"-"z","A"-"Z","0"-"9",";","/","?",":","@","&","=","+","$",".","-","_","!","~","*","'","%"])*)? | "#" (["a"-"z","A"-"Z","0"-"9",";","/","?",":","@","&","=","+","$",".","-","_","!","~","*","'","%"])+> |
+ < IDENTIFIER: ["a"-"z","A"-"Z","0"-"9","_"](["a"-"z","A"-"Z","0"-"9","_","'","-"])* > |
+ < #URICHAR: ["a"-"z","A"-"Z","0"-"9",";","/","?",":","@","&","=","+","$",".","-","_","!","~","*","'","%"] >
+}
+
+Map<String, String> Namespaces() :
+{
+ HashMap<String, String> ns = new HashMap<String, String>();
+ Entry<String, String> namespace = null;
+}
+{
+ (
+ namespace = Namespace() {
+ ns.put(namespace.getKey(), namespace.getValue());
+ }
+ )+
+ {
+ return ns;
+ }
+}
+
+Entry<String, String> Namespace() :
+{
+ Token id = null;
+ Token uri;
+}
+{
+ (
+ "@prefix" id = <IDENTIFIER> ":" "<" uri = <URI> ">" (";")? {
+ }
+ ) { return new Namespace(id.image, uri.image); }
+}
+
+Program Program() :
+{
+ Program<Node> program = new Program();
+ NodeTest<Node> filter = null;
+ Map<String, String> nss = null;
+ FieldMapping<?,Node> rule;
+ NodeSelector<Node> boostSelector;
+}
+{
+ (
+ nss = Namespaces() {
+ namespaces.putAll(nss);
+ for (String k : nss.keySet()) {
+ program.addNamespace(k, nss.get(k));
+ }
+ }
+ )?
+
+ (
+ "@filter" filter = NodeTest() ";" {
+ program.setFilter(filter);
+ }
+ )?
+
+ (
+ "@boost" boostSelector = Selector() ";" {
+ NodeTransformer transformer = getTransformer(Program.DOCUMENT_BOOST_TYPE);
+ FieldMapping booster = new FieldMapping("@boost", Program.DOCUMENT_BOOST_TYPE, boostSelector, transformer, null);
+ program.setBooster(booster);
+ }
+ )?
+
+ (
+ rule = Rule()
+ {
+ program.addMapping(rule);
+ }
+ )*
+ <EOF>
+ {
+ return program;
+ }
+}
+
+FieldMapping Rule() :
+{
+ FieldMapping<?,Node> rule;
+ Token name;
+ String uri;
+ String type = null;
+ NodeSelector<Node> selector;
+ NodeTransformer<?,Node> transformer;
+ Map<String, String> conf = null;
+}
+{
+ name = <IDENTIFIER> "=" selector = Selector() ("::" type = Uri())? ("(" conf = FieldConfig() ")")? ";" {
+ if(type != null) {
+ transformer = getTransformer(type);
+ } else {
+ transformer = new IdentityTransformer();
+ }
+ if(mode != Mode.PROGRAM) {
+ throw new ParseException("cannot use field names when parsing single paths");
+ }
+ rule = new FieldMapping(name.image,type,selector,transformer, conf);
+ return rule;
+ }
+| uri = Uri() "=" selector = Selector() ("::" type = Uri())? ("(" conf = FieldConfig() ")")? ";" {
+ if(type != null) {
+ transformer = getTransformer(type);
+ } else {
+ transformer = new IdentityTransformer();
+ }
+ if(mode != Mode.PROGRAM) {
+ throw new ParseException("cannot use field names when parsing single paths");
+ }
+ rule = new FieldMapping(uri,type,selector,transformer, conf);
+ return rule;
+ }
+| selector = Selector() ("::" type = Uri())? ("(" conf = FieldConfig() ")")? (";")? {
+ if(type != null) {
+ transformer = getTransformer(type);
+ } else {
+ transformer = new IdentityTransformer();
+ }
+ if(mode != Mode.PROGRAM && conf != null) {
+ throw new ParseException("cannot use configuration parameters when parsing single paths");
+ }
+ try {
+ rule = new FieldMapping(selector.getName(backend),type,selector,transformer, conf);
+ } catch(UnsupportedOperationException ex) {
+ if(mode == Mode.PROGRAM) {
+ rule = new FieldMapping("unnamed",type,selector,transformer, conf);
+ log.error("error while parsing {}: {}", rule.getPathExpression(backend),ex.getMessage());
+ throw new ParseException("error while parsing "+rule.getPathExpression(backend)+": "+ex.getMessage());
+ } else {
+ rule = new FieldMapping("unnamed",type,selector,transformer, conf);
+ }
+ }
+ return rule;
+ }
+}
+
+
+Map<String,String> FieldConfig() : {
+ Map<String, String> conf = new HashMap<String, String>();
+ Token key = null;
+ String val = null;
+ Map<String,String> more = null;
+}
+{
+ ( key = <IDENTIFIER> "=" val = ConfVal() ("," more = FieldConfig() )? )? {
+ if (key == null || val == null) return null;
+ conf.put(key.image, val);
+ if (more != null) {
+ conf.putAll(more);
+ }
+ return conf;
+ }
+}
+
+String ConfVal() : {
+ Token str, id;
+}
+{
+ str = <STRLIT> { return str.image.substring(1, str.image.length() -1); }
+| id = <IDENTIFIER> { return id.image; }
+}
+
+String Uri() : {
+ Token uri, prefix, localName;
+
+}
+{
+ "<" uri = <URI> ">" {
+ return uri.image;
+ }
+| prefix = <IDENTIFIER> ":" localName = <IDENTIFIER> {
+ return resolveNamespace(prefix.image)+localName.image;
+ }
+}
+
+
+NodeSelector Selector() :
+{
+ NodeSelector result;
+}
+{
+ (
+ result = CompoundSelector()
+ | result = TestingSelector()
+ | result = AtomicSelector()
+ )
+ {
+ return result;
+ }
+}
+
+
+NodeSelector CompoundSelector() :
+{
+ NodeSelector result = null;
+}
+{
+ (
+ /* Union Selector */
+ result = UnionSelector() |
+
+ /* Intersection Selector */
+ result = IntersectionSelector() |
+
+ /* Path Selector */
+ result = PathSelector()
+
+
+ )
+ {
+ return result;
+ }
+}
+
+/**
+ * As path elements, we do not allow arbitrary compound selectors, but we allow all atomic and path selectors.
+ */
+NodeSelector AtomicOrTestingOrPathSelector() :
+{
+ NodeSelector result = null;
+}
+{
+ (
+ /* Path Selector */
+ result = PathSelector() |
+
+ /* Atomic Selector */
+ result = AtomicOrTestingSelector()
+ )
+ {
+ return result;
+ }
+}
+
+NodeSelector AtomicOrTestingSelector() :
+{
+ NodeSelector result = null;
+}
+{
+ (
+ /* Testing Selector */
+ result = TestingSelector() |
+
+ /* Atomic Selector */
+ result = AtomicSelector()
+ )
+ {
+ return result;
+ }
+}
+
+NodeSelector AtomicSelector() :
+{
+ NodeSelector result = null;
+}
+{
+ (
+ /* Self Selector */
+ result = SelfSelector() |
+
+ /* Property Selector */
+ result = PropertySelector() |
+
+ /* Wildcard Selector */
+ result = WildcardSelector() |
+
+ /* Reverse Property Selector */
+ result = ReversePropertySelector() |
+
+ /* Function Selector */
+ result = FunctionSelector() |
+
+ /* String Constant Selector */
+ result = StringConstantSelector() |
+
+ /* Recursive Path Selector */
+ result = RecursivePathSelector() |
+
+ /* Other selector enclosed in braces */
+ result = GroupedSelector()
+
+ )
+ {
+ return result;
+ }
+}
+
+NodeSelector SelfSelector() :
+{
+}
+{
+ "." { return new SelfSelector(); }
+}
+
+NodeSelector GroupedSelector() :
+{
+ NodeSelector result = null;
+}
+{
+ /* Other selector enclosed in braces */
+ "(" result = Selector() ")"
+ {
+ return result;
+ }
+
+}
+
+RecursivePathSelector RecursivePathSelector() :
+{
+ RecursivePathSelector result = null;
+ NodeSelector delegate = null;
+}
+{
+ "(" delegate = Selector() ")" "+"
+ {
+ result = RecursivePathSelector.getPathSelectorPlused(delegate);
+ return result;
+ } |
+ "(" delegate = Selector() ")" "*"
+ {
+ result = RecursivePathSelector.getPathSelectorStared(delegate);
+ return result;
+ }
+}
+
+PathSelector PathSelector() :
+{
+ PathSelector result = null;
+ NodeSelector left = null;
+ NodeSelector right = null;
+}
+{
+ left = AtomicOrTestingSelector() "/" right = AtomicOrTestingOrPathSelector()
+ {
+ result = new PathSelector(left,right);
+ return result;
+ }
+}
+
+IntersectionSelector IntersectionSelector() :
+{
+ IntersectionSelector result = null;
+ NodeSelector left = null;
+ NodeSelector right = null;
+}
+{
+ left = AtomicOrTestingOrPathSelector() "&" right = Selector()
+ {
+ result = new IntersectionSelector(left,right);
+ return result;
+ }
+}
+
+UnionSelector UnionSelector() :
+{
+ UnionSelector result = null;
+ NodeSelector left = null;
+ NodeSelector right = null;
+}
+{
+ left = AtomicOrTestingOrPathSelector() "|" right = Selector()
+ {
+ result = new UnionSelector(left,right);
+ return result;
+ }
+}
+
+TestingSelector TestingSelector() :
+{
+ TestingSelector result = null;
+ NodeSelector delegate = null;
+ NodeTest test = null;
+}
+{
+ delegate = AtomicSelector() "[" test = NodeTest() "]" {
+ result = new TestingSelector(delegate,test);
+ return result;
+ }
+}
+
+ReversePropertySelector ReversePropertySelector() :
+{
+ ReversePropertySelector result = null;
+ Node property;
+ String uri;
+}
+{
+ "^" uri = Uri() {
+ property = resolveResource(uri);
+ result = new ReversePropertySelector(property);
+ return result;
+ }
+}
+
+PropertySelector PropertySelector() :
+{
+ PropertySelector result = null;
+ Node property;
+ String uri;
+}
+{
+ uri = Uri() {
+ property = resolveResource(uri);
+ result = new PropertySelector(property);
+ return result;
+ }
+}
+
+WildcardSelector WildcardSelector() :
+{
+ WildcardSelector result = null;
+}
+{
+ "*" {
+ result = new WildcardSelector();
+ return result;
+ }
+}
+
+FunctionSelector FunctionSelector() :
+{
+ FunctionSelector result = null;
+ List<NodeSelector> arguments = new ArrayList<NodeSelector>();
+ NodeSelector argument;
+ String uri;
+ Token fName;
+}
+{
+ /* Function-Calls without arguments can skip parenthesis */
+ /* Does not work... why?
+ "fn:" fName = <IDENTIFIER> {
+ uri = namespaces.get("fn") + fName.image;
+ result = new FunctionSelector(getFunction(uri),Collections.emptyList());
+ return result;
+ } | */
+ /* Functions do not need to have arguments */
+ "fn:" fName = <IDENTIFIER> "(" ")" {
+ uri = namespaces.get("fn") + fName.image;
+ result = new FunctionSelector(getFunction(uri),Collections.emptyList());
+ return result;
+ } |
+ /* Sometimes arguments are required */
+ "fn:" fName = <IDENTIFIER> "("
+ argument = Selector() { arguments.add(argument); }
+ ( "," argument = Selector() { arguments.add(argument); } )*
+ ")" {
+ uri = namespaces.get("fn") + fName.image;
+ result = new FunctionSelector(getFunction(uri),arguments);
+ return result;
+ }
+}
+
+
+StringConstantSelector StringConstantSelector() :
+{
+ StringConstantSelector result = null;
+ Token literal;
+}
+{
+ literal = <STRLIT> {
+ result = new StringConstantSelector(literal.image.substring(1, literal.image.length()-1));
+ return result;
+ }
+}
+
+
+
+NodeTest NodeTest() :
+{
+ NodeTest result;
+}
+{
+ (
+ result = GroupedTest()
+ | result = NotTest()
+ | result = AndTest()
+ | result = OrTest()
+ | result = AtomicNodeTest()
+ )
+ {
+ return result;
+ }
+}
+
+NodeTest GroupedTest() :
+{
+ NodeTest delegate;
+}
+{
+ "(" delegate = NodeTest() ")" {
+ return delegate;
+ }
+}
+
+NodeTest AtomicNodeTest() :
+{
+ NodeTest result;
+}
+{
+ (
+ result = LiteralLanguageTest()
+ | result = LiteralTypeTest()
+ | result = TypeTest()
+ | result = PathEqualityTest()
+ | result = FunctionTest()
+ | result = PathTest()
+ )
+ {
+ return result;
+ }
+}
+
+FunctionTest FunctionTest() :
+{
FunctionTest result;
+ List<NodeSelector> arguments = new ArrayList<NodeSelector>();
+ NodeSelector argument;
+ String uri;
+ Token fName;
+}
+{
+ (
+ /* Function-Calls without arguments can skip parenthesis */
+ /* Does not work... why?
+ "fn:" fName = <IDENTIFIER> {
+ uri = namespaces.get("fn") + fName.image;
+ result = new FunctionSelector(getTestFunction(uri),Collections.emptyList());
+ } | */
+ /* Functions do not need to have arguments */
+ "fn:" fName = <IDENTIFIER> "(" ")" {
+ uri = namespaces.get("fn") + fName.image;
+ result = new FunctionTest(getTestFunction(uri),Collections.emptyList());
+ } |
+ /* Sometimes arguments are required */
+ "fn:" fName = <IDENTIFIER> "("
+ argument = Selector() { arguments.add(argument); }
+ ( "," argument = Selector() { arguments.add(argument); } )*
+ ")" {
+ uri = namespaces.get("fn") + fName.image;
+ result = new FunctionTest(getTestFunction(uri),arguments);
+ }
+ )
+ {
return result;
}
}
+
+LiteralLanguageTest LiteralLanguageTest():
+{
+ Token lang;
+}
+{
+ "@" lang = <IDENTIFIER> {
+ return new LiteralLanguageTest(lang.image);
+ }
+}
+
+LiteralTypeTest LiteralTypeTest():
+{
+ String type;
+}
+{
+ "^^" type = Uri() {
+ return new LiteralTypeTest(type);
+ }
+}
+
+NotTest NotTest() :
+{
+ NodeTest delegate;
+}
+{
+ "!" delegate = NodeTest() {
+ return new NotTest(delegate);
+ }
+}
+
+PathEqualityTest TypeTest() :
+{
+ Node node;
+}
+{
+ <IS_A> node = Node() {
+ return new PathEqualityTest(new PropertySelector(resolveResource("http://www.w3.org/1999/02/22-rdf-syntax-ns#type")), node);
+ }
+}
+
+
+AndTest AndTest():
+{
+ NodeTest left, right;
+}
+{
+ left = AtomicNodeTest() "&" right = NodeTest() {
+ return new AndTest(left,right);
+ }
+}
+
+OrTest OrTest():
+{
+ NodeTest left, right;
+}
+{
+ left = AtomicNodeTest() "|" right = NodeTest() {
+ return new OrTest(left,right);
+ }
+}
+
+PathEqualityTest PathEqualityTest():
+{
+ NodeSelector path;
+ Node node;
+}
+{
+ path = Selector() "is" node = Node() {
+ return new PathEqualityTest(path,node);
+ }
+}
+
+
+Node Node():
+{
+ String uri, type = null;
+ Token literal, language;
+}
+{
+ uri = Uri() {
+ return resolveResource(uri);
+ }
+| literal = <STRLIT> ("^^" type = Uri() )? {
+ try {
+ return backend.createLiteral(literal.image.substring(1, literal.image.length()-1),null,type == null ? null : new URI(type));
+ } catch(java.net.URISyntaxException ex) {
+ throw new ParseException("could not parse type URI "+type+": "+ex.getMessage());
+ }
+ }
+| literal = <STRLIT> "@" language = <IDENTIFIER> {
+ return backend.createLiteral(literal.image.substring(1, literal.image.length()-1),new Locale(language.image),null);
+ }
+}
+
+
+PathTest PathTest():
+{
+ NodeSelector path;
+}
+{
+ (
+ path = PathSelector()
+ | path = TestingSelector()
+ | path = AtomicSelector()
+ )
+ {
+ return new PathTest(path);
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/32a909f7/ldpath/ldpath-core/src/main/resources/META-INF/MANIFEST.MF
----------------------------------------------------------------------
diff --git a/ldpath/ldpath-core/src/main/resources/META-INF/MANIFEST.MF b/ldpath/ldpath-core/src/main/resources/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..07a1274
--- /dev/null
+++ b/ldpath/ldpath-core/src/main/resources/META-INF/MANIFEST.MF
@@ -0,0 +1 @@
+SPI-Consumer: *
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/32a909f7/ldpath/ldpath-core/src/main/resources/META-INF/services/at.newmedialab.ldpath.api.functions.SelectorFunction
----------------------------------------------------------------------
diff --git a/ldpath/ldpath-core/src/main/resources/META-INF/services/at.newmedialab.ldpath.api.functions.SelectorFunction b/ldpath/ldpath-core/src/main/resources/META-INF/services/at.newmedialab.ldpath.api.functions.SelectorFunction
new file mode 100644
index 0000000..6fac049
--- /dev/null
+++ b/ldpath/ldpath-core/src/main/resources/META-INF/services/at.newmedialab.ldpath.api.functions.SelectorFunction
@@ -0,0 +1,5 @@
+at.newmedialab.ldpath.model.functions.ConcatenateFunction
+at.newmedialab.ldpath.model.functions.FirstFunction
+at.newmedialab.ldpath.model.functions.LastFunction
+at.newmedialab.ldpath.model.functions.SortFunction
+at.newmedialab.ldpath.model.functions.CountFunction
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/32a909f7/ldpath/ldpath-core/src/main/resources/META-INF/services/at.newmedialab.ldpath.api.functions.TestFunction
----------------------------------------------------------------------
diff --git a/ldpath/ldpath-core/src/main/resources/META-INF/services/at.newmedialab.ldpath.api.functions.TestFunction b/ldpath/ldpath-core/src/main/resources/META-INF/services/at.newmedialab.ldpath.api.functions.TestFunction
new file mode 100644
index 0000000..99a27a3
--- /dev/null
+++ b/ldpath/ldpath-core/src/main/resources/META-INF/services/at.newmedialab.ldpath.api.functions.TestFunction
@@ -0,0 +1,6 @@
+at.newmedialab.ldpath.model.tests.functions.EqualTest
+at.newmedialab.ldpath.model.tests.functions.NotEqualTest
+at.newmedialab.ldpath.model.tests.functions.GreaterEqualTest
+at.newmedialab.ldpath.model.tests.functions.GreaterThanTest
+at.newmedialab.ldpath.model.tests.functions.LessEqualTest
+at.newmedialab.ldpath.model.tests.functions.LessThanTest
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/32a909f7/ldpath/ldpath-core/src/test/java/core/AbstractTestBase.java
----------------------------------------------------------------------
diff --git a/ldpath/ldpath-core/src/test/java/core/AbstractTestBase.java b/ldpath/ldpath-core/src/test/java/core/AbstractTestBase.java
new file mode 100644
index 0000000..43dd7db
--- /dev/null
+++ b/ldpath/ldpath-core/src/test/java/core/AbstractTestBase.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2013 Salzburg Research.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package core;
+
+import at.newmedialab.ldpath.api.selectors.NodeSelector;
+import at.newmedialab.ldpath.backend.sesame.SesameRepositoryBackend;
+import at.newmedialab.ldpath.model.fields.FieldMapping;
+import at.newmedialab.ldpath.parser.ParseException;
+import at.newmedialab.ldpath.parser.RdfPathParser;
+import org.hamcrest.CoreMatchers;
+import org.junit.After;
+import org.junit.Assume;
+import org.junit.Before;
+import org.openrdf.model.URI;
+import org.openrdf.model.Value;
+import org.openrdf.repository.RepositoryException;
+import org.openrdf.repository.sail.SailRepository;
+import org.openrdf.repository.sail.SailRepositoryConnection;
+import org.openrdf.rio.RDFFormat;
+import org.openrdf.rio.RDFParseException;
+import org.openrdf.sail.memory.MemoryStore;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringReader;
+import java.net.URL;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.NoSuchElementException;
+
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assume.assumeThat;
+
+public abstract class AbstractTestBase {
+ protected final static Map<String, String> NSS;
+ static {
+ Map<String, String> nss = new HashMap<String, String>();
+
+ nss.put("ex", "http://www.example.com/");
+ nss.put("foo", "http://localhost/vcab#");
+
+ NSS = Collections.unmodifiableMap(nss);
+ }
+
+ protected static String ns(String prefix) {
+ final String ns = NSS.get(prefix);
+ if (ns == null) { throw new NoSuchElementException("Unknown Prefix '" + prefix + "'"); }
+ return ns;
+ }
+
+ protected static String ns(String prefix, String local) {
+ return ns(prefix) + local;
+ }
+
+ protected SesameRepositoryBackend backend;
+ protected SailRepository repository;
+
+ @Before
+ public void before() throws RepositoryException {
+
+ repository = new SailRepository(new MemoryStore());
+ repository.initialize();
+
+ backend = new SesameRepositoryBackend(repository);
+
+ }
+
+ @After
+ public void after() throws RepositoryException {
+ repository.shutDown();
+ }
+
+ protected RdfPathParser<Value> createParserFromResource(String input) throws IOException {
+ final URL resource = this.getClass().getResource(input);
+ assumeThat("Could not load test input data '" + input + "'", resource, CoreMatchers.notNullValue());
+
+ RdfPathParser<Value> parser = new RdfPathParser<Value>(backend, resource.openStream());
+ assertThat("Could not parse ldPath", parser, CoreMatchers.notNullValue());
+
+ return parser;
+ }
+
+ protected RdfPathParser<Value> createParserFromString(String program) {
+ final RdfPathParser<Value> parser = new RdfPathParser<Value>(backend, new StringReader(program));
+ assertThat("Could not parse ldPath", parser, CoreMatchers.notNullValue());
+
+ return parser;
+ }
+
+ protected final void loadData(String datafile, RDFFormat format) throws RepositoryException, RDFParseException, IOException {
+ loadData(datafile, format, "http://www.example.com/ldpath/");
+ }
+
+ protected final void loadData(String datafile, RDFFormat format, String baseURI) throws RepositoryException, RDFParseException, IOException {
+ // load demo data
+ InputStream data = this.getClass().getResourceAsStream(datafile);
+ Assume.assumeThat("Could not load test-data: " + datafile, data, notNullValue(InputStream.class));
+
+ final SailRepositoryConnection con = repository.getConnection();
+ try {
+
+ con.add(data, baseURI, format);
+
+ con.commit();
+ } finally {
+ con.close();
+ }
+ }
+
+ protected Collection<Object> evaluateRule(final String ldPath, URI context) throws ParseException {
+ final RdfPathParser<Value> parser = createParserFromString(ldPath);
+ final FieldMapping<Object, Value> rule = parser.parseRule(NSS);
+ final Collection<Object> values = rule.getValues(backend, context);
+ return values;
+ }
+
+ protected URI createURI(String uri) {
+ if (uri.matches("\\w+:[a-zA-z0-9_%-]+")) {
+ final String[] s = uri.split(":");
+ return repository.getValueFactory().createURI(ns(s[0], s[1]));
+ } else {
+ return repository.getValueFactory().createURI(uri);
+ }
+ }
+
+ protected URI createURI(String prefix, String local) {
+ return repository.getValueFactory().createURI(ns(prefix, local));
+ }
+
+ protected Collection<Value> evaluateSelector(final String ldPath, URI context) throws ParseException {
+ final RdfPathParser<Value> parser = createParserFromString(ldPath);
+ final NodeSelector<Value> sel = parser.parseSelector(NSS);
+ final Collection<Value> nodes = sel.select(backend, context, null, null);
+ return nodes;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/32a909f7/ldpath/ldpath-core/src/test/java/ldpath/BinaryNumericTestFunctionsTest.java
----------------------------------------------------------------------
diff --git a/ldpath/ldpath-core/src/test/java/ldpath/BinaryNumericTestFunctionsTest.java b/ldpath/ldpath-core/src/test/java/ldpath/BinaryNumericTestFunctionsTest.java
new file mode 100644
index 0000000..ddfebcb
--- /dev/null
+++ b/ldpath/ldpath-core/src/test/java/ldpath/BinaryNumericTestFunctionsTest.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2013 Salzburg Research.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ldpath;
+
+import at.newmedialab.ldpath.api.selectors.NodeSelector;
+import at.newmedialab.ldpath.parser.ParseException;
+import at.newmedialab.ldpath.parser.RdfPathParser;
+import core.AbstractTestBase;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+import org.openrdf.model.URI;
+import org.openrdf.model.Value;
+import org.openrdf.repository.RepositoryException;
+import org.openrdf.rio.RDFFormat;
+import org.openrdf.rio.RDFParseException;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+import static org.hamcrest.CoreMatchers.hasItem;
+import static org.hamcrest.CoreMatchers.not;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+@RunWith(Parameterized.class)
+public class BinaryNumericTestFunctionsTest extends AbstractTestBase {
+
+ @Parameters(name = "fn:{0}")
+ public static List<String[]> data() {
+ ArrayList<String[]> data = new ArrayList<String[]>();
+ data.add(new String[] { "eq", "Eq", "Lt,Gt" });
+ data.add(new String[] { "ne", "Lt,Gt", "Eq" });
+ data.add(new String[] { "lt", "Lt", "Eq,Gt" });
+ data.add(new String[] { "le", "Lt,Eq", "Gt" });
+ data.add(new String[] { "gt", "Gt", "Eq,Lt" });
+ data.add(new String[] { "ge", "Eq,Gt", "Lt" });
+ return data;
+ }
+
+ @Parameter(0)
+ public String funktion;
+
+ @Parameter(1)
+ public String expected;
+
+ @Parameter(2)
+ public String forbidden;
+
+ @Before
+ public void loadData() throws RepositoryException, RDFParseException, IOException {
+ super.loadData("test-data.n3", RDFFormat.N3);
+ }
+
+ @Test
+ public void straight() throws ParseException {
+ runTest("fn:" + funktion, expected, forbidden);
+ }
+
+ @Test
+ public void inverse() throws ParseException {
+ runTest("!fn:" + funktion, forbidden, expected);
+ }
+
+ private void runTest(String fkt, String pos, String neg) throws ParseException {
+ final URI start = repository.getValueFactory().createURI("http://www.example.com/Compare");
+
+ ArrayList<Value> yes = new ArrayList<Value>();
+ for (String p : pos.split(",")) {
+ yes.add(repository.getValueFactory().createURI(NSS.get("ex") + p.trim()));
+ }
+ ArrayList<Value> no = new ArrayList<Value>();
+ for (String p : neg.split(",")) {
+ no.add(repository.getValueFactory().createURI(NSS.get("ex") + p.trim()));
+ }
+
+
+ final RdfPathParser<Value> parser = createParserFromString("ex:hasItem[" + fkt + "(foo:left, foo:right)]");
+ final NodeSelector<Value> sel = parser.parseSelector(NSS);
+
+ final Collection<Value> result = sel.select(backend, start, null, null);
+ assertEquals("items found", yes.size(), result.size());
+
+ for (Value value : yes) {
+ assertThat("matching resources", result, hasItem(value));
+ }
+ for (Value value : no) {
+ assertThat("not-matching resources", result, not(hasItem(value)));
+ }
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/32a909f7/ldpath/ldpath-core/src/test/java/ldpath/FunctionsTest.java
----------------------------------------------------------------------
diff --git a/ldpath/ldpath-core/src/test/java/ldpath/FunctionsTest.java b/ldpath/ldpath-core/src/test/java/ldpath/FunctionsTest.java
new file mode 100644
index 0000000..861aa02
--- /dev/null
+++ b/ldpath/ldpath-core/src/test/java/ldpath/FunctionsTest.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2013 Salzburg Research.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package ldpath;
+
+import at.newmedialab.ldpath.api.selectors.NodeSelector;
+import at.newmedialab.ldpath.model.fields.FieldMapping;
+import at.newmedialab.ldpath.parser.ParseException;
+import at.newmedialab.ldpath.parser.RdfPathParser;
+import core.AbstractTestBase;
+import org.hamcrest.CoreMatchers;
+import org.junit.Before;
+import org.junit.Test;
+import org.openrdf.model.URI;
+import org.openrdf.model.Value;
+import org.openrdf.repository.RepositoryException;
+import org.openrdf.rio.RDFFormat;
+import org.openrdf.rio.RDFParseException;
+
+import java.io.IOException;
+import java.util.Collection;
+
+import static org.hamcrest.CoreMatchers.*;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+
+
+public class FunctionsTest extends AbstractTestBase {
+
+
+ @Before
+ public void loadData() throws RepositoryException, RDFParseException, IOException {
+ loadData("test-data.n3", RDFFormat.N3);
+ }
+
+ @Test
+ public void testConcat() throws ParseException {
+
+ RdfPathParser<Value> parser = createParserFromString("fn:concat(foo:title, \" \", foo:subtitle) :: xsd:string; ");
+ final URI context = repository.getValueFactory().createURI("http://www.example.com/1");
+
+ final FieldMapping<Object, Value> field = parser.parseRule(NSS);
+ final Collection<Object> result = field.getValues(backend, context);
+
+ assertThat(result, CoreMatchers.hasItem("One SubOne"));
+ }
+
+ @Test
+ public void testFirst() throws ParseException {
+ final URI ctx1 = repository.getValueFactory().createURI("http://www.example.com/1");
+ final URI ctx2 = repository.getValueFactory().createURI("http://www.example.com/2");
+
+ RdfPathParser<Value> parser = createParserFromString("fn:first(foo:not_valid, foo:title, foo:subtitle, foo:not_valid2) :: xsd:string; ");
+ final FieldMapping<Object, Value> field = parser.parseRule(NSS);
+
+ final Collection<Object> result = field.getValues(backend, ctx1);
+ assertEquals(1, result.size());
+ assertThat(result, CoreMatchers.hasItem("One"));
+
+ final Collection<Object> result2 = field.getValues(backend, ctx2);
+ assertEquals(1, result2.size());
+ assertThat(result2, CoreMatchers.hasItem("Two"));
+ }
+
+ @Test
+ public void testFirst2() throws ParseException {
+ final URI ctx1 = repository.getValueFactory().createURI("http://www.example.com/1");
+ final URI ctx2 = repository.getValueFactory().createURI("http://www.example.com/2");
+
+ RdfPathParser<Value> parser = createParserFromString("fn:first(foo:i) :: xsd:int; ");
+ final FieldMapping<Object, Value> field = parser.parseRule(NSS);
+
+ final Collection<Object> result = field.getValues(backend, ctx1);
+ assertEquals(3, result.size());
+ assertThat(result, CoreMatchers.hasItem(1));
+
+ final Collection<Object> result2 = field.getValues(backend, ctx2);
+ assertEquals(1, result2.size());
+ assertThat(result2, CoreMatchers.hasItem(99));
+ }
+
+ @Test
+ public void testLast() throws ParseException {
+ final URI ctx1 = repository.getValueFactory().createURI("http://www.example.com/1");
+ final URI ctx2 = repository.getValueFactory().createURI("http://www.example.com/2");
+
+ RdfPathParser<Value> parser = createParserFromString("fn:last(foo:not_valid, foo:title, foo:subtitle, foo:not_valid2) :: xsd:string; ");
+ final FieldMapping<Object, Value> field = parser.parseRule(NSS);
+
+ final Collection<Object> result = field.getValues(backend, ctx1);
+ assertEquals(1, result.size());
+ assertThat(result, CoreMatchers.hasItem("SubOne"));
+
+ final Collection<Object> result2 = field.getValues(backend, ctx2);
+ assertEquals(1, result2.size());
+ assertThat(result2, hasItem("SubTwo"));
+ }
+
+ @Test
+ public void testLast2() throws ParseException {
+ final URI ctx1 = repository.getValueFactory().createURI("http://www.example.com/1");
+ final URI ctx2 = repository.getValueFactory().createURI("http://www.example.com/2");
+
+ RdfPathParser<Value> parser = createParserFromString("fn:last(foo:i, ex:not_here) :: xsd:int; ");
+ final FieldMapping<Object, Value> field = parser.parseRule(NSS);
+
+ final Collection<Object> result = field.getValues(backend, ctx1);
+ assertEquals(3, result.size());
+ assertThat(result, CoreMatchers.<Object> hasItems(1, 2, 3));
+
+ final Collection<Object> result2 = field.getValues(backend, ctx2);
+ assertEquals(1, result2.size());
+ assertThat(result2, hasItem(99));
+ }
+
+ @Test
+ public void testEq() throws ParseException {
+ final URI start = repository.getValueFactory().createURI("http://www.example.com/start");
+ final URI ex1 = repository.getValueFactory().createURI("http://www.example.com/1");
+ final URI ex2 = repository.getValueFactory().createURI("http://www.example.com/2");
+
+ final RdfPathParser<Value> parser = createParserFromString("ex:hasItem[fn:eq(foo:i, foo:j)]");
+ final NodeSelector<Value> sel = parser.parseSelector(NSS);
+
+ final Collection<Value> result = sel.select(backend, start, null, null);
+ assertEquals(1, result.size());
+ assertThat(result, allOf(hasItem(ex2), not(hasItem(ex1))));
+
+ final RdfPathParser<Value> parseri = createParserFromString("ex:hasItem[! fn:eq(foo:i, foo:j)]");
+ final NodeSelector<Value> seli = parseri.parseSelector(NSS);
+
+ final Collection<Value> resulti = seli.select(backend, start, null, null);
+ assertEquals(1, resulti.size());
+ assertThat(resulti, allOf(hasItem(ex1), not(hasItem(ex2))));
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/32a909f7/ldpath/ldpath-core/src/test/java/parse/EmptyTestingBackend.java
----------------------------------------------------------------------
diff --git a/ldpath/ldpath-core/src/test/java/parse/EmptyTestingBackend.java b/ldpath/ldpath-core/src/test/java/parse/EmptyTestingBackend.java
new file mode 100644
index 0000000..5e31d20
--- /dev/null
+++ b/ldpath/ldpath-core/src/test/java/parse/EmptyTestingBackend.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2013 Salzburg Research.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package parse;
+
+import at.newmedialab.ldpath.model.backend.AbstractBackend;
+
+import java.net.URI;
+import java.util.Collection;
+import java.util.Locale;
+import java.util.concurrent.ThreadPoolExecutor;
+
+
+public class EmptyTestingBackend extends
+ AbstractBackend<String> {
+ @Override
+ public boolean supportsThreading() {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public ThreadPoolExecutor getThreadPool() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public boolean isLiteral(String n) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean isURI(String n) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean isBlank(String n) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public Locale getLiteralLanguage(String n) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public URI getLiteralType(String n) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String createLiteral(String content) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String createLiteral(String content, Locale language,
+ URI type) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String createURI(String uri) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Collection<String> listObjects(String subject,
+ String property) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Collection<String> listSubjects(String property,
+ String object) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String stringValue(String node) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/32a909f7/ldpath/ldpath-core/src/test/java/parse/ParserTest.java
----------------------------------------------------------------------
diff --git a/ldpath/ldpath-core/src/test/java/parse/ParserTest.java b/ldpath/ldpath-core/src/test/java/parse/ParserTest.java
new file mode 100644
index 0000000..a048b41
--- /dev/null
+++ b/ldpath/ldpath-core/src/test/java/parse/ParserTest.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2013 Salzburg Research.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package parse;
+
+import at.newmedialab.ldpath.api.backend.RDFBackend;
+import at.newmedialab.ldpath.api.tests.NodeTest;
+import at.newmedialab.ldpath.api.transformers.NodeTransformer;
+import at.newmedialab.ldpath.model.programs.Program;
+import at.newmedialab.ldpath.parser.ParseException;
+import at.newmedialab.ldpath.parser.RdfPathParser;
+import org.apache.commons.io.IOUtils;
+import org.hamcrest.CoreMatchers;
+import org.junit.Assume;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.net.URL;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.Assert.*;
+
+
+public class ParserTest {
+
+ private static RDFBackend<String> backend;
+ private static final String NS_TEST = "http://example.com/";
+ private static final String NS_FOO = "http://foo.com/some/path#";
+
+ private static final Map<String, String> NAMESPACES;
+ static {
+ Map<String, String> ns = new HashMap<String, String>();
+ ns.put("test", NS_TEST);
+ ns.put("foo", NS_FOO);
+ NAMESPACES = Collections.unmodifiableMap(ns);
+ }
+
+ @BeforeClass
+ public static void initClass() {
+ backend = new EmptyTestingBackend();
+ }
+
+
+ @Test
+ public void testParseProgram() throws IOException {
+ RdfPathParser<String> parser = createParser("program.txt");
+ try {
+ Program<String> program = parser.parseProgram();
+ assertNotNull(program.getField("path"));
+ assertNotNull(program.getField("lang_test"));
+ assertNotNull(program.getField("type_test"));
+ assertNotNull(program.getField("int_s"));
+ assertNotNull(program.getField("int_p"));
+ assertNotNull(program.getField("inverse"));
+ assertNotNull(program.getField("config"));
+ assertNotNull(program.getBooster());
+ assertNotNull(program.getFilter());
+
+ } catch (ParseException e) {
+ assertFalse(e.getMessage(), true);
+ }
+ }
+
+ @Test
+ public void testParseTest() throws IOException {
+ RdfPathParser<String> parser = createParser("test.txt");
+ try {
+ NodeTest<String> test = parser.parseTest(NAMESPACES);
+ assertNotNull(test);
+ assertNotNull(test.getPathExpression(backend));
+ } catch (ParseException e) {
+ fail(e.getMessage());
+ }
+ }
+
+ @Test
+ public void testParsePrefixes() throws IOException {
+ RdfPathParser<String> parser = createParser("namespaces.txt");
+ try {
+ Map<String, String> prefixes = parser.parsePrefixes();
+ assertTrue(prefixes.containsKey("test"));
+ assertTrue(prefixes.containsKey("foo"));
+ assertEquals(NS_TEST, prefixes.get("test"));
+ assertEquals(NS_FOO, prefixes.get("foo"));
+ } catch (ParseException e) {
+ assertFalse(e.getMessage(), true);
+ }
+ }
+
+
+ private RdfPathParser<String> createParser(String input) throws IOException {
+ final URL resource = ParserTest.class.getResource(input);
+ Assume.assumeThat("Could not load test input data '" + input + "'", resource, CoreMatchers.notNullValue());
+
+ RdfPathParser<String> rdfPathParser = new RdfPathParser<String>(backend,new StringReader(IOUtils.toString(resource)));
+ rdfPathParser.registerTransformer(NS_TEST + "type", new NodeTransformer<String, String>() {
+ @Override
+ public String transform(RDFBackend<String> backend, String node)
+ throws IllegalArgumentException {
+ return node;
+ }
+ });
+ return rdfPathParser;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/32a909f7/ldpath/ldpath-core/src/test/resources/ldpath/test-data.n3
----------------------------------------------------------------------
diff --git a/ldpath/ldpath-core/src/test/resources/ldpath/test-data.n3 b/ldpath/ldpath-core/src/test/resources/ldpath/test-data.n3
new file mode 100644
index 0000000..c6c7b38
--- /dev/null
+++ b/ldpath/ldpath-core/src/test/resources/ldpath/test-data.n3
@@ -0,0 +1,32 @@
+@prefix ex: <http://www.example.com/> .
+@prefix foo: <http://localhost/vcab#> .
+
+ex:start a ex:Test;
+ ex:hasItem ex:1, ex:2.
+
+ex:1 a ex:Item;
+ foo:title "One";
+ foo:subtitle "SubOne";
+ foo:i "1", "2", "3";
+ foo:j "2".
+
+ex:2 a ex:Item;
+ foo:title "Two";
+ foo:subtitle "SubTwo";
+ foo:i "99";
+ foo:j "99".
+
+ex:Compare a ex:Test;
+ ex:hasItem ex:Eq, ex:Lt, ex:Gt.
+
+ex:Eq a ex:Item;
+ foo:left "5";
+ foo:right "5".
+
+ex:Lt a ex:Item;
+ foo:left "1";
+ foo:right "5".
+
+ex:Gt a ex:Item;
+ foo:left "9";
+ foo:right "5".
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/32a909f7/ldpath/ldpath-core/src/test/resources/parse/namespaces.txt
----------------------------------------------------------------------
diff --git a/ldpath/ldpath-core/src/test/resources/parse/namespaces.txt b/ldpath/ldpath-core/src/test/resources/parse/namespaces.txt
new file mode 100644
index 0000000..057b0a0
--- /dev/null
+++ b/ldpath/ldpath-core/src/test/resources/parse/namespaces.txt
@@ -0,0 +1,5 @@
+@prefix skos: <http://www.w3.org/2004/02/skos/core#>
+@prefix foo: <http://foo.com/some/path#> ;
+@prefix foaf: <http://xmlns.com/foaf/0.1/> ;
+@prefix test: <http://example.com/>
+@prefix dcterms: <http://purl.org/dc/terms/> ;
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/32a909f7/ldpath/ldpath-core/src/test/resources/parse/program.txt
----------------------------------------------------------------------
diff --git a/ldpath/ldpath-core/src/test/resources/parse/program.txt b/ldpath/ldpath-core/src/test/resources/parse/program.txt
new file mode 100644
index 0000000..1271b39
--- /dev/null
+++ b/ldpath/ldpath-core/src/test/resources/parse/program.txt
@@ -0,0 +1,16 @@
+@prefix test: <http://example.com/>;
+@prefix foo: <http://foo.com/some/path#> ;
+
+@filter test:type is foo:bar | test:p1 & is-a test:Case ;
+
+@boost foo:boost / ^test:boost ;
+
+path = test:p1 / test:p2 :: test:type;
+lang_test = test:p1[@en] :: test:type;
+type_test = foo:p2[^^test:int] :: test:type;
+int_s = (foo:go)* :: test:type;
+int_p = (foo:go)+ :: test:type;
+
+inverse = ^test:incoming :: test:type;
+
+config = test:foo :: test:type(c1=true, c2="false", c3="1.234");
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/32a909f7/ldpath/ldpath-core/src/test/resources/parse/test.txt
----------------------------------------------------------------------
diff --git a/ldpath/ldpath-core/src/test/resources/parse/test.txt b/ldpath/ldpath-core/src/test/resources/parse/test.txt
new file mode 100644
index 0000000..0f8c4f4
--- /dev/null
+++ b/ldpath/ldpath-core/src/test/resources/parse/test.txt
@@ -0,0 +1 @@
+test:type is foo:bar | test:p1 & fn:eq("1", "2")
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/32a909f7/ldpath/ldpath-functions-collections/.classpath
----------------------------------------------------------------------
diff --git a/ldpath/ldpath-functions-collections/.classpath b/ldpath/ldpath-functions-collections/.classpath
new file mode 100644
index 0000000..0f53f3e
--- /dev/null
+++ b/ldpath/ldpath-functions-collections/.classpath
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" output="target/classes" path="src/main/java"/>
+ <classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources"/>
+ <classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
+ <classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
+ <classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER"/>
+ <classpathentry kind="output" path="target/classes"/>
+</classpath>
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/32a909f7/ldpath/ldpath-functions-collections/.project
----------------------------------------------------------------------
diff --git a/ldpath/ldpath-functions-collections/.project b/ldpath/ldpath-functions-collections/.project
new file mode 100644
index 0000000..919dc87
--- /dev/null
+++ b/ldpath/ldpath-functions-collections/.project
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>ldpath-functions-collections</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.m2e.core.maven2Builder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ <nature>org.eclipse.m2e.core.maven2Nature</nature>
+ </natures>
+</projectDescription>
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/32a909f7/ldpath/ldpath-functions-collections/.settings/org.eclipse.core.resources.prefs
----------------------------------------------------------------------
diff --git a/ldpath/ldpath-functions-collections/.settings/org.eclipse.core.resources.prefs b/ldpath/ldpath-functions-collections/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000..dc1b414
--- /dev/null
+++ b/ldpath/ldpath-functions-collections/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,5 @@
+eclipse.preferences.version=1
+encoding//src/main/java=UTF-8
+encoding//src/main/resources=UTF-8
+encoding//src/test/java=UTF-8
+encoding//src/test/resources=UTF-8
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/32a909f7/ldpath/ldpath-functions-collections/.settings/org.eclipse.jdt.core.prefs
----------------------------------------------------------------------
diff --git a/ldpath/ldpath-functions-collections/.settings/org.eclipse.jdt.core.prefs b/ldpath/ldpath-functions-collections/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..60105c1
--- /dev/null
+++ b/ldpath/ldpath-functions-collections/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,5 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
+org.eclipse.jdt.core.compiler.source=1.6
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/32a909f7/ldpath/ldpath-functions-collections/.settings/org.eclipse.m2e.core.prefs
----------------------------------------------------------------------
diff --git a/ldpath/ldpath-functions-collections/.settings/org.eclipse.m2e.core.prefs b/ldpath/ldpath-functions-collections/.settings/org.eclipse.m2e.core.prefs
new file mode 100644
index 0000000..f897a7f
--- /dev/null
+++ b/ldpath/ldpath-functions-collections/.settings/org.eclipse.m2e.core.prefs
@@ -0,0 +1,4 @@
+activeProfiles=
+eclipse.preferences.version=1
+resolveWorkspaceProjects=true
+version=1
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/32a909f7/ldpath/ldpath-functions-collections/.settings/org.eclipse.pde.core.prefs
----------------------------------------------------------------------
diff --git a/ldpath/ldpath-functions-collections/.settings/org.eclipse.pde.core.prefs b/ldpath/ldpath-functions-collections/.settings/org.eclipse.pde.core.prefs
new file mode 100644
index 0000000..ba582c2
--- /dev/null
+++ b/ldpath/ldpath-functions-collections/.settings/org.eclipse.pde.core.prefs
@@ -0,0 +1,2 @@
+BUNDLE_ROOT_PATH=target/classes
+eclipse.preferences.version=1
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/32a909f7/ldpath/ldpath-functions-collections/pom.xml
----------------------------------------------------------------------
diff --git a/ldpath/ldpath-functions-collections/pom.xml b/ldpath/ldpath-functions-collections/pom.xml
new file mode 100644
index 0000000..6436216
--- /dev/null
+++ b/ldpath/ldpath-functions-collections/pom.xml
@@ -0,0 +1,107 @@
+<!--
+ ~ Copyright (c) 2013 Salzburg Research.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>at.newmedialab.ldpath</groupId>
+ <artifactId>ldpath-parent</artifactId>
+ <version>3.0.0-SNAPSHOT</version>
+ <relativePath>../</relativePath>
+ </parent>
+
+ <name>LDPath Functions: rdf-Collections</name>
+
+ <artifactId>ldpath-functions-collections</artifactId>
+ <packaging>bundle</packaging>
+
+ <description>Collection-Functions for ldpath (rdf:Bag, rdf:Sequence, rdf:Collection)</description>
+
+ <dependencies>
+ <dependency>
+ <groupId>at.newmedialab.ldpath</groupId>
+ <artifactId>ldpath-core</artifactId>
+ </dependency>
+
+
+ <dependency>
+ <groupId>at.newmedialab.ldpath</groupId>
+ <artifactId>ldpath-core</artifactId>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.openrdf.sesame</groupId>
+ <artifactId>sesame-repository-sail</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.openrdf.sesame</groupId>
+ <artifactId>sesame-sail-memory</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>at.newmedialab.ldpath</groupId>
+ <artifactId>ldpath-backend-sesame</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.openrdf.sesame</groupId>
+ <artifactId>sesame-rio-n3</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-Name>LDPath Functions: Math</Bundle-Name>
+ <!-- Enable this for including your enhancement chain configuration -->
+ <!-- <Install-Path>config</Install-Path> -->
+ <Export-Package>
+ at.newmedialab.ldpath.model.*;version=${project.version},
+ </Export-Package>
+ <_include>src/main/resources/META-INF/MANIFEST.MF</_include>
+ </instructions>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-scr-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>generate-scr-scrdescriptor</id>
+ <goals>
+ <goal>scr</goal>
+ </goals>
+ <configuration>
+ <properties>
+ <service.vendor>Salzburg Research</service.vendor>
+ </properties>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+
+ </build>
+
+</project>
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/32a909f7/ldpath/ldpath-functions-collections/src/main/java/at/newmedialab/ldpath/model/functions/coll/AbstractCollFunction.java
----------------------------------------------------------------------
diff --git a/ldpath/ldpath-functions-collections/src/main/java/at/newmedialab/ldpath/model/functions/coll/AbstractCollFunction.java b/ldpath/ldpath-functions-collections/src/main/java/at/newmedialab/ldpath/model/functions/coll/AbstractCollFunction.java
new file mode 100644
index 0000000..5fc0e4a
--- /dev/null
+++ b/ldpath/ldpath-functions-collections/src/main/java/at/newmedialab/ldpath/model/functions/coll/AbstractCollFunction.java
@@ -0,0 +1,40 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package at.newmedialab.ldpath.model.functions.coll;
+
+import at.newmedialab.ldpath.api.backend.RDFBackend;
+import at.newmedialab.ldpath.api.functions.SelectorFunction;
+
+import java.util.Collection;
+
+public abstract class AbstractCollFunction<Node> extends SelectorFunction<Node> {
+
+ protected static final String RDF = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+
+ protected int getIndex(RDFBackend<Node> backend, Collection<Node> collection) {
+ if (collection.size() != 1) { throw new IllegalArgumentException("index must be a singel integer literal"); }
+ return backend.intValue(collection.iterator().next());
+ }
+
+ protected boolean hasType(RDFBackend<Node> backend, Node node, String type) {
+ return backend.listObjects(node, backend.createURI(RDF + "type")).contains(backend.createURI(type));
+ }
+
+ protected boolean isNil(RDFBackend<Node> backend, Node node) {
+ return backend.isURI(node) && backend.stringValue(node).equals(RDF + "nil");
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/32a909f7/ldpath/ldpath-functions-collections/src/main/java/at/newmedialab/ldpath/model/functions/coll/FlattenFunction.java
----------------------------------------------------------------------
diff --git a/ldpath/ldpath-functions-collections/src/main/java/at/newmedialab/ldpath/model/functions/coll/FlattenFunction.java b/ldpath/ldpath-functions-collections/src/main/java/at/newmedialab/ldpath/model/functions/coll/FlattenFunction.java
new file mode 100644
index 0000000..8050a64
--- /dev/null
+++ b/ldpath/ldpath-functions-collections/src/main/java/at/newmedialab/ldpath/model/functions/coll/FlattenFunction.java
@@ -0,0 +1,104 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package at.newmedialab.ldpath.model.functions.coll;
+
+import at.newmedialab.ldpath.api.backend.RDFBackend;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+
+
+public class FlattenFunction<Node> extends AbstractCollFunction<Node> {
+
+
+ @Override
+ public Collection<Node> apply(RDFBackend<Node> backend, Node context, Collection<Node>... args) throws IllegalArgumentException {
+ if (args.length > 1) {
+ throw new IllegalArgumentException(getLocalName() + " must not have more than one parameter");
+ }
+ final Collection<Node> nodes;
+ if (args.length > 0) {
+ nodes = args[0];
+ } else {
+ nodes = Collections.singleton(context);
+ }
+
+ final List<Node> result = new LinkedList<Node>();
+ for (Node node : nodes) {
+ if (hasType(backend, node, RDF + "Bag")) {
+ flattenContainer(backend, node, result);
+ } else if (hasType(backend, node, RDF + "Seq")) {
+ flattenContainer(backend, node, result);
+ } else if (hasType(backend, node, RDF + "List")) {
+ flattenCollection(backend, node, result, new HashSet<Node>());
+ } else {
+ flattenCollection(backend, node, result, new HashSet<Node>());
+ }
+ }
+
+ return result;
+ }
+
+ private void flattenCollection(RDFBackend<Node> backend, Node node, Collection<Node> result, Collection<Node> backtrace) {
+ if (isNil(backend, node)) {
+ return;
+ }
+
+ // Stop if we detect a cycle.
+ if (!backtrace.add(node)) {
+ return;
+ }
+
+ // Add the (all) firsts
+ result.addAll(backend.listObjects(node, backend.createURI(RDF + "first")));
+
+ // Recursively add the rest
+ final Collection<Node> rest = backend.listObjects(node, backend.createURI(RDF + "rest"));
+ for (Node r : rest) {
+ flattenCollection(backend, r, result, backtrace);
+ }
+ }
+
+ private void flattenContainer(RDFBackend<Node> backend, Node node, Collection<Node> result) {
+ for (int i = 1; /* exit via break */; i++) {
+ final Collection<Node> objects = backend.listObjects(node, backend.createURI(RDF + "_" + i));
+ if (objects.size() > 0) {
+ result.addAll(objects);
+ } else {
+ break;
+ }
+ }
+ }
+
+ @Override
+ public String getSignature() {
+ return "fn:flatten([nodes: NodeList]) :: NodeList";
+ }
+
+ @Override
+ public String getDescription() {
+ return "Flattens a rdf-Collection";
+ }
+
+ @Override
+ protected String getLocalName() {
+ return "flatten";
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/32a909f7/ldpath/ldpath-functions-collections/src/main/java/at/newmedialab/ldpath/model/functions/coll/GetFunction.java
----------------------------------------------------------------------
diff --git a/ldpath/ldpath-functions-collections/src/main/java/at/newmedialab/ldpath/model/functions/coll/GetFunction.java b/ldpath/ldpath-functions-collections/src/main/java/at/newmedialab/ldpath/model/functions/coll/GetFunction.java
new file mode 100644
index 0000000..ef993d0
--- /dev/null
+++ b/ldpath/ldpath-functions-collections/src/main/java/at/newmedialab/ldpath/model/functions/coll/GetFunction.java
@@ -0,0 +1,91 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package at.newmedialab.ldpath.model.functions.coll;
+
+import at.newmedialab.ldpath.api.backend.RDFBackend;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+
+public class GetFunction<Node> extends AbstractCollFunction<Node> {
+
+ @Override
+ public Collection<Node> apply(RDFBackend<Node> backend, Node context, Collection<Node>... args) throws IllegalArgumentException {
+ final Collection<Node> nodes;
+ final int index;
+ switch (args.length) {
+ case 1:
+ nodes = Collections.singleton(context);
+ index = getIndex(backend, args[0]);
+ break;
+ case 2:
+ nodes = args[0];
+ index = getIndex(backend, args[1]);
+ break;
+ default:
+ throw new IllegalArgumentException(getLocalName() + " must not have more than one or two parameters");
+ }
+
+ Collection<Node> result = new HashSet<Node>();
+ for (Node node : nodes) {
+ if (hasType(backend, node, RDF + "Bag")) {
+ result.addAll(getFromContainer(backend, node, index));
+ } else if (hasType(backend, node, RDF + "Seq")) {
+ result.addAll(getFromContainer(backend, node, index));
+ } else if (hasType(backend, node, RDF + "List")) {
+ result.addAll(getFromCollection(backend, node, index));
+ } else {
+ result.addAll(getFromCollection(backend, node, index));
+ }
+ }
+ return result;
+ }
+
+ private Collection<Node> getFromCollection(RDFBackend<Node> backend, Node node, int index) {
+ if (index < 0 || isNil(backend, node)) {
+ return Collections.emptySet();
+ } else if (index == 0) {
+ return backend.listObjects(node, backend.createURI(RDF + "first"));
+ } else {
+ HashSet<Node> result = new HashSet<Node>();
+ for (Node n : backend.listObjects(node, backend.createURI(RDF + "rest"))) {
+ result.addAll(getFromCollection(backend, n, index - 1));
+ }
+ return result;
+ }
+ }
+
+ private Collection<Node> getFromContainer(RDFBackend<Node> backend, Node node, int index) {
+ return backend.listObjects(node, backend.createURI(RDF + "_" + (index + 1)));
+ }
+
+ @Override
+ public String getSignature() {
+ return "fn:get([nodes: NodeList,] n: Integer) :: NodeList";
+ }
+
+ @Override
+ public String getDescription() {
+ return "retrieve the nth element from a rdf-Collection (0-based)";
+ }
+
+ @Override
+ protected String getLocalName() {
+ return "get";
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/32a909f7/ldpath/ldpath-functions-collections/src/main/java/at/newmedialab/ldpath/model/functions/coll/SubListFunction.java
----------------------------------------------------------------------
diff --git a/ldpath/ldpath-functions-collections/src/main/java/at/newmedialab/ldpath/model/functions/coll/SubListFunction.java b/ldpath/ldpath-functions-collections/src/main/java/at/newmedialab/ldpath/model/functions/coll/SubListFunction.java
new file mode 100644
index 0000000..0e27333
--- /dev/null
+++ b/ldpath/ldpath-functions-collections/src/main/java/at/newmedialab/ldpath/model/functions/coll/SubListFunction.java
@@ -0,0 +1,115 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package at.newmedialab.ldpath.model.functions.coll;
+
+import at.newmedialab.ldpath.api.backend.RDFBackend;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+public class SubListFunction<Node> extends AbstractCollFunction<Node> {
+
+ @Override
+ public Collection<Node> apply(RDFBackend<Node> backend, Node context, Collection<Node>... args) throws IllegalArgumentException {
+ final Collection<Node> nodes;
+ final int start, end;
+ switch (args.length) {
+ case 1:
+ nodes = Collections.singleton(context);
+ start = getIndex(backend, args[0]);
+ end = Integer.MAX_VALUE;
+ break;
+ case 2:
+ if (args[0].size() == 1 && backend.isLiteral(args[0].iterator().next())) {
+ nodes = Collections.singleton(context);
+ start = getIndex(backend, args[0]);
+ end = getIndex(backend, args[1]);
+ } else {
+ nodes = args[0];
+ start = getIndex(backend, args[1]);
+ end = Integer.MAX_VALUE;
+ }
+ break;
+ case 3:
+ nodes = args[0];
+ start = getIndex(backend, args[1]);
+ end = getIndex(backend, args[2]);
+ break;
+ default:
+ throw new IllegalArgumentException(getLocalName() + " takes at most 3 arguments");
+ }
+
+ final List<Node> result = new LinkedList<Node>();
+ for (Node node : nodes) {
+ if (hasType(backend, node, RDF + "Bag")) {
+ result.addAll(subListFromContainer(backend, node, start, end));
+ } else if (hasType(backend, node, RDF + "Seq")) {
+ result.addAll(subListFromContainer(backend, node, start, end));
+ } else if (hasType(backend, node, RDF + "List")) {
+ subListFromCollection(backend, node, start, end, result);
+ } else {
+ subListFromCollection(backend, node, start, end, result);
+ }
+ }
+
+ return result;
+ }
+
+ private void subListFromCollection(RDFBackend<Node> backend, Node node, int start, int end, List<Node> result) {
+ if (isNil(backend, node)) { return; }
+
+ if (end > 0) {
+ if (start <= 0) {
+ result.addAll(backend.listObjects(node, backend.createURI(RDF + "first")));
+ }
+ for (Node n : backend.listObjects(node, backend.createURI(RDF + "rest"))) {
+ subListFromCollection(backend, n, start - 1, end - 1, result);
+ }
+ }
+
+ }
+
+ private Collection<? extends Node> subListFromContainer(RDFBackend<Node> backend, Node node, int start, int end) {
+ List<Node> result = new LinkedList<Node>();
+ for (int i = start; i < end; i++) {
+ final Collection<Node> objects = backend.listObjects(node, backend.createURI(RDF + "_" + (i + 1)));
+ if (objects.size() > 0) {
+ result.addAll(objects);
+ } else {
+ break;
+ }
+ }
+ return result;
+ }
+
+ @Override
+ public String getSignature() {
+ return "fn:subList([nodes: NodeList,] start: Integer [, end: Integer]) :: NodeList";
+ }
+
+ @Override
+ public String getDescription() {
+ return "select a range from a rdf-Collection (like substring does for strings, 0-based)";
+ }
+
+ @Override
+ protected String getLocalName() {
+ return "subList";
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/32a909f7/ldpath/ldpath-functions-collections/src/main/resources/META-INF/MANIFEST.MF
----------------------------------------------------------------------
diff --git a/ldpath/ldpath-functions-collections/src/main/resources/META-INF/MANIFEST.MF b/ldpath/ldpath-functions-collections/src/main/resources/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..7547fd6
--- /dev/null
+++ b/ldpath/ldpath-functions-collections/src/main/resources/META-INF/MANIFEST.MF
@@ -0,0 +1 @@
+SPI-Provider: *
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/32a909f7/ldpath/ldpath-functions-collections/src/main/resources/META-INF/services/at.newmedialab.ldpath.api.functions.SelectorFunction
----------------------------------------------------------------------
diff --git a/ldpath/ldpath-functions-collections/src/main/resources/META-INF/services/at.newmedialab.ldpath.api.functions.SelectorFunction b/ldpath/ldpath-functions-collections/src/main/resources/META-INF/services/at.newmedialab.ldpath.api.functions.SelectorFunction
new file mode 100644
index 0000000..8c0f779
--- /dev/null
+++ b/ldpath/ldpath-functions-collections/src/main/resources/META-INF/services/at.newmedialab.ldpath.api.functions.SelectorFunction
@@ -0,0 +1,3 @@
+at.newmedialab.ldpath.model.functions.coll.FlattenFunction
+at.newmedialab.ldpath.model.functions.coll.GetFunction
+at.newmedialab.ldpath.model.functions.coll.SubListFunction
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/32a909f7/ldpath/ldpath-functions-collections/src/test/java/coll/CollectionsTest.java
----------------------------------------------------------------------
diff --git a/ldpath/ldpath-functions-collections/src/test/java/coll/CollectionsTest.java b/ldpath/ldpath-functions-collections/src/test/java/coll/CollectionsTest.java
new file mode 100644
index 0000000..85889ad
--- /dev/null
+++ b/ldpath/ldpath-functions-collections/src/test/java/coll/CollectionsTest.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2013 Salzburg Research.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package coll;
+
+
+import core.AbstractTestBase;
+import org.hamcrest.CoreMatchers;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+import org.openrdf.model.URI;
+import org.openrdf.model.Value;
+import org.openrdf.repository.RepositoryException;
+import org.openrdf.rio.RDFFormat;
+import org.openrdf.rio.RDFParseException;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+@RunWith(Parameterized.class)
+public class CollectionsTest extends AbstractTestBase {
+
+ private static final int BAG_SIZE = 4;
+
+ @Parameters(name = "{0}")
+ public static List<String[]> data() {
+ return Arrays.asList(
+ new String[] { "ex:List" },
+ new String[] { "ex:Bag" },
+ new String[] { "ex:Seq" }
+ );
+ }
+
+ @Parameter
+ public String testContextUri;
+
+ private URI uri;
+
+ @Before
+ public void loadData() throws RepositoryException, RDFParseException, IOException {
+ super.loadData("data.n3", RDFFormat.N3);
+
+ uri = createURI(testContextUri);
+ }
+
+ @Test
+ public void testFlatten() throws Exception {
+ for (String ldPath : Arrays.asList("foo:hasItems / fn:flatten()", "fn:flatten(foo:hasItems)")) {
+ final Collection<Value> nodes = evaluateSelector(ldPath, uri);
+ Assert.assertEquals(ldPath, BAG_SIZE, nodes.size());
+ Assert.assertThat(ldPath, nodes,
+ CoreMatchers.<Value> hasItems(createURI("ex:1"), createURI("ex:2"), createURI("ex:3"), createURI("ex:4")));
+ }
+ }
+
+ @Test
+ public void testGet() throws Exception {
+ for (int i = 0; i < BAG_SIZE + 1; i++) {
+ for ( String pattern : Arrays.asList("foo:hasItems / fn:get(\"%d\")", "fn:get(foo:hasItems,\"%d\")")) {
+ final String ldPath = String.format(pattern, i);
+ final Collection<Value> nodes = evaluateSelector(ldPath, uri);
+ if (i < BAG_SIZE) {
+ Assert.assertEquals(ldPath, 1, nodes.size());
+ Assert.assertThat(ldPath, nodes,
+ CoreMatchers.<Value> hasItem(createURI("ex", String.valueOf(i + 1))));
+ } else {
+ Assert.assertEquals(ldPath, 0, nodes.size());
+ }
+
+ }
+ }
+ }
+
+ @Test
+ public void testSubList() throws Exception {
+ for (int i = 0; i <= BAG_SIZE + 1; i++) {
+ for (String pattern : Arrays.asList("foo:hasItems / fn:subList(", "fn:subList(foo:hasItems, ")) {
+ final String ldPath_1A = String.format("%s\"%d\")", pattern, i);
+ final Collection<Value> nodes_1A = evaluateSelector(ldPath_1A, uri);
+
+ final int expStart = Math.max(0, Math.min(i, BAG_SIZE));
+
+ Assert.assertEquals(ldPath_1A, Math.max(BAG_SIZE - expStart, 0), nodes_1A.size());
+ for (int e = expStart; e < BAG_SIZE; e++) {
+ Assert.assertThat(ldPath_1A, nodes_1A,
+ CoreMatchers.<Value> hasItem(createURI("ex", String.valueOf(e + 1))));
+ }
+ for (int j = i; j <= BAG_SIZE + 1; j++) {
+ final String ldPath_2A = String.format("%s\"%d\", \"%d\")", pattern, i, j);
+ final Collection<Value> nodes_2A = evaluateSelector(ldPath_2A, uri);
+
+ final int expEnd = Math.max(0, Math.min(j, BAG_SIZE));
+
+ Assert.assertEquals(ldPath_2A, expEnd - expStart, nodes_2A.size());
+ for (int e = expStart; e < expEnd; e++) {
+ Assert.assertThat(ldPath_2A, nodes_2A,
+ CoreMatchers.<Value> hasItem(createURI("ex", String.valueOf(e + 1))));
+ }
+ }
+ }
+ }
+ }
+}