解讀郭神LitePal源代碼-litepal.xml的解析
在開始使用LitePal時,要求在項目的assets文件夾下新建一個litepal.xml文件:
<?xml version="1.0" encoding="utf-8"?> <litepal> <dbname value="Questionnaire"/> <version value="1"></version> <list> <mapping class="com.aliao.parser.entity.UserInfo"></mapping> <mapping class="com.aliao.parser.entity.SurveyInfo"></mapping> </list> </litepal>
該配置文件用來設定數據庫的名字、版本以及全部的對象關系映射模型。
什麽是對象關系映射模型?
由於sqlite數據庫是關系型數據庫,而編程是面向對象的,為了使用面向對象的方式來操作數據庫,所以在關系數據庫和實體對象之間做了一個映射,這樣在進行數據庫操作的時候,我們僅僅須要操作實體對象就可以,不須要直接處理sql語句。
在litepal.xml文件的<list>標簽裏來設置須要進行映射的對象,數據庫裏的每一張的表都相應一個實體對象類。
一個litepal.xml文件讓我們在進行數據庫基本信息配置上變得異常方便。那程序是怎麽來獲取到我們配置後的信息呢?
首先須要通過解析xml文件來獲取到數據庫名,版本號信息,以及須要映射的對象。
在Litepal裏使用SAXParser來解析xml。那解析後的信息放在哪裏呢,是由LitePalAttr該實體類來接收從litepal.xml裏讀取到的全部屬性值。
本來想直接貼源代碼的,還是立足源代碼自己手動實現一下好了,勤奮寶寶在咬我,biaji biaji biaji~~~
創建一個LitePalAttr實體類,相應litepal.xml的屬性及其set/get方法:
package com.aliao.parser.entity; import java.util.ArrayList; import java.util.List; /** * Created by aliao on 2015/6/4. */ public class LitePalAttr { private static LitePalAttr litePalAttr; //數據庫版本號號 private int version; //數據庫名 private String dbName; //全部在數據庫中想要有映射關系的實體類 private List<String> classNames; public int getVersion() { return version; } public void setVersion(int version) { this.version = version; } public String getDbName() { return dbName; } public void setDbName(String dbName) { this.dbName = dbName; } /** * 在sqlite裏table_schema表示自己主動生成的,這裏一定要手動加入進去 * table_schema用來查看數據庫的元數據。這裏的元數據包含表名及表類型 * @return */ public List<String> getClassNames() { if (classNames == null){ classNames = new ArrayList<>(); classNames.add("com.aliao.parser.entity.Table_Schema"); }else if (classNames.isEmpty()){ classNames.add("com.aliao.parser.entity.Table_Schema"); } return classNames; } public void addClassName(String className){ getClassNames().add(className); } /** * 這裏用雙重檢測來實現單例模式 * 整個程序創建一個唯一的litePalAttr對象,能夠通過這個對象拿到數據庫的基本信息 * @return */ public static LitePalAttr getIntance(){ if (litePalAttr == null){ synchronized (LitePalAttr.class){ if (litePalAttr == null){ litePalAttr = new LitePalAttr(); } } } return litePalAttr; } @Override public String toString() { return "數據庫名稱:"+dbName+" ,數據庫版本號"+version; } }
接下來就是怎樣解析litepal.xml的問題了。源代碼裏郭神使用SAXParser來解析,怎樣使用SAXParser來解析一個xml文件的知識會單獨寫篇blog總結一下,這裏就不啰嗦直接上吧。
解析litepal.xml須要創建兩個類:
LitePalParser:這個類基本的操作就是創建解析器。然後解析文檔
LitePalContentHandler(繼承DefaultHandler):解析文檔的詳細實現,開始對文檔進行掃描分析。將xml裏的屬性值保存到LitePalAttr的相應屬性裏。
創建解析器:
package com.aliao.parser.entity; import java.util.ArrayList; import java.util.List; /** * Created by aliao on 2015/6/4. */ public class LitePalAttr { private static LitePalAttr litePalAttr; //數據庫版本號號 private int version; //數據庫名 private String dbName; //全部在數據庫中想要有映射關系的實體類 private List<String> classNames; public int getVersion() { return version; } public void setVersion(int version) { this.version = version; } public String getDbName() { return dbName; } public void setDbName(String dbName) { this.dbName = dbName; } /** * 在sqlite裏table_schema表示自己主動生成的,這裏一定要手動加入進去 * table_schema用來查看數據庫的元數據,這裏的元數據包含表名及表類型 * @return */ public List<String> getClassNames() { if (classNames == null){ classNames = new ArrayList<>(); classNames.add("com.aliao.parser.entity.Table_Schema"); }else if (classNames.isEmpty()){ classNames.add("com.aliao.parser.entity.Table_Schema"); } return classNames; } public void addClassName(String className){ getClassNames().add(className); } /** * 這裏用雙重檢測來實現單例模式 * 整個程序創建一個唯一的litePalAttr對象,能夠通過這個對象拿到數據庫的基本信息 * @return */ public static LitePalAttr getIntance(){ if (litePalAttr == null){ synchronized (LitePalAttr.class){ if (litePalAttr == null){ litePalAttr = new LitePalAttr(); } } } return litePalAttr; } @Override public String toString() { return "數據庫名稱:"+dbName+"\n數據庫版本號:"+version+"\n\n數據庫映射對象類名:"; } }
將xml的屬性值保存到實體類相應屬性裏:
package com.aliao.parser.saxparser; import com.aliao.parser.entity.LitePalAttr; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; /** * Created by aliao on 2015/6/4. */ public class LitePalContentHandler extends DefaultHandler{ private LitePalAttr litePalAttr; @Override public void startDocument() throws SAXException { litePalAttr = LitePalAttr.getIntance(); litePalAttr.getClassNames().clear();//由於litePalAttr是靜態的,所以假設再次進行解析要清空之前的數據 } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if ("dbname".equalsIgnoreCase(localName)){ for (int i = 0; i<attributes.getLength(); i++){ if ("value".equalsIgnoreCase(attributes.getLocalName(i))){ litePalAttr.setDbName(attributes.getValue(i).trim()); } } }else if ("version".equalsIgnoreCase(localName)){ for (int i = 0; i<attributes.getLength();i++){ if ("value".equalsIgnoreCase(attributes.getLocalName(i))){ litePalAttr.setVersion(Integer.parseInt(attributes.getValue(i).trim())); } } }else if ("mapping".equalsIgnoreCase(localName)){ for (int i = 0; i<attributes.getLength();i++){ if ("class".equalsIgnoreCase(attributes.getLocalName(i))){ litePalAttr.addClassName(attributes.getValue(i).trim()); } } } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { super.endElement(uri, localName, qName); } @Override public void endDocument() throws SAXException { super.endDocument(); } @Override public void characters(char[] ch, int start, int length) throws SAXException { super.characters(ch, start, length); } }
在主程序裏啟動解析:
package com.aliao.parser.saxparser; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.TextView; import com.aliao.parser.R; import com.aliao.parser.entity.LitePalAttr; /** * Created by aliao on 2015/6/4. */ public class LitePalParserFragment extends Fragment implements View.OnClickListener { public static final String TAG = LitePalParserFragment.class.getSimpleName(); private TextView mTvResult; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_saxparser_litepal, container, false); } @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); Button btnParse = (Button) view.findViewById(R.id.btn_parse_litepal); btnParse.setOnClickListener(this); mTvResult = (TextView) view.findViewById(R.id.tvSaxParserResult); } @Override public void onClick(View v) { LitePalParser.parseLitePalConfiguration(); showResult(); } private void showResult() { mTvResult.setVisibility(View.VISIBLE); LitePalAttr mLitePalAttr = LitePalAttr.getIntance(); StringBuffer sb = new StringBuffer(mLitePalAttr.toString()); for (String className:mLitePalAttr.getClassNames()){ sb.append("\n\n"+className); } mTvResult.setText("SAXParser解析litepal.xml結果:\n\n"+sb.toString()); } }
執行結果:
先到這吧
解讀郭神LitePal源代碼-litepal.xml的解析