blob: 0d2587926e3df254a1ae5a733c35285b82b777c1 [file] [log] [blame]
/*
* Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
// Contributors:
// mmacivor - September 14/2009 - 2.0 - Initial implementation
package org.eclipse.persistence.internal.oxm.record;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.Characters;
import javax.xml.stream.events.Comment;
import javax.xml.stream.events.EndElement;
import javax.xml.stream.events.Namespace;
import javax.xml.stream.events.ProcessingInstruction;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
import org.eclipse.persistence.internal.oxm.Constants;
import org.eclipse.persistence.internal.oxm.Unmarshaller;
import org.xml.sax.InputSource;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.ext.Locator2;
/**
* Convert and XMLEventReader into SAX events.
*/
public class XMLEventReaderReader extends XMLReaderAdapter {
private int depth = 0;
//Required because the EndElement fails to properly won't give the list of namespaces going out of
//scope in some STAX implementations
private Map<Integer, List<Namespace>> namespaces;
private XMLEventReaderAttributes indexedAttributeList;
private XMLEvent lastEvent;
public XMLEventReaderReader() {
this.namespaces = new HashMap<>();
this.indexedAttributeList = new XMLEventReaderAttributes();
}
public XMLEventReaderReader(Unmarshaller xmlUnmarshaller) {
super(xmlUnmarshaller);
this.namespaces = new HashMap<>();
this.indexedAttributeList = new XMLEventReaderAttributes();
}
@Override
public void parse(InputSource input) throws SAXException {
if(null == contentHandler) {
return;
}
if(input instanceof XMLEventReaderInputSource) {
XMLEventReader xmlEventReader = ((XMLEventReaderInputSource) input).getXmlEventReader();
parse(xmlEventReader);
}
}
@Override
public Locator getLocator(){
if(locator == null){
locator = new EventReaderLocator();
}
((EventReaderLocator)locator).setEvent(lastEvent);
return locator;
}
private void parse(XMLEventReader xmlEventReader) throws SAXException {
try {
contentHandler.startDocument();
parseEvent(xmlEventReader.nextEvent());
while(depth > 0) {
parseEvent(xmlEventReader.nextEvent());
}
contentHandler.endDocument();
} catch(XMLStreamException ex) {
throw new RuntimeException(ex);
}
}
private void parseEvent(XMLEvent xmlEvent) throws SAXException {
switch (xmlEvent.getEventType()) {
case XMLEvent.ATTRIBUTE: {
break;
}
case XMLEvent.CDATA: {
Characters characters = xmlEvent.asCharacters();
if(null == lexicalHandler) {
contentHandler.characters(characters.getData().toCharArray(), 0, characters.getData().length());
} else {
lexicalHandler.startCDATA();
contentHandler.characters(characters.getData().toCharArray(), 0, characters.getData().length());
lexicalHandler.endCDATA();
}
break;
}
case XMLEvent.CHARACTERS: {
char[] characters = xmlEvent.asCharacters().getData().toCharArray();
contentHandler.characters(characters, 0, characters.length);
break;
}
case XMLEvent.COMMENT: {
if(null != lexicalHandler) {
char[] comment = ((Comment) xmlEvent).getText().toCharArray();
lexicalHandler.comment(comment, 0, comment.length);
}
break;
}
case XMLEvent.DTD: {
break;
}
case XMLEvent.END_DOCUMENT: {
depth--;
return;
}
case XMLEvent.END_ELEMENT: {
List<Namespace> declaredNs = this.namespaces.get(depth);
depth--;
EndElement endElement = xmlEvent.asEndElement();
QName name = endElement.getName();
String prefix = endElement.getName().getPrefix();
if(null == prefix || prefix.length() == 0) {
contentHandler.endElement(name.getNamespaceURI(), name.getLocalPart(), name.getLocalPart());
} else {
contentHandler.endElement(name.getNamespaceURI(), name.getLocalPart(), prefix + Constants.COLON + name.getLocalPart());
}
if(declaredNs != null) {
for(Namespace next : declaredNs) {
contentHandler.endPrefixMapping(next.getPrefix());
}
}
break;
}
case XMLEvent.ENTITY_DECLARATION: {
break;
}
case XMLEvent.ENTITY_REFERENCE: {
break;
}
case XMLEvent.NAMESPACE: {
break;
}
case XMLEvent.NOTATION_DECLARATION: {
break;
}
case XMLEvent.PROCESSING_INSTRUCTION: {
ProcessingInstruction pi = (ProcessingInstruction)xmlEvent;
contentHandler.processingInstruction(pi.getTarget(), pi.getData());
break;
}
case XMLEvent.SPACE: {
char[] characters = xmlEvent.asCharacters().getData().toCharArray();
contentHandler.characters(characters, 0, characters.length);
break;
}
case XMLEvent.START_DOCUMENT: {
depth++;
break;
}
case XMLEvent.START_ELEMENT: {
lastEvent = xmlEvent;
depth++;
StartElement startElement = xmlEvent.asStartElement();
Iterator<Namespace> namespaces = startElement.getNamespaces();
List<Namespace> declaredNs = null;
if(namespaces.hasNext()) {
declaredNs = new ArrayList<>();
}
while(namespaces.hasNext()) {
Namespace next = namespaces.next();
contentHandler.startPrefixMapping(next.getPrefix(), next.getNamespaceURI());
declaredNs.add(next);
}
if(declaredNs != null) {
this.namespaces.put(depth, declaredNs);
}
QName qName = startElement.getName();
String prefix = qName.getPrefix();
indexedAttributeList.setIterators(startElement.getAttributes(), startElement.getNamespaces());
if(null == prefix || prefix.length() == 0) {
contentHandler.startElement(qName.getNamespaceURI(), qName.getLocalPart(), qName.getLocalPart(), indexedAttributeList);
} else {
contentHandler.startElement(qName.getNamespaceURI(), qName.getLocalPart(), prefix + Constants.COLON + qName.getLocalPart(), indexedAttributeList);
}
break;
}
}
}
// Made static final for performance reasons.
private static final class XMLEventReaderAttributes extends IndexedAttributeList {
private Iterator namespaces;
private Iterator attrs;
public void setIterators(Iterator attrs, Iterator namespaces) {
reset();
this.namespaces = namespaces;
this.attrs = attrs;
}
@Override
protected Attribute[] attributes() {
if(null == attributes) {
if(attrs.hasNext() || namespaces.hasNext()) {
ArrayList<Attribute> attributesList = new ArrayList<>();
while(namespaces.hasNext()) {
Namespace next = (Namespace)namespaces.next();
String uri = javax.xml.XMLConstants.XMLNS_ATTRIBUTE_NS_URI;
String localName = next.getPrefix();
String qName;
if(null == localName || localName.length() == 0) {
localName = javax.xml.XMLConstants.XMLNS_ATTRIBUTE;
qName = javax.xml.XMLConstants.XMLNS_ATTRIBUTE;
} else {
qName = javax.xml.XMLConstants.XMLNS_ATTRIBUTE + Constants.COLON + localName;
}
String value = next.getNamespaceURI();
attributesList.add(new Attribute(uri, localName, qName, value));
}
while(attrs.hasNext()) {
javax.xml.stream.events.Attribute next = (javax.xml.stream.events.Attribute)attrs.next();
String uri = next.getName().getNamespaceURI();
String localName = next.getName().getLocalPart();
String prefix = next.getName().getPrefix();
String qName;
if(null == prefix || prefix.length() == 0) {
qName = localName;
} else {
qName = prefix + Constants.COLON + localName;
}
String value = next.getValue();
attributesList.add(new Attribute(uri, localName, qName, value));
}
attributes = attributesList.toArray(new Attribute[attributesList.size()]);
}else{
attributes = NO_ATTRIBUTES;
}
}
return attributes;
}
}
// Made static final for performance reasons.
/**
* <p>An implementation of Locator, with location data provided by an existing XMLEvent.</p>
*
* @see org.xml.sax.Locator
* @see javax.xml.stream.events.XMLEvent
*/
private static final class EventReaderLocator implements Locator2 {
private XMLEvent event;
/**
* Instantiates a new EventReaderLocator.
*/
public EventReaderLocator() {
}
/**
* Set the XMLEvent for this EventReaderLocator.
*
* @param e the XMLEvent object from which to copy location information.
*/
public void setEvent(XMLEvent e) {
this.event = e;
}
/**
* Returns the public ID of this Locator.
*/
@Override
public String getPublicId() {
if (this.event == null) {
return null;
}
return this.event.getLocation().getPublicId();
}
/**
* Returns the system ID of this Locator.
*/
@Override
public String getSystemId() {
if (this.event == null) {
return null;
}
return this.event.getLocation().getSystemId();
}
/**
* Returns the line number of this Locator.
*/
@Override
public int getLineNumber() {
if (this.event == null) {
return -1;
}
return this.event.getLocation().getLineNumber();
}
/**
* Returns the column number of this Locator.
*/
@Override
public int getColumnNumber() {
if (this.event == null) {
return -1;
}
return this.event.getLocation().getColumnNumber();
}
@Override
public String getXMLVersion() {
return null;
}
@Override
public String getEncoding() {
return null;
}
}
}