cdc.io.data.paths.SPath Maven / Gradle / Ivy
package cdc.io.data.paths;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;
import cdc.io.data.Element;
import cdc.io.data.Parent;
import cdc.util.lang.Checks;
import cdc.util.lang.CollectionUtils;
/**
* Simple path.
*
* It must have the form: {@code (part/)*part} or {@code (part(/part)*)?@part}
*
* @author Damien Carbonne
*
*/
public final class SPath {
private final List parts;
private final boolean isAttribute;
public SPath(String text) {
// Index of the attribute separator
final int index = text.lastIndexOf('@');
this.isAttribute = index >= 0;
final String[] tmp;
if (index == 0) {
// Only an attribute
tmp = new String[0];
} else if (index > 0) {
// Elements and attribute
tmp = text.substring(0, index).split("/");
} else {
// No attribute
tmp = text.split("/");
}
final List l = CollectionUtils.toList(tmp);
if (isAttribute) {
final String last = text.substring(index + 1);
Checks.isFalse(last.contains("/"), "An attribute name can not contain '/'");
l.add(last);
}
this.parts = Collections.unmodifiableList(l);
}
public List getParts() {
return parts;
}
public boolean isAttribute() {
return isAttribute;
}
public boolean isElement() {
return !isAttribute;
}
@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
final int size = parts.size();
for (int index = 0; index < size; index++) {
if (index > 0) {
if (index == size - 1 && isAttribute) {
builder.append('@');
} else {
builder.append('/');
}
}
builder.append(parts.get(index));
}
return builder.toString();
}
private boolean matches(Parent parent,
String name,
boolean attribute) {
// System.out.println(this + ".matches(" + (parent == null ? "null" : parent.getQName()) + ", " + name + ") " + getParts());
if (attribute != isAttribute || parts.isEmpty()) {
// System.out.println("1");
return false;
} else {
if (Objects.equals(name, parts.get(parts.size() - 1))) {
// System.out.println("Last part match");
Parent p = parent;
for (int index = parts.size() - 2; index >= 0; index--) {
// System.out.println("Check: " + p.getQName());
if (p instanceof Element) {
final Element e = (Element) p;
if (e.getName().equals(parts.get(index))) {
// System.out.println("part match: " + e.getName());
p = e.getParent();
} else {
return false;
}
} else {
return false;
}
}
return true;
} else {
// System.out.println("2");
return false;
}
}
}
public boolean matchesElement(Parent parent) {
if (parent instanceof Element) {
final Element element = (Element) parent;
return matchesElement(element.getParent(), element.getName());
} else {
return false;
}
}
/**
* Returns {@code true} if this SPath matches an element.
*
* @param parent The parent element.
* @param name The name of the child element.
* @return {@code true} if this SPath matches {@code child} under {@code parent}.
*/
public boolean matchesElement(Parent parent,
String name) {
return matches(parent, name, false);
}
/**
* Returns {@code true} if this SPath matches an attribute in an element.
*
* @param parent The element.
* @param name The attribute name.
* @return {@code true} if this SPath matches an attribute named {@code name} in {@code parent}.
*/
public boolean matchesAttribute(Element parent,
String name) {
return matches(parent, name, true);
}
public static Predicate toStandardPredicate(Collection paths) {
Checks.isNotNull(paths, "paths");
return (Element element) -> {
for (final SPath path : paths) {
if (path.matchesElement(element)) {
return true;
}
}
return false;
};
}
@Override
public int hashCode() {
return toString().hashCode();
}
@Override
public boolean equals(Object object) {
if (this == object) {
return true;
}
if (!(object instanceof SPath)) {
return false;
}
final SPath other = (SPath) object;
return this.isAttribute == other.isAttribute
&& this.parts.equals(other.parts);
}
}