[Mulgara-svn] r1878 - in trunk/src/jar: query/java/org/mulgara/query/xpath util/java/org/mulgara/util

pag at mulgara.org pag at mulgara.org
Thu Dec 17 09:20:43 UTC 2009


Author: pag
Date: 2009-12-17 01:20:42 -0800 (Thu, 17 Dec 2009)
New Revision: 1878

Added:
   trunk/src/jar/query/java/org/mulgara/query/xpath/AfnFunctionGroup.java
   trunk/src/jar/query/java/org/mulgara/query/xpath/SmfFunctionGroup.java
Modified:
   trunk/src/jar/query/java/org/mulgara/query/xpath/FnFunctionGroup.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/util/java/org/mulgara/util/NumberUtil.java
   trunk/src/jar/util/java/org/mulgara/util/URIUtil.java
Log:
Added a new set of functions for SPARQL, particularly the ARQ extensions

Added: trunk/src/jar/query/java/org/mulgara/query/xpath/AfnFunctionGroup.java
===================================================================
--- trunk/src/jar/query/java/org/mulgara/query/xpath/AfnFunctionGroup.java	                        (rev 0)
+++ trunk/src/jar/query/java/org/mulgara/query/xpath/AfnFunctionGroup.java	2009-12-17 09:20:42 UTC (rev 1878)
@@ -0,0 +1,307 @@
+/*
+ * 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.URI;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.xml.xpath.XPathFunctionException;
+
+import org.jrdf.graph.BlankNode;
+import org.mulgara.query.functions.MulgaraFunction;
+import org.mulgara.query.functions.MulgaraFunctionGroup;
+import org.mulgara.util.URIUtil;
+
+/**
+ * Container for functions in the afn domain.
+ *
+ * @created Dec 14, 2009
+ * @author Paul Gearon
+ * @copyright &copy; 2009 <a href="http://www.duraspace.org/">DuraSpace</a>
+ */
+public class AfnFunctionGroup implements MulgaraFunctionGroup {
+
+  /** The prefix for the afn: namespace */
+  static final String PREFIX = "afn";
+
+  /** The afn: namespace */
+  static final String NAMESPACE = "http://jena.hpl.hp.com/ARQ/function#";
+  // static final String NAMESPACE = "http://openjena.org/ARQ/function#";
+
+  /**
+   * 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 Substring2());
+    functions.add(new Substring3());
+    functions.add(new Substr2());
+    functions.add(new Substr3());
+    functions.add(new Strjoin());
+    functions.add(new Sha1sum());
+    functions.add(new Now());
+    functions.add(new Bnode());
+    functions.add(new Localname());
+    functions.add(new Namespace());
+    functions.add(new Min());
+    functions.add(new Max());
+    functions.add(new Pi());
+    functions.add(new E());
+    return functions;
+  }
+
+  /**
+   * As for {@link org.mulgara.query.xpath.FnFunctionGroup.Substring2}, but with Java semantics.
+   * @see http://jena.hpl.hp.com/ARQ/function#substr
+   */
+  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);
+    }
+  }
+
+  /**
+   * As for {@link org.mulgara.query.xpath.FnFunctionGroup.Substring3} but with Java semantics.
+   * @see http://jena.hpl.hp.com/ARQ/function#substr
+   */
+  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();
+      int end = ((Number)args.get(2)).intValue();
+      // perform boundary checking
+      if (start < 0) start = 0;
+      int len = source.length();
+      if (start > len) {
+        start = len;
+        end = len;
+      }
+      if (end > len) end = len;
+      if (end < start) end = start;
+      
+      return source.substring(start, end);
+    }
+  }
+
+  /**
+   * Synonym for afn:substring
+   */
+  static private class Substr2 extends Substring2 {
+    public String getName() { return "substr/2"; }
+  }
+
+  /**
+   * Synonym for afn:substring
+   */
+  static private class Substr3 extends Substring3 {
+    public String getName() { return "substr/3"; }
+  }
+
+  /**
+   * Join all the arguments using a separator found in the first parameter.
+   * afn:strjoin(separator, sequence...)
+   * @see http://jena.hpl.hp.com/ARQ/function#strjoin
+   */
+  static private class Strjoin extends MulgaraFunction {
+    public String getName() { return "strjoin/*"; }
+    public int getArity() { return -1; }
+    public Object eval(List<?> args) throws XPathFunctionException {
+      StringBuilder s = new StringBuilder();
+      int lastIndex = args.size() - 1;
+      String separator = (String)args.get(0);
+      for (int i = 1; i < lastIndex; i++) {
+        if (i != 1) s.append(separator);
+        s.append(args.get(i));
+      }
+      return s.toString();
+    }
+  }
+
+  /**
+   * Calculate the SHA1 checkum of a literal or URI
+   * afn:sha1sum(resource)
+   * @see http://jena.hpl.hp.com/ARQ/function#sha1sum
+   */
+  static private class Sha1sum extends MulgaraFunction {
+    public String getName() { return "sha1sum/1"; }
+    public Object eval(List<?> args) throws XPathFunctionException {
+      String resource = args.get(0).toString();
+      try {
+        byte[] bytes = resource.getBytes("UTF8");
+        MessageDigest digest = MessageDigest.getInstance("SHA1");
+        digest.update(bytes, 0, bytes.length);
+        
+        return toHexString(digest.digest());
+      } catch (UnsupportedEncodingException e) {
+        throw new XPathFunctionException("Unable to handle data as UTF-8: " + e.getMessage());
+      } catch (NoSuchAlgorithmException e) {
+        throw new XPathFunctionException("SHA1 algorithm is not available: " + e.getMessage());
+      }
+    }
+    static final String toHexString(byte[] data) {
+      StringBuilder s = new StringBuilder();
+      for (byte b: data) {
+        s.append(Integer.toHexString((b & 0xF0) >> 4));
+        s.append(Integer.toHexString(b & 0x0F));
+      }
+      return s.toString();
+    }
+  }
+
+  /**
+   * Returns the time this function is called. This will increase throughout a query if the
+   * query takes any measurable time.
+   * afn:now()
+   * @see http://jena.hpl.hp.com/ARQ/function#now
+   */
+  static private class Now extends MulgaraFunction {
+    public int getArity() { return 0; }
+    public Object eval(List<?> args) throws XPathFunctionException {
+      return new Date();
+    }
+  }
+  
+  /**
+   * Return the blank node label if ?x is a blank node.
+   * afn:bnode(node)
+   * @see http://jena.hpl.hp.com/ARQ/function#bnode
+   */
+  static private class Bnode extends MulgaraFunction {
+    public Object eval(List<?> args) throws XPathFunctionException {
+      Object resource = args.get(0);
+      return (resource instanceof BlankNode) ? ((BlankNode)resource).toString() : "";
+    }
+  }
+
+  /**
+   * The local name of u if an IRI.
+   * Based on splitting the IRI, not on any prefixes in the query or dataset
+   * afn:localname(u)
+   * @see http://jena.hpl.hp.com/ARQ/function#localname
+   */
+  static private class Localname extends MulgaraFunction {
+    public Object eval(List<?> args) throws XPathFunctionException {
+      Object resource = args.get(0);
+      return (resource instanceof URI) ? localName((URI)resource) : "";
+    }
+    static String localName(URI u) {
+      return URIUtil.parseQName(u).getLocalPart();
+    }
+  }
+  
+  /**
+   * The namespace of an IRI.
+   * Based on splitting the IRI, not on any prefixes in the query or dataset
+   * afn:namespace(u)
+   * @see http://jena.hpl.hp.com/ARQ/function#namespace
+   */
+  static private class Namespace extends MulgaraFunction {
+    public Object eval(List<?> args) throws XPathFunctionException {
+      Object resource = args.get(0);
+      return (resource instanceof URI) ? namespace((URI)resource) : "";
+    }
+    static String namespace(URI u) {
+      return URIUtil.parseQName(u).getNamespaceURI();
+    }
+  }
+  
+  /**
+   * Return the minimum of two expressions evaluating to numbers.
+   * afn:min(x,y)
+   * @see http://jena.hpl.hp.com/ARQ/function#min
+   */
+  static private class Min extends MulgaraFunction {
+    public int getArity() { return 2; }
+    public Object eval(List<?> args) throws XPathFunctionException {
+      Number x = (Number)args.get(0);
+      Number y = (Number)args.get(1);
+      return x.doubleValue() < y.doubleValue() ? x : y;
+    }
+  }
+
+  /**
+   * Return the maximum of two expressions evaluating to numbers.
+   * afn:max(x,y)
+   * @see http://jena.hpl.hp.com/ARQ/function#max
+   */
+  static private class Max extends MulgaraFunction {
+    public int getArity() { return 2; }
+    public Object eval(List<?> args) throws XPathFunctionException {
+      Number x = (Number)args.get(0);
+      Number y = (Number)args.get(1);
+      return x.doubleValue() > y.doubleValue() ? x : y;
+    }
+  }
+
+  /**
+   * The value of pi.
+   * afn:pi()
+   * @see http://jena.hpl.hp.com/ARQ/function#pi
+   */
+  static private class Pi extends MulgaraFunction {
+    public int getArity() { return 0; }
+    public Object eval(List<?> args) throws XPathFunctionException {
+      return Math.PI;
+    }
+  }
+
+  /**
+   * The value of e.
+   * afn:e()
+   * @see http://jena.hpl.hp.com/ARQ/function#e
+   */
+  static private class E extends MulgaraFunction {
+    public int getArity() { return 0; }
+    public Object eval(List<?> args) throws XPathFunctionException {
+      return Math.E;
+    }
+  }
+
+}

Modified: trunk/src/jar/query/java/org/mulgara/query/xpath/FnFunctionGroup.java
===================================================================
--- trunk/src/jar/query/java/org/mulgara/query/xpath/FnFunctionGroup.java	2009-12-17 09:17:46 UTC (rev 1877)
+++ trunk/src/jar/query/java/org/mulgara/query/xpath/FnFunctionGroup.java	2009-12-17 09:20:42 UTC (rev 1878)
@@ -27,6 +27,7 @@
 import org.apache.xerces.impl.xpath.regex.RegularExpression;
 import org.mulgara.query.functions.MulgaraFunction;
 import org.mulgara.query.functions.MulgaraFunctionGroup;
+import org.mulgara.util.NumberUtil;
 
 /**
  * Container for functions in the fn domain.
@@ -35,7 +36,6 @@
  * @author Paul Gearon
  * @copyright &copy; 2009 <a href="http://www.duraspace.org/">DuraSpace</a>
  */
- at SuppressWarnings("unchecked")
 public class FnFunctionGroup implements MulgaraFunctionGroup {
 
   /** The prefix for the fn: namespace */
@@ -84,6 +84,14 @@
     functions.add(new EncodeForUri());
     functions.add(new IriToUri());
     functions.add(new EscapeHtmlUri());
+    functions.add(new Contains());
+    functions.add(new StartsWith());
+    functions.add(new EndsWith());
+    functions.add(new StringJoin());
+    functions.add(new Round());
+    functions.add(new Abs());
+    functions.add(new Floor());
+    functions.add(new Ceiling());
     return functions;
   }
 
@@ -94,7 +102,7 @@
   static private class Matches2 extends MulgaraFunction {
     public String getName() { return "matches/2"; }
     public int getArity() { return 2; }
-    public Object eval(List args) {
+    public Object eval(List<?> args) {
       String str = (String)args.get(0);
       String pattern = (String)args.get(1);
       return new RegularExpression(pattern).matches(str);
@@ -108,7 +116,7 @@
   static private class Matches3 extends MulgaraFunction {
     public String getName() { return "matches/3"; }
     public int getArity() { return 3; }
-    public Object eval(List args) {
+    public Object eval(List<?> args) {
       String str = (String)args.get(0);
       String pattern = (String)args.get(1);
       String flags = (String)args.get(2);
@@ -123,7 +131,7 @@
   static private class FnBoolean extends MulgaraFunction {
     public String getName() { return "boolean"; }
     public int getArity() { return 1; }
-    public Object eval(List args) throws XPathFunctionException {
+    public Object eval(List<?> args) throws XPathFunctionException {
       // no sequence info available here. Look at singleton only for the moment
       return toBool(args.get(0));
     }
@@ -137,7 +145,7 @@
    */
   static private class Not extends MulgaraFunction {
     public int getArity() { return 1; }
-    public Object eval(List args) throws XPathFunctionException {
+    public Object eval(List<?> args) throws XPathFunctionException {
       return !toBool(args.get(0));
     }
   }
@@ -149,7 +157,7 @@
   static private class Concat extends MulgaraFunction {
     public int getArity() { return -1; }
     public String getName() { return "concat/*"; }
-    public Object eval(List args) throws XPathFunctionException {
+    public Object eval(List<?> args) throws XPathFunctionException {
       StringBuilder s = new StringBuilder();
       for (Object o: args) s.append(o);
       return s.toString();
@@ -163,9 +171,9 @@
   static private class Substring2 extends MulgaraFunction {
     public int getArity() { return 2; }
     public String getName() { return "substring/2"; }
-    public Object eval(List args) throws XPathFunctionException {
+    public Object eval(List<?> args) throws XPathFunctionException {
       String source = args.get(0).toString();
-      int start = ((Number)args.get(1)).intValue();
+      int start = ((Number)args.get(1)).intValue() - 1;
       // perform boundary checking
       int len = source.length();
       if (start < 0) start = 0;
@@ -181,7 +189,7 @@
   static private class Substring3 extends MulgaraFunction {
     public int getArity() { return 3; }
     public String getName() { return "substring/3"; }
-    public Object eval(List args) throws XPathFunctionException {
+    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;
@@ -205,7 +213,7 @@
    */
   static private class StringLength extends MulgaraFunction {
     public String getName() { return "string-length/1"; }
-    public Object eval(List args) throws XPathFunctionException {
+    public Object eval(List<?> args) throws XPathFunctionException {
       return args.get(0).toString().length();
     }
   }
@@ -216,7 +224,7 @@
    */
   static private class NormalizeSpace extends MulgaraFunction {
     public String getName() { return "normalize-space/1"; }
-    public Object eval(List args) throws XPathFunctionException {
+    public Object eval(List<?> args) throws XPathFunctionException {
       String str = args.get(0).toString().trim();
       return str.replaceAll(" +", " ");
     }
@@ -228,7 +236,7 @@
    */
   static private class UpperCase extends MulgaraFunction {
     public String getName() { return "upper-case/1"; }
-    public Object eval(List args) throws XPathFunctionException {
+    public Object eval(List<?> args) throws XPathFunctionException {
       return args.get(0).toString().toUpperCase();
     }
   }
@@ -239,7 +247,7 @@
    */
   static private class LowerCase extends MulgaraFunction {
     public String getName() { return "lower-case/1"; }
-    public Object eval(List args) throws XPathFunctionException {
+    public Object eval(List<?> args) throws XPathFunctionException {
       return args.get(0).toString().toLowerCase();
     }
   }
@@ -251,7 +259,7 @@
    */
   static private class Translate extends MulgaraFunction {
     public int getArity() { return 3; }
-    public Object eval(List args) throws XPathFunctionException {
+    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();
@@ -291,7 +299,7 @@
    */
   static private class EncodeForUri extends MulgaraFunction {
     public String getName() { return "encode-for-uri/1"; }
-    public Object eval(List args) throws XPathFunctionException {
+    public Object eval(List<?> args) throws XPathFunctionException {
       try {
         return URLEncoder.encode(args.get(0).toString(), UTF8);
       } catch (UnsupportedEncodingException e) {
@@ -307,7 +315,7 @@
    */
   static private class IriToUri extends MulgaraFunction {
     public String getName() { return "iri-to-uri/1"; }
-    public Object eval(List args) throws XPathFunctionException {
+    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);
@@ -334,7 +342,7 @@
    */
   static private class EscapeHtmlUri extends MulgaraFunction {
     public String getName() { return "escape-html-uri/1"; }
-    public Object eval(List args) throws XPathFunctionException {
+    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);
@@ -366,4 +374,115 @@
     return result.toString();
   }
 
+  /**
+   * Test whether a substring occurs in a string
+   * fn:contains(string,substr)
+   * @see http://www.w3.org/TR/xpath-functions/#contains
+   */
+  static private class Contains extends MulgaraFunction {
+    public int getArity() { return 2; }
+    public Object eval(List<?> args) {
+      String str = (String)args.get(0);
+      String substr = (String)args.get(1);
+      return str.contains(substr);
+    }
+  }
+
+  /**
+   * Test whether a string starts with substr
+   * fn:starts-with(string,substr)
+   * @see http://www.w3.org/TR/xpath-functions/#starts-with
+   */
+  static private class StartsWith extends MulgaraFunction {
+    public String getName() { return "starts-with/2"; }
+    public int getArity() { return 2; }
+    public Object eval(List<?> args) {
+      String str = (String)args.get(0);
+      String substr = (String)args.get(1);
+      return str.startsWith(substr);
+    }
+  }
+
+  /**
+   * Test whether a string ends with substr
+   * fn:ends-with(string,substr)
+   * @see http://www.w3.org/TR/xpath-functions/#ends-with
+   */
+  static private class EndsWith extends MulgaraFunction {
+    public String getName() { return "ends-with/2"; }
+    public int getArity() { return 2; }
+    public Object eval(List<?> args) {
+      String str = (String)args.get(0);
+      String substr = (String)args.get(1);
+      return str.endsWith(substr);
+    }
+  }
+
+  /**
+   * Join all the arguments except the last, using the last argument as a separator.
+   * fn:string-join(sequence..., separator)
+   * @see http://www.w3.org/TR/xpath-functions/#string-join
+   */
+  static private class StringJoin extends MulgaraFunction {
+    public String getName() { return "string-join/*"; }
+    public int getArity() { return -1; }
+    public Object eval(List<?> args) throws XPathFunctionException {
+      StringBuilder s = new StringBuilder();
+      int lastIndex = args.size() - 1;
+      String separator = (String)args.get(lastIndex);
+      for (int i = 0; i < lastIndex; i++) {
+        if (i != 0) s.append(separator);
+        s.append(args.get(i));
+      }
+      return s.toString();
+    }
+  }
+
+  /**
+   * Return the nearest integer value to the argument.
+   * fn:round(x)
+   * @see http://www.w3.org/TR/xpath-functions/#round
+   */
+  static private class Round extends MulgaraFunction {
+    public Object eval(List<?> args) throws XPathFunctionException {
+      Number x = (Number)args.get(0);
+      return Math.round(x.doubleValue());
+    }
+  }
+
+  /**
+   * Return the absolute value.
+   * fn:abs(x)
+   * @see http://www.w3.org/TR/xpath-functions/#abs
+   */
+  static private class Abs extends MulgaraFunction {
+    public Object eval(List<?> args) throws XPathFunctionException {
+      Number x = (Number)args.get(0);
+      return x.doubleValue() < 0 ? NumberUtil.minus(x) : x;
+    }
+  }
+
+  /**
+   * Return the greatest integer value less than the argument (as a double).
+   * fn:floor(x)
+   * @see http://www.w3.org/TR/xpath-functions/#floor
+   */
+  static private class Floor extends MulgaraFunction {
+    public Object eval(List<?> args) throws XPathFunctionException {
+      Number x = (Number)args.get(0);
+      return Math.floor(x.doubleValue());
+    }
+  }
+
+  /**
+   * Return the smallest integer value greater than the argument (as a double).
+   * fn:ceiling(x)
+   * @see http://www.w3.org/TR/xpath-functions/#ceiling
+   */
+  static private class Ceiling extends MulgaraFunction {
+    public Object eval(List<?> args) throws XPathFunctionException {
+      Number x = (Number)args.get(0);
+      return Math.ceil(x.doubleValue());
+    }
+  }
 }

Modified: trunk/src/jar/query/java/org/mulgara/query/xpath/MulgaraXPathFunctionResolver.java
===================================================================
--- trunk/src/jar/query/java/org/mulgara/query/xpath/MulgaraXPathFunctionResolver.java	2009-12-17 09:17:46 UTC (rev 1877)
+++ trunk/src/jar/query/java/org/mulgara/query/xpath/MulgaraXPathFunctionResolver.java	2009-12-17 09:20:42 UTC (rev 1878)
@@ -34,6 +34,7 @@
     addFunctionGroup(new SparqlFunctionGroup());
     addFunctionGroup(new FnFunctionGroup());
     addFunctionGroup(new OpFunctionGroup());
+    addFunctionGroup(new AfnFunctionGroup());
   }
 
 }

Modified: trunk/src/jar/query/java/org/mulgara/query/xpath/OpFunctionGroup.java
===================================================================
--- trunk/src/jar/query/java/org/mulgara/query/xpath/OpFunctionGroup.java	2009-12-17 09:17:46 UTC (rev 1877)
+++ trunk/src/jar/query/java/org/mulgara/query/xpath/OpFunctionGroup.java	2009-12-17 09:20:42 UTC (rev 1878)
@@ -32,10 +32,9 @@
  * @author Paul Gearon
  * @copyright &copy; 2009 <a href="http://www.duraspace.org/">DuraSpace</a>
  */
- at SuppressWarnings("unchecked")
 public class OpFunctionGroup implements MulgaraFunctionGroup {
 
-  /** The prefix for the fn: namespace */
+  /** The prefix for the op: namespace */
   static final String PREFIX = "op";
 
   /** The op: namespace */
@@ -78,7 +77,7 @@
   static private class NumericEqual extends MulgaraFunction {
     public String getName() { return "numeric-equal/2"; }
     public int getArity() { return 2; }
-    public Object eval(List args) {
+    public Object eval(List<?> args) {
       Number left = (Number)args.get(0);
       Number right = (Number)args.get(1);
       return left.doubleValue() == right.doubleValue();
@@ -92,7 +91,7 @@
   static private class NumericLessThan extends MulgaraFunction {
     public String getName() { return "numeric-less-than/2"; }
     public int getArity() { return 2; }
-    public Object eval(List args) {
+    public Object eval(List<?> args) {
       Number left = (Number)args.get(0);
       Number right = (Number)args.get(1);
       return left.doubleValue() < right.doubleValue();
@@ -106,7 +105,7 @@
   static private class NumericGreaterThan extends MulgaraFunction {
     public String getName() { return "numeric-greater-than/2"; }
     public int getArity() { return 2; }
-    public Object eval(List args) {
+    public Object eval(List<?> args) {
       Number left = (Number)args.get(0);
       Number right = (Number)args.get(1);
       return left.doubleValue() > right.doubleValue();
@@ -121,7 +120,7 @@
   static private class NumericIntegerDivision extends MulgaraFunction {
     public String getName() { return "numeric-integer-divide/2"; }
     public int getArity() { return 2; }
-    public Object eval(List args) {
+    public Object eval(List<?> args) {
       Number left = (Number)args.get(0);
       Number right = (Number)args.get(1);
       if (left instanceof BigDecimal) {
@@ -146,7 +145,7 @@
   static private class NumericMod extends MulgaraFunction {
     public String getName() { return "numeric-mod/2"; }
     public int getArity() { return 2; }
-    public Object eval(List args) {
+    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) {

Added: trunk/src/jar/query/java/org/mulgara/query/xpath/SmfFunctionGroup.java
===================================================================
--- trunk/src/jar/query/java/org/mulgara/query/xpath/SmfFunctionGroup.java	                        (rev 0)
+++ trunk/src/jar/query/java/org/mulgara/query/xpath/SmfFunctionGroup.java	2009-12-17 09:20:42 UTC (rev 1878)
@@ -0,0 +1,144 @@
+/*
+ * 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.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.xml.xpath.XPathFunctionException;
+
+import org.mulgara.query.functions.MulgaraFunction;
+import org.mulgara.query.functions.MulgaraFunctionGroup;
+
+/**
+ * Container for functions in the smf domain.
+ *
+ * @created Dec 15, 2009
+ * @author Paul Gearon
+ * @copyright &copy; 2009 <a href="http://www.duraspace.org/">DuraSpace</a>
+ */
+public class SmfFunctionGroup implements MulgaraFunctionGroup {
+
+  /** The prefix for the afn: namespace */
+  static final String PREFIX = "smf";
+
+  /** The afn: namespace */
+  static final String NAMESPACE = "http://www.topquadrant.com/sparqlmotion/smf.html#smf:";
+
+  /**
+   * 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 IndexOf());
+    functions.add(new LastIndexOf());
+    functions.add(new TitleCase());
+    functions.add(new Trim());
+    return functions;
+  }
+
+  // can't do cast, as we don't control RDF types here
+
+  /**
+   * Gets the index of the first occurrence of a certain substring in a given search string.
+   * Returns null if the substring is not found.
+   * smf:indexOf(text, substr)
+   * @see http://www.topquadrant.com/sparqlmotion/smf.html#smf:indexOf
+   */
+  static private class IndexOf extends MulgaraFunction {
+    public int getArity() { return 2; }
+    public String getName() { return "indexOf/2"; }
+    public Object eval(List<?> args) throws XPathFunctionException {
+      String text = args.get(0).toString();
+      String substr = args.get(1).toString();
+      int i = text.indexOf(substr);
+      return i >= 0 ? i : null;
+    }
+  }
+
+  /**
+   * Gets the last index of the first occurrence of a certain substring in a given search string.
+   * Returns null if the substring is not found
+   * smf:lastIndexOf(text, substr)
+   * @see http://www.topquadrant.com/sparqlmotion/smf.html#smf:lastIndexOf
+   */
+  static private class LastIndexOf extends MulgaraFunction {
+    public int getArity() { return 2; }
+    public Object eval(List<?> args) throws XPathFunctionException {
+      String text = args.get(0).toString();
+      String substr = args.get(1).toString();
+      int i = text.lastIndexOf(substr);
+      return i >= 0 ? i : null;
+    }
+  }
+
+  // can't do setLanguage at this level
+
+  /**
+   * Converts an input string to title case. For example, germany becomes Germany.
+   * smf:titleCase(text)
+   * @see http://www.topquadrant.com/sparqlmotion/smf.html#smf:titleCase
+   */
+  static private class TitleCase extends MulgaraFunction {
+    public Object eval(List<?> args) throws XPathFunctionException {
+      StringBuilder text = new StringBuilder(args.get(0).toString());
+      int textLen = text.length();
+      if (textLen == 0) return "";
+      char c = text.charAt(0);
+      if (Character.isLowerCase(c)) text.setCharAt(0, Character.toUpperCase(c));
+      for (int i = 0; i < textLen; i++) {
+        if (text.charAt(i) == ' ' && i < textLen - 1) {
+          c = text.charAt(i + 1);
+          if (Character.isLowerCase(c)) text.setCharAt(i + 1, Character.toUpperCase(c));
+        }
+      }
+      return text.toString();
+    }
+  }
+
+  /**
+   * Creates a new string value by trimming an input string.
+   * Leading and trailing whitespaces are deleted
+   * smf:trim
+   * @see http://www.topquadrant.com/sparqlmotion/smf.html#smf:trim
+   */
+  static private class Trim extends MulgaraFunction {
+    public Object eval(List<?> args) throws XPathFunctionException {
+      return args.get(0).toString().trim();
+    }
+  }
+
+  
+}

Modified: trunk/src/jar/util/java/org/mulgara/util/NumberUtil.java
===================================================================
--- trunk/src/jar/util/java/org/mulgara/util/NumberUtil.java	2009-12-17 09:17:46 UTC (rev 1877)
+++ trunk/src/jar/util/java/org/mulgara/util/NumberUtil.java	2009-12-17 09:20:42 UTC (rev 1878)
@@ -103,6 +103,21 @@
     return (st == null) ? null : st.valueOf(str);
   }
 
+  /**
+   * Returns The negation of a number, regardless of its type.
+   * @param n The number to negate.
+   * @return Negative the number, or null if the number was null.
+   */
+  static public Number minus(Number n) {
+    if (n instanceof Long) return new Long(-n.longValue());
+    if (n instanceof Integer) return new Integer(-n.intValue());
+    if (n instanceof Short) return new Short((short)-n.shortValue());
+    if (n instanceof Byte) return new Byte((byte)-n.byteValue());
+    if (n instanceof Double) return new Double(-n.doubleValue());
+    if (n instanceof Float) return new Float(-n.floatValue());
+    return null;
+  }
+
   ///////////////////////////////////////////////////////////////////////////////
   // Internal structures for handling conversion of numeric types to XSD and back
   ///////////////////////////////////////////////////////////////////////////////

Modified: trunk/src/jar/util/java/org/mulgara/util/URIUtil.java
===================================================================
--- trunk/src/jar/util/java/org/mulgara/util/URIUtil.java	2009-12-17 09:17:46 UTC (rev 1877)
+++ trunk/src/jar/util/java/org/mulgara/util/URIUtil.java	2009-12-17 09:20:42 UTC (rev 1878)
@@ -20,6 +20,8 @@
 import java.net.URISyntaxException;
 import java.util.Map;
 
+import javax.xml.namespace.QName;
+
 /**
  * Utilities for working with URIs in Mulgara.
  *
@@ -66,4 +68,60 @@
       throw new RuntimeException("Bad URI syntax in resource", e);
     }
   }
+
+  /**
+   * Converts a URI into a QName, based entirely on parsing.
+   * @param u The URI to parse.
+   * @return A QName containing the URI as a namespace/localpart combination, or the entire
+   *         uri as a localpart if it could not be parsed.
+   */
+  public static QName parseQName(URI u) {
+    String s = u.toString();
+    for (int i = s.length() - 1; i > 0; i--) {
+      if (!localNameChar(s.charAt(i))) {
+        // found the place where a name has to start after
+        for (int p = i + 1; p < s.length(); p++) {
+          if (localStartNameChar(s.charAt(p))) return new QName(s.substring(0, p), s.substring(p));
+        }
+        return new QName(s);
+      }
+    }
+    return new QName(s);
+  }
+
+  /**
+   * Indicates if the char is a valid XML name character, minus the colon character.
+   * @see http://www.w3.org/TR/REC-xml/#NT-NameStartChar
+   * @param c The character to test.
+   * @return <code>true</code> if the character is a valid start to an XML name.
+   */
+  private static final boolean localNameChar(char c) {
+    return localStartNameChar(c) ||
+           c == '-' || c == '.' || (c >= '0' && c <= '9') ||
+           c == 0xB7 || (c >= 0x0300 && c <= 0x036F) || (c >= 0x203F && c <= 0x2040);
+  }
+
+  /**
+   * Indicates if the char is a valid start for an XML name character, minus the colon character.
+   * @see http://www.w3.org/TR/REC-xml/#NT-NameStartChar
+   * @param c The character to test.
+   * @return <code>true</code> if the character is a valid start to an XML name.
+   */
+  private static final boolean localStartNameChar(char c) {
+    return (c >= 'A' && c <= 'Z') ||
+           (c >= 'a' && c <= 'z') ||
+           c == '_' ||
+           (c >= 0xC0 && c <= 0xD6) ||
+           (c >= 0xD8 && c <= 0xF6) ||
+           (c >= 0xF8 && c <= 0x2FF) ||
+           (c >= 0x370 && c <= 0x37D) ||
+           (c >= 0x37F && c <= 0x1FFF) ||
+           (c >= 0x200C && c <= 0x200D) ||
+           (c >= 0x2070 && c <= 0x218F) ||
+           (c >= 0x2C00 && c <= 0x2FEF) ||
+           (c >= 0x3001 && c <= 0xD7FF) ||
+           (c >= 0xF900 && c <= 0xFDCF) ||
+           (c >= 0xFDF0 && c <= 0xFFFD) ||
+           (c >= 0x10000 && c <= 0xEFFFF);
+  }
 }




More information about the Mulgara-svn mailing list