net.sf.saxon.s9api.streams.Predicates Maven / Gradle / Ivy
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2018-2023 Saxonica Limited
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
// This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
package net.sf.saxon.s9api.streams;
import net.sf.saxon.expr.sort.AtomicMatchKey;
import net.sf.saxon.om.NamespaceUri;
import net.sf.saxon.s9api.*;
import java.util.Objects;
import java.util.function.Predicate;
import java.util.regex.Pattern;
/**
* This non-instantiable class provides a number of useful implementations of the {@link Predicate}
* interface, designed for use when navigating streams of XDM items.
*/
public class Predicates {
/**
* A predicate to test whether an item is a node
* @return a predicate that returns true if given an item that is a node
*/
public static Predicate isNode() {
return item -> item instanceof XdmNode;
}
/**
* A predicate to test whether an item is an element node
* @return a predicate that returns true if given an item that is an element node
*/
public static Predicate isElement() {
return nodeKindPredicate(XdmNodeKind.ELEMENT);
}
/**
* A predicate to test whether an item is an attribute node
* @return a predicate that returns true if given an item that is an attribute node
*/
public static Predicate isAttribute() {
return nodeKindPredicate(XdmNodeKind.ATTRIBUTE);
}
/**
* A predicate to test whether an item is a text node
* @return a predicate that returns true if given an item that is a text node
*/
public static Predicate isText() {
return nodeKindPredicate(XdmNodeKind.TEXT);
}
/**
* A predicate to test whether an item is a comment node
* @return a predicate that returns true if given an item that is a comment node
*/
public static Predicate isComment() {
return nodeKindPredicate(XdmNodeKind.COMMENT);
}
/**
* A predicate to test whether an item is a processing instruction node
* @return a predicate that returns true if given an item that is a processing instruction node
*/
public static Predicate isProcessingInstruction() {
return nodeKindPredicate(XdmNodeKind.PROCESSING_INSTRUCTION);
}
/**
* A predicate to test whether an item is a document node
* @return a predicate that returns true if given an item that is a document node
*/
public static Predicate isDocument() {
return nodeKindPredicate(XdmNodeKind.DOCUMENT);
}
/**
* A predicate to test whether an item is a namespace node
* @return a predicate that returns true if given an item that is a namespace node
*/
public static Predicate isNamespace() {
return nodeKindPredicate(XdmNodeKind.NAMESPACE);
}
/**
* A predicate to test whether an item is an atomic value
* Note: to test for a specific type of atomic value, use a predicate such as
* {@code hasType(ItemType.XS_INTEGER)}
* @return a predicate that returns true if given an item that is an atomic value.
*/
public static Predicate isAtomic() {
return item -> item instanceof XdmAtomicValue;
}
/**
* A predicate to test whether an item is a function value (this includes maps and arrays)
* @return a predicate that returns true if given an item that is a function, including
* maps and arrays
*/
public static Predicate isFunction() {
return item -> item instanceof XdmFunctionItem;
}
/**
* A predicate to test whether an item is an XDM map
* @return a predicate that returns true if given an item that is a map
*/
public static Predicate isMap() {
return item -> item instanceof XdmMap;
}
/**
* A predicate to test whether an item is an XDM array
* @return a predicate that returns true if given an item that is an array
*/
public static Predicate isArray() {
return item -> item instanceof XdmArray;
}
/**
* Obtain a predicate that tests whether a supplied {@link Step} delivers an empty result
*
* @param step a step to be applied to the item being tested
* @param the type of items returned by the step
* @return a predicate that returns true if the supplied step returns an empty result.
* For example {@code empty(attribute("id")} is a predicate that returns true for a node that
* has no "id" attribute. Similarly {@code CHILD.where(empty(child(IS_ELEMENT)))} is a step
* that selects child elements having no element children.
*/
public static Predicate empty(Step step) {
//noinspection SimplifyOptionalCallChains
return item -> !step.apply(item).findFirst().isPresent();
}
/**
* Return a {@link Predicate} that is the negation of a supplied {@link Predicate}
*
* @param condition the supplied predicate
* @param The type of object to which the predicate is applicable
* @return a Predicate that matches an item if and only if the supplied Predicate does
* not match the item.
*/
public static Predicate not(Predicate condition) {
return condition.negate();
}
/**
* Obtain a predicate that tests whether a supplied Step delivers a non-empty result
*
* @param step a step to be applied to the item being tested
* @param the type of items returned by the step
* @return a predicate that returns true if the
* step returns a non-empty result. For example {@code exists(attribute("id")} is a
* predicate that returns true for a node that has an "id" attribute. So
* {@code CHILD.where(exists(attribute("id"))} is a step that selects child elements
* having an "id" attribute.
*/
public static Predicate exists(Step step) {
return item -> step.apply(item).findFirst().isPresent();
}
/**
* Obtain a predicate that tests whether an item is a node with a given namespace URI and local name
*
* @param uri the required namespace URI: supply a zero-length string to indicate the null namespace
* @param localName the required local name
* @return a predicate that returns true if and only if the supplied item is a node with the given
* namespace URI and local name
*/
public static Predicate super XdmNode> hasName(String uri, String localName) {
NamespaceUri nsUri = NamespaceUri.of(uri);
return item -> {
QName name = item.getNodeName();
return name != null &&
name.getLocalName().equals(localName) &&
name.getNamespaceUri().equals(nsUri);
};
}
/**
* Obtain a predicate that tests whether an item is a node with a given local name,
* irrespective of the namespace
*
* @param localName the required local name. If a zero-length string is supplied, the predicate
* will match nodes having no name (for example, comments and text nodes)
* @return a predicate that returns true if and only if the supplied item is a node with the given
* local name, irrespective of the namespace
*/
public static Predicate hasLocalName(String localName) {
Objects.requireNonNull(localName);
if (localName.isEmpty()) {
return item -> item.getNodeName() == null;
}
return item -> {
QName name = item.getNodeName();
return name != null &&
name.getLocalName().equals(localName);
};
}
/**
* Obtain a predicate that tests whether an item is a node with a given namespace URI
*
* @param uri the required namespace URI: supply a zero-length string to identify the null namespace
* @return a predicate that returns true if and only if the supplied item is a node with the given
* namespace URI. If a zero-length string is supplied, the predicate will also match nodes having no name,
* such as text and comment nodes, and nodes having a local name only, such as namespace and processing-instruction
* nodes.
*/
public static Predicate hasNamespace(String uri) {
NamespaceUri nsUri = NamespaceUri.of(uri);
return item -> {
QName name = item.getNodeName();
return name != null &&
name.getNamespaceUri().equals(nsUri);
};
}
/**
* Obtain a predicate that tests whether an item is an element node with a given attribute (whose
* name is in no namespace)
*
* @param local the required attribute name
* @return a predicate that returns true if and only if the supplied item is an element having an attribute
* with the given local name, in no namespace
*/
public static Predicate hasAttribute(String local) {
return item -> item.attribute(local) != null;
}
/**
* Obtain a predicate that tests whether an item is an element node with a given attribute (whose
* name is in no namespace) whose string value is equal to a given value
*
* @param local the required attribute name
* @param value the required attribute value
* @return a predicate that returns true if and only if the supplied item is an element having an attribute
* with the given local name, in no namespace, whose string value is equal to the given value
*/
public static Predicate attributeEq(String local, String value) {
return item -> value.equals(item.attribute(local));
}
/**
* Obtain a predicate that tests whether an item matches a given item type
*
* @param type the required item type
* @return a predicate that returns true if and only if the supplied item matches the supplied
* item type. For example, {@code hasType(ItemType.DATE_TIME)} matches atomic values of type
* xs:dateTime
.
*/
public static Predicate hasType(ItemType type) {
return type::matches;
}
/**
* Obtain a predicate that tests whether there is some item in the result of applying a step that
* satisfies the supplied condition.
* For example, {@code some(CHILD, exists(attribute("foo"))} matches an element if it has a child
* element with an attribute whose local name is "foo".
* If the step returns an empty sequence the result will always be false.
*
* @param step the step to be evaluated
* @param the type of items returned by the step
* @param condition the predicate to be applied to the items returned by the step
* @return a predicate that is true if at least one item selected by the step matches the supplied condition
*/
public static Predicate some(Step step, Predicate super T> condition) {
return item -> step.apply(item).anyMatch(condition);
}
/**
* Obtain a predicate that tests whether every item in the result of applying a step
* satisfies the supplied condition.
* For example, {@code every(CHILD, exists(attribute("foo"))} matches an element if each of its child
* elements has an attribute whose local name is "foo".
* If the step returns an empty sequence the result will always be true.
*
* @param step the step to be evaluated
* @param the type of items returned by the step
* @param condition the predicate to be applied to the items returned by the step
* @return a predicate that is true if every item selected by the step matches the supplied condition
*/
public static Predicate every(Step step, Predicate super XdmItem> condition) {
return item -> step.apply(item).allMatch(condition);
}
/**
* Obtain a predicate that tests whether an atomic value compares equal to a supplied atomic value of
* a comparable type
*
* @param value the atomic value to be compared with
* @return a Predicate which returns true when applied to a value that is equal to the supplied
* value under the "is-same-key" comparison rules. (These are the rules used to compare key values
* in an XDM map. The rules are chosen to be context-free, error-free, and transitive.)
*/
public static Predicate eq(XdmAtomicValue value) {
AtomicMatchKey k2 = value.getUnderlyingValue().asMapKey();
return item -> item.getUnderlyingValue().asMapKey().equals(k2);
}
/**
* Obtain a predicate that tests whether the result of applying the XPath string() function to an item
* is equal to a given string
*
* @param value the string being tested
* @return a Predicate which returns true if the string value of the item being tested
* is equal to the given string under Java comparison rules for comparing strings.
*/
public static Predicate eq(String value) {
return item -> item.getStringValue().equals(value);
}
/**
* Obtain a predicate that tests whether the result of applying the XPath string() function to an item
* matches a given regular expression
*
* @param regex the regular expression (this is a Java regular expression, not an XPath regular expression)
* @return a Predicate which returns true if the string value of the item being tested
* contains a substring that matches the given regular expression. To test the string in its entirety,
* use anchors "^" and "$" in the regular expression.
*/
public static Predicate matchesRegex(String regex) {
Pattern re = Pattern.compile(regex);
return item -> re.matcher(item.getStringValue()).find();
}
/**
* Obtain a predicate that tests whether there is some item in the result of applying a step,
* whose string value is equal to a given string.
* For example, {@code eq(attribute("id"), "foo")} matches an element if it has an "id"
* attribute whose value is "foo".
*
* @param step the step to be evaluated
* @param value the string to be compared against the items returned by the step
* @param the type of items to which the step applies
* @return a Predicate which returns true if some item selected by the step has as string value
* equal to the given string
*/
public static Predicate eq(Step step, String value) {
return some(step, eq(value));
}
private static Predicate nodeKindPredicate(XdmNodeKind kind) {
return item -> item instanceof XdmNode && ((XdmNode) item).getNodeKind() == kind;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy