为啥非要单独传入一个绝对路径呢?其实可以直接传入Json文件的路径,这样既能拿到需要解析的Json字符串,又能获取当前Json文件的绝对路径。但这样有一个缺点,就是每调用一次,就要读一次文件,小菜单独把路径写成一个参数,就是要把读文件的过程留给用户,具体怎么读,由用户说了算,最终把需要解析的Json字符串和参照路径给我就可以了。例如:
1 String json = "{@Jean(\"item1\",\"./../../item.js\"),@Jean(\"item2\",\"../item.js\")}";
2 System.out.println(parseAll(json, "E:/root/json")); //print {"item1": {"name": "xxx1"},"item2": {"name": "xxx2"}}
第二个方法可以直接解析一个@Jean表达式,不多解释。例如:
1 String expression = "@Jean(\"item1\",\"./../../item.js\")";
2 System.out.println(parseOne(expression, "E:/root/json")); //print "item1": {"name": "xxx1"}
第三个方法可以解析指定的@Jean表达式,@Jean表达式第一个参数是属性名称,想解析哪个属性,就把它放在List中,其他不做解析的,属性值为null。这样就实现了懒加载。例如:
1 List names = new ArrayList();
2 names.add("item1");
3 String json = "{@Jean(\"item1\",\"./../../item.js\"),@Jean(\"item2\",\"../item.js\")}";
4 System.out.println(parseTarget(json, "E:/root/json", names)); //print {"item1": {"name": "xxx"},"item2": null}
Jean源码
1 import java.io.BufferedReader;
2 import java.io.File;
3 import java.io.FileInputStream;
4 import java.io.IOException;
5 import java.io.InputStreamReader;
6 import java.util.ArrayList;
7 import java.util.HashMap;
8 import java.util.List;
9 import java.util.Map;
10 import java.util.regex.Matcher;
11 import java.util.regex.Pattern;
12
13
14 /**
15 * json文件合并工具类
16 * @author 杨元
17 */
18 public class Jean {
19
20 /**
21 * 识别jean表达式
22 */
23 private static Pattern jeanRegex = Pattern.compile("(@Jean\\((\"[^\"]*\",)?\"[^\"]*\"\\))");
24 /**
25 * 识别jean表达式中的所有参数
26 */
27 private static Pattern paramRegex = Pattern.compile("\"([^\"]*)\"");
28 /**
29 * 识别jean表达式中的name参数
30 */
31 private static Pattern nameRegex = Pattern.compile("\"([^\"]*)\",");
32 /**
33 * 默认属性名称
34 */
35 private static String defaultName = "jean";
36
37 /**
38 * 解析所有的jean表达式
39 * @param json json字符串
40 * @param jsonPath json字符串所在路径,完整路径
41 * @return 解析后的json字符串
42 */
43 public static String parseAll(String json,String jsonPath){
44 //识别jean表达式
45 List jeans = regexMatchList(jeanRegex, json);
46 jeans = noRepeat(jeans);
47
48 //解析
49 for(String jean : jeans){
50 json = json.replace(jean, parse(jean, jsonPath));
51 }
52
53 return json;
54 }
55
56 /**
57 * 解析单个jean表达式
58 * @param express jean表达式
59 * @param jsonPath json字符串所在路径,完整路径
60 * @return 解析结果
61 */
62 public static String parseOne(String express,String jsonPath){
63 return parse(express, jsonPath);
64 }
65
66 /**
67 * 解析特定的jean表达式
68 * @param json json字符串
69 * @param jsonPath json字符串所在路径,完整路径
70 * @param names 需要解析的属性名称列表
71 * @return 解析后的json字符串
72 */
73 public static String parseTarget(String json,String jsonPath,List names){
74 //识别jean表达式
75 List jeans = regexMatchList(jeanRegex, json);
76 jeans = noRepeat(jeans);
77 //处理属性名映射
78 Map
79 for(String s : names){
80 nameMap.put(s, true);
81 }
82
83 //解析
84 String replacement = "";
85 Matcher matcher = null;
86 String name = "";
87 for(String jean : jeans){
88 matcher = nameRegex.matcher(jean);
89
90 //判断是否传入属性名称
91 if(matcher.find()){
92 name = matcher.group(1);
93 //判断是否需要解析
94 if(nameMap.get(name) != null){
95 replacement = parse(jean, jsonPath);
96 }else{
97 //不需要解析直接将属性值写为null
98 replacement = "\""+name+"\": null";
99 }
100 }else{
101 //无属性名直接用默认的jean
102 replacement = "\""+defaultName+"\": null";
103 }
104
105 json = json.replace(jean, replacement);
106 }
107
108 return json;
109 }
110
111 /**
112 * 解析jean表达式
113 * @param express jean表达式
114 * @param jsonPath json文件所在路径,完整路径
115 * @return jean表达式执行结果
116 */
117 private static String parse(String express,String jsonPath){
118 //识别参数
119 List params = regexMatchList(paramRegex, express);
120 //默认属性名称
121 String name = defaultName;
122 //格式化路径
123 jsonPath = removeSuffix(jsonPath, "/");
124
125 //判断是否传入了属性名称
126 if(params.size() > 1){
127 name = params.get(0);
128 }
129
130 //解析路径
131 String path = getAbsolutePath(jsonPath, params.get(params.size()-1));
132
133 //读取内容并返回
134 name = wrapWith(name, "\"");
135 return name + ": " + readJsonFile(path);
136 }
137
138 /**
139 * 从字符串中移除指定后缀
140 * @param source 源字符串
141 * @param suffix 需要移除的后缀
142 * @return 处理后的源字符串
143 */
144 private static String removeSuffix(String source,String suffix){
145 if(source.endsWith(suffix)){
146 source = source.substring(0, source.length()-suffix.length());
147 }
148
149 return source;
150 }
151
152 /**
153 * list内容去重
154 * @param list 内容为string的list
155 * @return 内容去重后的list
156 */
157 private static List noRepeat(List list){
158 Map
159 List result = new ArrayList();
160
161 for(String s : list){
162 map.put(s, null);
163 }
164
165 for(String s : map.keySet()){
166 result.add(s);
167 }
168
169 return result;
170 }
171
172 /**
173 * 用指定的字符串包裹内容
174 * @param content 内容
175 * @param wrap 包裹字符串
176 * @return 包裹后的内容
177 */
178 private static String wrapWith(String content,String wrap){
179 return wrap+content+wrap;
180 }
181
182 /**
183 * 读取Json文件(纯文本文件,utf-8编码)
184 * 这个方法可以替换成自己项目中封装的方法
185 * @param path 文件路径
186 * @return 文件内容
187 */
188 private static String readJsonFile(String path){
189 String encoding = "utf-8";
190 StringBuilder sb = new StringBuilder(256);
191
192 File file = new File(path);
193 InputStreamReader iReader = null;
194 BufferedReader bReader = null;
195
196 try{
197 iReader = new InputStreamReader(new FileInputStream(file), encoding);
198 bReader = new BufferedReader(iReader);
199 String line = null;
200
201 while((line = bReader.readLine()) != null){
202 sb.append(line.trim());
203 }
204
205 bReader.close();
206 iReader.close();
207
208 }catch(Exception e){
209 if(iReader != null){
210 try {
211 iReader.close();
212 } catch (IOException e1) {
213 iReader = null;
214 }
215 }
216 , if(bReader != null){
217 try {
218 bReader.close();
219 } catch (IOException e1) {
220 bReader = null;
221 }
222 }
223 }
224
225 return sb.toString();
226 }
227
228 /**
229 * 将相对路径转换成绝对路径
230 * 只识别 ./ ../
231 * @param refrence 基准参照路径
232 * @param relative 相对路径表达式
233 * @return 绝对路径
234 */
235 private static String getAbsolutePath(String refrence,String relative){
236 if(relative.startsWith("./")){
237 refrence = getAbsolutePath(refrence, relative.replaceFirst("\\./", ""));
238 }else if(relative.startsWith("../")){
239 refrence = getAbsolutePath(refrence.substring(0, refrence.lastIndexOf("/")),
240 relative.replaceFirst("\\.\\./", ""));
241 }else{
242 refrence = refrence + "/" + relative;
243 }
244
245 return refrence;
246 }
247
248 /**
249 * 将正则表达式的匹配结果转换成列表
250 * @param regex 正则表达式对象
251 * @param input 要检索的字符串
252 * @return 结果列表
253 */
254 private static List regexMatchList(Pattern regex,String input){
255 List result = new ArrayList();
256 Matcher matcher = regex.matcher(input);
257 while(matcher.find()){
258 result.add(matcher.group(1));
259 }
260
261 return result;
262 }
263
264
265 }