in processing/src/main/java/org/apache/druid/segment/nested/NestedPathFinder.java [230:328]
public static List<NestedPathPart> parseJqPath(@Nullable String path)
{
if (path == null || path.isEmpty()) {
return Collections.emptyList();
}
List<NestedPathPart> parts = new ArrayList<>();
if (path.charAt(0) != '.') {
badFormat(path, "it must start with '.'");
}
int partMark = -1; // position to start the next substring to build the path part
int dotMark = -1; // last position where a '.' character was encountered, indicating the start of a new part
int arrayMark = -1; // position of leading '[' indicating start of array (or field name if '"' immediately follows)
int quoteMark = -1; // position of leading '"', indicating a quoted field name
for (int i = 0; i < path.length(); i++) {
final char current = path.charAt(i);
if (current == '.' && arrayMark < 0 && quoteMark < 0) {
if (dotMark >= 0) {
parts.add(new NestedPathField(getPathSubstring(path, partMark, i)));
}
dotMark = i;
partMark = i + 1;
} else if (current == '?' && quoteMark < 0) {
// eat optional marker
if (partMark != i) {
if (dotMark >= 0) {
parts.add(new NestedPathField(getPathSubstring(path, partMark, i)));
dotMark = -1;
} else {
badFormat(path, "found '?' at invalid position [%s]", i);
}
}
partMark = i + 1;
} else if (current == '[' && arrayMark < 0 && quoteMark < 0) {
if (dotMark == (i - 1) && dotMark != 0) {
badFormat(path, "found '[' at invalid position [%s], must not follow '.' or must be contained with '\"'", i);
}
if (dotMark >= 0 && i > 1) {
parts.add(new NestedPathField(getPathSubstring(path, partMark, i)));
dotMark = -1;
}
arrayMark = i;
partMark = i + 1;
} else if (current == ']' && arrayMark >= 0 && quoteMark < 0) {
String maybeNumber = getPathSubstring(path, partMark, i);
try {
int index = Integer.parseInt(maybeNumber);
parts.add(new NestedPathArrayElement(index));
dotMark = -1;
arrayMark = -1;
partMark = i + 1;
}
catch (NumberFormatException ignored) {
badFormat(path, "array specifier [%s] should be a number, it was not. Use \"\" if this value was meant to be a field name", maybeNumber);
}
} else if (dotMark == -1 && arrayMark == -1) {
badFormat(path, "path parts must be separated with '.'");
} else if (current == '"' && quoteMark < 0) {
if (partMark != i) {
badFormat(path, "found '\"' at invalid position [%s], it must immediately follow '.' or '['", i);
}
if (arrayMark > 0 && arrayMark != i - 1) {
badFormat(path, "'\"' within '[', must be immediately after");
}
quoteMark = i;
partMark = i + 1;
} else if (current == '"' && quoteMark >= 0 && path.charAt(i - 1) != '\\') {
parts.add(new NestedPathField(getPathSubstring(path, partMark, i)));
dotMark = -1;
quoteMark = -1;
if (arrayMark > 0) {
// chomp to next char to eat closing array
if (++i == path.length()) {
break;
}
if (path.charAt(i) != ']') {
badFormat(path, "closing '\"' must immediately precede ']'");
}
partMark = i + 1;
arrayMark = -1;
} else {
partMark = i + 1;
}
}
}
// add the last element, this should never be an array because they close themselves
if (partMark < path.length()) {
if (quoteMark != -1) {
badFormat(path, "unterminated '\"'");
}
if (arrayMark != -1) {
badFormat(path, "unterminated '['");
}
parts.add(new NestedPathField(path.substring(partMark)));
}
return parts;
}