[Mulgara-svn] r1797 - in trunk/src/jar/query/java/org/mulgara/query: . xpath
pag at mulgara.org
pag at mulgara.org
Tue Oct 6 06:29:59 UTC 2009
Author: pag
Date: 2009-10-05 23:29:59 -0700 (Mon, 05 Oct 2009)
New Revision: 1797
Added:
trunk/src/jar/query/java/org/mulgara/query/xpath/
trunk/src/jar/query/java/org/mulgara/query/xpath/FnFunctionGroup.java
trunk/src/jar/query/java/org/mulgara/query/xpath/MulgaraFunction.java
trunk/src/jar/query/java/org/mulgara/query/xpath/MulgaraFunctionGroup.java
trunk/src/jar/query/java/org/mulgara/query/xpath/MulgaraXPathFunctionResolver.java
trunk/src/jar/query/java/org/mulgara/query/xpath/OpFunctionGroup.java
trunk/src/jar/query/java/org/mulgara/query/xpath/SparqlFunctionGroup.java
Log:
Initial implementation of a set of functions for Mulgara, and the XPathFunctionResolver
Added: trunk/src/jar/query/java/org/mulgara/query/xpath/FnFunctionGroup.java
===================================================================
--- trunk/src/jar/query/java/org/mulgara/query/xpath/FnFunctionGroup.java (rev 0)
+++ trunk/src/jar/query/java/org/mulgara/query/xpath/FnFunctionGroup.java 2009-10-06 06:29:59 UTC (rev 1797)
@@ -0,0 +1,367 @@
+/*
+ * Copyright 2009 DuraSpace.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mulgara.query.xpath;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.xml.xpath.XPathFunctionException;
+
+import org.apache.xerces.impl.xpath.regex.RegularExpression;
+
+/**
+ * Container for functions in the fn domain.
+ *
+ * @created Oct 5, 2009
+ * @author Paul Gearon
+ * @copyright © 2009 <a href="http://www.duraspace.org/">DuraSpace</a>
+ */
+ at SuppressWarnings("unchecked")
+public class FnFunctionGroup extends MulgaraFunctionGroup {
+
+ /** The prefix for the fn: namespace */
+ static final String PREFIX = "fn";
+
+ /** The fn: namespace */
+ static final String NAMESPACE = "http://www.w3.org/2005/xpath-functions/#";
+
+ /** The name of the UTF-8 encoding scheme */
+ static private final String UTF8 = "UTF-8";
+
+ /**
+ * Get the prefix used for the namespace of these operations.
+ * @return The short string used for a prefix in a QName.
+ */
+ public String getPrefix() {
+ return PREFIX;
+ }
+
+ /**
+ * Get the namespace of these operations.
+ * @return The string of the namespace URI.
+ */
+ public String getNamespace() {
+ return NAMESPACE;
+ }
+
+ /**
+ * Get the set of SPARQL functions.
+ * @return A set of MulgaraFunction for this entire group.
+ */
+ public Set<MulgaraFunction> getAllFunctions() {
+ Set<MulgaraFunction> functions = new HashSet<MulgaraFunction>();
+ functions.add(new Matches2());
+ functions.add(new Matches3());
+ functions.add(new FnBoolean());
+ functions.add(new Not());
+ functions.add(new Concat());
+ functions.add(new Substring2());
+ functions.add(new Substring3());
+ functions.add(new StringLength());
+ functions.add(new NormalizeSpace());
+ functions.add(new UpperCase());
+ functions.add(new LowerCase());
+ functions.add(new Translate());
+ functions.add(new EncodeForUri());
+ functions.add(new IriToUri());
+ functions.add(new EscapeHtmlUri());
+ return functions;
+ }
+
+ /**
+ * Function to evaluate if a string matches a pattern.
+ * @see http://www.w3.org/TR/xpath-functions/#func-matches
+ */
+ static private class Matches2 extends MulgaraFunction {
+ public String getName() { return "matches/2"; }
+ public int getArity() { return 2; }
+ public Object eval(List args) {
+ String str = (String)args.get(0);
+ String pattern = (String)args.get(1);
+ return new RegularExpression(pattern).matches(str);
+ }
+ }
+
+ /**
+ * Function to evaluate if a string matches a pattern, with a set of modifying flags.
+ * @see http://www.w3.org/TR/xpath-functions/#func-matches
+ */
+ static private class Matches3 extends MulgaraFunction {
+ public String getName() { return "matches/3"; }
+ public int getArity() { return 3; }
+ public Object eval(List args) {
+ String str = (String)args.get(0);
+ String pattern = (String)args.get(1);
+ String flags = (String)args.get(2);
+ return new RegularExpression(pattern, flags).matches(str);
+ }
+ }
+
+ /**
+ * Function to compute the EBV of a sequence. Unfortunately, no sequence info is available at this level.
+ * @see http://www.w3.org/TR/xpath-functions/#func-boolean
+ */
+ static private class FnBoolean extends MulgaraFunction {
+ public String getName() { return "boolean"; }
+ public int getArity() { return 1; }
+ public Object eval(List args) throws XPathFunctionException {
+ // no sequence info available here. Look at singleton only for the moment
+ return toBool(args.get(0));
+ }
+ }
+
+ // No implementation of fn:compare
+
+ /**
+ * Function to compute the inverse EBV of a sequence. See FnBoolean for restrictions.
+ * @see http://www.w3.org/TR/xpath-functions/#func-not
+ */
+ static private class Not extends MulgaraFunction {
+ public int getArity() { return 1; }
+ public Object eval(List args) throws XPathFunctionException {
+ return !toBool(args.get(0));
+ }
+ }
+
+ /**
+ * Concatenates two or more arguments cast to string.
+ * @see http://www.w3.org/TR/xpath-functions/#func-concat
+ */
+ static private class Concat extends MulgaraFunction {
+ public int getArity() { return -1; }
+ public String getName() { return "concat/*"; }
+ public Object eval(List args) throws XPathFunctionException {
+ StringBuilder s = new StringBuilder();
+ for (Object o: args) s.append(o);
+ return s.toString();
+ }
+ }
+
+ /**
+ * Returns the string located at a specified place within an argument string.
+ * @see http://www.w3.org/TR/xpath-functions/#func-substring
+ */
+ static private class Substring2 extends MulgaraFunction {
+ public int getArity() { return 2; }
+ public String getName() { return "substring/2"; }
+ public Object eval(List args) throws XPathFunctionException {
+ String source = args.get(0).toString();
+ int start = ((Number)args.get(1)).intValue();
+ // perform boundary checking
+ int len = source.length();
+ if (start < 0) start = 0;
+ if (start > len) start = len;
+ return source.substring(start);
+ }
+ }
+
+ /**
+ * Returns the string located at a specified place within an argument string.
+ * @see http://www.w3.org/TR/xpath-functions/#func-substring
+ */
+ static private class Substring3 extends MulgaraFunction {
+ public int getArity() { return 3; }
+ public String getName() { return "substring/3"; }
+ public Object eval(List args) throws XPathFunctionException {
+ String source = args.get(0).toString();
+ int start = ((Number)args.get(1)).intValue() - 1;
+ int end = ((Number)args.get(2)).intValue() + start;
+ // perform boundary checking
+ int len = source.length();
+ if (start < 0) start = 0;
+ if (start > len) {
+ start = len;
+ end = len;
+ }
+ if (end > len) end = len;
+ if (end < start) end = start;
+
+ return source.substring(start, end);
+ }
+ }
+
+ /**
+ * Returns the length of the argument.
+ * @see http://www.w3.org/TR/xpath-functions/#func-string-length
+ */
+ static private class StringLength extends MulgaraFunction {
+ public String getName() { return "string-length/1"; }
+ public Object eval(List args) throws XPathFunctionException {
+ return args.get(0).toString().length();
+ }
+ }
+
+ /**
+ * Returns the whitespace-normalized value of the argument.
+ * @see http://www.w3.org/TR/xpath-functions/#func-normalize-space
+ */
+ static private class NormalizeSpace extends MulgaraFunction {
+ public String getName() { return "normalize-space/1"; }
+ public Object eval(List args) throws XPathFunctionException {
+ String str = args.get(0).toString().trim();
+ return str.replaceAll(" +", " ");
+ }
+ }
+
+ /**
+ * Returns the upper-cased value of the argument.
+ * @see http://www.w3.org/TR/xpath-functions/#func-upper-case
+ */
+ static private class UpperCase extends MulgaraFunction {
+ public String getName() { return "upper-case/1"; }
+ public Object eval(List args) throws XPathFunctionException {
+ return args.get(0).toString().toUpperCase();
+ }
+ }
+
+ /**
+ * Returns the lower-cased value of the argument.
+ * @see http://www.w3.org/TR/xpath-functions/#func-lower-case
+ */
+ static private class LowerCase extends MulgaraFunction {
+ public String getName() { return "lower-case/1"; }
+ public Object eval(List args) throws XPathFunctionException {
+ return args.get(0).toString().toLowerCase();
+ }
+ }
+
+ /**
+ * Returns the first xs:string argument with occurrences of characters contained
+ * in the second argument replaced by the character at the corresponding position
+ * in the third argument.
+ */
+ static private class Translate extends MulgaraFunction {
+ public int getArity() { return 3; }
+ public Object eval(List args) throws XPathFunctionException {
+ String str = args.get(0).toString();
+ String mapStr = args.get(1).toString();
+ String transStr = args.get(2).toString();
+ // iterate through the map chars
+ for (int i = 0; i < mapStr.length(); i++) {
+ char c = mapStr.charAt(i);
+ if (i < transStr.length()) str = replaceChars(str, c, transStr.charAt(i));
+ else str = removeChars(str, c);
+ }
+ return str;
+ }
+
+ private static String replaceChars(String str, char c, char r) {
+ StringBuilder s = new StringBuilder(str);
+ for (int i = 0; i < s.length(); i++) {
+ if (s.charAt(i) == c) s.setCharAt(i, r);
+ }
+ return s.toString();
+ }
+
+ private static String removeChars(String str, char c) {
+ StringBuilder s = new StringBuilder(str);
+ for (int i = 0; i < s.length(); i++) {
+ if (s.charAt(i) == c) {
+ s.replace(i, i + 1, "");
+ i--;
+ }
+ }
+ return s.toString();
+ }
+ }
+
+ /**
+ * Returns the xs:string argument with certain characters escaped to enable the
+ * resulting string to be used as a path segment in a URI.
+ * @see http://www.w3.org/TR/xpath-functions/#func-encode-for-uri
+ */
+ static private class EncodeForUri extends MulgaraFunction {
+ public String getName() { return "encode-for-uri/1"; }
+ public Object eval(List args) throws XPathFunctionException {
+ try {
+ return URLEncoder.encode(args.get(0).toString(), UTF8);
+ } catch (UnsupportedEncodingException e) {
+ throw new XPathFunctionException("Unable to encode string for URL: " + e.getMessage());
+ }
+ }
+ }
+
+ /**
+ * Returns the xs:string argument with certain characters escaped to enable the
+ * resulting string to be used as (part of) a URI.
+ * @see http://www.w3.org/TR/xpath-functions/#func-iri-to-uri
+ */
+ static private class IriToUri extends MulgaraFunction {
+ public String getName() { return "iri-to-uri/1"; }
+ public Object eval(List args) throws XPathFunctionException {
+ StringBuilder str = new StringBuilder(args.get(0).toString());
+ for (int i = 0; i < str.length(); i++) {
+ char c = str.charAt(i);
+ if (outOfRange(c)) str.replace(i, i + 1, escape(str.substring(i, i + 1)));
+ }
+ return str.toString();
+ }
+ /**
+ * Test for URI compatibility. See Errata note:
+ * @see http://www.w3.org/XML/2007/qt-errata/xpath-functions-errata.html#E8
+ * @param c The character to test.
+ * @return <code>true</code> if the character is out of range for a URI and must be encoded.
+ */
+ static private final boolean outOfRange(char c) {
+ return c < 0x20 || c > 0x7E || c == '<' || c == '>' || c == '"' ||
+ c == '{' || c == '}' || c == '|' || c == '\\' || c == '^' || c == '`';
+ }
+ }
+
+ /**
+ * Returns the string argument with certain characters escaped in the manner that html user agents
+ * handle attribute values that expect URIs.
+ * @see http://www.w3.org/TR/xpath-functions/#func-escape-html-uri
+ */
+ static private class EscapeHtmlUri extends MulgaraFunction {
+ public String getName() { return "escape-html-uri/1"; }
+ public Object eval(List args) throws XPathFunctionException {
+ StringBuilder str = new StringBuilder(args.get(0).toString());
+ for (int i = 0; i < str.length(); i++) {
+ char c = str.charAt(i);
+ if (outOfRange(c)) str.replace(i, i + 1, escape(str.substring(i, i + 1)));
+ }
+ return str.toString();
+ }
+ static private final boolean outOfRange(char c) {
+ return c < 0x20 || c > 0x7E;
+ }
+ }
+
+ /**
+ * Converts a single character to a string containing escaped UTF-8 encoding.
+ * A utility used by both EscapeHtmlUri and IriToUri.
+ * @param c The character to escape.
+ * @return A string containing a sequence of %HH representing the UTF-8 encoding of <var>c</var>
+ * @throws XPathFunctionException If UTF-8 encoding fails.
+ */
+ static private final String escape(String c) throws XPathFunctionException {
+ byte[] bytes = null;
+ try {
+ bytes = c.getBytes(UTF8);
+ } catch (UnsupportedEncodingException e) {
+ throw new XPathFunctionException("Unable to encode string for URL: " + e.getMessage());
+ }
+ StringBuilder result = new StringBuilder();
+ for (int i = 0; i < bytes.length; i++) result.append(String.format("%%%02X", bytes[i]));
+ return result.toString();
+ }
+
+}
Added: trunk/src/jar/query/java/org/mulgara/query/xpath/MulgaraFunction.java
===================================================================
--- trunk/src/jar/query/java/org/mulgara/query/xpath/MulgaraFunction.java (rev 0)
+++ trunk/src/jar/query/java/org/mulgara/query/xpath/MulgaraFunction.java 2009-10-06 06:29:59 UTC (rev 1797)
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2009 DuraSpace.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mulgara.query.xpath;
+
+import java.util.List;
+
+import javax.xml.xpath.XPathFunction;
+import javax.xml.xpath.XPathFunctionException;
+
+import org.jrdf.graph.Literal;
+import org.mulgara.query.QueryException;
+import org.mulgara.query.filter.value.SimpleLiteral;
+
+/**
+ * General class for providing management information for XPath function implementations.
+ *
+ * @created Oct 5, 2009
+ * @author Paul Gearon
+ * @copyright © 2009 <a href="http://www.duraspace.org/">DuraSpace</a>
+ */
+ at SuppressWarnings("unchecked")
+public abstract class MulgaraFunction implements XPathFunction {
+
+ /**
+ * Evaluate the method represented by this class, using the supplied arguments.
+ * @see javax.xml.xpath.XPathFunction#evaluate(java.util.List)
+ */
+ public Object evaluate(List args) throws XPathFunctionException {
+ checkArgs(getArity(), args);
+ try {
+ return eval(args);
+ } catch (ClassCastException e) {
+ throw new XPathFunctionException("Incorrect parameter types passed to function: " + e.getMessage());
+ }
+ }
+
+ /**
+ * Test that the correct number of arguments were provided to the function call.
+ * @param expected The expected number of arguments.
+ * @param args The list of arguments.
+ * @throws XPathFunctionException Thrown if the argument list is the wrong length.
+ */
+ protected void checkArgs(int expected, List args) throws XPathFunctionException {
+ if (expected >= 0 && args.size() != expected) {
+ throw new XPathFunctionException("Incorrect number of parameters. Should be " + expected + ", but was: " + args.size());
+ }
+ }
+
+ /**
+ * Returns the number of arguments required to use this function. Default is 1.
+ * @return The number of arguments for this function.
+ */
+ protected int getArity() { return 1; }
+
+ /**
+ * The name of this function, followed by its arity.
+ * If not overridden then this will be the function class's name, starting with a lower-case letter.
+ * @return The name/arity of this function.
+ */
+ protected String getName() {
+ StringBuilder name = new StringBuilder(getClass().getSimpleName());
+ char c = name.charAt(0);
+ if (Character.isUpperCase(c)) {
+ name.setCharAt(0, Character.toLowerCase(c));
+ }
+ for (int i = 1; i < name.length(); i++) {
+ c = name.charAt(0);
+ if (Character.isUpperCase(c)) name.replace(i, i + 1, "-" + Character.toLowerCase(c));
+ }
+ name.append("/");
+ int arity = getArity();
+ if (arity >= 0) name.append(getArity());
+ else name.append("*");
+ return name.toString();
+ }
+
+ /**
+ * Evaluates the operation of the function. The argument list will be the correct length.
+ * @param args The arguments for the function.
+ * @return The return value of the function.
+ * @throws XPathFunctionException If there was an error executing the function.
+ */
+ protected abstract Object eval(List<?> args) throws XPathFunctionException;
+
+ /**
+ * Convert a singleton value into its effective boolean value (EBV).
+ * @param o The singleton to test.
+ * @return The EBV of the value.
+ * @throws XPathFunctionException If a complex evaluation throws an exception.
+ */
+ protected static final boolean toBool(Object o) throws XPathFunctionException {
+ if (o == null) return false;
+ if (o instanceof String) return ((String)o).length() != 0;
+ if (o instanceof Number) return ((Number)o).doubleValue() != 0 && ((Number)o).doubleValue() != Double.NaN;
+ if (o instanceof Boolean) return ((Boolean)o).booleanValue();
+ try {
+ if (o instanceof Literal) return new SimpleLiteral(((Literal)o).getLexicalForm(), ((Literal)o).getLanguage()).test(null);
+ } catch (NullPointerException e) {
+ throw new XPathFunctionException("Conversion of data to a simple literal requires a context: " + e.getMessage());
+ } catch (QueryException e) {
+ throw new XPathFunctionException("Unable to convert data to a simple literal: " + e.getMessage());
+ }
+ throw new XPathFunctionException("Type error: " + o + " [" + o.getClass() + "]");
+ }
+
+}
Added: trunk/src/jar/query/java/org/mulgara/query/xpath/MulgaraFunctionGroup.java
===================================================================
--- trunk/src/jar/query/java/org/mulgara/query/xpath/MulgaraFunctionGroup.java (rev 0)
+++ trunk/src/jar/query/java/org/mulgara/query/xpath/MulgaraFunctionGroup.java 2009-10-06 06:29:59 UTC (rev 1797)
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2009 DuraSpace.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mulgara.query.xpath;
+
+import java.net.URI;
+import java.util.Set;
+
+/**
+ * Represents a group of functions exposed as XPathFunctions in a single namespace.
+ *
+ * @created Oct 5, 2009
+ * @author Paul Gearon
+ * @copyright © 2009 <a href="http://www.duraspace.org/">DuraSpace</a>
+ */
+public abstract class MulgaraFunctionGroup {
+
+ /**
+ * Get the prefix used for the namespace of these operations.
+ * @return The short string used for a prefix in a QName.
+ */
+ public abstract String getPrefix();
+
+ /**
+ * Get the namespace of these operations.
+ * @return The string of the namespace URI.
+ */
+ public abstract String getNamespace();
+
+ /**
+ * Get the set of function in this group.
+ * @return A set of MulgaraFunction for this entire group.
+ */
+ public abstract Set<MulgaraFunction> getAllFunctions();
+
+}
Added: trunk/src/jar/query/java/org/mulgara/query/xpath/MulgaraXPathFunctionResolver.java
===================================================================
--- trunk/src/jar/query/java/org/mulgara/query/xpath/MulgaraXPathFunctionResolver.java (rev 0)
+++ trunk/src/jar/query/java/org/mulgara/query/xpath/MulgaraXPathFunctionResolver.java 2009-10-06 06:29:59 UTC (rev 1797)
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2009 DuraSpace.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mulgara.query.xpath;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.xml.namespace.QName;
+import javax.xml.xpath.XPathFunction;
+import javax.xml.xpath.XPathFunctionResolver;
+
+/**
+ * Retrieves functions for SPARQL expressions.
+ *
+ * @created Oct 5, 2009
+ * @author Paul Gearon
+ * @copyright © 2009 <a href="http://www.duraspace.org/">DuraSpace</a>
+ */
+public class MulgaraXPathFunctionResolver implements XPathFunctionResolver {
+
+ /**
+ * @see javax.xml.xpath.XPathFunctionResolver#resolveFunction(javax.xml.namespace.QName, int)
+ */
+ public XPathFunction resolveFunction(QName functionName, int arity) {
+ XPathFunction result = null;
+ String namespace = functionName.getNamespaceURI();
+ if (namespace != null) {
+ Map<String,XPathFunction> fnGroupMap = functionGroups.get(namespace);
+ if (fnGroupMap != null) {
+ result = fnGroupMap.get(functionName.getLocalPart() + "/" + arity);
+ // fall back to multiple arity
+ if (result == null) result = fnGroupMap.get(functionName.getLocalPart() + "/*");
+ }
+ }
+ return result;
+ }
+
+
+ /**
+ * A mapping of namespace URIs to the map of (name->functions) in that namespace.
+ * This is used to look up the requested function object.
+ */
+ private static final Map<String,Map<String,XPathFunction>> functionGroups = new HashMap<String,Map<String,XPathFunction>>();
+
+
+ // initialize the maps of requested parameters to the function object being asked for
+ static {
+ addFunctionGroup(new SparqlFunctionGroup());
+ addFunctionGroup(new FnFunctionGroup());
+ addFunctionGroup(new OpFunctionGroup());
+ }
+
+ /**
+ * A helper method to create a mapping of function names to their implementing classes,
+ * and of namespaces to these mappings.
+ * @param fnGroup A group of functions to be added into a single namespace.
+ * This group also provides that namespace.
+ */
+ private static final void addFunctionGroup(MulgaraFunctionGroup fnGroup) {
+ // map the function names to the functions
+ Map<String,XPathFunction> functionMap = new HashMap<String,XPathFunction>();
+ for (MulgaraFunction fn: fnGroup.getAllFunctions()) functionMap.put(fn.getName(), fn);
+ // map the namespace to the name->function map
+ functionGroups.put(fnGroup.getNamespace(), functionMap);
+ }
+
+}
Added: trunk/src/jar/query/java/org/mulgara/query/xpath/OpFunctionGroup.java
===================================================================
--- trunk/src/jar/query/java/org/mulgara/query/xpath/OpFunctionGroup.java (rev 0)
+++ trunk/src/jar/query/java/org/mulgara/query/xpath/OpFunctionGroup.java 2009-10-06 06:29:59 UTC (rev 1797)
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2009 DuraSpace.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mulgara.query.xpath;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Container for functions in the op pseudo-domain.
+ *
+ * @created Oct 5, 2009
+ * @author Paul Gearon
+ * @copyright © 2009 <a href="http://www.duraspace.org/">DuraSpace</a>
+ */
+ at SuppressWarnings("unchecked")
+public class OpFunctionGroup extends MulgaraFunctionGroup {
+
+ /** The prefix for the fn: namespace */
+ static final String PREFIX = "op";
+
+ /** The op: namespace */
+ static final String NAMESPACE = PREFIX;
+
+ /**
+ * Get the prefix used for the namespace of these operations.
+ * @return The short string used for a prefix in a QName.
+ */
+ public String getPrefix() {
+ return PREFIX;
+ }
+
+ /**
+ * Get the namespace of these operations.
+ * @return The string of the namespace URI.
+ */
+ public String getNamespace() {
+ return NAMESPACE;
+ }
+
+ /**
+ * Get the set of SPARQL functions.
+ * @return A set of MulgaraFunction for this entire group.
+ */
+ public Set<MulgaraFunction> getAllFunctions() {
+ Set<MulgaraFunction> functions = new HashSet<MulgaraFunction>();
+ functions.add(new NumericEqual());
+ functions.add(new NumericLessThan());
+ functions.add(new NumericGreaterThan());
+ functions.add(new NumericIntegerDivision());
+ functions.add(new NumericMod());
+ return functions;
+ }
+
+ /**
+ * Function to evaluate if two numbers are equal.
+ * @see http://www.w3.org/TR/xpath-functions/#func-numeric-equal
+ */
+ static private class NumericEqual extends MulgaraFunction {
+ public String getName() { return "numeric-equal/2"; }
+ public int getArity() { return 2; }
+ public Object eval(List args) {
+ Number left = (Number)args.get(0);
+ Number right = (Number)args.get(1);
+ return left.doubleValue() == right.doubleValue();
+ }
+ }
+
+ /**
+ * Function to evaluate if one number is less than another.
+ * @see http://www.w3.org/TR/xpath-functions/#func-numeric-less-than
+ */
+ static private class NumericLessThan extends MulgaraFunction {
+ public String getName() { return "numeric-less-than/2"; }
+ public int getArity() { return 2; }
+ public Object eval(List args) {
+ Number left = (Number)args.get(0);
+ Number right = (Number)args.get(1);
+ return left.doubleValue() < right.doubleValue();
+ }
+ }
+
+ /**
+ * Function to evaluate if one number is greater than another.
+ * @see http://www.w3.org/TR/xpath-functions/#func-numeric-greater-than
+ */
+ static private class NumericGreaterThan extends MulgaraFunction {
+ public String getName() { return "numeric-greater-than/2"; }
+ public int getArity() { return 2; }
+ public Object eval(List args) {
+ Number left = (Number)args.get(0);
+ Number right = (Number)args.get(1);
+ return left.doubleValue() > right.doubleValue();
+ }
+ }
+
+ /**
+ * Function to evaluate integer division between numbers. This does not meet the XPath semantics
+ * perfectly, but will work for many situations.
+ * @see http://www.w3.org/TR/xpath-functions/#func-numeric-integer-divide
+ */
+ static private class NumericIntegerDivision extends MulgaraFunction {
+ public String getName() { return "numeric-integer-divide/2"; }
+ public int getArity() { return 2; }
+ public Object eval(List args) {
+ Number left = (Number)args.get(0);
+ Number right = (Number)args.get(1);
+ if (left instanceof BigDecimal) {
+ return ((BigDecimal)left).divide(
+ (right instanceof BigDecimal) ? (BigDecimal)right : new BigDecimal(right.toString())
+ );
+ }
+ if (left instanceof BigInteger) {
+ return ((BigInteger)left).divide(
+ (right instanceof BigInteger) ? (BigInteger)right : new BigInteger(right.toString())
+ );
+ }
+ return Double.valueOf(left.doubleValue() / right.doubleValue()).longValue();
+ }
+ }
+
+ /**
+ * Function to evaluate the numeric mod operation. This does not meet the XPath semantics
+ * perfectly, but will work for most situations.
+ * @see http://www.w3.org/TR/xpath-functions/#func-numeric-mod
+ */
+ static private class NumericMod extends MulgaraFunction {
+ public String getName() { return "numeric-mod/2"; }
+ public int getArity() { return 2; }
+ public Object eval(List args) {
+ Number left = (Number)args.get(0);
+ Number right = (Number)args.get(1);
+ if (left instanceof Byte || left instanceof Short || left instanceof Integer || left instanceof Long) {
+ return left.longValue() % right.longValue();
+ }
+ if (left instanceof Float || left instanceof Double) {
+ return left.doubleValue() % right.doubleValue();
+ }
+ if (left instanceof BigDecimal) {
+ return ((BigDecimal)left).remainder(
+ (right instanceof BigDecimal) ? (BigDecimal)right : new BigDecimal(right.toString())
+ );
+ }
+ if (left instanceof BigInteger) {
+ return ((BigInteger)left).remainder(
+ (right instanceof BigInteger) ? (BigInteger)right : new BigInteger(right.toString())
+ );
+ }
+ return Double.valueOf(left.doubleValue() % right.doubleValue()).longValue();
+ }
+ }
+}
Added: trunk/src/jar/query/java/org/mulgara/query/xpath/SparqlFunctionGroup.java
===================================================================
--- trunk/src/jar/query/java/org/mulgara/query/xpath/SparqlFunctionGroup.java (rev 0)
+++ trunk/src/jar/query/java/org/mulgara/query/xpath/SparqlFunctionGroup.java 2009-10-06 06:29:59 UTC (rev 1797)
@@ -0,0 +1,179 @@
+/*
+ * Copyright 2009 DuraSpace.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.mulgara.query.xpath;
+
+import java.net.URI;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.xml.xpath.XPathFunctionException;
+
+import org.jrdf.graph.BlankNode;
+import org.jrdf.graph.Literal;
+import org.mulgara.query.QueryException;
+import org.mulgara.query.filter.value.SimpleLiteral;
+
+/**
+ * Container for functions in the SPARQL domain.
+ *
+ * @created Oct 5, 2009
+ * @author Paul Gearon
+ * @copyright © 2009 <a href="http://www.duraspace.org/">DuraSpace</a>
+ */
+ at SuppressWarnings("unchecked")
+public class SparqlFunctionGroup extends MulgaraFunctionGroup {
+
+ /** The prefix for the sparql: namespace */
+ static final String PREFIX = "sparql";
+
+ /** The sparql: namespace */
+ static final String NAMESPACE = "http://www.w3.org/2006/sparql-functions#";
+
+ /**
+ * Get the prefix used for the namespace of these operations.
+ * @return The short string used for a prefix in a QName.
+ */
+ public String getPrefix() {
+ return PREFIX;
+ }
+
+ /**
+ * Get the namespace of these operations.
+ * @return The string of the namespace URI.
+ */
+ public String getNamespace() {
+ return NAMESPACE;
+ }
+
+ /**
+ * Get the set of SPARQL functions.
+ * @return A set of MulgaraFunction for this entire group.
+ */
+ public Set<MulgaraFunction> getAllFunctions() {
+ Set<MulgaraFunction> functions = new HashSet<MulgaraFunction>();
+ functions.add(new Bound());
+ functions.add(new IsIRI());
+ functions.add(new IsURI());
+ functions.add(new IsBlank());
+ functions.add(new IsLiteral());
+ functions.add(new Str());
+ functions.add(new Lang());
+ functions.add(new Datatype());
+ functions.add(new LangMatches());
+ functions.add(new LogicalOr());
+ functions.add(new LogicalAnd());
+ return functions;
+ }
+
+ /** Function to evaluate if a parameter is bound. */
+ static private class Bound extends MulgaraFunction {
+ public Object eval(List args) { return args.get(0) != null; }
+ }
+
+ /** Function to evaluate if a parameter is an IRI. */
+ static private class IsIRI extends MulgaraFunction {
+ public Object eval(List args) { return args.get(0) instanceof URI; }
+ }
+
+ /** Function to evaluate if a parameter is a URI. */
+ static private class IsURI extends MulgaraFunction {
+ public Object eval(List args) { return args.get(0) instanceof URI; }
+ }
+
+ /** Function to evaluate if a parameter is a blank node. */
+ static private class IsBlank extends MulgaraFunction {
+ public Object eval(List args) { return args.get(0) instanceof BlankNode; }
+ }
+
+ /** Function to evaluate if a parameter is a literal. */
+ static private class IsLiteral extends MulgaraFunction {
+ public Object eval(List args) {
+ Object o = args.get(0);
+ return o instanceof Literal || o instanceof String || o instanceof Number;
+ }
+ }
+
+ /** Function to convert a value to a string. */
+ static private class Str extends MulgaraFunction {
+ public Object eval(List args) { return args.get(0).toString(); }
+ }
+
+ /** Function to get the language of a literal. This information is probably not available for this implementation. */
+ static private class Lang extends MulgaraFunction {
+ public Object eval(List args) {
+ Object o = args.get(0);
+ return o instanceof Literal ? ((Literal)o).getLanguage() : "";
+ }
+ }
+
+ /** Function to get the datatype of a literal. This information is probably not available for this implementation. */
+ static private class Datatype extends MulgaraFunction {
+ public Object eval(List args) {
+ Object o = args.get(0);
+ return o instanceof Literal ? ((Literal)o).getDatatype() : null;
+ }
+ }
+
+ /**
+ * Function to test if a language code matches a pattern.
+ * This information is probably not available for this implementation.
+ */
+ static private class LangMatches extends MulgaraFunction {
+ protected int getArity() { return 2; }
+ public Object eval(List args) throws XPathFunctionException {
+ Object o = args.get(0);
+ if (o instanceof Literal) {
+ Literal l = (Literal)o;
+ if (l.getLanguage() == null || l.getLanguage().length() == 0) return false;
+ org.mulgara.query.filter.LangMatches match = new org.mulgara.query.filter.LangMatches(new SimpleLiteral(l.getLexicalForm(), l.getLanguage()), new SimpleLiteral((String)args.get(1)));
+ try {
+ return match.getValue();
+ } catch (QueryException e) {
+ throw new XPathFunctionException("Unable to get data from lang matching test: " + e.getMessage());
+ }
+ }
+ return false;
+ }
+ }
+
+ /** Common operations required for a logical operation. */
+ static private abstract class LogicOp extends MulgaraFunction {
+ protected int getArity() { return 2; }
+ protected abstract boolean op(Object left, Object right) throws XPathFunctionException;
+ public Object eval(List args) throws XPathFunctionException {
+ return op(args.get(0), args.get(1));
+ }
+ }
+
+ /** Function to perform a logical OR between 2 operands. */
+ static private class LogicalOr extends LogicOp {
+ protected String getName() { return "logical-or"; }
+ public boolean op(Object left, Object right) throws XPathFunctionException {
+ return toBool(left) || toBool(right);
+ }
+ }
+
+ /** Function to perform a logical AND between 2 operands. */
+ static private class LogicalAnd extends LogicOp {
+ protected String getName() { return "logical-and"; }
+ public boolean op(Object left, Object right) throws XPathFunctionException {
+ return toBool(left) && toBool(right);
+ }
+ }
+
+}
More information about the Mulgara-svn
mailing list