JAVA SAX parser split calls to characters()
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" ???
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.
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.
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.
This is a feature of SAX. The parser can split the Text segments and call your characters
method as many times as it likes.
The reason for this is performance, which SAX prioritises over ease of use. SAX may have used up its internal buffer so to avoid copying it passes the data it has so far through to your code.
精彩评论