JSon數(shù)據(jù)的解析

 

最近一個項目要對藝龍,攜程等酒店預訂網(wǎng)站進行價格信息采集.因為這兩個網(wǎng)站都不是省油的燈啊,多次提交ajax表單,參數(shù)編碼,獲取特定的城市和酒店代碼等等手段,可謂過五關(guān)斬六將,總算是把數(shù)據(jù)采集回來,但是又面臨一個難題:采集回來的信息是json格式的,那就涉及到j(luò)son數(shù)據(jù)轉(zhuǎn)換成java對象了

首先要了解json數(shù)據(jù)的格式

[{"CityType":"hotel","TabList":[{"TabId":"1","Name":"\u70ED\u95E8","NameEn":"Hot","CityList":[{"ProvinceId":null,"CityId":"0101","CityCode":"0101","CityNameCn":"\u5317\u4EAC","CityNameEn":"Beijing","CityThreeSign":"","CityType":"hotel","OldEnglishName":"peking"},{"ProvinceId":null,"CityId":"0201","CityCode":"0201","CityNameCn":"\u4E0A\u6D77","CityNameEn":"Shanghai","CityThreeSign":"","CityType":"hotel","OldEnglishName":""},{"ProvinceId":null,"CityId":"2001","CityCode":"2001","CityNameCn":"\u5E7F\u5DDE","CityNameEn":"Guangzhou","CityThreeSign":"","CityType":"hotel","OldEnglishName":"canton"}]}]}];

jsonViewer是個好東西,不過HTTPAnalysis直接就集成了jsonViewer,不過還是前者比較輕巧:

json和java之間的互換可以使用json-lib, 基本的使用可以看文檔就行.網(wǎng)上也有一些集成的類,我建議直接看它的源代碼,了解他是如何通過反射和使用臨時對象解析json數(shù)據(jù),并封裝成java對象.

這個json數(shù)據(jù)時list的嵌套,如果要對整個json文件解析,需要使用如下方法,需要構(gòu)造跟json數(shù)據(jù)對應(yīng)的Tab.class 和City.class,而且字段名稱必須一致(駱駝首字母小寫),提供默認構(gòu)造方法,這樣就可以將json數(shù)據(jù)作為一個完整的對象,想怎么干都行了.

 

HashMap<String,Class> map = new HashMap<String,Class>();
map.put("tabList", Tab.class);
map.put("cityList", City.class);

	    /**
	     * 從一個JSON數(shù)組得到一個java對象集合,其中對象中包含有集合屬性
	     * @param object
	     * @param clazz
	     * @param map 集合屬性的類型 (key : 集合屬性名, value : 集合屬性類型class) eg: ("beansList" : Bean.class)
	     * @return
	     */
	    public static List getDTOList(String jsonString, Class clazz, Map map){
	        setDataFormat2JAVA();
	        JSONArray array = JSONArray.fromObject(jsonString);
	        List list = new ArrayList();
	        for(Iterator iter = array.iterator(); iter.hasNext();){
	            JSONObject jsonObject = (JSONObject)iter.next();
	            list.add(JSONObject.toBean(jsonObject, clazz, map));
	        }
	        return list;
	    }     

由于我的需求只是需要重json數(shù)據(jù)中獲取特定的信息對象,如上面的cityList,像tabList等對象我沒必要去構(gòu)造和獲取,而且在實際使用過程中我發(fā)現(xiàn)

json數(shù)據(jù)中變量如果不是首字母小寫,是無法轉(zhuǎn)換成java對象的.這個確實很坑爹!!!!!

 

于是乎,我就寫了個直接讀取和解析一個片段json數(shù)據(jù)的類,有了這個類,加上對象映射,基本上沒什么解析不了

 

package com.engine.logic.component.loader.impl.json.utils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

public class JSonStrUtils {

	/**
	 * json 數(shù)據(jù)括號自動補全
	 * **/
	public static String autoComplete(String targetJson){
		LinkedList<Character> stack = new LinkedList<Character>();
		String returnStr ="";
		char[] charArray = targetJson.toCharArray();
		for(int i = 0;i<charArray.length;i++){
			if(charArray[i]=='['||charArray[i]=='{'){//入棧
				stack.addFirst(charArray[i]);
			}else if(charArray[i]==']'){
				//判斷是否閉合
				char last = stack.peekFirst();
				if(last !='['){//不閉合,補 }
					returnStr+='}';
				}else//閉合
				{
					stack.pollFirst();
				}
			}else if(charArray[i]=='}'){
				//判斷是否閉合
				char last = stack.peekFirst();
				if(last !='{'){//不閉合,補 }
					returnStr+=']';
				}else//閉合
				{
					stack.pollFirst();
				}
			}
			returnStr+=charArray[i];
		}
		for(char c:stack){
			System.out.println("left in stack:"+c);
		}
		return returnStr;
	}

	/***
	 * 用于處理json數(shù)據(jù)中出現(xiàn)變量名非首字母小寫的情況,利用正則匹配變量,然后把首字母變成小寫
	 * */
	public static String dealWithFirstChar(String jsonInput){
		String originalInput = jsonInput;
		StringBuilder inputStr = new StringBuilder(jsonInput);
		String regex = "\"(\\w+)\":";
		Pattern p = Pattern.compile(regex,Pattern.CASE_INSENSITIVE);
		Matcher m = p.matcher(inputStr);
		List<String> result=new ArrayList<String>();
		while(m.find()){
			String valueName = m.group(1);
			String newValueName = null;
			char[] words =valueName.toCharArray();
			if(Character.isUpperCase(words[0])){//首字母大寫,不符合變量命名規(guī)范

				words[0] = Character.toLowerCase(words[0]);
				newValueName = new String(words);
//				System.out.println("orignal value:"+valueName+" new value :"+ newValueName);
//				String regexWord = "\""+valueName+"\":";
				String regx1 = "\""+valueName+"\":";
				String replace = "\""+newValueName+"\":";
				originalInput=originalInput.replaceAll(regx1, replace);
			}
			result.add(valueName);
			inputStr.delete(0, m.end(0));
			m=p.matcher(inputStr);
		}
		return originalInput;

	}

	/***
	 * 用戶將unicode編碼轉(zhuǎn)換成漢字
	 * */
	public static String UnicodeToString(String str) {
        Pattern pattern = Pattern.compile("(\\\\u(\\p{XDigit}{4}))");
        Matcher matcher = pattern.matcher(str);
        char ch;
        while (matcher.find()) {
            ch = (char) Integer.parseInt(matcher.group(2), 16);
            str = str.replace(matcher.group(1), ch + "");
        }
        return str;
    }

	/***
	 * 用戶將漢字轉(zhuǎn)換成unicode編碼
	 * */
	public static String toUNICODE(String s)
    {
        StringBuilder sb=new StringBuilder();
        for(int i=0;i<s.length();i++)
        {
            if(s.charAt(i)<=256)
            {
                sb.append("\\u00");
            }
            else
            {
                sb.append("\\u");
            }
            sb.append(Integer.toHexString(s.charAt(i)).toUpperCase());
        }
        return sb.toString();
    }

	/**
	 * 讀取json文件,轉(zhuǎn)換為字符串
	 * */
	public static String readJSonFile(String fileName){
		InputStream in = null;
		String jsonStr = "";
		try {
			in = JSonStrUtils.class.getResourceAsStream(fileName);
			BufferedReader reader = new BufferedReader(new InputStreamReader(in));
			String temp = reader.readLine();
			while(temp!=null){
				jsonStr+=temp;
				temp = reader.readLine();
			}
			in.close();
		} catch (IOException e) {
			e.printStackTrace();
			System.out.println("read json file failed :"+fileName);
		}
		return jsonStr;
	}

	/***
	 * 在指定的JSONObject 中尋找特定屬性的第一個值
	 * */
	public static List<String> findTargetProperty(JSONObject object,String propertyName,boolean isRecursive){
		List<String> values = new ArrayList<String>();
		for( Iterator entries = object.names().iterator();
		 entries.hasNext(); ){
			String name = (String) entries.next();
			Object value = object.get(name);
			if(name.equals(propertyName)){//找到目標屬性
				values.add(value.toString());
			}else if(isRecursive){
				if(value instanceof JSONObject){
					values.addAll(findTargetProperty((JSONObject)value,propertyName,isRecursive));
				}else if(value instanceof JSONArray){
					JSONArray array = (JSONArray)value;
					for(Iterator iter = array.iterator(); iter.hasNext();){
						JSONObject jsonObject = (JSONObject)iter.next();
						values.addAll(findTargetProperty(jsonObject,propertyName,isRecursive));
					}
				}
			}
		}
		return values;
	}

	/***
	 * 從指定的JSonArray中尋找指定名稱的子json數(shù)組
	 * */
    public  static List<JSONArray> findTargetJSonArray(JSONArray array,String targetName){
    	List<JSONArray> arrays = new ArrayList<JSONArray>();
    	for(Iterator iter = array.iterator(); iter.hasNext();){//遍歷數(shù)組中的JSONObject
			JSONObject jsonObject = (JSONObject)iter.next();
			if( jsonObject == null || jsonObject.isNullObject() ){
		         continue;
		    }
			for( Iterator entries = jsonObject.names().iterator();
			 entries.hasNext(); ){
				 String name = (String) entries.next();
				 Object value = jsonObject.get(name);
				 if(value instanceof JSONArray){//屬性為數(shù)組
					 //先判斷是否目標數(shù)組
					 if(name.equals(targetName)){
						 arrays.add((JSONArray) value);
					 }
					 //遞歸查找
					 arrays.addAll(findTargetJSonArray((JSONArray) value,targetName));
				 }
			}
    	}
    	return arrays;

    }
}