/******************************************************************************* * Copyright (c) 2013 Gabriele Mariotti. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ package it.gmariotti.changelibs.library.parser; import android.content.Context; import android.util.Log; import android.util.Xml; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; import java.io.InputStream; import it.gmariotti.changelibs.library.Constants; import it.gmariotti.changelibs.library.internal.ChangeLog; import it.gmariotti.changelibs.library.internal.ChangeLogException; import it.gmariotti.changelibs.library.internal.ChangeLogRow; import it.gmariotti.changelibs.library.internal.ChangeLogRowHeader; /** * Read and parse res/raw/changelog.xml. * Example: * <p/> * <pre> * XmlParser parse = new XmlParser(this); * ChangeLog log=parse.readChangeLogFile(); * </pre> * <p/> * If you want to use a custom xml file, you can use: * <pre> * XmlParser parse = new XmlParser(this,R.raw.mycustomfile); * ChangeLog log=parse.readChangeLogFile(); * </pre> * <p/> * It is a example for changelog.xml * <pre> * <?xml version="1.0" encoding="utf-8"?> * <changelog bulletedList=false> * <changelogversion versionName="1.2" changeDate="20/01/2013"> * <changelogtext>new feature to share data</changelogtext> * <changelogtext>performance improvement</changelogtext> * </changelogversion> * <changelogversion versionName="1.1" changeDate="13/01/2013"> * <changelogtext>issue on wifi connection</changelogtext>* * </changelogversion>* * </changelog> * </pre> * * @author Gabriele Mariotti (gabri.mariotti@gmail.com) */ public class XmlParser extends BaseParser { private static final String TAG_CHANGELOG = "changelog"; private static final String TAG_CHANGELOGVERSION = "changelogversion"; //-------------------------------------------------------------------------------- //TAGs and ATTRIBUTEs in xml file //-------------------------------------------------------------------------------- private static final String TAG_CHANGELOGTEXT = "changelogtext"; private static final String ATTRIBUTE_BULLETEDLIST = "bulletedList"; private static final String ATTRIBUTE_VERSIONNAME = "versionName"; private static final String ATTRIBUTE_CHANGEDATE = "changeDate"; private static final String ATTRIBUTE_CHANGETEXT = "changeText"; private static final String ATTRIBUTE_CHANGETEXTTITLE = "changeTextTitle"; /** * TAG for logging * */ private static String TAG = "XmlParser"; private int mChangeLogFileResourceId = Constants.mChangeLogFileResourceId; //-------------------------------------------------------------------------------- //Constructors //-------------------------------------------------------------------------------- /** * Create a new instance for a context. * * @param context current Context */ public XmlParser(Context context) { super(context); } /** * Create a new instance for a context and for a custom changelogfile. * <p/> * You have to use file in res/raw folder. * * @param context current Context * @param changeLogFileResourceId reference for a custom xml file */ public XmlParser(Context context, int changeLogFileResourceId) { super(context); this.mChangeLogFileResourceId = changeLogFileResourceId; } //-------------------------------------------------------------------------------- /** * Read and parse res/raw/changelog.xml or custom file * * @return {@link ChangeLog} obj with all data * @throws Exception if changelog.xml or custom file is not found or if there are errors on parsing */ @Override public ChangeLog readChangeLogFile() throws Exception { ChangeLog chg = null; try { InputStream is = mContext.getResources().openRawResource(mChangeLogFileResourceId); if (is != null) { // Create a new XML Pull Parser. XmlPullParser parser = Xml.newPullParser(); parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false); parser.setInput(is, null); parser.nextTag(); // Create changelog obj that will contain all data chg = new ChangeLog(); // Parse file readChangeLogNode(parser, chg); // Close inputstream is.close(); } else { Log.d(TAG, "Changelog.xml not found"); throw new ChangeLogException("Changelog.xml not found"); } } catch (XmlPullParserException xpe) { Log.d(TAG, "XmlPullParseException while parsing changelog file", xpe); throw xpe; } catch (IOException ioe) { Log.d(TAG, "Error i/o with changelog.xml", ioe); throw ioe; } if (chg != null) Log.d(TAG, "Process ended. ChangeLog:" + chg.toString()); return chg; } /** * Parse changelog node * * @param parser * @param changeLog */ protected void readChangeLogNode(XmlPullParser parser, ChangeLog changeLog) throws Exception { if (parser == null || changeLog == null) return; // Parse changelog node parser.require(XmlPullParser.START_TAG, null, TAG_CHANGELOG); Log.d(TAG, "Processing main tag="); // Read attributes String bulletedList = parser.getAttributeValue(null, ATTRIBUTE_BULLETEDLIST); if (bulletedList == null || bulletedList.equals("true")) { changeLog.setBulletedList(true); super.bulletedList = true; } else { changeLog.setBulletedList(false); super.bulletedList = false; } //Parse nested nodes while (parser.next() != XmlPullParser.END_TAG) { if (parser.getEventType() != XmlPullParser.START_TAG) { continue; } String tag = parser.getName(); Log.d(TAG, "Processing tag=" + tag); if (tag.equals(TAG_CHANGELOGVERSION)) { readChangeLogVersionNode(parser, changeLog); } } } /** * Parse changeLogVersion node * * @param parser * @param changeLog * @throws Exception */ protected void readChangeLogVersionNode(XmlPullParser parser, ChangeLog changeLog) throws Exception { if (parser == null) return; parser.require(XmlPullParser.START_TAG, null, TAG_CHANGELOGVERSION); // Read attributes String versionName = parser.getAttributeValue(null, ATTRIBUTE_VERSIONNAME); String changeDate = parser.getAttributeValue(null, ATTRIBUTE_CHANGEDATE); if (versionName == null) throw new ChangeLogException("VersionName required in changeLogVersion node"); ChangeLogRowHeader row = new ChangeLogRowHeader(); row.setVersionName(versionName); row.setChangeDate(changeDate); changeLog.addRow(row); Log.d(TAG, "Added rowHeader:" + row.toString()); // Parse nested nodes while (parser.next() != XmlPullParser.END_TAG) { if (parser.getEventType() != XmlPullParser.START_TAG) { continue; } String tag = parser.getName(); Log.d(TAG, "Processing tag=" + tag); if (tag.equals(TAG_CHANGELOGTEXT)) { readChangeLogRowNode(parser, changeLog, versionName); } } } /** * Parse changeLogText node * * @param parser * @param changeLog * @throws Exception */ private void readChangeLogRowNode(XmlPullParser parser, ChangeLog changeLog, String versionName) throws Exception { if (parser == null) return; parser.require(XmlPullParser.START_TAG, null, TAG_CHANGELOGTEXT); String tag = parser.getName(); if (tag.equals(TAG_CHANGELOGTEXT)) { ChangeLogRow row = new ChangeLogRow(); row.setVersionName(versionName); // Read attributes String changeLogTextTitle = parser.getAttributeValue(null, ATTRIBUTE_CHANGETEXTTITLE); if (changeLogTextTitle != null) row.setChangeTextTitle(changeLogTextTitle); // It is possible to force bulleted List String bulletedList = parser.getAttributeValue(null, ATTRIBUTE_BULLETEDLIST); if (bulletedList != null) { if (bulletedList.equals("true")) { row.setBulletedList(true); } else { row.setBulletedList(false); } } else { row.setBulletedList(super.bulletedList); } // Read text if (parser.next() == XmlPullParser.TEXT) { String changeLogText = parser.getText(); if (changeLogText == null) throw new ChangeLogException("ChangeLogText required in changeLogText node"); row.parseChangeText(changeLogText); parser.nextTag(); } changeLog.addRow(row); Log.d(TAG, "Added row:" + row.toString()); } parser.require(XmlPullParser.END_TAG, null, TAG_CHANGELOGTEXT); } }