For the xml parsing in android environments, usually XMLPullParser is recommended in android docs. This example uses ExpatPullParser.
ExpatPullParser has pre-defined set of interfaces. So what we need is, adapting the interfaces of this class according to our needs. According to wikpedia and this stackoverflow question, adapter pattern is the right candidate for this situation.
This is our xml file.
First we create an abstract class as follows.
Use of Builder pattern in model class generation
In order to decouple the model class generation from xml parsing, I have used builder pattern. Here what we do is, generating a complex class structure.So in this situation, builder is useful than something like abstract factory. I will show you how Controller models were generated using the builder pattern.
ExpatPullParser has pre-defined set of interfaces. So what we need is, adapting the interfaces of this class according to our needs. According to wikpedia and this stackoverflow question, adapter pattern is the right candidate for this situation.
This is our xml file.
So lets first create models and the necessary interfaces.<Window dynamic="true" delay="10"> <controller automationId=\"Settings1\" monitoring=\"false\" check=\"existance\"> </controller> <controller automationId=\"Settings2\" monitoring=\"true\" check=\"existance\"> </controller> </Window>
public interface IBasicModel { }
import java.util.List; public interface IWindow extends IBasicModel { public boolean isDynamic(); public String getDelay(); public void setDynamic(boolean dynamic); public void setDelay(String delay); public void setControllerList(ListcontrollerList); }
import java.util.ArrayList; import java.util.List; public class Window implements IWindow{ private boolean dynamic; private String delay; private ListcontrollerList; public Window () { controllerList = new ArrayList (); } public boolean isDynamic() { return dynamic; } public String getDelay() { return delay; } public void setDynamic(boolean dynamic) { this.dynamic = dynamic; } public void setDelay(String delay) { this.delay = delay; } public void setControllerList(List controllerList) { this.controllerList = controllerList; } }
public interface IController extends IBasicModel{ public String getAutomationId(); public boolean isMonitoring(); public String getCheck(); public void setAutomationId(String automationId); public void setMonitoring(boolean monitoring); public void setCheck(String check); }
public class Controller implements IController{ private String automationId; private boolean monitoring; private String check; public String getAutomationId() { return automationId; } public boolean isMonitoring() { return monitoring; } public String getCheck() { return check; } public void setAutomationId(String automationId) { this.automationId = automationId; } public void setMonitoring(boolean monitoring) { this.monitoring = monitoring; } public void setCheck(String check) { this.check = check; } }Now what we need is adapting the interfaces of ExpatPullParser according to our requirements.
First we create an abstract class as follows.
public abstract class AbstractXMLAdapterHere is the concrete implementation of the adapter using ExpatFullParser{ protected T1 parser; public abstract IWindow parseXML(T2 xmlResource); public abstract IWindow processWindowTag() throws Exception; public abstract IController processControllerTag() throws Exception; }
public class ExpatPullParserAdapter extends AbstractXMLAdapter<XmlPullParser, String>This is the implementation of adapter pattern. Now next question is, generating the models. For that purpose, I have used builder pattern{ @Override public IWindow parseXML(String xmlResource) { try { parser = Xml.newPullParser(); parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false); parser.setInput(new StringReader(xmlResource)); parser.nextTag(); return processWindowTag(); } catch (Exception e) { e.printStackTrace(); return null; } } @Override public IWindow processWindowTag() throws Exception { List entries = new ArrayList(); parser.require(XmlPullParser.START_TAG, null, "Window"); IWindowBuilder windowBuilder = new WindowBuilder(); windowBuilder.processDelayTag(parser.getAttributeValue(null, "delay")); windowBuilder.processDynamicTag(parser.getAttributeValue(null, "dynamic")); while (parser.next() != XmlPullParser.END_TAG) { if (parser.getEventType() != XmlPullParser.START_TAG) { continue; } String name = parser.getName(); // Starts by looking for the entry tag if (name.equals("controller")) { entries.add(processControllerTag()); } else { skip(parser); } } windowBuilder.setControllerList(entries); return (IWindow)windowBuilder.getInstace(); } private void skip(XmlPullParser parser) throws XmlPullParserException, IOException { if (parser.getEventType() != XmlPullParser.START_TAG) { throw new IllegalStateException(); } int depth = 1; while (depth != 0) { switch (parser.next()) { case XmlPullParser.END_TAG: depth--; break; case XmlPullParser.START_TAG: depth++; break; } } } @Override public IController processControllerTag() throws Exception { IControllerBuilder builder = new ControllerBuilder(); builder.processAutomationId(parser.getAttributeValue(null, "automationId")); builder.processMonitoring(parser.getAttributeValue(null, "monitoring")); builder.processCheck(parser.getAttributeValue(null, "check")); while (parser.next() != XmlPullParser.END_TAG) { if (parser.getEventType() != XmlPullParser.START_TAG) { continue; } } return (IController)builder.getInstace(); } }
Use of Builder pattern in model class generation
In order to decouple the model class generation from xml parsing, I have used builder pattern. Here what we do is, generating a complex class structure.So in this situation, builder is useful than something like abstract factory. I will show you how Controller models were generated using the builder pattern.
public interface IBuilder { public IBasicModel getInstace(); }
public interface IControllerBuilder extends IBuilder { public void processAutomationId(String automationId); public void processMonitoring(String monitoring); public void processCheck(String check); }
public class ControllerBuilder implements IControllerBuilder{ private IController controller; public ControllerBuilder() { controller = new Controller(); } @Override public IController getInstace() { return controller; } @Override public void processAutomationId(String automationId) { controller.setAutomationId(automationId); } @Override public void processMonitoring(String monitoring) { controller.setMonitoring(Boolean.parseBoolean(monitoring)); } @Override public void processCheck(String check) { controller.setCheck(check); } }Complete example is now available in the github. For any query, feel free to contact me via my linkedin profile.