TMA-1
TMA-1

Reputation: 84

Stop/break an SaxXMLparsing

Im making an app that fetches some XML using SAXparser. Im parsing the xml and if the xml does not have a specific node I have to start over the SAXparser with a different URL.

This means that when I'm in my XML handler inside startElement I have to break/stop it and do it again. How can I do this break/stop/exit?

Here are some fake code to explain:

private String browsLevel(String url) {
                SAXParserFactory spf = SAXParserFactory.newInstance();
                SAXParser sp = spf.newSAXParser();
                XMLReader xr = sp.getXMLReader();


                URL sourceUrl = new URL(url);
                MyXMLHandler myXMLHandler = new MyXMLHandler();
                xr.setContentHandler(myXMLHandler);
                xr.parse(new InputSource(sourceUrl.openStream()));
}

//external class in a separate document
 public class MyXMLHandler extends DefaultHandler {

    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        // Im checking here if a special node exsists and if not I need to break/stop this and go to the Restart point above. 
        //I need to do something like this:                                     
            if (!localName.equals("mysspecialnode")) {
                MyXMLHandler.break(); //????
                browsLevel("a different url");
            }

Upvotes: 0

Views: 2136

Answers (3)

Adrian
Adrian

Reputation: 2354

Throw an exception. A SAXException suffices. If the document is short, the cost of throwing an exception may be greater than the cost of just allowing the SAX parser to finish though.

Or use a pull parser like kxml2 instead, where you are under control of the document flow and not the SAX engine - less weighty than using DOM.

Upvotes: 1

Trevor
Trevor

Reputation: 10993

Firstly, even if it were somehow possible to tell the SAX parser to terminate parsing early somehow in the callback method, it would be a bad idea to call browsLevel() again from within the handler. The handler is, of course, called by the SAX parser. The handler has to do its stuff and then return execution back to the SAX parser.

Also, I think you may misunderstand the purpose of startElement() in the handler. This method is called for each and every element start tag, in the order that they appear in the parsed XML document. The very first time startElement() is called will be for the very first element start tag in the document. Therefore, the code block within the if (!localName.equals("mysspecialnode")) statement will execute if the very first tag string, or any subsequent tag string, isn’t “myspecialnode”. In other words, this if statement alone isn’t sufficient to detect whether or not a particular start tag string appears anywhere in the XML document.

My suggestions are that you do either of the following:

1: Continue to use the SAX parser, but study the SAX parser documentation a little more so that you understand the purpose of the handler and the methods within it. The handler and its startElement() method will be called for every start element that exists in the document. If the data that you’re interested in is only contained within an element <myspecialnode ... > then you could simply do:

public class MyXMLHandler extends DefaultHandler { 

@Override 
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { 

    if (localName.equals("mysspecialnode")) { 
    // If you are here, then the XML document DOES contain <myspecialnode>. Now that you are here, you can parse the attributes
    // that are contained in this node. You could also set a flag to indicate that you’re now inside the <myspecialnode> element, 
    // to indicate that subsequent start tags are nodes inside <myspecialnode>, until the point where you get a </myspecialnode>
    // end tag.  
    // When parsing has finished, you check this flag and if it is false, you call
    // the SAX parser again to parse "a different url".
     }

Basically, with the SAX parser, your application code has to consume all of the document data through the handler, in the order it appears in the XML document.

2: The second option is to use the DOM parser. The Android platform contains both SAX and DOM parsers. The advantage of SAX is that it doesn’t have to build up a document object model of your XML document in memory beforehand; instead, it traverses the document and calls your handlers with the data as the document is parsed. The disadvantage of this is that you have to be able to deal with the data as it is delivered to your handler, in the order that the data appears in your document. With a DOM parser, you have the CPU and memory penalty associated with initially building up a document model of your XML. However, once that is done, you have the advantage of being able to use standard DOM calls to randomly navigate around your XML document, obtain nodelists of elements by given name, etc. I think you can achieve what you want to using SAX once you’ve understood how the handler works a little better, but it might also be worth doing an Android DOM parser tutorial too.

Upvotes: 0

Shachilies
Shachilies

Reputation: 1616

I have not seen any break method in SAX parser as this is event driven so to bypass it take a boolean as member variable and make it true where your condition matches and write "return" statement and use that boolean variable reference and return from every other event method (i.e. endElement and others if you want ).Then initiate call for another URL. (writing return statement will bypass all events faster and you can initiate your call).

private String browsLevel(String url) { SAXParserFactory spf = SAXParserFactory.newInstance(); SAXParser sp = spf.newSAXParser(); XMLReader xr = sp.getXMLReader();

            URL sourceUrl = new URL(url);
            MyXMLHandler myXMLHandler = new MyXMLHandler();
            xr.setContentHandler(myXMLHandler);
            xr.parse(new InputSource(sourceUrl.openStream()));

            if(myXMLHandler.isStart == true)
            {
                  // Now initiate a call here with different URL

                     browsLevel("a different url");
            }

}

         public class MyXMLHandler extends DefaultHandler
         {
            boolean isStart = false;

            @Override
            public void startElement(String uri, String localName, String qName, Attributes                                      attributes) throws SAXException
             {
                // Now check for boolean flag
                  if(isStart)
                  {
                    return;
                  }                                   
                  if (!localName.equals("mysspecialnode"))
                  {


                  isStart = true;


                  }

Upvotes: 0

Related Questions