/* 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 java.util.Iterator; import java.util.LinkedList; import java.util.Queue; import javax.xml.namespace.NamespaceContext; import javax.xml.namespace.QName; import javax.xml.stream.Location; 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.QuiXToken; import innovimax.quixproc.datamodel.event.AQuiXEvent; import innovimax.quixproc.datamodel.stream.IQuiXStreamReader; import innovimax.quixproc.datamodel.stream.QuiXStreamException; public class QuiXStreamReader implements IQuiXStreamReader { private final Iterator<Source> sources; private int position; private final XMLInputFactory ifactory; private XMLStreamReader sreader; private QuiXCharStream baseURI; private final Queue<AQuiXEvent> buffer = new LinkedList<AQuiXEvent>(); public QuiXStreamReader(Iterable<Source> sources) { this.ifactory = XMLInputFactory.newFactory(); this.position = 0; this.ifactory.setProperty(XMLInputFactory.IS_COALESCING, Boolean.FALSE); this.ifactory.setProperty(XMLInputFactory.IS_VALIDATING, Boolean.FALSE); this.sources = sources.iterator(); } private void loadSource() throws XMLStreamException { Source current = this.sources.next(); this.sreader = this.ifactory.createXMLStreamReader(current); this.baseURI = QuiXCharStream.fromSequence(current.getSystemId()); } @Override public boolean hasNext() throws QuiXStreamException { return this.state != State.FINISH; } private enum State { INIT, START_SEQUENCE, START_DOCUMENT, END_DOCUMENT, FINISH } private State state = State.INIT; private final StringBuilder charBuffer = new StringBuilder(); @Override public QuiXToken next() throws QuiXStreamException { try { if (this.state == State.FINISH) { return null; } QuiXToken event; if (this.state == State.INIT) { event = QuiXToken.START_SEQUENCE; this.state = State.START_SEQUENCE; return event; } if (this.state == State.START_SEQUENCE) { if (!this.sources.hasNext()) { event = QuiXToken.END_SEQUENCE; this.state = State.FINISH; return event; } // there is at least one source loadSource(); event = QuiXToken.START_DOCUMENT; this.position++; this.state = State.START_DOCUMENT; return event; } if (!this.buffer.isEmpty()) { return this.buffer.poll().getType(); } if (!this.sreader.hasNext() && this.state == State.START_DOCUMENT) { // special case if the buffer is empty but the document has not // been closed event = QuiXToken.END_DOCUMENT; this.state = State.END_DOCUMENT; return event; } if (this.state == State.END_DOCUMENT) { if (this.sources.hasNext()) { // there is still sources loadSource(); this.position++; event = QuiXToken.START_DOCUMENT; this.state = State.START_DOCUMENT; return event; } event = QuiXToken.END_SEQUENCE; this.state = State.FINISH; return event; } 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 = QuiXToken.START_ELEMENT; // AQuiXEvent.getStartElement(sreader.getLocalName(), // sreader.getNamespaceURI(), 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 = QuiXToken.END_DOCUMENT; // AQuiXEvent.getEndDocument(this.baseURI); event = updateText(event); this.state = State.END_DOCUMENT; return event; case XMLStreamConstants.END_ELEMENT: // System.out.println("END_ELEMENT"); event = QuiXToken.END_ELEMENT; // AQuiXEvent.getEndElement(sreader.getLocalName(), // sreader.getNamespaceURI(), // sreader.getPrefix()); event = updateText(event); return event; case XMLStreamConstants.ATTRIBUTE: // System.out.println("ATTRIBUTE"); for (int i = 0; i < this.sreader.getAttributeCount(); i++) { // buffer.add( // QuiXToken.ATTRIBUTE // AQuiXEvent.getAttribute(sreader.getAttributeLocalName(i), // sreader.getAttributeNamespace(i), // sreader.getAttributePrefix(i), // sreader.getAttributeValue(i)) // ); } return this.buffer.poll().getType(); case XMLStreamConstants.CDATA: // System.out.println("CDATA"); this.charBuffer.append(this.sreader.getText()); // do loop break; case XMLStreamConstants.CHARACTERS: // System.out.println("CHARACTERS"); 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(sreader.getText()); // event = updateText(event); // return event; return null; case XMLStreamConstants.PROCESSING_INSTRUCTION: // System.out.println("PI"); // event = AQuiXEvent.getPI(sreader.getPITarget(), // sreader.getPIData()); // event = updateText(event); // return event; return null; // case XMLStreamConstants.NAMESPACE: // System.out.println("NAMESPACE"); default: // do loop break; } } } catch (XMLStreamException e) { throw new QuiXStreamException(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 QuiXToken updateText(QuiXToken event) { if (this.charBuffer.length() != 0) { // AQuiXEvent.getText(charBuffer.toString()); this.charBuffer.setLength(0); // this.buffer.add(event); QuiXToken text = QuiXToken.TEXT; return text; } return event; } @Override public void close() { try { this.sreader.close(); } catch (XMLStreamException e) { e.printStackTrace(); } } @Override public Object getProperty(String name) throws IllegalArgumentException { // TODO Auto-generated method stub return null; } @Override public void require(int type, String namespaceURI, String localName) throws QuiXStreamException { // TODO Auto-generated method stub } @Override public QuiXCharStream getElementText() throws QuiXStreamException { // TODO Auto-generated method stub return null; } @Override public int nextTag() throws QuiXStreamException { // TODO Auto-generated method stub return 0; } @Override public QuiXCharStream getNamespaceURI(String prefix) { // TODO Auto-generated method stub return null; } @Override public boolean isStartElement() { // TODO Auto-generated method stub return false; } @Override public boolean isEndElement() { // TODO Auto-generated method stub return false; } @Override public boolean isCharacters() { // TODO Auto-generated method stub return false; } @Override public boolean isWhiteSpace() { // TODO Auto-generated method stub return false; } @Override public String getAttributeValue(String namespaceURI, String localName) { // TODO Auto-generated method stub return null; } @Override public int getAttributeCount() { // TODO Auto-generated method stub return 0; } @Override public QName getAttributeName(int index) { // TODO Auto-generated method stub return null; } @Override public String getAttributeNamespace(int index) { // TODO Auto-generated method stub return null; } @Override public String getAttributeLocalName(int index) { // TODO Auto-generated method stub return null; } @Override public String getAttributePrefix(int index) { // TODO Auto-generated method stub return null; } @Override public String getAttributeType(int index) { // TODO Auto-generated method stub return null; } @Override public String getAttributeValue(int index) { // TODO Auto-generated method stub return null; } @Override public boolean isAttributeSpecified(int index) { // TODO Auto-generated method stub return false; } @Override public int getNamespaceCount() { // TODO Auto-generated method stub return 0; } @Override public String getNamespacePrefix(int index) { // TODO Auto-generated method stub return null; } @Override public String getNamespaceURI(int index) { // TODO Auto-generated method stub return null; } @Override public NamespaceContext getNamespaceContext() { // TODO Auto-generated method stub return null; } @Override public int getEventType() { // TODO Auto-generated method stub return 0; } @Override public String getText() { // TODO Auto-generated method stub return null; } @Override public char[] getTextCharacters() { // TODO Auto-generated method stub return null; } @Override public int getTextCharacters(int sourceStart, char[] target, int targetStart, int length) throws QuiXStreamException { // TODO Auto-generated method stub return 0; } @Override public int getTextStart() { // TODO Auto-generated method stub return 0; } @Override public int getTextLength() { // TODO Auto-generated method stub return 0; } @Override public String getEncoding() { // TODO Auto-generated method stub return null; } @Override public boolean hasText() { // TODO Auto-generated method stub return false; } @Override public Location getLocation() { // TODO Auto-generated method stub return null; } @Override public QName getName() { // TODO Auto-generated method stub return null; } @Override public String getLocalName() { // TODO Auto-generated method stub return null; } @Override public boolean hasName() { // TODO Auto-generated method stub return false; } @Override public String getNamespaceURI() { // TODO Auto-generated method stub return null; } @Override public String getPrefix() { // TODO Auto-generated method stub return null; } @Override public String getVersion() { // TODO Auto-generated method stub return null; } @Override public boolean isStandalone() { // TODO Auto-generated method stub return false; } @Override public boolean standaloneSet() { // TODO Auto-generated method stub return false; } @Override public String getCharacterEncodingScheme() { // TODO Auto-generated method stub return null; } @Override public String getPITarget() { // TODO Auto-generated method stub return null; } @Override public String getPIData() { // TODO Auto-generated method stub return null; } public static void main(String[] args) throws QuiXException { Iterable<Source> sources = java.util.Arrays .asList(new Source[] { new javax.xml.transform.stream.StreamSource( "/Users/innovimax/tmp/gs1/new/1000/1000_KO_22062015.xml"), new javax.xml.transform.stream.StreamSource( "/Users/innovimax/tmp/gs1/new/1000/1000_OK_22062015.xml") }); IQuiXStreamReader qesr = new QuiXStreamReader(sources); while (qesr.hasNext()) { System.out.println(qesr.next()); } } }