Bei langen Zeichenketten ist es nicht zwingend, dass sie in einem Rutsch der characters() Methode übergeben werden.
<TSeq_sequence>
TAACCCTAACCCTAACCCTAACCCTAAC
</TSeq_sequence>
Denkbar ist hier ein (skizzierter) Aufruf von
characters(„T“);
characters(„AACCCTAAC“);
characters(„CCTAACCCTAACCCTAAC“);
Die Anwendung muss mit Character „Chunking“ rechnen und damit umgehen. Man kann es nicht abstellen! Viele Parser teilen die CDATA-Sektion auf, so dass nach jedem Carriage Returns einmal characters() aufgerufen wird.
Eine Lösung ist, die Zeichen zwischenzuspeichern, etwa in einem StringBuilder/StringBuffer.
public void characters(char[] ch, int start, int length)
throws SAXException {
currentText.append( ch, start, length );
}
Wenn endElement() aufgerufen wird, kann man den Puffer auswerten.
Eine interessante Idee ist, einen Delegate zu bauen, der sich für den SAX-Parser wie ein ContentHandler verhält, aber characters() abfängt und die Zeichen intern speichert. Alle anderen Methoden wie endDocument(), … gehen zum Original.
Zuvor jedoch werden die Methoden „flushen“, also ein Aufruf von characters() auf dem Original durchführen und alle Zeichen übergeben.
Anschauen kann man eine solche unter http://koders.com/java/fid607C6038FB8FD26D12EED5B32042D3EF48038AA7.aspx. Die Implementierung steht unter der Apache-Lizenz.
/*
* Copyright 2004 Outerthought bvba and Schaubroeck nv
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.outerj.daisy.htmlcleaner;import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
import org.xml.sax.Locator;
import org.xml.sax.Attributes;class MergeCharacterEventsHandler implements ContentHandler {
private ContentHandler consumer;
private char[] ch;
private int start = 0;
private int length = 0;public MergeCharacterEventsHandler(ContentHandler consumer) {
this.consumer = consumer;
}public void characters(char ch[], int start, int length) throws SAXException {
char[] newCh = new char[this.length + length];
if (this.ch != null)
System.arraycopy(this.ch, this.start, newCh, 0, this.length);
System.arraycopy(ch, start, newCh, this.length, length);
this.start = 0;
this.length = newCh.length;
this.ch = newCh;
}private void flushCharacters() throws SAXException {
if (ch != null) {
consumer.characters(ch, start, length);
ch = null;
start = 0;
length = 0;
}
}public void endDocument() throws SAXException {
flushCharacters();
consumer.endDocument();
}public void startDocument() throws SAXException {
flushCharacters();
consumer.startDocument();
}public void ignorableWhitespace(char ch[], int start, int length) throws SAXException {
flushCharacters();
consumer.ignorableWhitespace(ch, start, length);
}public void endPrefixMapping(String prefix) throws SAXException {
flushCharacters();
consumer.endPrefixMapping(prefix);
}public void skippedEntity(String name) throws SAXException {
flushCharacters();
consumer.skippedEntity(name);
}public void setDocumentLocator(Locator locator) {
consumer.setDocumentLocator(locator);
}public void processingInstruction(String target, String data) throws SAXException {
flushCharacters();
consumer.processingInstruction(target, data);
}public void startPrefixMapping(String prefix, String uri) throws SAXException {
flushCharacters();
consumer.startPrefixMapping(prefix, uri);
}public void endElement(String namespaceURI, String localName, String qName) throws SAXException {
flushCharacters();
consumer.endElement(namespaceURI, localName, qName);
}public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
flushCharacters();
consumer.startElement(namespaceURI, localName, qName, atts);
}
}