This is an automated email from the ASF dual-hosted git repository. andy pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/jena.git
commit ad4f7f23787424d462836af2c650a2cbd6b453d4 Author: Andy Seaborne <[email protected]> AuthorDate: Sun Apr 20 11:27:49 2025 +0100 Move argument checking library code to NodeValueOps --- .../java/org/apache/jena/sparql/expr/E_Regex.java | 4 +- .../org/apache/jena/sparql/expr/E_Subtract.java | 1 - .../jena/sparql/expr/nodevalue/NodeFunctions.java | 67 ------------------ .../jena/sparql/expr/nodevalue/NodeValueOps.java | 80 +++++++++++++++++++++- .../jena/sparql/expr/nodevalue/XSDFuncOp.java | 32 ++++----- .../apache/jena/sparql/expr/TestNodeFunctions.java | 31 +-------- .../apache/jena/sparql/expr/TestNodeValueOps.java | 31 +++++++++ 7 files changed, 128 insertions(+), 118 deletions(-) diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/expr/E_Regex.java b/jena-arq/src/main/java/org/apache/jena/sparql/expr/E_Regex.java index 94f14e752f..eaa58e299a 100644 --- a/jena-arq/src/main/java/org/apache/jena/sparql/expr/E_Regex.java +++ b/jena-arq/src/main/java/org/apache/jena/sparql/expr/E_Regex.java @@ -24,7 +24,7 @@ import org.apache.commons.lang3.StringUtils ; import org.apache.jena.atlas.logging.Log ; import org.apache.jena.graph.Node ; import org.apache.jena.query.ARQ ; -import org.apache.jena.sparql.expr.nodevalue.NodeFunctions ; +import org.apache.jena.sparql.expr.nodevalue.NodeValueOps; import org.apache.jena.sparql.sse.Tags ; import org.apache.jena.sparql.util.FmtUtils ; @@ -62,7 +62,7 @@ public class E_Regex extends ExprFunctionN @Override public NodeValue eval(List<NodeValue> args) { - Node arg = NodeFunctions.checkAndGetStringLiteral("REGEX", args.get(0)); + Node arg = NodeValueOps.checkAndGetStringLiteral("REGEX", args.get(0)); NodeValue vPattern = args.get(1); NodeValue vFlags = (args.size() == 2 ? null : args.get(2)); diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/expr/E_Subtract.java b/jena-arq/src/main/java/org/apache/jena/sparql/expr/E_Subtract.java index 846a981e4c..904e692286 100644 --- a/jena-arq/src/main/java/org/apache/jena/sparql/expr/E_Subtract.java +++ b/jena-arq/src/main/java/org/apache/jena/sparql/expr/E_Subtract.java @@ -38,7 +38,6 @@ public class E_Subtract extends ExprFunction2 { if ( ARQ.isStrictMode() ) return XSDFuncOp.numSubtract(x, y) ; - return NodeValueOps.subtractionNV(x, y) ; } diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/expr/nodevalue/NodeFunctions.java b/jena-arq/src/main/java/org/apache/jena/sparql/expr/nodevalue/NodeFunctions.java index 0d04b2021f..4dfef10acc 100644 --- a/jena-arq/src/main/java/org/apache/jena/sparql/expr/nodevalue/NodeFunctions.java +++ b/jena-arq/src/main/java/org/apache/jena/sparql/expr/nodevalue/NodeFunctions.java @@ -53,73 +53,6 @@ import org.apache.jena.vocabulary.XSD; */ public class NodeFunctions { - /** - * check and get a string (may be a simple literal, literal with language - * tag or an XSD string). - */ - public static Node checkAndGetStringLiteral(String label, NodeValue nv) { - Node n = nv.asNode(); - if ( !n.isLiteral() ) - throw new ExprEvalException(label + ": Not a literal: " + nv); - String lang = n.getLiteralLanguage(); - - if ( NodeUtils.isLangString(n) ) - // Language tag. Legal. - return n; - - // No language tag : either no datatype or a datatype of xsd:string - // Includes the case of rdf:langString and no language ==> Illegal as a compatible string. - - if ( nv.isString() ) - return n; - throw new ExprEvalException(label + ": Not a string literal: " + nv); - } - - /** - * Check for string operations with primary first arg and second arg - * (e.g. CONTAINS). The arguments are not used in the same way and the check - * operation is not symmetric. - * <ul> - * <li> "abc"@en is compatible with "abc" - * <li> "abc" is NOT compatible with "abc"@en - * </ul> - */ - public static void checkTwoArgumentStringLiterals(String label, NodeValue arg1, NodeValue arg2) { - - /* Quote the spec: - * Compatibility of two arguments is defined as: - * The arguments are simple literals or literals typed as xsd:string - * The arguments are plain literals with identical language tags - * The first argument is a plain literal with language tag and the second argument is a simple literal or literal typed as xsd:string - */ - - Node n1 = checkAndGetStringLiteral(label, arg1); - Node n2 = checkAndGetStringLiteral(label, arg2); - String lang1 = n1.getLiteralLanguage(); - String lang2 = n2.getLiteralLanguage(); - if ( lang1 == null ) - lang1 = ""; - if ( lang2 == null ) - lang2 = ""; - - // Case 1 - if ( lang1.equals("") ) { - if ( lang2.equals("") ) - return; - throw new ExprEvalException(label + ": Incompatible: " + arg1 + " and " + arg2); - } - - // Case 2 - if ( lang1.equalsIgnoreCase(lang2) ) - return; - - // Case 3 - if ( lang2.equals("") ) - return; - - throw new ExprEvalException(label + ": Incompatible: " + arg1 + " and " + arg2); - } - // -------- sameTerm public static NodeValue sameTerm(NodeValue nv1, NodeValue nv2) { diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/expr/nodevalue/NodeValueOps.java b/jena-arq/src/main/java/org/apache/jena/sparql/expr/nodevalue/NodeValueOps.java index f1fc4a2ad5..b76ddf2460 100644 --- a/jena-arq/src/main/java/org/apache/jena/sparql/expr/nodevalue/NodeValueOps.java +++ b/jena-arq/src/main/java/org/apache/jena/sparql/expr/nodevalue/NodeValueOps.java @@ -30,11 +30,20 @@ import javax.xml.datatype.XMLGregorianCalendar; import org.apache.jena.datatypes.xsd.XSDDatatype; import org.apache.jena.graph.Node; import org.apache.jena.graph.NodeFactory; +import org.apache.jena.sparql.expr.ExprEvalException; import org.apache.jena.sparql.expr.ExprEvalTypeException; import org.apache.jena.sparql.expr.NodeValue; import org.apache.jena.sparql.expr.ValueSpace; - -/** The code parts of arithmetic operations on {@link NodeValue}s. +import org.apache.jena.sparql.util.NodeUtils; + +/** + * Operations relating to {@link NodeValue NodeValues}. + * <ul> + * <li>The code parts of arithmetic operations on {@link NodeValue}s. + * <li>Library code such as Argument testing + * </ul> + * <p> + * This class is not considered to be part of the ARQ API. */ public class NodeValueOps { @@ -284,4 +293,71 @@ public class NodeValueOps long x2 = gcal2.getTimeInMillis(); return NodeValue.xmlDatatypeFactory.newDuration(x1 - x2); } + + /** + * check and get a string (may be a simple literal, literal with language + * tag or an XSD string). + */ + public static Node checkAndGetStringLiteral(String label, NodeValue nv) { + Node n = nv.asNode(); + if ( !n.isLiteral() ) + throw new ExprEvalException(label + ": Not a literal: " + nv); + String lang = n.getLiteralLanguage(); + + if ( NodeUtils.isLangString(n) ) + // Language tag. Legal. + return n; + + // No language tag : either no datatype or a datatype of xsd:string + // Includes the case of rdf:langString and no language ==> Illegal as a compatible string. + + if ( nv.isString() ) + return n; + throw new ExprEvalException(label + ": Not a string literal: " + nv); + } + + /** + * Check for string operations with primary first arg and second arg + * (e.g. CONTAINS). The arguments are not used in the same way and the check + * operation is not symmetric. + * <ul> + * <li> "abc"@en is compatible with "abc" + * <li> "abc" is NOT compatible with "abc"@en + * </ul> + */ + public static void checkTwoArgumentStringLiterals(String label, NodeValue arg1, NodeValue arg2) { + + /* Quote the spec: + * Compatibility of two arguments is defined as: + * The arguments are simple literals or literals typed as xsd:string + * The arguments are plain literals with identical language tags + * The first argument is a plain literal with language tag and the second argument is a simple literal or literal typed as xsd:string + */ + + Node n1 = checkAndGetStringLiteral(label, arg1); + Node n2 = checkAndGetStringLiteral(label, arg2); + String lang1 = n1.getLiteralLanguage(); + String lang2 = n2.getLiteralLanguage(); + if ( lang1 == null ) + lang1 = ""; + if ( lang2 == null ) + lang2 = ""; + + // Case 1 + if ( lang1.equals("") ) { + if ( lang2.equals("") ) + return; + throw new ExprEvalException(label + ": Incompatible: " + arg1 + " and " + arg2); + } + + // Case 2 + if ( lang1.equalsIgnoreCase(lang2) ) + return; + + // Case 3 + if ( lang2.equals("") ) + return; + + throw new ExprEvalException(label + ": Incompatible: " + arg1 + " and " + arg2); + } } diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/expr/nodevalue/XSDFuncOp.java b/jena-arq/src/main/java/org/apache/jena/sparql/expr/nodevalue/XSDFuncOp.java index fa049da431..4a17dbc04c 100644 --- a/jena-arq/src/main/java/org/apache/jena/sparql/expr/nodevalue/XSDFuncOp.java +++ b/jena-arq/src/main/java/org/apache/jena/sparql/expr/nodevalue/XSDFuncOp.java @@ -19,8 +19,6 @@ package org.apache.jena.sparql.expr.nodevalue; import static javax.xml.datatype.DatatypeConstants.*; -import static org.apache.jena.sparql.expr.nodevalue.NodeFunctions.checkAndGetStringLiteral; -import static org.apache.jena.sparql.expr.nodevalue.NodeFunctions.checkTwoArgumentStringLiterals; import static org.apache.jena.sparql.expr.nodevalue.NumericType.OP_DECIMAL; import static org.apache.jena.sparql.expr.nodevalue.NumericType.OP_DOUBLE; import static org.apache.jena.sparql.expr.nodevalue.NumericType.OP_FLOAT; @@ -63,7 +61,7 @@ public class XSDFuncOp { private XSDFuncOp() {} - // The choice of "24" is arbitrary but more than 18 (XSD 1.0) or 16 XSD 1.1) as required by F&O + // The choice of "24" is arbitrary but more than 18 (XSD 1.0) or 16 (XSD 1.1) as required by F&O // F&O 3.1: section 4.2 (end intro) // https://www.w3.org/TR/xpath-functions/#op.numeric section 4.2 private static final int DIVIDE_PRECISION = 24; @@ -556,23 +554,23 @@ public class XSDFuncOp } public static NodeValue strlen(NodeValue nvString) { - Node n = checkAndGetStringLiteral("strlen", nvString); + Node n = NodeValueOps.checkAndGetStringLiteral("strlen", nvString); String str = n.getLiteralLexicalForm(); int len = str.codePointCount(0, str.length()); return NodeValue.makeInteger(len); } public static NodeValue strReplace(NodeValue nvStr, NodeValue nvPattern, NodeValue nvReplacement, NodeValue nvFlags) { - String pat = checkAndGetStringLiteral("replace", nvPattern).getLiteralLexicalForm(); + String pat = NodeValueOps.checkAndGetStringLiteral("replace", nvPattern).getLiteralLexicalForm(); String flagsStr = null; if ( nvFlags != null ) - flagsStr = checkAndGetStringLiteral("replace", nvFlags).getLiteralLexicalForm(); + flagsStr = NodeValueOps.checkAndGetStringLiteral("replace", nvFlags).getLiteralLexicalForm(); return strReplace(nvStr, RegexEngine.makePattern("replace", pat, flagsStr), nvReplacement); } public static NodeValue strReplace(NodeValue nvStr, Pattern pattern, NodeValue nvReplacement) { - String n = checkAndGetStringLiteral("replace", nvStr).getLiteralLexicalForm(); - String rep = checkAndGetStringLiteral("replace", nvReplacement).getLiteralLexicalForm(); + String n = NodeValueOps.checkAndGetStringLiteral("replace", nvStr).getLiteralLexicalForm(); + String rep = NodeValueOps.checkAndGetStringLiteral("replace", nvReplacement).getLiteralLexicalForm(); String x = replaceAll(pattern.matcher(n), rep); if ( x == null ) // No replacement. @@ -621,7 +619,7 @@ public class XSDFuncOp } public static NodeValue substring(NodeValue nvString, NodeValue nvStart, NodeValue nvLength) { - Node n = checkAndGetStringLiteral("substring", nvString); + Node n = NodeValueOps.checkAndGetStringLiteral("substring", nvString); RDFDatatype dt = n.getLiteralDatatype(); // XSD F&O: try { @@ -708,7 +706,7 @@ public class XSDFuncOp } public static NodeValue strContains(NodeValue string, NodeValue match) { - checkTwoArgumentStringLiterals("contains", string, match); + NodeValueOps.checkTwoArgumentStringLiterals("contains", string, match); String lex1 = string.asNode().getLiteralLexicalForm(); String lex2 = match.asNode().getLiteralLexicalForm(); boolean x = StrUtils.contains(lex1, lex2); @@ -716,14 +714,14 @@ public class XSDFuncOp } public static NodeValue strStartsWith(NodeValue string, NodeValue match) { - checkTwoArgumentStringLiterals("strStarts", string, match); + NodeValueOps.checkTwoArgumentStringLiterals("strStarts", string, match); String lex1 = string.asNode().getLiteralLexicalForm(); String lex2 = match.asNode().getLiteralLexicalForm(); return NodeValue.booleanReturn(lex1.startsWith(lex2)); } public static NodeValue strEndsWith(NodeValue string, NodeValue match) { - checkTwoArgumentStringLiterals("strEnds", string, match); + NodeValueOps.checkTwoArgumentStringLiterals("strEnds", string, match); String lex1 = string.asNode().getLiteralLexicalForm(); String lex2 = match.asNode().getLiteralLexicalForm(); return NodeValue.booleanReturn(lex1.endsWith(lex2)); @@ -736,7 +734,7 @@ public class XSDFuncOp } public static NodeValue strBefore(NodeValue string, NodeValue match) { - checkTwoArgumentStringLiterals("strBefore", string, match); + NodeValueOps.checkTwoArgumentStringLiterals("strBefore", string, match); String lex1 = string.asNode().getLiteralLexicalForm(); String lex2 = match.asNode().getLiteralLexicalForm(); Node mainArg = string.asNode(); @@ -753,7 +751,7 @@ public class XSDFuncOp } public static NodeValue strAfter(NodeValue string, NodeValue match) { - checkTwoArgumentStringLiterals("strAfter", string, match); + NodeValueOps.checkTwoArgumentStringLiterals("strAfter", string, match); String lex1 = string.asNode().getLiteralLexicalForm(); String lex2 = match.asNode().getLiteralLexicalForm(); Node mainArg = string.asNode(); @@ -770,14 +768,14 @@ public class XSDFuncOp } public static NodeValue strLowerCase(NodeValue string) { - Node n = checkAndGetStringLiteral("lcase", string); + Node n = NodeValueOps.checkAndGetStringLiteral("lcase", string); String lex = n.getLiteralLexicalForm(); String lex2 = lex.toLowerCase(); return calcReturn(lex2, string.asNode()); } public static NodeValue strUpperCase(NodeValue string) { - Node n = checkAndGetStringLiteral("ucase", string); + Node n = NodeValueOps.checkAndGetStringLiteral("ucase", string); String lex = n.getLiteralLexicalForm(); String lex2 = lex.toUpperCase(); return calcReturn(lex2, string.asNode()); @@ -820,7 +818,7 @@ public class XSDFuncOp StringBuilder sb = new StringBuilder(); for (NodeValue nv : args) { - Node n = checkAndGetStringLiteral("CONCAT", nv); + Node n = NodeValueOps.checkAndGetStringLiteral("CONCAT", nv); String lang1 = n.getLiteralLanguage(); if ( !lang1.equals("") ) { if ( lang != null && !lang1.equals(lang) ) diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestNodeFunctions.java b/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestNodeFunctions.java index ab46dbb938..1491c3c96d 100644 --- a/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestNodeFunctions.java +++ b/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestNodeFunctions.java @@ -20,6 +20,8 @@ package org.apache.jena.sparql.expr; import static org.junit.Assert.*; +import org.junit.Test; + import org.apache.jena.datatypes.xsd.XSDDatatype; import org.apache.jena.graph.Node; import org.apache.jena.graph.NodeFactory; @@ -28,9 +30,7 @@ import org.apache.jena.query.ARQ; import org.apache.jena.sparql.expr.nodevalue.NodeFunctions; import org.apache.jena.sparql.graph.NodeConst; import org.apache.jena.sparql.sse.SSE; -import org.apache.jena.vocabulary.RDF; import org.apache.jena.vocabulary.XSD; -import org.junit.Test; public class TestNodeFunctions { private static final double accuracyExact = 0.0d; @@ -396,31 +396,4 @@ public class TestNodeFunctions { NodeValue r = NodeFunctions.isLiteral(nv); assertEquals(NodeValue.FALSE, r); } - - @Test public void testCheckAndGetStringLiteral1() { - NodeValue nv = NodeValue.makeNode("abc", XSDDatatype.XSDstring); - Node n = NodeFunctions.checkAndGetStringLiteral("Test", nv); - assertEquals( "abc", n.getLiteralLexicalForm()); - } - - @Test public void testCheckAndGetStringLiteral2() { - NodeValue nv = NodeValue.makeNode("abc", XSDDatatype.XSDnormalizedString); - Node n = NodeFunctions.checkAndGetStringLiteral("Test", nv); - assertEquals( "abc", n.getLiteralLexicalForm()); - } - - @Test public void testCheckAndGetStringLiteral3() { - NodeValue nv = NodeValue.makeString("abc"); - Node n = NodeFunctions.checkAndGetStringLiteral("Test", nv); - assertEquals( "abc", n.getLiteralLexicalForm()); - } - - @Test(expected=ExprEvalException.class) - public void testCheckAndGetStringLiteral4() { - // The form "abc"^^rdf:langString (no lang tag) is not derived from xsd:string. - NodeValue nv = NodeValue.makeNode("abc", RDF.dtLangString); - Node n = NodeFunctions.checkAndGetStringLiteral("Test", nv); - assertEquals( "abc", n.getLiteralLexicalForm()); - } - } diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestNodeValueOps.java b/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestNodeValueOps.java index 7651c9a37f..ff64564e64 100644 --- a/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestNodeValueOps.java +++ b/jena-arq/src/test/java/org/apache/jena/sparql/expr/TestNodeValueOps.java @@ -20,10 +20,41 @@ package org.apache.jena.sparql.expr; import static org.junit.Assert.assertEquals; +import org.apache.jena.datatypes.xsd.XSDDatatype; +import org.apache.jena.graph.Node; import org.apache.jena.sparql.expr.nodevalue.NodeValueOps; +import org.apache.jena.vocabulary.RDF; + import org.junit.Test; public class TestNodeValueOps { + + @Test public void testCheckAndGetStringLiteral1() { + NodeValue nv = NodeValue.makeNode("abc", XSDDatatype.XSDstring); + Node n = NodeValueOps.checkAndGetStringLiteral("Test", nv); + assertEquals( "abc", n.getLiteralLexicalForm()); + } + + @Test public void testCheckAndGetStringLiteral2() { + NodeValue nv = NodeValue.makeNode("abc", XSDDatatype.XSDnormalizedString); + Node n = NodeValueOps.checkAndGetStringLiteral("Test", nv); + assertEquals( "abc", n.getLiteralLexicalForm()); + } + + @Test public void testCheckAndGetStringLiteral3() { + NodeValue nv = NodeValue.makeString("abc"); + Node n = NodeValueOps.checkAndGetStringLiteral("Test", nv); + assertEquals( "abc", n.getLiteralLexicalForm()); + } + + @Test(expected=ExprEvalException.class) + public void testCheckAndGetStringLiteral4() { + // The form "abc"^^rdf:langString (no lang tag) is not derived from xsd:string. + NodeValue nv = NodeValue.makeNode("abc", RDF.dtLangString); + Node n = NodeValueOps.checkAndGetStringLiteral("Test", nv); + assertEquals( "abc", n.getLiteralLexicalForm()); + } + // ** Addition // Numerics @Test
