/**
* Licensed to Apereo under one or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information regarding copyright ownership. Apereo
* licenses this file to you 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 the
* following location:
*
* <p>http://www.apache.org/licenses/LICENSE-2.0
*
* <p>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.apereo.portal.xml.stream;
import java.util.ListIterator;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.Characters;
import javax.xml.stream.events.EntityDeclaration;
import javax.xml.stream.events.EntityReference;
import javax.xml.stream.events.XMLEvent;
/**
* Wraps a {@link ListIterator} of {@link XMLEvent}s with an {@link XMLEventReader}
*
*/
public class XMLEventBufferReader implements XMLEventReader {
private final ListIterator<XMLEvent> eventBuffer;
private XMLEvent previousEvent;
public XMLEventBufferReader(ListIterator<XMLEvent> eventBuffer) {
this.eventBuffer = eventBuffer;
}
@Override
public void close() {
//NO-OP
}
@Override
public XMLEvent peek() {
final XMLEvent event = this.eventBuffer.next();
//Step back by one in the list
this.eventBuffer.previous();
return event;
}
@Override
public boolean hasNext() {
return this.eventBuffer.hasNext();
}
@Override
public XMLEvent next() {
this.previousEvent = this.eventBuffer.next();
return this.previousEvent;
}
@Override
public void remove() {
this.eventBuffer.remove();
}
@Override
public String getElementText() throws XMLStreamException {
XMLEvent event = this.previousEvent;
if (event == null) {
throw new XMLStreamException(
"Must be on START_ELEMENT to read next text, element was null");
}
if (!event.isStartElement()) {
throw new XMLStreamException(
"Must be on START_ELEMENT to read next text", event.getLocation());
}
final StringBuilder text = new StringBuilder();
while (!event.isEndDocument()) {
switch (event.getEventType()) {
case XMLStreamConstants.CHARACTERS:
case XMLStreamConstants.SPACE:
case XMLStreamConstants.CDATA:
{
final Characters characters = event.asCharacters();
text.append(characters.getData());
break;
}
case XMLStreamConstants.ENTITY_REFERENCE:
{
final EntityReference entityReference = (EntityReference) event;
final EntityDeclaration declaration = entityReference.getDeclaration();
text.append(declaration.getReplacementText());
break;
}
case XMLStreamConstants.COMMENT:
case XMLStreamConstants.PROCESSING_INSTRUCTION:
{
//Ignore
break;
}
default:
{
throw new XMLStreamException(
"Unexpected event type '"
+ XMLStreamConstantsUtils.getEventName(event.getEventType())
+ "' encountered. Found event: "
+ event,
event.getLocation());
}
}
event = this.nextEvent();
}
return text.toString();
}
@Override
public Object getProperty(String name) throws IllegalArgumentException {
// TODO no idea how to cache these :(
return null;
}
@Override
public XMLEvent nextEvent() throws XMLStreamException {
return this.next();
}
@Override
public XMLEvent nextTag() throws XMLStreamException {
XMLEvent event = this.nextEvent();
while ((event.isCharacters() && event.asCharacters().isWhiteSpace())
|| event.isProcessingInstruction()
|| event.getEventType() == XMLStreamConstants.COMMENT) {
event = this.nextEvent();
}
if (!event.isStartElement() && event.isEndElement()) {
throw new XMLStreamException(
"Unexpected event type '"
+ XMLStreamConstantsUtils.getEventName(event.getEventType())
+ "' encountered. Found event: "
+ event,
event.getLocation());
}
return event;
}
}