package com.gh.mygreen.xlsmapper; import java.util.LinkedList; import com.gh.mygreen.xlsmapper.PropertyPath.Token; /** * プロパティアクセス用の式をパースする。 * <p>{@link PropertyNavigator}で使用する。 * @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 path * @return */ 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())); } } }