| /* |
| * 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; |
| } |
| |
| } |
| |
| } |