PropertyPathTokenizer.java
package com.gh.mygreen.xlsmapper.util;
import java.util.LinkedList;
import com.gh.mygreen.xlsmapper.util.PropertyPath.Token;
/**
* プロパティアクセス用の式をパースする。
* <p>{@link PropertyValueNavigator}で使用する。
* @since 1.0
* @author T.TSUCHIE
*
*/
public class PropertyPathTokenizer {
/**
* エスケープ文字(バックスペース\\)
*/
private static final String STR_ESCAPE_CHAR = "\\";
/**
* プロパティのアクセス用の書式をトークンに分割する。
* @param path
* @return
* @throws IllegalArgumentException path is null or empty.
*/
public PropertyPath parse(final String path) {
ArgUtils.notEmpty(path, "path");
final PropertyPath tokenStore = new PropertyPath(path);
splitToken(tokenStore, path);
return tokenStore;
}
/**
* パスを最小限の項目に分割する。
*
* @param tokenStore 分割した結果
* @param path パス
*
*/
private void splitToken(final PropertyPath tokenStore, final String path) {
// 解析時の途中の文字を一時的に補完しておく。
final LinkedList<String> stack = new LinkedList<String>();
final int length = path.length();
for(int i=0; i < length; i++) {
final char c = path.charAt(i);
if(StackUtils.equalsTopElement(stack, STR_ESCAPE_CHAR)) {
// スタックの一番上がエスケープの文字の場合、通常の文字として扱う。
stack.push(String.valueOf(c));
} else if (c == '.') {
if(StackUtils.equalsBottomElement(stack, "[")) {
// キーの囲み文字の途中の場合、文字列としてスタックに積む。
stack.push(String.valueOf(c));
} else if(!stack.isEmpty()) {
// 既に文字が入っている場合は、既存のものを取り出し分割する。
tokenStore.add(new Token.Name(StackUtils.popupAndConcat(stack).trim()));
tokenStore.add(new Token.Separator());
} else {
tokenStore.add(new Token.Separator());
}
} else if(c == '[') {
if(!stack.isEmpty()) {
// 既に文字が入っている場合は、既存のものを取り出し分割する。
tokenStore.add(new Token.Name(StackUtils.popupAndConcat(stack).trim()));
}
stack.push(String.valueOf(c));
} else if(c == ']') {
if(StackUtils.equalsBottomElement(stack, "[")) {
// 条件の終わりの場合
tokenStore.add(new Token.Key(StackUtils.popupAndConcat(stack) + c));
} else {
stack.push(String.valueOf(c));
}
} else if(c == ' ') {
// キーの囲み文字の中であれば、空白は無視しない。
if(StackUtils.equalsBottomElement(stack, "[")) {
stack.push(String.valueOf(c));
}
} else {
stack.push(String.valueOf(c));
}
}
if(!stack.isEmpty()) {
tokenStore.add(new Token.Name(StackUtils.popupAndConcat(stack).trim()));
}
}
}