首页 > 代码库 > 如何用Google APIs和Google的应用系统进行集成(7)----在把JSON转换成XML数据过程中,JSON数据中包含违背XML数据规范:XML节点名不能只是数字的Java解决方案

如何用Google APIs和Google的应用系统进行集成(7)----在把JSON转换成XML数据过程中,JSON数据中包含违背XML数据规范:XML节点名不能只是数字的Java解决方案

笔者在调用Google Calendar APIs的GetColors过程当中(具体关于Google Calendar API已经Google API的介绍请见我其他的博文,当前我们只是拿Google Calendar API返回的结果举一个例子),JSON返回的数据中,出现了以数字作为键(key)的数据;但是因为我们在企业应用集成中,有时候需要把JSON数据转换成XML数据;那么这个时候,JSON数据中的键(key)映射到XML数据中将成为XML数据的节点名字(Node Name),如果JSON中的键(key)是数字的话,映射到XML数据的时候就会出错,因为XML规范中不支持把纯粹的数字作为XML数据的节点名字;这种情况下,我们就需要在对JSON数据转换成XML数据之间,进行一下处理。

以Google 日历(Calendar) API中的获取颜色(Get Color)的数据为例子,请见下面的数据。Calendar键(key)中的值,是一个包含多个对象的对象;每个对象的键(key)是一个数字,而且数字呈现递增的趋势;同理Event键(key)中的值也有同样的特征;如果把这样的数据转换成XML的数据的话,转换将不会成功。

{
 "kind": "calendar#colors",
 "updated": "2012-02-14T00:00:00.000Z",
 "calendar": {
  "1": {
   "background": "#ac725e",
   "foreground": "#1d1d1d"
  },
  "2": {
   "background": "#d06b64",
   "foreground": "#1d1d1d"
  },
  "3": {
   "background": "#f83a22",
   "foreground": "#1d1d1d"
  }
 },
 "event": {
  "1": {
   "background": "#a4bdfc",
   "foreground": "#1d1d1d"
  },
  "2": {
   "background": "#7ae7bf",
   "foreground": "#1d1d1d"
  }
 }
}

比如,我们把上面的数据,在一个在线的JSON转XML的网站上进行转换,http://www.freeformatter.com/json-to-xml-converter.html,在这个在线工具里面将会提示下面的错误信息:



那么解决的办法是什么呢?解决的办法就是把上面的带有数字的键(key)值对集合,变成一个没有数字的键(key)的数组,如下面的格式,

{
 "kind": "calendar#colors",
 "updated": "2012-02-14T00:00:00.000Z",
 "calendar": [{
   "background": "#ac725e",
   "foreground": "#1d1d1d"
  },
  {
   "background": "#d06b64",
   "foreground": "#1d1d1d"
  },
  {
   "background": "#f83a22",
   "foreground": "#1d1d1d"
  }
  ]
 },
 "event": [{
   "background": "#a4bdfc",
   "foreground": "#1d1d1d"
  },
  {
   "background": "#7ae7bf",
   "foreground": "#1d1d1d"
  }
  ]
 }
}

转换后的XML的数据如下,

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <calendar>
      <element>
         <background>#ac725e</background>
         <foreground>#1d1d1d</foreground>
      </element>
      <element>
         <background>#d06b64</background>
         <foreground>#1d1d1d</foreground>
      </element>
      <element>
         <background>#f83a22</background>
         <foreground>#1d1d1d</foreground>
      </element>
   </calendar>
   <kind>calendar#colors</kind>
   <updated>2012-02-14T00:00:00.000Z</updated>
</root>

那么问题来,如果用代码自动来实现转换且不引入任何的除JDK自带的API之外的其他的jar包呢?具体算法,请见下面的代码。

1. NumberKeyPosition Java Bean: 用来存储数字键(key)在JSON字符串中出现的开始位置,结束位置,以及是否是第一个数字键(key),是否是最后一个数字数字键(key),比如上面的中下面的数据,是calendar的第一个,所以isFirstOne的值为True。

 "1": {
   "background": "#ac725e",
   "foreground": "#1d1d1d"
  }

public class NumberKeyPosition {

	private int startPos;
	private int endPos;
	private boolean isFirstOne=false;
	private boolean isLastOne=false;

	public int getStartPos() {
		return startPos;
	}

	public void setStartPos(int startPos) {
		this.startPos = startPos;
	}

	public int getEndPos() {
		return endPos;
	}

	public void setEndPos(int endPos) {
		this.endPos = endPos;
	}

	public boolean isFirstOne() {
		return isFirstOne;
	}

	public void setFirstOne(boolean isFirstOne) {
		this.isFirstOne = isFirstOne;
	}

	public boolean isLastOne() {
		return isLastOne;
	}

	public void setLastOne(boolean isLastOne) {
		this.isLastOne = isLastOne;
	}
}

2. CovertNumberKeyAsArrayUtil 类:这个类就是执行上面处理JSON数据的具体的执行算法的类了。

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class CovertNumberKeyAsArrayUtil {
	private String jsonString;
	public void setJsonString(String jsonString) {
		this.jsonString = jsonString;
	}
	public CovertNumberKeyAsArrayUtil(){
		
	}
	public CovertNumberKeyAsArrayUtil(String jsonString){
		this.jsonString=jsonString;
	}
	
	public String readFileAsString(String fileName){
		InputStream ins=this.getClass().getResourceAsStream(fileName);
		StringBuffer sBuffer=new StringBuffer();
		BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(ins));
		String lineString="";
		try {
			while((lineString=bufferedReader.readLine())!=null){
				sBuffer.append(lineString);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		//System.out.println(sBuffer.toString());
		return sBuffer.toString();
	}
	/**
	 * getNumberKeyPositions
	 * @param jsonString
	 * @return
	 */
	private List<NumberKeyPosition> getNumberKeyPositions(){
		List<NumberKeyPosition> lsNumberKeyPosition=new ArrayList<NumberKeyPosition>();
		String expression="\"\\d*\":";
		Pattern p = Pattern.compile(expression);
		Matcher m = p.matcher(jsonString);
		StringBuffer sb = new StringBuffer();
		int prevIndex=0;
		while (m.find()) {
			NumberKeyPosition numberKeyPosition=new NumberKeyPosition();
			String matchString=m.group();
			int currentIndex=Integer.parseInt(matchString.trim().replace("\"", "").replace(":", ""));
			numberKeyPosition.setStartPos(m.start());
			numberKeyPosition.setEndPos(m.end());
			//System.out.println("Start Pos:"+m.start());
			//System.out.println("End Pos:"+m.end());
			if(currentIndex==1){
				numberKeyPosition.setFirstOne(true);
				if(prevIndex==1){
					if(lsNumberKeyPosition.size()>0){
					   lsNumberKeyPosition.get(lsNumberKeyPosition.size()-1).setLastOne(true);
					}
				}else{
					if(prevIndex>1){
						lsNumberKeyPosition.get(lsNumberKeyPosition.size()-1).setLastOne(true);
					}
				}
				
			}else{
					numberKeyPosition.setFirstOne(false);
					numberKeyPosition.setLastOne(false);
			}
			prevIndex=currentIndex;
			lsNumberKeyPosition.add(numberKeyPosition);
		}
		if(lsNumberKeyPosition!=null&&lsNumberKeyPosition.size()>0){
		  lsNumberKeyPosition.get(lsNumberKeyPosition.size()-1).setLastOne(true);
		}
		return lsNumberKeyPosition;
	}
	/**
	 * 
	 * @param endOfLastPositionString
	 * @return
	 * @Test data: {   "background": "#f83a22",   "foreground": "#1d1d1d"  } }, "event": {  
	 *  {   "background": "#f83a22",   "foreground": "#1d1d1d"  } }, "event": {
	 */
	public String addBracket4EndPostion(String endOfLastPositionString){
		StringBuffer sBuffer=new StringBuffer();
		int leftBracketCount=0;
		int leftBracketCountFirstIndex=endOfLastPositionString.indexOf('{');
		boolean isAddBracketSucc=false;
		boolean isRemovedLaterBrace=false;
		for(int i=0;i<endOfLastPositionString.length();i++){
			if(endOfLastPositionString.charAt(i)=='{'){
				leftBracketCount++;
			} else if(endOfLastPositionString.charAt(i)=='}'){
				leftBracketCount--;
			}
			sBuffer.append(endOfLastPositionString.charAt(i));
			if(leftBracketCount==0&&i>leftBracketCountFirstIndex&&!isAddBracketSucc){
				sBuffer.append(']');
				isAddBracketSucc=true;
				continue;
			}
			if(isAddBracketSucc&&!isRemovedLaterBrace&&endOfLastPositionString.charAt(i)=='}'){
				int lenStringBuffer=sBuffer.length();
				sBuffer=new StringBuffer(sBuffer.substring(0, lenStringBuffer-1));
				isRemovedLaterBrace=true;
			}
			
		}
		return sBuffer.toString();
	}
	
	private String trimRightBrace(String tmpString) {
		String trimRightBraceString = "";
		if (tmpString != null) {
			tmpString=tmpString.trim();
			int len = tmpString.length();
			if (len > 1 && tmpString.endsWith("{")) {
				trimRightBraceString = tmpString.substring(0, len - 2);
			}
		}
		return trimRightBraceString;
	}
	/**
	 * getRemovedNumberKeyJSONString
	 * @return
	 */
	public String getRemovedNumberKeyJSONString(){
		//String removedNumberKeyJSONString=null;
		List<NumberKeyPosition> lsNumberKeyPosition=this.getNumberKeyPositions();
		StringBuffer sbBuffer=new StringBuffer();
		if(lsNumberKeyPosition!=null&&lsNumberKeyPosition.size()>0){
			for(int i=0;i<lsNumberKeyPosition.size();i++){
				NumberKeyPosition currentnumberKeyPosition=lsNumberKeyPosition.get(i);
				if(i==0){
					    String tmpString=jsonString.substring(0, currentnumberKeyPosition.getStartPos()).trim();
					    sbBuffer.append(trimRightBrace(tmpString));
					    sbBuffer.append("[");
				}else{
					NumberKeyPosition preNumberKeyPosition=lsNumberKeyPosition.get(i-1);
					if(currentnumberKeyPosition.isFirstOne()){
						sbBuffer.append("[");
					}else{
						if(currentnumberKeyPosition.isLastOne()){
							sbBuffer.append(jsonString.substring(preNumberKeyPosition.getEndPos(), currentnumberKeyPosition.getStartPos()));
							if(i<lsNumberKeyPosition.size()-1){
								NumberKeyPosition nextNumberKeyPosition=lsNumberKeyPosition.get(i+1);
								String endOfLastPositionString=jsonString.substring(currentnumberKeyPosition.getEndPos(),nextNumberKeyPosition.getStartPos()).trim();
								sbBuffer.append(addBracket4EndPostion(trimRightBrace(endOfLastPositionString)));
							}else{
								String endOfLastPositionString=jsonString.substring(currentnumberKeyPosition.getEndPos(),jsonString.length());
								sbBuffer.append(addBracket4EndPostion(endOfLastPositionString));
							}
						}else{
							sbBuffer.append(jsonString.substring(preNumberKeyPosition.getEndPos(), currentnumberKeyPosition.getStartPos()));
						}
					}
				}	
			}
		}
		return sbBuffer.toString();
	}
	public static void main(String[] args) {
		CovertNumberKeyAsArrayUtil covertNumberKeyAsArrayUtil=new CovertNumberKeyAsArrayUtil();
		covertNumberKeyAsArrayUtil.setJsonString(covertNumberKeyAsArrayUtil.readFileAsString("jsonColorNumber.json"));
		String removedNumberKeyJSONString=covertNumberKeyAsArrayUtil.getRemovedNumberKeyJSONString();
		System.out.println(removedNumberKeyJSONString);
	}

}