forked from metaschema-framework/metaschema-java
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added support for the matches Metapth function. Resolves metaschema-f…
- Loading branch information
1 parent
7632478
commit 42cd173
Showing
6 changed files
with
445 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
166 changes: 166 additions & 0 deletions
166
core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/library/FnMatches.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
|
||
package gov.nist.secauto.metaschema.core.metapath.function.library; | ||
|
||
import gov.nist.secauto.metaschema.core.metapath.DynamicContext; | ||
import gov.nist.secauto.metaschema.core.metapath.ISequence; | ||
import gov.nist.secauto.metaschema.core.metapath.MetapathConstants; | ||
import gov.nist.secauto.metaschema.core.metapath.function.FunctionUtils; | ||
import gov.nist.secauto.metaschema.core.metapath.function.IArgument; | ||
import gov.nist.secauto.metaschema.core.metapath.function.IFunction; | ||
import gov.nist.secauto.metaschema.core.metapath.function.regex.RegexUtil; | ||
import gov.nist.secauto.metaschema.core.metapath.function.regex.RegularExpressionMetapathException; | ||
import gov.nist.secauto.metaschema.core.metapath.item.IItem; | ||
import gov.nist.secauto.metaschema.core.metapath.item.atomic.IBooleanItem; | ||
import gov.nist.secauto.metaschema.core.metapath.item.atomic.IStringItem; | ||
import gov.nist.secauto.metaschema.core.util.ObjectUtils; | ||
|
||
import java.util.List; | ||
import java.util.regex.Pattern; | ||
import java.util.regex.PatternSyntaxException; | ||
|
||
import edu.umd.cs.findbugs.annotations.NonNull; | ||
import edu.umd.cs.findbugs.annotations.Nullable; | ||
|
||
/** | ||
* Implements <a href= | ||
* "https://www.w3.org/TR/xpath-functions-31/#func-matches">fn:matches</a>. | ||
*/ | ||
public final class FnMatches { | ||
@NonNull | ||
static final IFunction SIGNATURE_TWO_ARG = IFunction.builder() | ||
.name("matches") | ||
.namespace(MetapathConstants.NS_METAPATH_FUNCTIONS) | ||
.deterministic() | ||
.contextIndependent() | ||
.focusIndependent() | ||
.argument(IArgument.builder() | ||
.name("input") | ||
.type(IStringItem.class) | ||
.zeroOrOne() | ||
.build()) | ||
.argument(IArgument.builder() | ||
.name("pattern") | ||
.type(IStringItem.class) | ||
.one() | ||
.build()) | ||
.returnType(IBooleanItem.class) | ||
.returnOne() | ||
.functionHandler(FnMatches::executeTwoArg) | ||
.build(); | ||
|
||
@NonNull | ||
static final IFunction SIGNATURE_THREE_ARG = IFunction.builder() | ||
.name("matches") | ||
.namespace(MetapathConstants.NS_METAPATH_FUNCTIONS) | ||
.deterministic() | ||
.contextIndependent() | ||
.focusIndependent() | ||
.argument(IArgument.builder() | ||
.name("input") | ||
.type(IStringItem.class) | ||
.zeroOrOne() | ||
.build()) | ||
.argument(IArgument.builder() | ||
.name("pattern") | ||
.type(IStringItem.class) | ||
.one() | ||
.build()) | ||
.argument(IArgument.builder() | ||
.name("flags") | ||
.type(IStringItem.class) | ||
.one() | ||
.build()) | ||
.returnType(IBooleanItem.class) | ||
.returnOne() | ||
.functionHandler(FnMatches::executeThreeArg) | ||
.build(); | ||
|
||
@SuppressWarnings("unused") | ||
@NonNull | ||
private static ISequence<IBooleanItem> executeTwoArg( | ||
@NonNull IFunction function, | ||
@NonNull List<ISequence<?>> arguments, | ||
@NonNull DynamicContext dynamicContext, | ||
IItem focus) { | ||
IStringItem input = FunctionUtils.asTypeOrNull(arguments.get(0).getFirstItem(true)); | ||
IStringItem pattern = ObjectUtils.requireNonNull(FunctionUtils.asTypeOrNull(arguments.get(1).getFirstItem(true))); | ||
|
||
return execute(input, pattern, IStringItem.valueOf("")); | ||
} | ||
|
||
@SuppressWarnings("unused") | ||
|
||
@NonNull | ||
private static ISequence<IBooleanItem> executeThreeArg( | ||
@NonNull IFunction function, | ||
@NonNull List<ISequence<?>> arguments, | ||
@NonNull DynamicContext dynamicContext, | ||
IItem focus) { | ||
|
||
IStringItem input = FunctionUtils.asTypeOrNull(arguments.get(0).getFirstItem(true)); | ||
IStringItem pattern = ObjectUtils.requireNonNull(FunctionUtils.asTypeOrNull(arguments.get(1).getFirstItem(true))); | ||
IStringItem flags = ObjectUtils.requireNonNull(FunctionUtils.asTypeOrNull(arguments.get(2).getFirstItem(true))); | ||
|
||
return execute(input, pattern, flags); | ||
} | ||
|
||
@SuppressWarnings("PMD.OnlyOneReturn") | ||
@NonNull | ||
private static ISequence<IBooleanItem> execute( | ||
@Nullable IStringItem input, | ||
@NonNull IStringItem pattern, | ||
@NonNull IStringItem flags) { | ||
if (input == null) { | ||
return ISequence.empty(); | ||
} | ||
|
||
return ISequence.of(fnMatches(input, pattern, flags)); | ||
} | ||
|
||
/** | ||
* Implements <a href= | ||
* "https://www.w3.org/TR/xpath-functions-31/#func-matches">fn:matches</a>. | ||
* | ||
* @param input | ||
* the string to match against | ||
* @param pattern | ||
* the regular expression to use for matching | ||
* @param flags | ||
* matching options | ||
* @return {@link IBooleanItem#TRUE} if the pattern matches or | ||
* {@link IBooleanItem#FALSE} otherwise | ||
*/ | ||
public static IBooleanItem fnMatches( | ||
@NonNull IStringItem input, | ||
@NonNull IStringItem pattern, | ||
@NonNull IStringItem flags) { | ||
return IBooleanItem.valueOf(fnMatches(input.asString(), pattern.asString(), flags.asString())); | ||
} | ||
|
||
/** | ||
* Implements <a href= | ||
* "https://www.w3.org/TR/xpath-functions-31/#func-matches">fn:matches</a>. | ||
* | ||
* @param input | ||
* the string to match against | ||
* @param pattern | ||
* the regular expression to use for matching | ||
* @param flags | ||
* matching options | ||
* @return {@code true} if the pattern matches or {@code false} otherwise | ||
*/ | ||
public static boolean fnMatches(@NonNull String input, @NonNull String pattern, @NonNull String flags) { | ||
try { | ||
return Pattern.compile(pattern, RegexUtil.parseFlags(flags)) | ||
.matcher(input).find(); | ||
} catch (PatternSyntaxException ex) { | ||
throw new RegularExpressionMetapathException(RegularExpressionMetapathException.INVALID_EXPRESSION, ex); | ||
} catch (IllegalArgumentException ex) { | ||
throw new RegularExpressionMetapathException(RegularExpressionMetapathException.INVALID_FLAG, ex); | ||
} | ||
} | ||
|
||
private FnMatches() { | ||
// disable construction | ||
} | ||
} |
54 changes: 54 additions & 0 deletions
54
core/src/main/java/gov/nist/secauto/metaschema/core/metapath/function/regex/RegexUtil.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
|
||
package gov.nist.secauto.metaschema.core.metapath.function.regex; | ||
|
||
import java.util.regex.Pattern; | ||
|
||
import edu.umd.cs.findbugs.annotations.NonNull; | ||
|
||
public final class RegexUtil { | ||
|
||
/** | ||
* Parse the regular expression flags according to | ||
* <a href="https://www.w3.org/TR/xpath-functions-31/#flags">the | ||
* specification</a> producing a bitmask suitable for use in | ||
* {@link Pattern#compile(String, int)}. | ||
* | ||
* @param flags | ||
* the flags to process | ||
* @return the bitmask | ||
*/ | ||
public static int parseFlags(@NonNull String flags) { | ||
return flags.chars() | ||
.map(i -> characterToFlag((char) i)) | ||
.reduce(0, (mask, flag) -> mask | flag); | ||
} | ||
|
||
private static int characterToFlag(Character ch) { | ||
int retval; | ||
switch (ch) { | ||
case 's': | ||
retval = Pattern.DOTALL; | ||
break; | ||
case 'm': | ||
retval = Pattern.MULTILINE; | ||
break; | ||
case 'i': | ||
retval = Pattern.CASE_INSENSITIVE; | ||
break; | ||
case 'x': | ||
retval = Pattern.COMMENTS; | ||
break; | ||
case 'q': | ||
retval = Pattern.LITERAL; | ||
break; | ||
default: | ||
throw new RegularExpressionMetapathException(RegularExpressionMetapathException.INVALID_FLAG, | ||
String.format("Invalid flag '%s'.", ch)); | ||
} | ||
return retval; | ||
} | ||
|
||
private RegexUtil() { | ||
// disable construction | ||
} | ||
} |
97 changes: 97 additions & 0 deletions
97
...t/secauto/metaschema/core/metapath/function/regex/RegularExpressionMetapathException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
|
||
package gov.nist.secauto.metaschema.core.metapath.function.regex; | ||
|
||
import gov.nist.secauto.metaschema.core.metapath.AbstractCodedMetapathException; | ||
|
||
public class RegularExpressionMetapathException | ||
extends AbstractCodedMetapathException { | ||
/** | ||
* the serial version UID. | ||
*/ | ||
private static final long serialVersionUID = 1L; | ||
/** | ||
* <a href= | ||
* "https://www.w3.org/TR/xpath-functions-31/#ERRFORX0001">err:MPRX0001</a>: | ||
* Raised by regular expression functions such as <a href= | ||
* "https://www.w3.org/TR/xpath-functions-31/#func-matches">fn:matches</a> and | ||
* <a href= | ||
* "https://www.w3.org/TR/xpath-functions-31/#func-replace">fn:replace</a> if | ||
* the regular expression flags contain a character other than i, m, q, s, or x. | ||
*/ | ||
public static final int INVALID_FLAG = 1; | ||
/** | ||
* <a href= | ||
* "https://www.w3.org/TR/xpath-functions-31/#ERRFORX0002">err:MPRX0002</a>: | ||
* Raised by regular expression functions such as <a href= | ||
* "https://www.w3.org/TR/xpath-functions-31/#func-matches">fn:matches</a> and | ||
* <a href= | ||
* "https://www.w3.org/TR/xpath-functions-31/#func-replace">fn:replace</a> if | ||
* the regular expression is syntactically invalid. | ||
*/ | ||
public static final int INVALID_EXPRESSION = 2; | ||
/** | ||
* <a href= | ||
* "https://www.w3.org/TR/xpath-functions-31/#ERRFORX0003">err:MPRX0003</a>: For | ||
* functions such as <a href= | ||
* "https://www.w3.org/TR/xpath-functions-31/#func-replace">fn:replace</a> and | ||
* <a href= | ||
* "https://www.w3.org/TR/xpath-functions-31/#func-tokenize">fn:tokenize</a>, | ||
* raises an error if the supplied regular expression is capable of matching a | ||
* zero length string. | ||
*/ | ||
public static final int MATCHES_ZERO_LENGTH_STRING = 3; | ||
/** | ||
* <a href= | ||
* "https://www.w3.org/TR/xpath-functions-31/#ERRFORX0004">err:MPRX0004</a>: | ||
* Raised by <a href= | ||
* "https://www.w3.org/TR/xpath-functions-31/#func-replace">fn:replace</a> to | ||
* report errors in the replacement string. | ||
*/ | ||
public static final int INVALID_REPLACEMENT_STRING = 4; | ||
|
||
/** | ||
* Constructs a new exception with the provided {@code code}, {@code message}, | ||
* and {@code cause}. | ||
* | ||
* @param code | ||
* the error code value | ||
* @param message | ||
* the exception message | ||
* @param cause | ||
* the original exception cause | ||
*/ | ||
public RegularExpressionMetapathException(int code, String message, Throwable cause) { | ||
super(code, message, cause); | ||
} | ||
|
||
/** | ||
* Constructs a new exception with the provided {@code code}, {@code message}, | ||
* and no cause. | ||
* | ||
* @param code | ||
* the error code value | ||
* @param message | ||
* the exception message | ||
*/ | ||
public RegularExpressionMetapathException(int code, String message) { | ||
super(code, message); | ||
} | ||
|
||
/** | ||
* Constructs a new exception with the provided {@code code}, no message, and | ||
* the {@code cause}. | ||
* | ||
* @param code | ||
* the error code value | ||
* @param cause | ||
* the original exception cause | ||
*/ | ||
public RegularExpressionMetapathException(int code, Throwable cause) { | ||
super(code, cause); | ||
} | ||
|
||
@Override | ||
public String getCodePrefix() { | ||
return "MPRX"; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.