Android SAXParser, parse into array and get child nodes
Asked Answered
K

4

3

I'm working on a small app that uses and xml file to print an ArrayList of chapters which in turn points to a specific html file.

I used this tutorial to get me started: http://www.anddev.org/novice-tutorials-f8/parsing-xml-from-the-net-using-the-saxparser-t353.html

My xml file looks something like this:

<chapters>
    <chapter title="Förutsättningar">
        <page title="Sida 3" url="sida_3.html" />
        <page title="Sida 4" url="sida_4.html" />
    </chapter>
</chapters>

Using the tutorial above I've managed to output each chapter node into an ArrayList with a onListItemClick function on each item. So far so good.

The problem I'm having is that I can't figure out how to get a specific child node and load the html file when I click an item. I'm pretty new to Android.

Any ideas? I would really appreciate ANY help on the subject.

Here's my source:

ParsingXML.java

public class ParsingXML extends ListActivity {
private final String MY_DEBUG_TAG = "XmlParser";
public String lang = null;

@Override
public void onCreate(Bundle icicle) {
    super.onCreate(icicle);
    setTitle("Lastsäkring");

    Bundle bundle = this.getIntent().getExtras();
    lang = bundle.getString("lang");

    Log.i("ParsingXML", "Chosen language: " + this.lang + ", Type: " + this.lang.getClass().getName());

    TextView tv = new TextView(this);

    try {
        SAXParserFactory spf = SAXParserFactory.newInstance();
        SAXParser sp = spf.newSAXParser();

        XMLReader xr = sp.getXMLReader();

        ExampleHandler myExampleHandler = new ExampleHandler();
        xr.setContentHandler(myExampleHandler);

        /*
         * If XML-file is located online (needs internet permissions in the manifest):
         * URL url = new URL("http://dev.houdini.se/android/demo.xml");
         * xr.parse(new InputSource(url.openStream()));
         */

        if(this.lang.equals("en"))
            xr.parse(new InputSource(this.getResources().openRawResource(R.raw.en_content)));
        else
            xr.parse(new InputSource(this.getResources().openRawResource(R.raw.sv_content)));

        ParsedExampleDataSet parsedExampleDataSet = myExampleHandler.getParsedData();                       
        this.setListAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, parsedExampleDataSet.toArrayList()));

    } catch(Exception e) {
        tv.setText("Error: " + e.getMessage());
        Log.e(MY_DEBUG_TAG, "XmlParseError", e);
        this.setContentView(tv);
    }
}

protected void onListItemClick(ListView l, View v, int position, long id) {
    super.onListItemClick(l, v, position, id);
    Context context = getApplicationContext();
    int duration = Toast.LENGTH_SHORT;

    CharSequence text = "Clicked position: " + position + ", id: " + id;
    Toast toast = Toast.makeText(context, text, duration);
    toast.show();


    /*switch( position )
    {
       case 0:                                  
                Bundle bundle = new Bundle();
                bundle.putString("WindowTitle", "TESTA");
                Intent intent = new Intent(this, TextPage.class);
                intent.putExtras(bundle);
                startActivity(intent);
                break;                  
       case 1:  
            Intent video = new Intent(this, Video.class);
            startActivity(video);
           break;

       case 2:  
            Intent swipe = new Intent(this, Swipe.class);
            startActivity(swipe);
          break;
    }*/
}

public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.options_menu, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle item selection
    switch (item.getItemId()) {
        case R.id.settings:
            Intent prefsActivity = new Intent(getBaseContext(), Preferences.class);
            startActivity(prefsActivity);
            return true;
        default:
            return super.onOptionsItemSelected(item);
    }
}
}

ExampleHandler.java

public class ExampleHandler extends DefaultHandler {
private boolean in_chapters = false;
private boolean in_chapter = false;
private boolean in_page = false;

private ParsedExampleDataSet myParsedExampleDataSet = new ParsedExampleDataSet();

public ParsedExampleDataSet getParsedData() {
    return this.myParsedExampleDataSet;
}

@Override
public void startDocument() throws SAXException {
    this.myParsedExampleDataSet = new ParsedExampleDataSet();
}

@Override
public void endDocument() throws SAXException {
    // Nothing to do
}

@Override
public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
    if(localName.equals("chapters")) {
        this.in_chapters = true;
    } else if(localName.equals("chapter")) {
        this.in_chapter = true;
        String attrValue = atts.getValue("title");
        myParsedExampleDataSet.setExtractedString(attrValue);
    } else if(localName.equals("page")) {
        this.in_page = true;
    }
}

@Override
public void endElement(String namespaceURI, String localName, String qName) throws SAXException {
    if(localName.equals("chapters")) {
        this.in_chapters = false;
    } else if(localName.equals("chapter")) {
        this.in_chapter = false;
    } else if(localName.equals("page")) {
        this.in_page = false;
    }
}

@Override
public void characters(char ch[], int start, int length) {
    if(this.in_page == true) {
        myParsedExampleDataSet.setExtractedString(new String(ch, start, length));
    }
}

}

ParsedExampleDataSet.java

public class ParsedExampleDataSet {
private String extractedString = "";
private ArrayList<String> myArr = new ArrayList<String>();
private int extractedInt = 0;

public ArrayList<String> getExtractedString() {
    //return extractedString; Function Type = String
    return myArr;
}

public void setExtractedString(String extractedString) {
    //this.extractedString += extractedString + "\n";
    myArr.add(extractedString);
}

public int getExtractedInt() {
    return extractedInt;
}

public void setExtractedInt(int extractedInt) {
    this.extractedInt = extractedInt;
}

public String toString() {
    return "NODER\n" + this.extractedString;
}

public ArrayList<String> toArrayList() {
    return this.myArr;
}
}
Krysta answered 2/12, 2011 at 10:1 Comment(4)
Dude, if somebody helped You, vote !Manes
Gotta have a reputation of 15 or higher to vote. I'll mark my accepted answer as soon as I've solved the problems I'm having.Milanmilanese
Sory, I forget about this restrication ;/ what kind of problem have you yet ?Manes
Got some issues with printing my chapters. Check the comments on LAS_VEGAS post :) #8355098Milanmilanese
N
2

First create proper data structure:

public class PageNode {
    public String title;
    public String url;
    /* Getters/setter/constructor etc. if you feel like*/
    public String toString() {
       return title;
    }
}

public class ChapterNode {
    public String title;
    public ArrayList<PageNode> pages = new ArrayList<PageNode>();
    /* Getters/setter/constructor etc. if you feel like*/
}

And parse the xml accordingly. Example:

ArrayList<ChapterNode> chapters = new ArrayList<ChapterNode>();
ChapterNode chapterNode = null;

public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
    if(localName.equals("chapters")) {
    } else if(localName.equals("chapter")) {
        chapterNode = new ChapterNode();
        chapterNode.title = atts.getValue("title");
    } else if(localName.equals("page")) {
        PageNode pageNode = new PageNode();
        pageNode.title = atts.getValue("title");
        pageNode.url = atts.getValue("url");
        chapterNode.pages.add(pageNode);
    }
}

@Override
public void endElement(String namespaceURI, String localName, String qName) throws SAXException {
    if(localName.equals("chapters")) {
    } else if(localName.equals("chapter")) {
        chapters.add(chapterNode);
        chapterNode = null;
    } else if(localName.equals("page")) {
    }
}

Then you can access the pageNode like this:

PageNode pageNode = chapterNode.pages.get(position);

And set adapter like this:

this.setListAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, chapterNode.pages));
Nunn answered 2/12, 2011 at 10:16 Comment(4)
This seems like a good solution. But how would I output the chapter array? Previously, I did it like this: ParsedExampleDataSet parsedExampleDataSet = myExampleHandler.getParsedData(); this.setListAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, parsedExampleDataSet.toArrayList())); I tried to write a function that just returned the chapters array from my handler. It printed the correct amount of items into my ArrayList but the titles are a bit strange. For example... "com.houdini.lathunden. ChapterNode@40535908"Milanmilanese
I edited my answer, have a look at the changes in PageNode class and at the end of my answer.Nunn
First of all, thanks for your answers! I'm trying to wrap my head around this. I've made the changes you suggested. However, I can't figure out how to get the chapters array from ExampleHandler.java into ParsingXML.java (where I would print it).Milanmilanese
I got it all working after all by using your solution. Thanks for the assistance!Milanmilanese
R
0

You have to check for boolean variables while chapter tag is true you have to add pages in one arraylist and when chapter tag is false you have to add that arraylist in another gloabl arraylist

Renny answered 2/12, 2011 at 10:15 Comment(0)
F
0

(Without having looked at the example tutorial...)

Have a look at the Attributes parameter of startElement in your example handler. It should contain a value for "url" (it looks like you're only getting the value for "title").

Fretted answered 2/12, 2011 at 10:17 Comment(0)
M
0

I'm used to using DocumentBuilderFactory, so my solution is:

firstly, you should create ArrayHelper class like this:

public class ArrayHelper {
    public static ArrayList<HashMap<String, ?>> list = new ArrayList<HashMap<String, ?>>();
}

than:

public class CoversParseTask extends AsyncTask<Void, Void, Boolean> {

    @Override
    protected void onPreExecute() {

    }

    @Override
    protected Boolean doInBackground(Void ... arg0) {
            try {
                DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
                DocumentBuilder dBuilder = dFactory.newDocumentBuilder();
                document = dBuilder.parse(new InputSource(this.getResources().openRawResource(R.raw.en_content)));
                document.getDocumentElement().normalize();  
                NodeList nodeListIssue = document.getElementsByTagName("page");

                for (int i = 0; i < nodeListIssue.getLength(); i++) {
                    HashMap<String, Object> temp = new HashMap<String, Object>();
                    Node node = nodeListIssue.item(i);
                    Element elementMain = (Element) node;
                    String pageID = elementMain.getAttribute("title");
                    String issueID = elementMain.getAttribute("url");
                    temp.put("title", pageID);
                    temp.put("url", issueID);
                    ArrayHelper.list.add(temp);
                }
            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (ParserConfigurationException e) {
                e.printStackTrace();
            } catch (SAXException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            };
        return false; 
    }

    @Override
    protected void onPostExecute(Boolean result) {
    //what happend if done.
    }
}

and execute this class like this:

new CoversParseTask().execute();

now we must create simple adapter:

SimpleAdapter adapter = new MySimpleAdapter(this, selectLastSearch(), R.layout.custom_row_view, new String[] { "Title", "Url" }, new int[] { R.id.title, R.id.url});

and our MySimpleAdapter looks like this:

public class MySimpleAdapter extends SimpleAdapter {
    Context localcontext = null;
    public MySimpleAdapter(Context context,List<? extends Map<String, ?>> data, int resource, String[] from, int[] to) {
        super(context, data, resource, from, to);
        localcontext = context;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View view = super.getView(position, convertView, parent);
        return view;
    }
}

noe set adapter to listview:

listview.setAdapter(adapter);

if You want to get URL from list, you should add listner to listview like this:

listview.setOnItemClickListener(new OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapter, View view,
                    int position, long arg) {
                Log.v("URL", ArrayHelper.list.get(position).get("url").toString());
            }
        });

and thats all, i hope that i help you :)

Manes answered 2/12, 2011 at 10:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.