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