com.jsftoolkit.utils.xmlpull.PullEventCollector Maven / Gradle / Ivy
package com.jsftoolkit.utils.xmlpull;
import java.io.IOException;
import java.io.StringReader;
import java.util.Iterator;
import java.util.LinkedList;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.XMLReaderFactory;
import com.jsftoolkit.utils.Utils;
/**
* This {@link PullEventSource} has a few unusual properties. Firstly, it only
* operates on text strings. Secondly, the given text string may have multiple
* root elements and contain text outside of elements.
*
* This class encloses the passed in text in an wrapper element before parsing
* so that the document will be considered well formed.
*
* Consecutive calls to {@link #characters(char[], int, int)} will be
* consolidated into one {@link BodyText} event.
*
* This class is intended for small XML fragments.
*
* Generated Events: {@link StartElement}, {@link AttributeEvent},
* {@link BodyText}, {@link EndElement}.
*
* @author noah
*
*/
public class PullEventCollector extends DefaultHandler implements
ContentHandler, PullEventSource {
/**
* Wrapper element to make the passed in text well formed.
*/
private static final String WRAPPER = "PullEventCollectorWrapper";
private static final XMLReader READER;
static {
String[] toTry = { "org.apache.xerces.parsers.SAXParser",
"org.apache.crimson.parser.XMLReaderImpl" };
int i = 0;
XMLReader reader = null;
while (reader == null && i < toTry.length) {
try {
reader = XMLReaderFactory.createXMLReader(toTry[i++]);
} catch (SAXException e) {
}
}
if (reader == null) {
try {
reader = XMLReaderFactory.createXMLReader();
} catch (SAXException e) {
throw new RuntimeException(e);
}
}
READER = reader;
}
protected final LinkedList events = new LinkedList();
/**
* Parses the given text for events.
*
* @param text
* @throws IOException
* @throws SAXException
*/
public PullEventCollector(String text) throws IOException, SAXException {
this(READER, text);
}
/**
* Constructs a new instance that uses the given reader.
*
* @param reader
* @param text
* @throws IOException
* @throws SAXException
*/
public PullEventCollector(XMLReader reader, String text)
throws IOException, SAXException {
reader.setContentHandler(this);
reader.parse(new InputSource(new StringReader(String.format(
"<%s>%s%1$s>", WRAPPER, Utils.toString(text)))));
}
@Override
public void startElement(String uri, String localName, String qName,
Attributes attributes) {
if (!WRAPPER.equals(qName)) {
events.offer(new StartElement(qName));
for (int i = 0; i < attributes.getLength(); i++) {
AttributeEvent ae = new AttributeEvent(attributes.getQName(i),
attributes.getValue(i));
events.offer(ae);
}
}
}
@Override
public void characters(char[] ch, int start, int length) {
if (isBodyText()) {
((BodyText) events.getLast()).getText().append(ch, start, length);
} else {
events.offer(new BodyText(ch, start, length));
}
}
protected boolean isBodyText() {
return !events.isEmpty() && events.getLast() instanceof BodyText;
}
@Override
public void endElement(String uri, String localName, String qName) {
if (!WRAPPER.equals(qName)) {
events.offer(new EndElement(qName));
}
}
public Iterator iterator() {
return events.iterator();
}
}