Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JAVA SAX parser split calls to characters()

Tags:

java

xml

I am doing a project to parse some data from the XML.

For example, the XML is

<abc>abcdefghijklmno</abc>

I need to parse "abcdefghijkmnlp".

But while I test my parse, I discover a big problem:

public class parser{
    private boolean hasABC = false;


        //Constructor HERE
        ......................
        ......................

     @Override
     public void startDocument () throws SAXException{  
     }

     @Override
     public void endDocument () throws SAXException{  
     }

     @Override
     public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException{  
          if ("abc".equalsIgnoreCase(localName)) {
              this.hasABC = true;
          }
      }
      @Override
      public void endElement(String namespaceURI, String localName, String qName) throws SAXException{
            if ("abc".equalsIgnoreCase(localName)) {
                 this.hasABC = false;
            }
       }
       @Override
       public void characters(char ch[], int start, int length){
            String content = new String(ch, start, length).trim(); 
            if(this.hasABC){
                 System.out.println("ABC = " + content);
            }
        }
    }

I discover that the parser has parsed the tag two time System print out is,

ABC = abcdefghi

ABC = jklmno <<============ split the message

Why the parser auto call back the characters() two time????

Is the XML haveing some "\n" or "\r" ???

like image 755
rebecca Avatar asked Dec 31 '10 02:12

rebecca


3 Answers

Parser is calling characters method more than one time, because it can and allowed per spec. This helps fast parser and keep their memory footprint low. If you want a single string create a new StringBuilder object in the startElement and process it on endElement method.

like image 118
Chandra Patni Avatar answered Oct 08 '22 01:10

Chandra Patni


You will be surprised but this is a documented behavior i.e. you can't assume that the parser will read and return all the text-data of an element in a single callback. I had the same experience earlier. You need to code to handle this situation or you can switch to Stax parser. You can use CharArrayWriter to accumulate the data across multiple callbacks.

See below from the JavaDoc of ContentHandler.characters(...)

The Parser will call this method to report each chunk of character data. SAX parsers may return all contiguous character data in a single chunk, or they may split it into several chunks; however, all of the characters in any single event must come from the same external entity so that the Locator provides useful information.

like image 27
Aravind Yarram Avatar answered Oct 08 '22 02:10

Aravind Yarram


You can change start, end and character method like:

  • add a "global" content variable
  • then null it in start method (content == null)
  • in end method u can println or add that content string to some object
  • in character method u can make if/else:

    if (content == null)
    {
        content = new String(ch, start, length);
    } else {
        content += new String(ch, start, length);
    }
    

    Brutal way (better to do it with stringbuilder) but works and "string" is not longer splitted.

like image 43
anthil Avatar answered Oct 08 '22 02:10

anthil