Skip to content

Instantly share code, notes, and snippets.

@kysnm
Created August 24, 2016 08:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kysnm/ba3cc5783a860bdc53ba20b0c2e63cc2 to your computer and use it in GitHub Desktop.
Save kysnm/ba3cc5783a860bdc53ba20b0c2e63cc2 to your computer and use it in GitHub Desktop.
Only in ./json-path/src/main/java/com/jayway/jsonpath/internal/path/: ArrayIndexOperation.java
diff -u ./json-path/src/main/java/com/jayway/jsonpath/internal/path/ArrayPathToken.java ~/src/sonots/embulk-filter-column/src/main/java/org/embulk/filter/column/path/ArrayPathToken.java
--- ./json-path/src/main/java/com/jayway/jsonpath/internal/path/ArrayPathToken.java 2016-08-03 17:14:02.000000000 +0900
+++ ~/src/sonots/embulk-filter-column/src/main/java/org/embulk/filter/column/path/ArrayPathToken.java 2016-08-24 14:33:21.000000000 +0900
@@ -1,189 +1,24 @@
-/*
- * Copyright 2011 the original author or authors.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.jayway.jsonpath.internal.path;
+package org.embulk.filter.column.path;
-import com.jayway.jsonpath.InvalidPathException;
-import com.jayway.jsonpath.PathNotFoundException;
-import com.jayway.jsonpath.internal.PathRef;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+public class ArrayPathToken extends PathToken
+{
+ private final Integer index;
-import static java.lang.String.format;
-
-/**
- *
- */
-public class ArrayPathToken extends PathToken {
-
- private static final Logger logger = LoggerFactory.getLogger(ArrayPathToken.class);
-
- private final ArraySliceOperation arraySliceOperation;
- private final ArrayIndexOperation arrayIndexOperation;
-
- ArrayPathToken(final ArraySliceOperation arraySliceOperation) {
- this.arraySliceOperation = arraySliceOperation;
- this.arrayIndexOperation = null;
+ public ArrayPathToken(Integer index)
+ {
+ this.index = index;
}
- ArrayPathToken(final ArrayIndexOperation arrayIndexOperation) {
- this.arrayIndexOperation = arrayIndexOperation;
- this.arraySliceOperation = null;
- }
+ public Integer index() { return index; }
@Override
- public void evaluate(String currentPath, PathRef parent, Object model, EvaluationContextImpl ctx) {
- if (! checkArrayModel(currentPath, model, ctx))
- return;
- if(arraySliceOperation != null){
- evaluateSliceOperation(currentPath, parent, model, ctx);
- } else {
- evaluateIndexOperation(currentPath, parent, model, ctx);
- }
-
- }
-
- public void evaluateIndexOperation(String currentPath, PathRef parent, Object model, EvaluationContextImpl ctx) {
-
- if (! checkArrayModel(currentPath, model, ctx))
- return;
-
- if(arrayIndexOperation.isSingleIndexOperation()){
- handleArrayIndex(arrayIndexOperation.indexes().get(0), currentPath, model, ctx);
- } else {
- for (Integer index : arrayIndexOperation.indexes()) {
- handleArrayIndex(index, currentPath, model, ctx);
- }
- }
- }
-
- public void evaluateSliceOperation(String currentPath, PathRef parent, Object model, EvaluationContextImpl ctx) {
-
- if (! checkArrayModel(currentPath, model, ctx))
- return;
-
- switch (arraySliceOperation.operation()) {
- case SLICE_FROM:
- sliceFrom(arraySliceOperation, currentPath, parent, model, ctx);
- break;
- case SLICE_BETWEEN:
- sliceBetween(arraySliceOperation, currentPath, parent, model, ctx);
- break;
- case SLICE_TO:
- sliceTo(arraySliceOperation, currentPath, parent, model, ctx);
- break;
- }
- }
-
- public void sliceFrom(ArraySliceOperation operation, String currentPath, PathRef parent, Object model, EvaluationContextImpl ctx) {
- int length = ctx.jsonProvider().length(model);
- int from = operation.from();
- if (from < 0) {
- //calculate slice start from array length
- from = length + from;
- }
- from = Math.max(0, from);
-
- logger.debug("Slice from index on array with length: {}. From index: {} to: {}. Input: {}", length, from, length - 1, toString());
-
- if (length == 0 || from >= length) {
- return;
- }
- for (int i = from; i < length; i++) {
- handleArrayIndex(i, currentPath, model, ctx);
- }
- }
-
- public void sliceBetween(ArraySliceOperation operation, String currentPath, PathRef parent, Object model, EvaluationContextImpl ctx) {
- int length = ctx.jsonProvider().length(model);
- int from = operation.from();
- int to = operation.to();
-
- to = Math.min(length, to);
-
- if (from >= to || length == 0) {
- return;
- }
-
- logger.debug("Slice between indexes on array with length: {}. From index: {} to: {}. Input: {}", length, from, to, toString());
-
- for (int i = from; i < to; i++) {
- handleArrayIndex(i, currentPath, model, ctx);
- }
- }
-
- public void sliceTo(ArraySliceOperation operation, String currentPath, PathRef parent, Object model, EvaluationContextImpl ctx) {
- int length = ctx.jsonProvider().length(model);
- if (length == 0) {
- return;
- }
- int to = operation.to();
- if (to < 0) {
- //calculate slice end from array length
- to = length + to;
- }
- to = Math.min(length, to);
-
- logger.debug("Slice to index on array with length: {}. From index: 0 to: {}. Input: {}", length, to, toString());
-
- for (int i = 0; i < to; i++) {
- handleArrayIndex(i, currentPath, model, ctx);
- }
- }
-
- @Override
- public String getPathFragment() {
- if(arrayIndexOperation != null){
- return arrayIndexOperation.toString();
- } else {
- return arraySliceOperation.toString();
- }
- }
-
- @Override
- public boolean isTokenDefinite() {
- if(arrayIndexOperation != null){
- return arrayIndexOperation.isSingleIndexOperation();
- } else {
- return false;
- }
- }
+ public String getPathFragment()
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.append("[");
+ sb.append(index);
+ sb.append("]");
- /**
- * Check if model is non-null and array.
- * @param currentPath
- * @param model
- * @param ctx
- * @return false if current evaluation call must be skipped, true otherwise
- * @throws PathNotFoundException if model is null and evaluation must be interrupted
- * @throws InvalidPathException if model is not an array and evaluation must be interrupted
- */
- protected boolean checkArrayModel(String currentPath, Object model, EvaluationContextImpl ctx) {
- if (model == null){
- if (! isUpstreamDefinite()) {
- return false;
- } else {
- throw new PathNotFoundException("The path " + currentPath + " is null");
- }
- }
- if (!ctx.jsonProvider().isArray(model)) {
- if (! isUpstreamDefinite()) {
- return false;
- } else {
- throw new PathNotFoundException(format("Filter: %s can only be applied to arrays. Current context is: %s", toString(), model));
- }
- }
- return true;
+ return sb.toString();
}
}
Only in ./json-path/src/main/java/com/jayway/jsonpath/internal/path/: ArraySliceOperation.java
Only in ~/src/sonots/embulk-filter-column/src/main/java/org/embulk/filter/column/path/: CharacterIndex.java
diff -u ./json-path/src/main/java/com/jayway/jsonpath/internal/path/CompiledPath.java ~/src/sonots/embulk-filter-column/src/main/java/org/embulk/filter/column/path/CompiledPath.java
--- ./json-path/src/main/java/com/jayway/jsonpath/internal/path/CompiledPath.java 2016-08-03 17:14:02.000000000 +0900
+++ ~/src/sonots/embulk-filter-column/src/main/java/org/embulk/filter/column/path/CompiledPath.java 2016-08-24 14:33:21.000000000 +0900
@@ -1,78 +1,68 @@
-/*
- * Copyright 2011 the original author or authors.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.jayway.jsonpath.internal.path;
-
-import com.jayway.jsonpath.Configuration;
-import com.jayway.jsonpath.internal.EvaluationAbortException;
-import com.jayway.jsonpath.internal.EvaluationContext;
-import com.jayway.jsonpath.internal.Path;
-import com.jayway.jsonpath.internal.PathRef;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class CompiledPath implements Path {
-
- private static final Logger logger = LoggerFactory.getLogger(CompiledPath.class);
-
- private final RootPathToken root;
-
- private final boolean isRootPath;
-
-
- public CompiledPath(RootPathToken root, boolean isRootPath) {
- this.root = root;
- this.isRootPath = isRootPath;
- }
+package org.embulk.filter.column.path;
- @Override
- public boolean isRootPath() {
- return isRootPath;
- }
+import org.apache.commons.lang3.StringUtils;
- @Override
- public EvaluationContext evaluate(Object document, Object rootDocument, Configuration configuration, boolean forUpdate) {
- if (logger.isDebugEnabled()) {
- logger.debug("Evaluating path: {}", toString());
- }
+// rename from RootPathToken
+public class CompiledPath extends PathToken
+{
- EvaluationContextImpl ctx = new EvaluationContextImpl(this, rootDocument, configuration, forUpdate);
- try {
- PathRef op = ctx.forUpdate() ? PathRef.createRoot(rootDocument) : PathRef.NO_OP;
- root.evaluate("", op, document, ctx);
- } catch (EvaluationAbortException abort){};
+ private PathToken tail;
+ private int tokenCount;
+ private final String rootToken;
- return ctx;
- }
- @Override
- public EvaluationContext evaluate(Object document, Object rootDocument, Configuration configuration){
- return evaluate(document, rootDocument, configuration, false);
+ CompiledPath(char rootToken)
+ {
+ this.rootToken = Character.toString(rootToken);
+ ;
+ this.tail = this;
+ this.tokenCount = 1;
}
- @Override
- public boolean isDefinite() {
- return root.isPathDefinite();
+ public PathToken getTail() { return tail; }
+
+ public String getTailPath() { return tail.toString(); }
+
+ public int getTokenCount() { return tokenCount; }
+
+ public Long baseIndex()
+ {
+ if (tail instanceof ArrayPathToken) {
+ return ((ArrayPathToken) tail).index().longValue();
+ } else {
+ return null;
+ }
}
- @Override
- public boolean isFunctionPath() {
- return root.isFunctionPath();
+ public String getParentPath()
+ {
+ return StringUtils.removeEnd(this.toString(), tail.toString());
+ }
+
+ public CompiledPath append(PathToken next)
+ {
+ this.tail = tail.appendTailToken(next);
+ this.tokenCount++;
+ return this;
+ }
+
+ public PathTokenAppender getPathTokenAppender()
+ {
+ return new PathTokenAppender()
+ {
+ @Override
+ public PathTokenAppender appendPathToken(PathToken next)
+ {
+ append(next);
+ return this;
+ }
+ };
}
@Override
- public String toString() {
- return root.toString();
+ public String getPathFragment()
+ {
+ return rootToken;
}
+
}
Only in ./json-path/src/main/java/com/jayway/jsonpath/internal/path/: EvaluationContextImpl.java
Only in ./json-path/src/main/java/com/jayway/jsonpath/internal/path/: FunctionPathToken.java
Only in ~/src/sonots/embulk-filter-column/src/main/java/org/embulk/filter/column/path/: InvalidPathException.java
diff -u ./json-path/src/main/java/com/jayway/jsonpath/internal/path/PathCompiler.java ~/src/sonots/embulk-filter-column/src/main/java/org/embulk/filter/column/path/PathCompiler.java
--- ./json-path/src/main/java/com/jayway/jsonpath/internal/path/PathCompiler.java 2016-08-12 17:11:54.000000000 +0900
+++ ~/src/sonots/embulk-filter-column/src/main/java/org/embulk/filter/column/path/PathCompiler.java 2016-08-24 14:33:21.000000000 +0900
@@ -1,33 +1,32 @@
-package com.jayway.jsonpath.internal.path;
+package org.embulk.filter.column.path;
-import com.jayway.jsonpath.InvalidPathException;
-import com.jayway.jsonpath.Predicate;
-import com.jayway.jsonpath.internal.CharacterIndex;
-import com.jayway.jsonpath.internal.Path;
-import com.jayway.jsonpath.internal.Utils;
-import com.jayway.jsonpath.internal.filter.FilterCompiler;
-import com.jayway.jsonpath.internal.function.ParamType;
-import com.jayway.jsonpath.internal.function.Parameter;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.LinkedList;
-import java.util.List;
+/*
+ Porting from https://github.com/jayway/JsonPath
+ equivalent version 2.2.0, latest commit is c2c1686
+
+ dropped features
+ - Filter
+ - Placeholder
+ - Function
+ - multi properties (ex. $.json1['a','b'])
+ - ArrayIndexOperation (ex. $.json1[0,1])
+ - ArraySliceOperation (ex. $.json1[1:2] (start:end))
+ */
+
+import org.embulk.filter.column.ColumnFilterPlugin.ColumnConfig;
+
+import java.io.StringWriter;
import static java.lang.Character.isDigit;
-import static java.util.Arrays.asList;
-public class PathCompiler {
+public class PathCompiler
+{
+
private static final char DOC_CONTEXT = '$';
- private static final char EVAL_CONTEXT = '@';
private static final char OPEN_SQUARE_BRACKET = '[';
private static final char CLOSE_SQUARE_BRACKET = ']';
- private static final char OPEN_PARENTHESIS = '(';
- private static final char CLOSE_PARENTHESIS = ')';
- private static final char OPEN_BRACE = '{';
- private static final char CLOSE_BRACE = '}';
private static final char WILDCARD = '*';
private static final char PERIOD = '.';
@@ -35,51 +34,38 @@
private static final char TAB = '\t';
private static final char CR = '\r';
private static final char LF = '\r';
- private static final char BEGIN_FILTER = '?';
- private static final char COMMA = ',';
- private static final char SPLIT = ':';
private static final char MINUS = '-';
private static final char SINGLE_QUOTE = '\'';
private static final char DOUBLE_QUOTE = '"';
- private final LinkedList<Predicate> filterStack;
private final CharacterIndex path;
- private PathCompiler(String path, LinkedList<Predicate> filterStack) {
- this.filterStack = filterStack;
+ public static Boolean isJsonPathNotation(ColumnConfig config)
+ {
+ StringBuilder dotNotationRootPath = new StringBuilder(DOC_CONTEXT).append(PERIOD);
+ StringBuilder bracketNotationRootPath = new StringBuilder(DOC_CONTEXT).append(OPEN_SQUARE_BRACKET);
+ return config.getName().contains(dotNotationRootPath.toString()) || config.getName().contains(bracketNotationRootPath.toString());
+ }
+
+ private PathCompiler(String path)
+ {
this.path = new CharacterIndex(path);
}
- private Path compile() {
- RootPathToken root = readContextToken();
- return new CompiledPath(root, root.getPathFragment().equals("$"));
+ private CompiledPath compile()
+ {
+ CompiledPath root = readContextToken();
+ return root;
}
- public static Path compile(String path, final Predicate... filters) {
- try {
- path = path.trim();
- if(!(path.charAt(0) == DOC_CONTEXT) && !(path.charAt(0) == EVAL_CONTEXT)){
- path = "$." + path;
- }
- if(path.endsWith(".")){
- fail("Path must not end with a '.' or '..'");
- }
- LinkedList filterStack = new LinkedList<Predicate>(asList(filters));
- Path p = new PathCompiler(path.trim(), filterStack).compile();
- return p;
- } catch (Exception e) {
- InvalidPathException ipe;
- if (e instanceof InvalidPathException) {
- ipe = (InvalidPathException) e;
- } else {
- ipe = new InvalidPathException(e);
- }
- throw ipe;
- }
+ public static CompiledPath compile(String path)
+ {
+ return new PathCompiler(path).compile();
}
- private void readWhitespace() {
+ private void readWhitespace()
+ {
while (path.inBounds()) {
char c = path.currentChar();
if (!isWhitespace(c)) {
@@ -89,20 +75,27 @@
}
}
- private Boolean isPathContext(char c) {
- return (c == DOC_CONTEXT || c == EVAL_CONTEXT);
+ private boolean isWhitespace(char c)
+ {
+ return (c == SPACE || c == TAB || c == LF || c == CR);
+ }
+
+ private Boolean isDocContext(char c)
+ {
+ return c == DOC_CONTEXT;
}
- //[$ | @]
- private RootPathToken readContextToken() {
+ // $
+ private CompiledPath readContextToken()
+ {
readWhitespace();
- if (!isPathContext(path.currentChar())) {
- throw new InvalidPathException("Path must start with '$' or '@'");
+ if (!isDocContext(path.currentChar())) {
+ fail("Path must start with '$'");
}
- RootPathToken pathToken = PathTokenFactory.createRootPathToken(path.currentChar());
+ CompiledPath pathToken = PathTokenFactory.createRootPathToken(path.currentChar());
PathTokenAppender appender = pathToken.getPathTokenAppender();
if (path.currentIsTail()) {
@@ -111,7 +104,7 @@
path.incrementPosition(1);
- if(path.currentChar() != PERIOD && path.currentChar() != OPEN_SQUARE_BRACKET){
+ if (path.currentChar() != PERIOD && path.currentChar() != OPEN_SQUARE_BRACKET) {
fail("Illegal character at position " + path.position() + " expected '.' or '[");
}
@@ -123,7 +116,8 @@
//
//
//
- private boolean readNextToken(PathTokenAppender appender) {
+ private boolean readNextToken(PathTokenAppender appender)
+ {
char c = path.currentChar();
@@ -132,8 +126,6 @@
return readBracketPropertyToken(appender) ||
readArrayToken(appender) ||
readWildCardToken(appender) ||
- readFilterToken(appender) ||
- readPlaceholderToken(appender) ||
fail("Could not parse token starting at position " + path.position() + ". Expected ?, ', 0-9, * ");
case PERIOD:
return readDotToken(appender) ||
@@ -142,7 +134,7 @@
return readWildCardToken(appender) ||
fail("Could not parse token starting at position " + path.position());
default:
- return readPropertyOrFunctionToken(appender) ||
+ return readPropertyToken(appender) ||
fail("Could not parse token starting at position " + path.position());
}
}
@@ -150,16 +142,14 @@
//
// . and ..
//
- private boolean readDotToken(PathTokenAppender appender) {
- if (path.currentCharIs(PERIOD) && path.nextCharIs(PERIOD)) {
- appender.appendPathToken(PathTokenFactory.crateScanToken());
- path.incrementPosition(2);
- } else if (!path.hasMoreCharacters()) {
+ private boolean readDotToken(PathTokenAppender appender)
+ {
+ if (!path.hasMoreCharacters()) {
throw new InvalidPathException("Path must not end with a '.");
} else {
path.incrementPosition(1);
}
- if(path.currentCharIs(PERIOD)){
+ if (path.currentCharIs(PERIOD)) {
throw new InvalidPathException("Character '.' on position " + path.position() + " is not valid.");
}
return readNextToken(appender);
@@ -168,7 +158,8 @@
//
// fooBar or fooBar()
//
- private boolean readPropertyOrFunctionToken(PathTokenAppender appender) {
+ private boolean readPropertyToken(PathTokenAppender appender)
+ {
if (path.currentCharIs(OPEN_SQUARE_BRACKET) || path.currentCharIs(WILDCARD) || path.currentCharIs(PERIOD) || path.currentCharIs(SPACE)) {
return false;
}
@@ -176,297 +167,35 @@
int readPosition = startPosition;
int endPosition = 0;
- boolean isFunction = false;
-
while (path.inBounds(readPosition)) {
char c = path.charAt(readPosition);
if (c == SPACE) {
throw new InvalidPathException("Use bracket notion ['my prop'] if your property contains blank characters. position: " + path.position());
- }
- else if (c == PERIOD || c == OPEN_SQUARE_BRACKET) {
+ } else if (c == PERIOD || c == OPEN_SQUARE_BRACKET) {
endPosition = readPosition;
break;
}
- else if (c == OPEN_PARENTHESIS) {
- isFunction = true;
- endPosition = readPosition++;
- break;
- }
readPosition++;
}
if (endPosition == 0) {
endPosition = path.length();
}
-
- List<Parameter> functionParameters = null;
- if (isFunction) {
- if (path.inBounds(readPosition+1)) {
- // read the next token to determine if we have a simple no-args function call
- char c = path.charAt(readPosition + 1);
- if (c != CLOSE_PARENTHESIS) {
- path.setPosition(endPosition+1);
- // parse the arguments of the function - arguments that are inner queries or JSON document(s)
- String functionName = path.subSequence(startPosition, endPosition).toString();
- functionParameters = parseFunctionParameters(functionName);
- } else {
- path.setPosition(readPosition + 1);
- }
- }
- else {
- path.setPosition(readPosition);
- }
- }
- else {
- path.setPosition(endPosition);
- }
+ path.setPosition(endPosition);
String property = path.subSequence(startPosition, endPosition).toString();
- if(isFunction){
- appender.appendPathToken(PathTokenFactory.createFunctionPathToken(property, functionParameters));
- } else {
- appender.appendPathToken(PathTokenFactory.createSinglePropertyPathToken(property, SINGLE_QUOTE));
- }
-
- return path.currentIsTail() || readNextToken(appender);
- }
- /**
- * Parse the parameters of a function call, either the caller has supplied JSON data, or the caller has supplied
- * another path expression which must be evaluated and in turn invoked against the root document. In this tokenizer
- * we're only concerned with parsing the path thus the output of this function is a list of parameters with the Path
- * set if the parameter is an expression. If the parameter is a JSON document then the value of the cachedValue is
- * set on the object.
- *
- * Sequence for parsing out the parameters:
- *
- * This code has its own tokenizer - it does some rudimentary level of lexing in that it can distinguish between JSON block parameters
- * and sub-JSON blocks - it effectively regex's out the parameters into string blocks that can then be passed along to the appropriate parser.
- * Since sub-jsonpath expressions can themselves contain other function calls this routine needs to be sensitive to token counting to
- * determine the boundaries. Since the Path parser isn't aware of JSON processing this uber routine is needed.
- *
- * Parameters are separated by COMMAs ','
- *
- * <pre>
- * doc = {"numbers": [1,2,3,4,5,6,7,8,9,10]}
- *
- * $.sum({10}, $.numbers.avg())
- * </pre>
- *
- * The above is a valid function call, we're first summing 10 + avg of 1...10 (5.5) so the total should be 15.5
- *
- * @return
- * An ordered list of parameters that are to processed via the function. Typically functions either process
- * an array of values and/or can consume parameters in addition to the values provided from the consumption of
- * an array.
- */
- private List<Parameter> parseFunctionParameters(String funcName) {
- PathToken currentToken;
- ParamType type = null;
-
- // Parenthesis starts at 1 since we're marking the start of a function call, the close paren will denote the
- // last parameter boundary
- Integer groupParen = 1, groupBracket = 0, groupBrace = 0, groupQuote = 0;
- Boolean endOfStream = false;
- char priorChar = 0;
- List<Parameter> parameters = new ArrayList<Parameter>();
- StringBuffer parameter = new StringBuffer();
- while (path.inBounds() && !endOfStream) {
- char c = path.currentChar();
- path.incrementPosition(1);
-
- // we're at the start of the stream, and don't know what type of parameter we have
- if (type == null) {
- if (isWhitespace(c)) {
- continue;
- }
-
- if (c == OPEN_BRACE || isDigit(c) || DOUBLE_QUOTE == c) {
- type = ParamType.JSON;
- }
- else if (isPathContext(c)) {
- type = ParamType.PATH; // read until we reach a terminating comma and we've reset grouping to zero
- }
- }
-
- switch (c) {
- case DOUBLE_QUOTE:
- if (priorChar != '\\' && groupQuote > 0) {
- if (groupQuote == 0) {
- throw new InvalidPathException("Unexpected quote '\"' at character position: " + path.position());
- }
- groupQuote--;
- }
- else {
- groupQuote++;
- }
- break;
- case OPEN_PARENTHESIS:
- groupParen++;
- break;
- case OPEN_BRACE:
- groupBrace++;
- break;
- case OPEN_SQUARE_BRACKET:
- groupBracket++;
- break;
-
- case CLOSE_BRACE:
- if (0 == groupBrace) {
- throw new InvalidPathException("Unexpected close brace '}' at character position: " + path.position());
- }
- groupBrace--;
- break;
- case CLOSE_SQUARE_BRACKET:
- if (0 == groupBracket) {
- throw new InvalidPathException("Unexpected close bracket ']' at character position: " + path.position());
- }
- groupBracket--;
- break;
-
- // In either the close paren case where we have zero paren groups left, capture the parameter, or where
- // we've encountered a COMMA do the same
- case CLOSE_PARENTHESIS:
- groupParen--;
- if (0 != groupParen) {
- parameter.append(c);
- }
- case COMMA:
- // In this state we've reach the end of a function parameter and we can pass along the parameter string
- // to the parser
- if ((0 == groupQuote && 0 == groupBrace && 0 == groupBracket
- && ((0 == groupParen && CLOSE_PARENTHESIS == c) || 1 == groupParen))) {
- endOfStream = (0 == groupParen);
-
- if (null != type) {
- Parameter param = null;
- switch (type) {
- case JSON:
- // parse the json and set the value
- param = new Parameter(parameter.toString());
- break;
- case PATH:
- LinkedList<Predicate> predicates = new LinkedList<Predicate>();
- PathCompiler compiler = new PathCompiler(parameter.toString(), predicates);
- param = new Parameter(compiler.compile());
- break;
- }
- if (null != param) {
- parameters.add(param);
- }
- parameter.delete(0, parameter.length());
- type = null;
- }
- }
- break;
- }
-
- if (type != null && !(c == COMMA && 0 == groupBrace && 0 == groupBracket && 1 == groupParen)) {
- parameter.append(c);
- }
- priorChar = c;
- }
- if (0 != groupBrace || 0 != groupParen || 0 != groupBracket) {
- throw new InvalidPathException("Arguments to function: '" + funcName + "' are not closed properly.");
- }
- return parameters;
- }
-
- private boolean isWhitespace(char c) {
- return (c == SPACE || c == TAB || c == LF || c == CR);
- }
-
- //
- // [?], [?,?, ..]
- //
- private boolean readPlaceholderToken(PathTokenAppender appender) {
-
- if (!path.currentCharIs(OPEN_SQUARE_BRACKET)) {
- return false;
- }
- int questionmarkIndex = path.indexOfNextSignificantChar(BEGIN_FILTER);
- if (questionmarkIndex == -1) {
- return false;
- }
- char nextSignificantChar = path.nextSignificantChar(questionmarkIndex);
- if (nextSignificantChar != CLOSE_SQUARE_BRACKET && nextSignificantChar != COMMA) {
- return false;
- }
-
- int expressionBeginIndex = path.position() + 1;
- int expressionEndIndex = path.nextIndexOf(expressionBeginIndex, CLOSE_SQUARE_BRACKET);
-
- if (expressionEndIndex == -1) {
- return false;
- }
-
- String expression = path.subSequence(expressionBeginIndex, expressionEndIndex).toString();
-
- String[] tokens = expression.split(",");
-
- if (filterStack.size() < tokens.length) {
- throw new InvalidPathException("Not enough predicates supplied for filter [" + expression + "] at position " + path.position());
- }
-
- Collection<Predicate> predicates = new ArrayList<Predicate>();
- for (String token : tokens) {
- token = token != null ? token.trim() : token;
- if (!"?".equals(token == null ? "" : token)) {
- throw new InvalidPathException("Expected '?' but found " + token);
- }
- predicates.add(filterStack.pop());
- }
-
- appender.appendPathToken(PathTokenFactory.createPredicatePathToken(predicates));
-
- path.setPosition(expressionEndIndex + 1);
-
- return path.currentIsTail() || readNextToken(appender);
- }
-
- //
- // [?(...)]
- //
- private boolean readFilterToken(PathTokenAppender appender) {
- if (!path.currentCharIs(OPEN_SQUARE_BRACKET) && !path.nextSignificantCharIs(BEGIN_FILTER)) {
- return false;
- }
-
- int openStatementBracketIndex = path.position();
- int questionMarkIndex = path.indexOfNextSignificantChar(BEGIN_FILTER);
- if (questionMarkIndex == -1) {
- return false;
- }
- int openBracketIndex = path.indexOfNextSignificantChar(questionMarkIndex, OPEN_PARENTHESIS);
- if (openBracketIndex == -1) {
- return false;
- }
- int closeBracketIndex = path.indexOfClosingBracket(openBracketIndex, true, true);
- if (closeBracketIndex == -1) {
- return false;
- }
- if (!path.nextSignificantCharIs(closeBracketIndex, CLOSE_SQUARE_BRACKET)) {
- return false;
- }
- int closeStatementBracketIndex = path.indexOfNextSignificantChar(closeBracketIndex, CLOSE_SQUARE_BRACKET);
-
- String criteria = path.subSequence(openStatementBracketIndex, closeStatementBracketIndex + 1).toString();
-
-
- Predicate predicate = FilterCompiler.compile(criteria);
- appender.appendPathToken(PathTokenFactory.createPredicatePathToken(predicate));
-
- path.setPosition(closeStatementBracketIndex + 1);
+ appender.appendPathToken(PathTokenFactory.createPropertyPathToken(property, SINGLE_QUOTE));
return path.currentIsTail() || readNextToken(appender);
-
}
//
// [*]
// *
//
- private boolean readWildCardToken(PathTokenAppender appender) {
+ private boolean readWildCardToken(PathTokenAppender appender)
+ {
boolean inBracket = path.currentCharIs(OPEN_SQUARE_BRACKET);
@@ -493,15 +222,16 @@
}
//
- // [1], [1,2, n], [1:], [1:2], [:2]
+ // [1]
//
- private boolean readArrayToken(PathTokenAppender appender) {
+ private boolean readArrayToken(PathTokenAppender appender)
+ {
if (!path.currentCharIs(OPEN_SQUARE_BRACKET)) {
return false;
}
char nextSignificantChar = path.nextSignificantChar();
- if (!isDigit(nextSignificantChar) && nextSignificantChar != MINUS && nextSignificantChar != SPLIT) {
+ if (!isDigit(nextSignificantChar) && nextSignificantChar != MINUS) {
return false;
}
@@ -521,7 +251,7 @@
//check valid chars
for (int i = 0; i < expression.length(); i++) {
char c = expression.charAt(i);
- if (!isDigit(c) && c != COMMA && c != MINUS && c != SPLIT && c != SPACE) {
+ if (!isDigit(c) && c != MINUS && c != SPACE) {
return false;
}
}
@@ -529,11 +259,9 @@
boolean isSliceOperation = expression.contains(":");
if (isSliceOperation) {
- ArraySliceOperation arraySliceOperation = ArraySliceOperation.parse(expression);
- appender.appendPathToken(PathTokenFactory.createSliceArrayPathToken(arraySliceOperation));
+ fail("slice is not supported");
} else {
- ArrayIndexOperation arrayIndexOperation = ArrayIndexOperation.parse(expression);
- appender.appendPathToken(PathTokenFactory.createIndexArrayPathToken(arrayIndexOperation));
+ appender.appendPathToken(PathTokenFactory.createIndexArrayPathToken(parseInteger(expression)));
}
path.setPosition(expressionEndIndex + 1);
@@ -541,19 +269,29 @@
return path.currentIsTail() || readNextToken(appender);
}
+ private static Integer parseInteger(String token)
+ {
+ try {
+ return Integer.parseInt(token);
+ } catch (Exception e) {
+ throw new InvalidPathException("Failed to parse token in ArrayIndexOperation: " + token, e);
+ }
+ }
+
//
// ['foo']
//
- private boolean readBracketPropertyToken(PathTokenAppender appender) {
+ private boolean readBracketPropertyToken(PathTokenAppender appender)
+ {
if (!path.currentCharIs(OPEN_SQUARE_BRACKET)) {
return false;
}
char potentialStringDelimiter = path.nextSignificantChar();
if (potentialStringDelimiter != SINGLE_QUOTE && potentialStringDelimiter != DOUBLE_QUOTE) {
- return false;
+ return false;
}
- List<String> properties = new ArrayList<String>();
+ String property = "";
int startPosition = path.position() + 1;
int readPosition = startPosition;
@@ -565,45 +303,121 @@
while (path.inBounds(readPosition)) {
char c = path.charAt(readPosition);
- if(inEscape){
+ if (inEscape) {
inEscape = false;
- } else if('\\' == c){
+ } else if ('\\' == c) {
inEscape = true;
} else if (c == CLOSE_SQUARE_BRACKET && !inProperty) {
- if (lastSignificantWasComma){
- fail("Found empty property at index "+readPosition);
+ if (lastSignificantWasComma) {
+ fail("Found empty property at index " + readPosition);
}
break;
} else if (c == potentialStringDelimiter) {
if (inProperty && !inEscape) {
endPosition = readPosition;
String prop = path.subSequence(startPosition, endPosition).toString();
- properties.add(Utils.unescape(prop));
+ property = unescape(prop);
inProperty = false;
} else {
startPosition = readPosition + 1;
inProperty = true;
lastSignificantWasComma = false;
}
- } else if (c == COMMA){
- if (lastSignificantWasComma){
- fail("Found empty property at index "+readPosition);
- }
- lastSignificantWasComma = true;
+
}
readPosition++;
}
int endBracketIndex = path.indexOfNextSignificantChar(endPosition, CLOSE_SQUARE_BRACKET) + 1;
+ if (endBracketIndex < endPosition) {
+ fail("endBracketIndex must be greater than endPosition " + path);
+ }
+
path.setPosition(endBracketIndex);
- appender.appendPathToken(PathTokenFactory.createPropertyPathToken(properties, potentialStringDelimiter));
+ appender.appendPathToken(PathTokenFactory.createPropertyPathToken(property, SINGLE_QUOTE));
return path.currentIsTail() || readNextToken(appender);
}
- public static boolean fail(String message) {
+ public static String unescape(String str)
+ {
+ if (str == null) {
+ return null;
+ }
+ int len = str.length();
+ StringWriter writer = new StringWriter(len);
+ StringBuffer unicode = new StringBuffer(4);
+ boolean hadSlash = false;
+ boolean inUnicode = false;
+ for (int i = 0; i < len; i++) {
+ char ch = str.charAt(i);
+ if (inUnicode) {
+ unicode.append(ch);
+ if (unicode.length() == 4) {
+ try {
+ int value = Integer.parseInt(unicode.toString(), 16);
+ writer.write((char) value);
+ unicode.setLength(0);
+ inUnicode = false;
+ hadSlash = false;
+ } catch (NumberFormatException nfe) {
+ throw new InvalidPathException("Unable to parse unicode value: " + unicode, nfe);
+ }
+ }
+ continue;
+ }
+ if (hadSlash) {
+ hadSlash = false;
+ switch (ch) {
+ case '\\':
+ writer.write('\\');
+ break;
+ case '\'':
+ writer.write('\'');
+ break;
+ case '\"':
+ writer.write('"');
+ break;
+ case 'r':
+ writer.write('\r');
+ break;
+ case 'f':
+ writer.write('\f');
+ break;
+ case 't':
+ writer.write('\t');
+ break;
+ case 'n':
+ writer.write('\n');
+ break;
+ case 'b':
+ writer.write('\b');
+ break;
+ case 'u': {
+ inUnicode = true;
+ break;
+ }
+ default:
+ writer.write(ch);
+ break;
+ }
+ continue;
+ } else if (ch == '\\') {
+ hadSlash = true;
+ continue;
+ }
+ writer.write(ch);
+ }
+ if (hadSlash) {
+ writer.write('\\');
+ }
+ return writer.toString();
+ }
+
+ public static boolean fail(String message)
+ {
throw new InvalidPathException(message);
}
}
diff -u ./json-path/src/main/java/com/jayway/jsonpath/internal/path/PathToken.java ~/src/sonots/embulk-filter-column/src/main/java/org/embulk/filter/column/path/PathToken.java
--- ./json-path/src/main/java/com/jayway/jsonpath/internal/path/PathToken.java 2016-08-03 17:14:02.000000000 +0900
+++ ~/src/sonots/embulk-filter-column/src/main/java/org/embulk/filter/column/path/PathToken.java 2016-08-24 14:38:07.000000000 +0900
@@ -1,217 +1,49 @@
-/*
- * Copyright 2011 the original author or authors.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.jayway.jsonpath.internal.path;
-
-import com.jayway.jsonpath.Option;
-import com.jayway.jsonpath.PathNotFoundException;
-import com.jayway.jsonpath.internal.PathRef;
-import com.jayway.jsonpath.internal.Utils;
-import com.jayway.jsonpath.internal.function.PathFunction;
-import com.jayway.jsonpath.spi.json.JsonProvider;
-
-import java.util.List;
-
-public abstract class PathToken {
+package org.embulk.filter.column.path;
+public abstract class PathToken
+{
private PathToken prev;
private PathToken next;
- private Boolean definite = null;
- private Boolean upstreamDefinite = null;
- PathToken appendTailToken(PathToken next) {
+ PathToken appendTailToken(PathToken next)
+ {
this.next = next;
this.next.prev = this;
return next;
}
- void handleObjectProperty(String currentPath, Object model, EvaluationContextImpl ctx, List<String> properties) {
-
- if(properties.size() == 1) {
- String property = properties.get(0);
- String evalPath = Utils.concat(currentPath, "['", property, "']");
- Object propertyVal = readObjectProperty(property, model, ctx);
- if(propertyVal == JsonProvider.UNDEFINED){
- // Conditions below heavily depend on current token type (and its logic) and are not "universal",
- // so this code is quite dangerous (I'd rather rewrite it & move to PropertyPathToken and implemented
- // WildcardPathToken as a dynamic multi prop case of PropertyPathToken).
- // Better safe than sorry.
- assert this instanceof PropertyPathToken : "only PropertyPathToken is supported";
-
- if(isLeaf()) {
- if(ctx.options().contains(Option.DEFAULT_PATH_LEAF_TO_NULL)){
- propertyVal = null;
- } else {
- if(ctx.options().contains(Option.SUPPRESS_EXCEPTIONS) ||
- !ctx.options().contains(Option.REQUIRE_PROPERTIES)){
- return;
- } else {
- throw new PathNotFoundException("No results for path: " + evalPath);
- }
- }
- } else {
- if (! (isUpstreamDefinite() && isTokenDefinite()) &&
- !ctx.options().contains(Option.REQUIRE_PROPERTIES) ||
- ctx.options().contains(Option.SUPPRESS_EXCEPTIONS)){
- // If there is some indefiniteness in the path and properties are not required - we'll ignore
- // absent property. And also in case of exception suppression - so that other path evaluation
- // branches could be examined.
- return;
- } else {
- throw new PathNotFoundException("Missing property in path " + evalPath);
- }
- }
- }
- PathRef pathRef = ctx.forUpdate() ? PathRef.create(model, property) : PathRef.NO_OP;
- if (isLeaf()) {
- ctx.addResult(evalPath, pathRef, propertyVal);
- }
- else {
- next().evaluate(evalPath, pathRef, propertyVal, ctx);
- }
- } else {
- String evalPath = currentPath + "[" + Utils.join(", ", "'", properties) + "]";
-
- assert isLeaf() : "non-leaf multi props handled elsewhere";
-
- Object merged = ctx.jsonProvider().createMap();
- for (String property : properties) {
- Object propertyVal;
- if(hasProperty(property, model, ctx)) {
- propertyVal = readObjectProperty(property, model, ctx);
- if(propertyVal == JsonProvider.UNDEFINED){
- if(ctx.options().contains(Option.DEFAULT_PATH_LEAF_TO_NULL)) {
- propertyVal = null;
- } else {
- continue;
- }
- }
- } else {
- if(ctx.options().contains(Option.DEFAULT_PATH_LEAF_TO_NULL)){
- propertyVal = null;
- } else if (ctx.options().contains(Option.REQUIRE_PROPERTIES)) {
- throw new PathNotFoundException("Missing property in path " + evalPath);
- } else {
- continue;
- }
- }
- ctx.jsonProvider().setProperty(merged, property, propertyVal);
- }
- PathRef pathRef = ctx.forUpdate() ? PathRef.create(model, properties) : PathRef.NO_OP;
- ctx.addResult(evalPath, pathRef, merged);
- }
- }
-
- private static boolean hasProperty(String property, Object model, EvaluationContextImpl ctx) {
- return ctx.jsonProvider().getPropertyKeys(model).contains(property);
- }
-
- private static Object readObjectProperty(String property, Object model, EvaluationContextImpl ctx) {
- return ctx.jsonProvider().getMapValue(model, property);
- }
-
-
- protected void handleArrayIndex(int index, String currentPath, Object model, EvaluationContextImpl ctx) {
- String evalPath = Utils.concat(currentPath, "[", String.valueOf(index), "]");
- PathRef pathRef = ctx.forUpdate() ? PathRef.create(model, index) : PathRef.NO_OP;
- try {
- Object evalHit = ctx.jsonProvider().getArrayIndex(model, index);
- if (isLeaf()) {
- ctx.addResult(evalPath, pathRef, evalHit);
- } else {
- next().evaluate(evalPath, pathRef, evalHit, ctx);
- }
- } catch (IndexOutOfBoundsException e) {
- }
- }
-
- PathToken prev(){
+ public PathToken prev()
+ {
return prev;
}
- PathToken next() {
+ public PathToken next()
+ {
if (isLeaf()) {
throw new IllegalStateException("Current path token is a leaf");
}
return next;
}
- boolean isLeaf() {
+ boolean isLeaf()
+ {
return next == null;
}
- boolean isRoot() {
- return prev == null;
- }
-
- boolean isUpstreamDefinite() {
- if (upstreamDefinite == null) {
- upstreamDefinite = isRoot() || prev.isTokenDefinite() && prev.isUpstreamDefinite();
- }
- return upstreamDefinite;
+ boolean isRoot()
+ {
+ return prev == null;
}
- public int getTokenCount() {
- int cnt = 1;
- PathToken token = this;
-
- while (!token.isLeaf()){
- token = token.next();
- cnt++;
- }
- return cnt;
- }
-
- public boolean isPathDefinite() {
- if(definite != null){
- return definite.booleanValue();
- }
- boolean isDefinite = isTokenDefinite();
- if (isDefinite && !isLeaf()) {
- isDefinite = next.isPathDefinite();
- }
- definite = isDefinite;
- return isDefinite;
- }
+ public abstract String getPathFragment();
@Override
- public String toString() {
+ public String toString()
+ {
if (isLeaf()) {
return getPathFragment();
} else {
return getPathFragment() + next().toString();
}
}
-
- @Override
- public int hashCode() {
- return toString().hashCode();
- }
-
- @Override
- public boolean equals(Object obj) {
- return super.equals(obj);
- }
-
- public void invoke(PathFunction pathFunction, String currentPath, PathRef parent, Object model, EvaluationContextImpl ctx) {
- ctx.addResult(currentPath, parent, pathFunction.invoke(currentPath, parent, model, ctx, null));
- }
-
- public abstract void evaluate(String currentPath, PathRef parent, Object model, EvaluationContextImpl ctx);
-
- public abstract boolean isTokenDefinite();
-
- protected abstract String getPathFragment();
-
}
diff -u ./json-path/src/main/java/com/jayway/jsonpath/internal/path/PathTokenAppender.java ~/src/sonots/embulk-filter-column/src/main/java/org/embulk/filter/column/path/PathTokenAppender.java
--- ./json-path/src/main/java/com/jayway/jsonpath/internal/path/PathTokenAppender.java 2016-08-03 17:14:02.000000000 +0900
+++ ~/src/sonots/embulk-filter-column/src/main/java/org/embulk/filter/column/path/PathTokenAppender.java 2016-08-24 14:33:21.000000000 +0900
@@ -1,5 +1,6 @@
-package com.jayway.jsonpath.internal.path;
+package org.embulk.filter.column.path;
-public interface PathTokenAppender {
+public interface PathTokenAppender
+{
PathTokenAppender appendPathToken(PathToken next);
}
diff -u ./json-path/src/main/java/com/jayway/jsonpath/internal/path/PathTokenFactory.java ~/src/sonots/embulk-filter-column/src/main/java/org/embulk/filter/column/path/PathTokenFactory.java
--- ./json-path/src/main/java/com/jayway/jsonpath/internal/path/PathTokenFactory.java 2016-08-03 17:14:02.000000000 +0900
+++ ~/src/sonots/embulk-filter-column/src/main/java/org/embulk/filter/column/path/PathTokenFactory.java 2016-08-24 14:33:21.000000000 +0900
@@ -1,52 +1,26 @@
-package com.jayway.jsonpath.internal.path;
+package org.embulk.filter.column.path;
-import com.jayway.jsonpath.Predicate;
-import com.jayway.jsonpath.internal.function.Parameter;
+public class PathTokenFactory
+{
-import java.util.Collection;
-import java.util.List;
-
-import static java.util.Collections.singletonList;
-
-public class PathTokenFactory {
-
- public static RootPathToken createRootPathToken(char token) {
- return new RootPathToken(token);
- }
-
- public static PathToken createSinglePropertyPathToken(String property, char stringDelimiter) {
- return new PropertyPathToken(singletonList(property), stringDelimiter);
- }
-
- public static PathToken createPropertyPathToken(List<String> properties, char stringDelimiter) {
- return new PropertyPathToken(properties, stringDelimiter);
+ public static CompiledPath createRootPathToken(char token)
+ {
+ return new CompiledPath(token);
}
- public static PathToken createSliceArrayPathToken(final ArraySliceOperation arraySliceOperation) {
- return new ArrayPathToken(arraySliceOperation);
+ public static PathToken createPropertyPathToken(String property, char stringDelimiter)
+ {
+ return new PropertyPathToken(property, stringDelimiter);
}
- public static PathToken createIndexArrayPathToken(final ArrayIndexOperation arrayIndexOperation) {
- return new ArrayPathToken(arrayIndexOperation);
+ public static PathToken createIndexArrayPathToken(final Integer index)
+ {
+ return new ArrayPathToken(index);
}
- public static PathToken createWildCardPathToken() {
+ public static PathToken createWildCardPathToken()
+ {
return new WildcardPathToken();
}
- public static PathToken crateScanToken() {
- return new ScanPathToken();
- }
-
- public static PathToken createPredicatePathToken(Collection<Predicate> predicates) {
- return new PredicatePathToken(predicates);
- }
-
- public static PathToken createPredicatePathToken(Predicate predicate) {
- return new PredicatePathToken(predicate);
- }
-
- public static PathToken createFunctionPathToken(String function, List<Parameter> parameters) {
- return new FunctionPathToken(function, parameters);
- }
}
Only in ./json-path/src/main/java/com/jayway/jsonpath/internal/path/: PredicateContextImpl.java
Only in ./json-path/src/main/java/com/jayway/jsonpath/internal/path/: PredicatePathToken.java
diff -u ./json-path/src/main/java/com/jayway/jsonpath/internal/path/PropertyPathToken.java ~/src/sonots/embulk-filter-column/src/main/java/org/embulk/filter/column/path/PropertyPathToken.java
--- ./json-path/src/main/java/com/jayway/jsonpath/internal/path/PropertyPathToken.java 2016-08-03 17:14:02.000000000 +0900
+++ ~/src/sonots/embulk-filter-column/src/main/java/org/embulk/filter/column/path/PropertyPathToken.java 2016-08-24 14:33:21.000000000 +0900
@@ -1,105 +1,30 @@
-/*
- * Copyright 2011 the original author or authors.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.jayway.jsonpath.internal.path;
+package org.embulk.filter.column.path;
-import com.jayway.jsonpath.InvalidPathException;
-import com.jayway.jsonpath.PathNotFoundException;
-import com.jayway.jsonpath.internal.PathRef;
-import com.jayway.jsonpath.internal.Utils;
+public class PropertyPathToken extends PathToken
+{
-import java.util.ArrayList;
-import java.util.List;
-
-import static com.jayway.jsonpath.internal.Utils.onlyOneIsTrueNonThrow;
-
-/**
- *
- */
-class PropertyPathToken extends PathToken {
-
- private final List<String> properties;
+ private final String property;
private final String stringDelimiter;
- public PropertyPathToken(List<String> properties, char stringDelimiter) {
- if (properties.isEmpty()) {
- throw new InvalidPathException("Empty properties");
+ public PropertyPathToken(String property, char stringDelimiter)
+ {
+ if (property.isEmpty()) {
+ throw new InvalidPathException("Empty property");
}
- this.properties = properties;
+ this.property = property;
this.stringDelimiter = Character.toString(stringDelimiter);
}
- public List<String> getProperties() {
- return properties;
- }
-
- public boolean singlePropertyCase() {
- return properties.size() == 1;
- }
-
- public boolean multiPropertyMergeCase() {
- return isLeaf() && properties.size() > 1;
- }
-
- public boolean multiPropertyIterationCase() {
- // Semantics of this case is the same as semantics of ArrayPathToken with INDEX_SEQUENCE operation.
- return ! isLeaf() && properties.size() > 1;
- }
-
- @Override
- public void evaluate(String currentPath, PathRef parent, Object model, EvaluationContextImpl ctx) {
- // Can't assert it in ctor because isLeaf() could be changed later on.
- assert onlyOneIsTrueNonThrow(singlePropertyCase(), multiPropertyMergeCase(), multiPropertyIterationCase());
-
- if (!ctx.jsonProvider().isMap(model)) {
- if (! isUpstreamDefinite()) {
- return;
- } else {
- String m = model == null ? "null" : model.getClass().getName();
-
- throw new PathNotFoundException(String.format(
- "Expected to find an object with property %s in path %s but found '%s'. " +
- "This is not a json object according to the JsonProvider: '%s'.",
- getPathFragment(), currentPath, m, ctx.configuration().jsonProvider().getClass().getName()));
- }
- }
-
- if (singlePropertyCase() || multiPropertyMergeCase()) {
- handleObjectProperty(currentPath, model, ctx, properties);
- return;
- }
-
- assert multiPropertyIterationCase();
- final List<String> currentlyHandledProperty = new ArrayList<String>(1);
- currentlyHandledProperty.add(null);
- for (final String property : properties) {
- currentlyHandledProperty.set(0, property);
- handleObjectProperty(currentPath, model, ctx, currentlyHandledProperty);
- }
- }
-
- @Override
- public boolean isTokenDefinite() {
- // in case of leaf multiprops will be merged, so it's kinda definite
- return singlePropertyCase() || multiPropertyMergeCase();
- }
+ public String getProperty() { return property; }
@Override
- public String getPathFragment() {
+ public String getPathFragment()
+ {
return new StringBuilder()
.append("[")
- .append(Utils.join(",", stringDelimiter, properties))
+ .append(stringDelimiter)
+ .append(property)
+ .append(stringDelimiter)
.append("]").toString();
}
}
Only in ./json-path/src/main/java/com/jayway/jsonpath/internal/path/: RootPathToken.java
Only in ./json-path/src/main/java/com/jayway/jsonpath/internal/path/: ScanPathToken.java
diff -u ./json-path/src/main/java/com/jayway/jsonpath/internal/path/WildcardPathToken.java ~/src/sonots/embulk-filter-column/src/main/java/org/embulk/filter/column/path/WildcardPathToken.java
--- ./json-path/src/main/java/com/jayway/jsonpath/internal/path/WildcardPathToken.java 2016-08-03 17:14:02.000000000 +0900
+++ ~/src/sonots/embulk-filter-column/src/main/java/org/embulk/filter/column/path/WildcardPathToken.java 2016-08-24 14:33:21.000000000 +0900
@@ -1,60 +1,14 @@
-/*
- * Copyright 2011 the original author or authors.
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.jayway.jsonpath.internal.path;
+package org.embulk.filter.column.path;
-import com.jayway.jsonpath.Option;
-import com.jayway.jsonpath.PathNotFoundException;
-import com.jayway.jsonpath.internal.PathRef;
-
-import static java.util.Arrays.asList;
-
-/**
- *
- */
-public class WildcardPathToken extends PathToken {
-
- WildcardPathToken() {
- }
-
- @Override
- public void evaluate(String currentPath, PathRef parent, Object model, EvaluationContextImpl ctx) {
- if (ctx.jsonProvider().isMap(model)) {
- for (String property : ctx.jsonProvider().getPropertyKeys(model)) {
- handleObjectProperty(currentPath, model, ctx, asList(property));
- }
- } else if (ctx.jsonProvider().isArray(model)) {
- for (int idx = 0; idx < ctx.jsonProvider().length(model); idx++) {
- try {
- handleArrayIndex(idx, currentPath, model, ctx);
- } catch (PathNotFoundException p){
- if(ctx.options().contains(Option.REQUIRE_PROPERTIES)){
- throw p;
- }
- }
- }
- }
- }
-
-
- @Override
- public boolean isTokenDefinite() {
- return false;
+public class WildcardPathToken extends PathToken
+{
+ WildcardPathToken()
+ {
}
@Override
- public String getPathFragment() {
+ public String getPathFragment()
+ {
return "[*]";
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment