/*
QuiXProc: efficient evaluation of XProc Pipelines.
Copyright (C) 2011-2015 Innovimax
All rights reserved.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package innovimax.quixproc.datamodel.in.xml;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.Source;
import innovimax.quixproc.datamodel.QuiXCharStream;
import innovimax.quixproc.datamodel.QuiXException;
import innovimax.quixproc.datamodel.event.AQuiXEvent;
import innovimax.quixproc.datamodel.in.AQuiXEventBufferStreamReader;
import innovimax.quixproc.datamodel.in.AStreamSource;
import innovimax.quixproc.datamodel.in.AStreamSource.XMLStreamSource;
import innovimax.quixproc.datamodel.in.QuiXEventStreamReader.State;
public class XMLQuiXEventStreamReader extends AQuiXEventBufferStreamReader {
private final XMLInputFactory ifactory;
private XMLStreamReader sreader;
private QuiXCharStream baseURI;
public XMLQuiXEventStreamReader() {
this.ifactory = XMLInputFactory.newFactory();
this.ifactory.setProperty(XMLInputFactory.IS_COALESCING, Boolean.FALSE);
this.ifactory.setProperty(XMLInputFactory.IS_VALIDATING, Boolean.FALSE);
}
private AQuiXEvent load(Source current) throws QuiXException {
try {
this.sreader = this.ifactory.createXMLStreamReader(current);
} catch (XMLStreamException e) {
throw new QuiXException(e);
}
this.baseURI = QuiXCharStream.fromSequence(current.getSystemId());
AQuiXEvent event = AQuiXEvent.getStartDocument(this.baseURI);
return event;
}
private QuiXCharStream charBuffer = QuiXCharStream.EMPTY;
@Override
public AQuiXEvent process(CallBack callback) throws QuiXException {
try {
if (!this.buffer.isEmpty()) {
return this.buffer.poll();
}
AQuiXEvent event = null;
if (!this.sreader.hasNext() && callback.getState() == State.START_SOURCE) {
// special case if the buffer is empty but the document has not
// been closed
event = AQuiXEvent.getEndDocument(this.baseURI);
callback.setState(State.END_SOURCE);
return event;
}
if (callback.getState() == State.END_SOURCE) {
return callback.processEndSource();
}
while (true) {
int code = this.sreader.next();
switch (code) {
case XMLStreamConstants.START_DOCUMENT:
// System.out.println("START_DOCUMENT");
// do nothing already opened so get next event
break;
case XMLStreamConstants.START_ELEMENT:
// System.out.println("START_ELEMENT");
event = AQuiXEvent.getStartElement(QuiXCharStream.fromSequence(this.sreader.getLocalName()),
QuiXCharStream.fromSequence(this.sreader.getNamespaceURI()),
QuiXCharStream.fromSequence(this.sreader.getPrefix()));
event = updateText(event);
for (int i = 0; i < this.sreader.getNamespaceCount(); i++) {
this.buffer.add(
AQuiXEvent.getNamespace(QuiXCharStream.fromSequence(this.sreader.getNamespacePrefix(i)),
QuiXCharStream.fromSequence(this.sreader.getNamespaceURI(i))));
}
for (int i = 0; i < this.sreader.getAttributeCount(); i++) {
this.buffer.add(AQuiXEvent.getAttribute(
QuiXCharStream.fromSequence(this.sreader.getAttributeLocalName(i)),
QuiXCharStream.fromSequence(this.sreader.getAttributeNamespace(i)),
QuiXCharStream.fromSequence(this.sreader.getAttributePrefix(i)),
QuiXCharStream.fromSequence(this.sreader.getAttributeValue(i))));
}
return event;
case XMLStreamConstants.END_DOCUMENT:
// System.out.println("END_DOCUMENT");
event = AQuiXEvent.getEndDocument(this.baseURI);
event = updateText(event);
callback.setState(State.END_SOURCE);
return event;
case XMLStreamConstants.END_ELEMENT:
// System.out.println("END_ELEMENT");
event = AQuiXEvent.getEndElement(QuiXCharStream.fromSequence(this.sreader.getLocalName()),
QuiXCharStream.fromSequence(this.sreader.getNamespaceURI()),
QuiXCharStream.fromSequence(this.sreader.getPrefix()));
event = updateText(event);
return event;
case XMLStreamConstants.ATTRIBUTE:
// System.out.println("ATTRIBUTE");
for (int i = 0; i < this.sreader.getAttributeCount(); i++) {
this.buffer.add(AQuiXEvent.getAttribute(
QuiXCharStream.fromSequence(this.sreader.getAttributeLocalName(i)),
QuiXCharStream.fromSequence(this.sreader.getAttributeNamespace(i)),
QuiXCharStream.fromSequence(this.sreader.getAttributePrefix(i)),
QuiXCharStream.fromSequence(this.sreader.getAttributeValue(i))));
}
return this.buffer.poll();
case XMLStreamConstants.CDATA:
// System.out.println("CDATA");
this.charBuffer = this.charBuffer.append(this.sreader.getText());
// do loop
break;
case XMLStreamConstants.CHARACTERS:
// System.out.println("CHARACTERS");
this.charBuffer = this.charBuffer.append(this.sreader.getText());
// do loop
break;
case XMLStreamConstants.SPACE:
// System.out.println("SPACE");
this.charBuffer.append(this.sreader.getText());
// do loop
break;
case XMLStreamConstants.COMMENT:
// System.out.println("COMMENT");
event = AQuiXEvent.getComment(QuiXCharStream.fromSequence(this.sreader.getText()));
event = updateText(event);
return event;
case XMLStreamConstants.PROCESSING_INSTRUCTION:
// System.out.println("PI");
event = AQuiXEvent.getPI(QuiXCharStream.fromSequence(this.sreader.getPITarget()),
QuiXCharStream.fromSequence(this.sreader.getPIData()));
event = updateText(event);
return event;
// case XMLStreamConstants.NAMESPACE:
// System.out.println("NAMESPACE");
default:
// do loop
break;
}
}
} catch (XMLStreamException e) {
throw new QuiXException(e);
}
}
/**
* This function take a QuiXEvent as parameter If there is character event
* waiting, it creates it, empties the charbuffer and push the current event
* in the stack. If not it return the parameter
*
* @param event
* @return
*/
private AQuiXEvent updateText(AQuiXEvent event) {
if (!this.charBuffer.isEmpty()) {
AQuiXEvent text = AQuiXEvent.getText(this.charBuffer);
this.charBuffer = QuiXCharStream.EMPTY;
this.buffer.add(event);
return text;
}
return event;
}
@Override
public void close() {
try {
this.sreader.close();
} catch (XMLStreamException e) {
e.printStackTrace();
}
}
@Override
protected AQuiXEvent load(AStreamSource current) throws QuiXException {
return load(((XMLStreamSource) current).asSource());
}
}