Path: blob/jdk8u272-b10-aarch32-20201026/jaxp/src/com/sun/xml/internal/stream/XMLEventReaderImpl.java
83408 views
/*1* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package com.sun.xml.internal.stream;2627import com.sun.xml.internal.stream.events.XMLEventAllocatorImpl;28import java.util.NoSuchElementException;29import javax.xml.stream.XMLInputFactory;30import javax.xml.stream.XMLStreamConstants;31import javax.xml.stream.XMLStreamException;32import javax.xml.stream.XMLStreamReader;33import javax.xml.stream.events.EntityReference;34import javax.xml.stream.events.XMLEvent;35import javax.xml.stream.util.XMLEventAllocator;3637/**38* @author @author Neeraj Bajaj Sun Microsystems39*40*/4142public class XMLEventReaderImpl implements javax.xml.stream.XMLEventReader{4344protected XMLStreamReader fXMLReader ;45protected XMLEventAllocator fXMLEventAllocator;4647//only constructor will do because we delegate everything to underlying XMLStreamReader48public XMLEventReaderImpl(XMLStreamReader reader) throws XMLStreamException {49fXMLReader = reader ;50fXMLEventAllocator = (XMLEventAllocator)reader.getProperty(XMLInputFactory.ALLOCATOR);51if(fXMLEventAllocator == null){52fXMLEventAllocator = new XMLEventAllocatorImpl();53}54fPeekedEvent = fXMLEventAllocator.allocate(fXMLReader);55}565758public boolean hasNext() {59//if we have the peeked event return 'true'60if(fPeekedEvent != null)return true;61//this is strange XMLStreamReader throws XMLStreamException62//XMLEventReader doesn't throw XMLStreamException63boolean next = false ;64try{65next = fXMLReader.hasNext();66}catch(XMLStreamException ex){67return false;68}69return next ;70}717273public XMLEvent nextEvent() throws XMLStreamException {74//if application peeked return the peeked event75if(fPeekedEvent != null){76fLastEvent = fPeekedEvent ;77fPeekedEvent = null;78return fLastEvent ;79}80else if(fXMLReader.hasNext()){81//advance the reader to next state.82fXMLReader.next();83return fLastEvent = fXMLEventAllocator.allocate(fXMLReader);84}85else{86fLastEvent = null;87throw new NoSuchElementException();88}89}9091public void remove(){92//remove of the event is not supported.93throw new java.lang.UnsupportedOperationException();94}959697public void close() throws XMLStreamException {98fXMLReader.close();99}100101/** Reads the content of a text-only element. Precondition:102* the current event is START_ELEMENT. Postcondition:103* The current event is the corresponding END_ELEMENT.104* @throws XMLStreamException if the current event is not a START_ELEMENT105* or if a non text element is encountered106*/107public String getElementText() throws XMLStreamException {108//we have to keep reference to the 'last event' of the stream to be able109//to make this check - is there another way ? - nb.110if(fLastEvent.getEventType() != XMLEvent.START_ELEMENT){111throw new XMLStreamException(112"parser must be on START_ELEMENT to read next text", fLastEvent.getLocation());113}114115// STag content ETag116//[43] content ::= CharData? ((element | Reference | CDSect | PI | Comment) CharData?)*117118//<foo>....some long text say in KB and underlying parser reports multiple character119// but getElementText() events....</foo>120121String data = null;122//having a peeked event makes things really worse -- we have to test the first event123if(fPeekedEvent != null){124XMLEvent event = fPeekedEvent ;125fPeekedEvent = null;126int type = event.getEventType();127128if( type == XMLEvent.CHARACTERS || type == XMLEvent.SPACE ||129type == XMLEvent.CDATA){130data = event.asCharacters().getData();131}132else if(type == XMLEvent.ENTITY_REFERENCE){133data = ((EntityReference)event).getDeclaration().getReplacementText();134}135else if(type == XMLEvent.COMMENT || type == XMLEvent.PROCESSING_INSTRUCTION){136//ignore137} else if(type == XMLEvent.START_ELEMENT) {138throw new XMLStreamException(139"elementGetText() function expects text only elment but START_ELEMENT was encountered.", event.getLocation());140}else if(type == XMLEvent.END_ELEMENT){141return "";142}143144//create the string buffer and add initial data145StringBuffer buffer = new StringBuffer();146if(data != null && data.length() > 0 ) {147buffer.append(data);148}149//get the next event -- we should stop at END_ELEMENT but it can be any thing150//things are worse when implementing this function in XMLEventReader because151//there isn't any function called getText() which can get values for152//space, cdata, characters and entity reference153//nextEvent() would also set the last event.154event = nextEvent();155while(event.getEventType() != XMLEvent.END_ELEMENT){156if( type == XMLEvent.CHARACTERS || type == XMLEvent.SPACE ||157type == XMLEvent.CDATA){158data = event.asCharacters().getData();159}160else if(type == XMLEvent.ENTITY_REFERENCE){161data = ((EntityReference)event).getDeclaration().getReplacementText();162}163else if(type == XMLEvent.COMMENT || type == XMLEvent.PROCESSING_INSTRUCTION){164//ignore165} else if(type == XMLEvent.END_DOCUMENT) {166throw new XMLStreamException("unexpected end of document when reading element text content");167} else if(type == XMLEvent.START_ELEMENT) {168throw new XMLStreamException(169"elementGetText() function expects text only elment but START_ELEMENT was encountered.", event.getLocation());170} else {171throw new XMLStreamException(172"Unexpected event type "+ type, event.getLocation());173}174//add the data to the buffer175if(data != null && data.length() > 0 ) {176buffer.append(data);177}178event = nextEvent();179}180return buffer.toString();181}//if (fPeekedEvent != null)182183//if there was no peeked, delegate everything to fXMLReader184//update the last event before returning the text185data = fXMLReader.getElementText();186fLastEvent = fXMLEventAllocator.allocate(fXMLReader);187return data;188}189190/** Get the value of a feature/property from the underlying implementation191* @param name The name of the property192* @return The value of the property193* @throws IllegalArgumentException if the property is not supported194*/195public Object getProperty(java.lang.String name) throws java.lang.IllegalArgumentException {196return fXMLReader.getProperty(name) ;197}198199/** Skips any insignificant space events until a START_ELEMENT or200* END_ELEMENT is reached. If anything other than space characters are201* encountered, an exception is thrown. This method should202* be used when processing element-only content because203* the parser is not able to recognize ignorable whitespace if204* the DTD is missing or not interpreted.205* @throws XMLStreamException if anything other than space characters are encountered206*/207public XMLEvent nextTag() throws XMLStreamException {208//its really a pain if there is peeked event before calling nextTag()209if(fPeekedEvent != null){210//check the peeked event first.211XMLEvent event = fPeekedEvent;212fPeekedEvent = null ;213int eventType = event.getEventType();214//if peeked event is whitespace move to the next event215//if peeked event is PI or COMMENT move to the next event216if( (event.isCharacters() && event.asCharacters().isWhiteSpace())217|| eventType == XMLStreamConstants.PROCESSING_INSTRUCTION218|| eventType == XMLStreamConstants.COMMENT219|| eventType == XMLStreamConstants.START_DOCUMENT){220event = nextEvent();221eventType = event.getEventType();222}223224//we have to have the while loop because there can be many PI or comment event in sucession225while((event.isCharacters() && event.asCharacters().isWhiteSpace())226|| eventType == XMLStreamConstants.PROCESSING_INSTRUCTION227|| eventType == XMLStreamConstants.COMMENT){228229event = nextEvent();230eventType = event.getEventType();231}232233if (eventType != XMLStreamConstants.START_ELEMENT && eventType != XMLStreamConstants.END_ELEMENT) {234throw new XMLStreamException("expected start or end tag", event.getLocation());235}236return event;237}238239//if there is no peeked event -- delegate the work of getting next event to fXMLReader240fXMLReader.nextTag();241return (fLastEvent = fXMLEventAllocator.allocate(fXMLReader));242}243244public Object next() {245Object object = null;246try{247object = nextEvent();248}catch(XMLStreamException streamException){249fLastEvent = null ;250//don't swallow the cause251NoSuchElementException e = new NoSuchElementException(streamException.getMessage());252e.initCause(streamException.getCause());253throw e;254255}256return object;257}258259public XMLEvent peek() throws XMLStreamException{260//if someone call peek() two times we should just return the peeked event261//this is reset if we call next() or nextEvent()262if(fPeekedEvent != null) return fPeekedEvent;263264if(hasNext()){265//revisit: we can implement peek() by calling underlying reader to advance266// the stream and returning the event without the knowledge of the user267// that the stream was advanced but the point is we are advancing the stream268//here. -- nb.269270// Is there any application that relies on this behavior ?271//Can it be an application knows that there is particularly very large 'comment' section272//or character data which it doesn't want to read or to be returned as event273//But as of now we are creating every event but it can be optimized not to create274// the event.275fXMLReader.next();276fPeekedEvent = fXMLEventAllocator.allocate(fXMLReader);277return fPeekedEvent;278}else{279return null;280}281}//peek()282283private XMLEvent fPeekedEvent;284private XMLEvent fLastEvent;285286}//XMLEventReaderImpl287288289