# SAX Parser optimieren



## Holger (10. Feb 2012)

Hey Leute,

ich wollte euch mal fragen ob es Grundsätzliche Regeln gibt wie man einen SAX-Parser aufbauen sollte, insbesondere den Handler um das höchstmögliche an Performance raus zu holen? 
Also ich parse momentan xml Dateien von 50kb und das dauert ca 10sec und das ist eindeutig zu lang. Weiß nur nicht woran das liegen könnte, arbeite zum ersten mal mit dem SAX-Parser.

Wäre für Performance steigernde Ratschläge echt dankbar.

Grüße


----------



## SlaterB (10. Feb 2012)

Tipp: Aufgabentrennung testen,
einmal den Sax-Parser quasi leer durchlaufen lassen, alle Einzel-Einträge in den Methoden loggen oder für noch schnellere Zeiten lediglich in eine Liste einfügen,
dauert das schon Zeit oder ist das für 50kb in unter 0.1 sec durch?

falls schnell genug, liegt der restliche Zeitverbrauch wohl in dem individuellen Handler-Code, da kann man pauschal wenig zu sagen,
außer dass es mit mit dem Thementitel SAX vielleicht gar nichts zu tun hat


----------



## Wildcard (10. Feb 2012)

Also der SAX Parser braucht in jedem Fall keine 10 Sekunden für ein paar KB, das ist sicherlich der Handler. Ohne Code kann man nicht viel sagen. IMO hat StAX die schönere API. Die Performance ist ähnlich, aber man tut sich oft leichter damit schnellen Code mit StAX zu schreiben als mit dem SAX Callback Interface (hängt natürlich auch vom Use-Case ab).


----------



## Holger (13. Feb 2012)

Danke schon einmal für eure Antworten. Also den Stax Parser werde ich nicht verwenden  können, da dieser unter Android nicht unterstützt wird. 

Ich hab euch jetzt mal den Handler Code angefügt. Ein Punkt der die ganze Sache Verzögert ist mir schion aufgefallen und das ist der content:encoded Tag.


```
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;

public class TextNewsHandler extends DefaultHandler{
	private boolean in_item = false;
	private boolean in_title = false;
	private boolean in_link = false;
	private boolean in_description = false;
	private boolean in_content = false;
	VideoLinkParser vlp = new VideoLinkParser();
	
	private ArrayList<TextNews> newslist = new ArrayList<TextNews>();
	private TextNews textnews;

	/**
	 * @return the newslist
	 */
	public ArrayList<TextNews> getNewslist() {
		return newslist;
	}
	
	public void startDocument() throws SAXException {
		
	}
	
	public void endDocument() throws SAXException {
		
	}
	
	public void startElement(String URI, String localName, String qName, Attributes attributes) throws SAXException {
		
		if(localName.equals("item")){
			textnews = new TextNews();
			in_item = true;
		}
		else if(localName.equals("title")){
			in_title = true;
		}
		else if(localName.equals("link")){
			in_link = true;
		}
		else if(localName.equals("description")){
			in_description = true;
		}
		else if(localName.equalsIgnoreCase("content:encoded") || qName.equals("content:encoded")){
			in_content = true;

		}
		
	}
	
	public void endElement(String URI, String localName, String qName) throws SAXException {
		if(localName.equals("item")){
			if(textnews.getImg() != null && textnews.getContent() != null){
				newslist.add(textnews);
			}
			in_item = false;
		}
		else if(localName.equals("title")){
			in_title = false;
		}
		else if(localName.equals("link")){
			in_link = false;
		}
		else if(localName.equals("description")){
			in_description = false;
		}
		else if(localName.equalsIgnoreCase("content:encoded") || qName.equals("content:encoded")){
			in_content = false;
			String content = textnews.getContent();
			
			String[] t = content.split("alt=\"\" />", 2);
			if(t.length >= 2){
				t[1].replaceAll("<.*.>", "");
				textnews.setNewContent(t[1]/*.replaceAll("]]>", "")*/);
				String[] temp2 =t[0].split("<img src=\"");
				if(temp2.length == 2){
					String[] temp3 = temp2[1].split("\".*");
					temp3[0].replaceAll("<.*.>", "");
					textnews.setImg_url(temp3[0]);
					textnews.setImg(getBitMapFromUrl(temp3[0]));
				}
				
				
			}
			else{
				textnews.setNewContent(t[0]);
			}
			
		}
		
		
		
	}
	
	public void characters(char[] charsequence, int start, int length){
		
		if(this.in_item && this.in_title){
		
			textnews.setTitle(new String(charsequence, start, length));

		}
		
		if(this.in_item && this.in_link && !this.in_content){
			
			//textnews.setLink(new String(charsequence, start, length));
			textnews.setVideoLink(vlp.getVideoLink(new String(charsequence, start, length)));
			
		}
		if(this.in_item && this.in_description){
			
			textnews.setDescription(new String(charsequence, start, length));
			
		}
		
		if(this.in_item && this.in_content && !this.in_link){
			textnews.setContent(new String(charsequence, start, length));
			
			

		}
		
	}
	public static Bitmap getBitMapFromUrl(String src){
		try {
			URL url = new URL(src);
			HttpURLConnection connection = (HttpURLConnection) url.openConnection();
			connection.setDoInput(true);
			connection.connect();
			InputStream input = connection.getInputStream();
			Bitmap myBitmap = BitmapFactory.decodeStream(input);
			return myBitmap;
			
		} catch (MalformedURLException e) {
			return null;
		} catch (IOException e) {
			return null;
			
		}
		
		
	}
}
```


----------



## Wildcard (13. Feb 2012)

Das hier dürfte dein Hauptproblem sein:


> textnews.setImg(getBitMapFromUrl(temp3[0]));


Die ganzen split und replace sind auch teuer, aber eine URL Connection und Bilder laden ist viel teuerer.
Wäre es nicht sinnvoll die Bilder lazy zu laden, anstatt eager beim Parsen?


----------



## Holger (14. Feb 2012)

Hey Wildcard,

danke für deine Antwort. Habe die Funktion total aus den Augen verloren. Ich werde es später mal ausprobieren ob es möglich ist die Bilder zu einem späteren Zeitpunkt zu laden. Ich danke dir für deinen Hinweis

Gruß
Holger


----------

