blob: b5a43bbdcab18f4337f798cb9aa5cc765bf381a3 [file] [log] [blame]
/*
* Copyright (c) 1998, 2019 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 09/2009 - 1.0 - Initial implementation
package org.eclipse.persistence.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.stream.XMLEventFactory;
import javax.xml.stream.XMLEventWriter;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.XMLEvent;
import org.eclipse.persistence.exceptions.XMLMarshalException;
import org.eclipse.persistence.internal.oxm.Constants;
import org.eclipse.persistence.internal.oxm.NamespaceResolver;
import org.eclipse.persistence.internal.oxm.XPathFragment;
import org.eclipse.persistence.internal.oxm.record.DomToXMLEventWriter;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
public class XMLEventWriterRecord extends MarshalRecord {
private Map<String, String> prefixMapping;
private NamespaceResolver namespaceResolver;
private XMLEventWriter xmlEventWriter;
private XMLEventFactory xmlEventFactory;
private DomToXMLEventWriter domToXMLEventWriter;
private boolean isStartElementOpen = false;
private List attributes;
private List namespaceDeclarations;
private XPathFragment xPathFragment;
public XMLEventWriterRecord(XMLEventWriter xmlEventWriter) {
this.xmlEventWriter = xmlEventWriter;
this.xmlEventFactory = XMLEventFactory.newInstance();
this.domToXMLEventWriter = new DomToXMLEventWriter(xmlEventFactory);
}
public XMLEventWriter getXMLEventWriter() {
return xmlEventWriter;
}
public void setXMLEventWriter(XMLEventWriter anXMLEventWriter) {
this.xmlEventWriter = anXMLEventWriter;
}
@Override
public void attribute(XPathFragment xPathFragment, NamespaceResolver namespaceResolver, String value) {
String namespaceURI = xPathFragment.getNamespaceURI();
XMLEvent event;
if(namespaceURI == null) {
event = xmlEventFactory.createAttribute(xPathFragment.getLocalName(), value);
} else {
String prefix = getPrefixForFragment(xPathFragment);
if(prefix == null) {
event = xmlEventFactory.createAttribute(null, namespaceURI, xPathFragment.getLocalName(), value);
} else {
if(xmlEventWriter.getNamespaceContext().getNamespaceURI(prefix) == null || !xmlEventWriter.getNamespaceContext().getNamespaceURI(prefix).equals(namespaceURI)) {
event = xmlEventFactory.createNamespace(prefix, namespaceURI);
try {
this.xmlEventWriter.setPrefix(prefix, namespaceURI);
} catch(XMLStreamException e) {
throw XMLMarshalException.marshalException(e);
}
}
event = xmlEventFactory.createAttribute(prefix, namespaceURI, xPathFragment.getLocalName(), value);
}
}
if(event.isNamespace()) {
if(null == this.namespaceDeclarations) {
this.namespaceDeclarations = new ArrayList();
}
this.namespaceDeclarations.add(event);
} else {
if(null == attributes) {
attributes = new ArrayList();
}
this.attributes.add(event);
}
}
@Override
public void attribute(String namespaceURI, String localName, String name, String value) {
XMLEvent event;
if(javax.xml.XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(namespaceURI)) {
try {
if(javax.xml.XMLConstants.XMLNS_ATTRIBUTE.equals(localName)) {
event = xmlEventFactory.createNamespace(value);
xmlEventWriter.setDefaultNamespace(value);
} else {
event = xmlEventFactory.createNamespace(localName, value);
xmlEventWriter.setPrefix(localName, value);
}
} catch(XMLStreamException e) {
throw XMLMarshalException.marshalException(e);
}
} else {
if(namespaceURI == null || namespaceURI.length() == 0) {
event = xmlEventFactory.createAttribute(localName, value);
} else {
int index = name.indexOf(':');
if(index == -1) {
event = xmlEventFactory.createAttribute(Constants.EMPTY_STRING, namespaceURI, localName, value);
} else {
String prefix = name.substring(0, index);
event = xmlEventFactory.createAttribute(prefix, namespaceURI, localName, value);
}
}
}
if(event.isNamespace()) {
if(null == this.namespaceDeclarations) {
this.namespaceDeclarations = new ArrayList();
}
this.namespaceDeclarations.add(event);
} else {
if(null == this.attributes) {
this.attributes = new ArrayList();
}
this.attributes.add(event);
}
}
private void openAndCloseStartElement() {
try {
String namespaceURI = xPathFragment.getNamespaceURI();
if(null == namespaceURI) {
Iterator attributesIterator = null;
if(null != attributes) {
attributesIterator = attributes.iterator();
}
Iterator namespaceDeclarationsIterator = null;
if(null != namespaceDeclarations) {
namespaceDeclarationsIterator = namespaceDeclarations.iterator();
}
xmlEventWriter.add(xmlEventFactory.createStartElement(Constants.EMPTY_STRING, Constants.EMPTY_STRING, xPathFragment.getLocalName(), attributesIterator, namespaceDeclarationsIterator));
String defaultNamespace = xmlEventWriter.getNamespaceContext().getNamespaceURI(Constants.EMPTY_STRING);
if(defaultNamespace != null && defaultNamespace.length() > 0 ) {
xmlEventWriter.setDefaultNamespace(Constants.EMPTY_STRING);
xmlEventWriter.add(xmlEventFactory.createNamespace(Constants.EMPTY_STRING));
}
} else {
String prefix = getPrefixForFragment(xPathFragment);
if(null == prefix) {
prefix = Constants.EMPTY_STRING;
}
Iterator attributesIterator = null;
if(null != attributes) {
attributesIterator = attributes.iterator();
}
Iterator namespaceDeclarationsIterator = null;
if(null != namespaceDeclarations) {
namespaceDeclarationsIterator = namespaceDeclarations.iterator();
}
xmlEventWriter.add(xmlEventFactory.createStartElement(prefix, namespaceURI, xPathFragment.getLocalName(), attributesIterator, namespaceDeclarationsIterator));
}
} catch(XMLStreamException ex) {
throw XMLMarshalException.marshalException(ex);
}
}
@Override
public void cdata(String value) {
try {
if(isStartElementOpen) {
openAndCloseStartElement();
isStartElementOpen = false;
}
for(String part : MarshalRecord.splitCData(value)) {
xmlEventWriter.add(xmlEventFactory.createCData(part));
}
} catch(Exception e) {
throw XMLMarshalException.marshalException(e);
}
}
@Override
public void characters(String value) {
try {
if(isStartElementOpen) {
openAndCloseStartElement();
isStartElementOpen = false;
}
xmlEventWriter.add(xmlEventFactory.createCharacters(value));
} catch(Exception e) {
throw XMLMarshalException.marshalException(e);
}
}
@Override
public void closeStartElement() {
}
@Override
public void openStartElement(XPathFragment xPathFragment, NamespaceResolver namespaceResolver) {
super.openStartElement(xPathFragment, namespaceResolver);
if (isStartElementOpen) {
openAndCloseStartElement();
}
isStartElementOpen = true;
this.xPathFragment = xPathFragment;
this.attributes = null;
this.namespaceDeclarations = null;
if(xPathFragment.isGeneratedPrefix()){
namespaceDeclaration(xPathFragment.getPrefix(), xPathFragment.getNamespaceURI());
}
writePrefixMappings();
}
@Override
public void element(XPathFragment frag) {
try {
if(isStartElementOpen) {
openAndCloseStartElement();
isStartElementOpen = false;
}
String namespaceURI = frag.getNamespaceURI();
String localName = frag.getLocalName();
String prefix = getPrefixForFragment(xPathFragment);
if(null == prefix) {
prefix = Constants.EMPTY_STRING;
}
xmlEventWriter.add(xmlEventFactory.createStartElement(prefix, namespaceURI, localName));
xmlEventWriter.add(xmlEventFactory.createEndElement(prefix, namespaceURI, localName));
} catch(Exception e) {
throw XMLMarshalException.marshalException(e);
}
}
@Override
public void endDocument() {
try {
if(isStartElementOpen) {
openAndCloseStartElement();
isStartElementOpen = false;
}
xmlEventWriter.add(xmlEventFactory.createEndDocument());
xmlEventWriter.flush();
} catch(Exception e) {
throw XMLMarshalException.marshalException(e);
}
}
@Override
public void endElement(XPathFragment pathFragment, NamespaceResolver namespaceResolver) {
if(isStartElementOpen) {
openAndCloseStartElement();
isStartElementOpen = false;
}
String prefix = getPrefixForFragment(pathFragment);
if(null == prefix) {
prefix = Constants.EMPTY_STRING;
}
try {
xmlEventWriter.add(xmlEventFactory.createEndElement(prefix, xPathFragment.getNamespaceURI(), pathFragment.getLocalName()));
} catch(Exception e) {
throw XMLMarshalException.marshalException(e);
}
}
@Override
public void node(Node node, NamespaceResolver resolver, String uri, String name) {
if(isStartElementOpen) {
openAndCloseStartElement();
isStartElementOpen = false;
}
try {
if(node.getNodeType() == Node.DOCUMENT_NODE) {
node = ((Document)node).getDocumentElement();
}
domToXMLEventWriter.writeToEventWriter(node, uri, name, xmlEventWriter);
} catch(XMLStreamException e) {
throw XMLMarshalException.marshalException(e);
}
}
@Override
public void startDocument(String encoding, String version) {
try {
xmlEventWriter.add(this.xmlEventFactory.createStartDocument(encoding, version, false));
} catch(Exception e) {
throw XMLMarshalException.marshalException(e);
}
}
@Override
public void startPrefixMapping(String prefix, String namespaceUri) {
if(null == this.prefixMapping) {
this.prefixMapping = new HashMap<>();
}
this.prefixMapping.put(prefix, namespaceUri);
}
private void writePrefixMappings() {
if(null != namespaceResolver) {
String defaultNamespace = namespaceResolver.getDefaultNamespaceURI();
if(defaultNamespace != null) {
XMLEvent namespace = xmlEventFactory.createNamespace(Constants.EMPTY_STRING, defaultNamespace);
if(null == namespaceDeclarations) {
namespaceDeclarations = new ArrayList();
}
namespaceDeclarations.add(namespace);
}
if(this.namespaceResolver.hasPrefixesToNamespaces()) {
for(Map.Entry<String, String> entry:this.namespaceResolver.getPrefixesToNamespaces().entrySet()) {
XMLEvent namespace = xmlEventFactory.createNamespace(entry.getKey(), entry.getValue());
if(null == namespaceDeclarations) {
namespaceDeclarations = new ArrayList();
}
namespaceDeclarations.add(namespace);
}
}
namespaceResolver = null;
}
if(null != prefixMapping) {
for(Map.Entry<String, String> entry:this.prefixMapping.entrySet()) {
XMLEvent namespace = xmlEventFactory.createNamespace(entry.getKey(), entry.getValue());
if(null == namespaceDeclarations) {
namespaceDeclarations = new ArrayList();
}
namespaceDeclarations.add(namespace);
}
prefixMapping = null;
}
}
@Override
public void namespaceDeclarations(NamespaceResolver namespaceResolver) {
}
@Override
public void startPrefixMappings(NamespaceResolver namespaceResolver) {
this.namespaceResolver = namespaceResolver;
}
}