net.sf.saxon.s9api.streams.Step Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of Saxon-HE Show documentation
Show all versions of Saxon-HE Show documentation
The XSLT and XQuery Processor
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 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.s9api.XdmItem;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Stream;
/**
* A {@code Step} is a function that can be applied to an item
* to return a stream of items.
* @param the type of {@link XdmItem} that is returned by the step. (Note that we
* don't parameterize Steps by the type of input item).
* @see Steps
*/
public abstract class Step
implements Function> {
/**
* Obtain a {@link Step} that filters the results of this Step using a supplied predicate.
* For example, {@code CHILD.where(isText())} returns a Step whose effect is
* to select the text node children of a supplied element or document node.
* @param predicate the predicate which will be applied to the results of this step
* @return a new Step (that is, a function from one Stream of items to another) that
* filters the results of this step by selecting only the items that satisfy the predicate.
*/
public Step where(Predicate super T> predicate) {
Step base = this;
return new Step() {
@Override
public Stream extends T> apply(XdmItem item) {
return base.apply(item).filter(predicate);
}
};
}
/**
* Obtain a {@link Step} that concatenates the results of this Step with the result of another
* Step applied to the same input item.
* For example, {@code attribute().cat(child())} returns a step whose effect is
* to select the attributes of a supplied element followed by its children.
*
* @param other the step whose results will be concatenated with the results of this step
* @return a new Step (that is, a function from one Stream of items to another) that
* concatenates the results of applying this step to the input item, followed by the
* results of applying the other step to the input item.
*/
public Step cat(Step other) {
Step base = this;
return new Step() {
@Override
public Stream apply(XdmItem item) {
return Stream.concat(base.apply(item), other.apply(item));
}
};
}
/**
* Obtain a step that selects the first item in the results of this step
*
* @return a new Step (that is, a function from one Stream of items to another) that
* filters the results of this step by selecting only the first item.
*/
public Step first() {
final Step base = this;
return new Step() {
@Override
public Stream extends T> apply(XdmItem item) {
return base.apply(item).limit(1);
}
};
}
/**
* Obtain a step that selects the last item in the results of this step
*
* @return a new Step (that is, a function from one Stream of items to another) that
* filters the results of this step by selecting only the last item.
*/
public Step last() {
final Step base = this;
return new Step() {
@Override
public Stream extends T> apply(XdmItem item) {
return base.apply(item).reduce((first, second) -> second)
.map(Stream::of).orElseGet(Stream::empty);
}
};
}
/**
* Obtain a step that selects the Nth item in the results of this step
*
* @param index the zero-based index of the item to be selected
* @return a new Step (that is, a function from one Stream of items to another) that
* filters the results of this step by selecting only the items that satisfy the predicate.
*/
public Step at(long index) {
final Step base = this;
return new Step() {
@Override
public Stream extends T> apply(XdmItem item) {
return base.apply(item).skip(index).limit(1);
}
};
}
/**
* Obtain a step that combines the results of this step with the results of another step
*
* @param next the step which will be applied to the results of this step
* @param the static type of the result of the step
* @return a new Step (that is, a function from one Stream of items to another) that
* performs this step and the next step in turn. The result is equivalent to the Java {code flatMap()}
* function or the XPath {code !} operator: there is no sorting of nodes into document order, and
* no elimination of duplicates.
*/
public Step then(Step next) {
Step me = this;
return new Step() {
@Override
public Stream extends U> apply(XdmItem item) {
return me.apply(item).flatMap(next);
}
};
}
}