All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.daisy.common.stax.XMLStreamWriterHelper Maven / Gradle / Ivy

There is a newer version: 6.1.0
Show newest version
package org.daisy.common.stax;

import java.net.URI;
import java.util.ArrayList;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Queue;
import java.util.Stack;

import javax.xml.namespace.NamespaceContext;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;

import static javax.xml.stream.XMLStreamConstants.CDATA;
import static javax.xml.stream.XMLStreamConstants.CHARACTERS;
import static javax.xml.stream.XMLStreamConstants.COMMENT;
import static javax.xml.stream.XMLStreamConstants.END_DOCUMENT;
import static javax.xml.stream.XMLStreamConstants.END_ELEMENT;
import static javax.xml.stream.XMLStreamConstants.PROCESSING_INSTRUCTION;
import static javax.xml.stream.XMLStreamConstants.SPACE;
import static javax.xml.stream.XMLStreamConstants.START_DOCUMENT;
import static javax.xml.stream.XMLStreamConstants.START_ELEMENT;

import org.daisy.common.transform.TransformerException;

import com.google.common.util.concurrent.SettableFuture;

import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NamedNodeMap;

public final class XMLStreamWriterHelper {
	
	public interface XMLStreamWritable {
		/**
		 * @return the writer
		 */
		public BaseURIAwareXMLStreamWriter getWriter();
		/**
		 * @return the result
		 */
		public R doneWriting();
	}
	
	/**
	 * Collect pushed documents in a list.
	 *
	 * @param writables The writable supplier
	 * @param pusher The transformer
	 * @return The collected documents
	 * @throws TransformerException
	 */
	public static  List collect(Consumer> pusher,Supplier> writables)
			throws TransformerException {
		List> supplied = new ArrayList<>();
		pusher.accept(() -> {
				XMLStreamWritable w = writables.get();
				supplied.add(w);
				return w.getWriter();
			});
		List collect = new ArrayList<>();
		for (XMLStreamWritable w : supplied)
			collect.add(w.doneWriting());
		return collect;
	}
	
	/**
	 * Provide a "pull" interface (Iterator) for an object that "pushes" documents.
	 *
	 * @param writables The writable supplier
	 * @param pusher The transformer
	 * @return The iterator. May throw TransformerException.
	 */
	public static  Iterator pushToPull(Consumer> pusher, Supplier> writables) {
		SettableFuture>> queue = SettableFuture.create();
		new Supplier() {
				XMLStreamWritable writable;
				SettableFuture resultNode;
				public BaseURIAwareXMLStreamWriter get() throws TransformerException {
					if (resultNode != null)
						resultNode.set(writable.doneWriting());
					resultNode = SettableFuture.create();
					writable = writables.get();
					if (!queue.isDone()) {
						Queue> q = new ConcurrentLinkedQueue<>();
						q.add(resultNode);
						queue.set(q);
					} else {
						try {
							queue.get().add(resultNode);
						} catch (ExecutionException | InterruptedException e) {
							throw new RuntimeException(); // cannot happen
						}
					}
					return writable.getWriter();
				}
				void doneWriting() {
					resultNode.set(writable.doneWriting());
				}
				void setException(Throwable e) {
					resultNode.setException(e);
				}
				{
					new Thread(() -> {
							try {
								pusher.accept(this);
								if (!queue.isDone())
									queue.set(new ConcurrentLinkedQueue<>());
								else
									doneWriting();
							} catch (TransformerException e) {
								if (!queue.isDone())
									queue.setException(e.getCause());
								else
									setException(e.getCause());
							}
					}).start();
				}
			};
		return new Iterator() {
			public boolean hasNext() throws TransformerException {
				try {
					return !queue.get().isEmpty();
				} catch (ExecutionException e) {
					try {
						throw e.getCause();
					} catch (RuntimeException ee) {
						throw ee;
					} catch (Throwable ee) {
						throw new RuntimeException(ee);
					}
				} catch (InterruptedException e) {
					throw new RuntimeException(e); // cannot happen
				}
			}
			public R next() throws TransformerException {
				try {
					return queue.get().remove().get();
				} catch (ExecutionException e) {
					try {
						throw e.getCause();
					} catch (RuntimeException ee) {
						throw ee;
					} catch (Throwable ee) {
						throw new RuntimeException(ee);
					}
				} catch (InterruptedException e) {
					throw new RuntimeException(e); // cannot happen
				}
			}
			public void remove() {
				throw new UnsupportedOperationException();
			}
		};
	}
	
	private static QName nodeName(Node node) {
		String prefix = node.getPrefix();
		String ns = node.getNamespaceURI();
		String localPart = node.getLocalName();
		if (prefix != null)
			return new QName(ns, localPart, prefix);
		else
			return new QName(ns, localPart);
	}
	
	public static Map getAttributes(XMLStreamReader reader) {
		Map map = new HashMap();
		for (int i = 0; i < reader.getAttributeCount(); i++)
			map.put(reader.getAttributeName(i), reader.getAttributeValue(i));
		return map;
	}
	
	public static void writeAttribute(XMLStreamWriter writer, QName name, String value) throws XMLStreamException {
		writeAttribute(writer, name, value, false);
	}
	
	public static void writeAttribute(XMLStreamWriter writer, QName name, String value, boolean writeNamespaceNodes)
			throws XMLStreamException {
		String prefix = name.getPrefix();
		String ns = name.getNamespaceURI();
		String localPart = name.getLocalPart();
		if ("http://www.w3.org/2000/xmlns/".equals(ns)) {
			if (!writeNamespaceNodes)
				return;
		}
		if (prefix == null || "".equals(prefix))
			writer.writeAttribute(ns, localPart, value);
		else
			writer.writeAttribute(prefix, ns, localPart, value);
	}
	
	public static void writeAttribute(XMLStreamWriter writer, Node attr) throws XMLStreamException {
		writeAttribute(writer, attr, false);
	}
	
	public static void writeAttribute(XMLStreamWriter writer, Node attr, boolean copyNamespaceNodes) throws XMLStreamException {
		writeAttribute(writer, nodeName(attr), attr.getNodeValue(), copyNamespaceNodes);
	}
	
	public static void writeAttribute(XMLStreamWriter writer, Map.Entry attribute) throws XMLStreamException {
		writeAttribute(writer, attribute.getKey(), attribute.getValue());
	}
	
	public static void writeAttributes(XMLStreamWriter writer, Element element) throws XMLStreamException {
		writeAttributes(writer, element, false);
	}
	
	public static void writeAttributes(XMLStreamWriter writer, Element element, boolean copyNamespaceNodes) throws XMLStreamException {
		NamedNodeMap attributes = element.getAttributes();
		for (int i = 0; i < attributes.getLength(); i++) {
			Node attr = attributes.item(i);
			writeAttribute(writer, attr, copyNamespaceNodes);
		}
	}
	
	public static void writeAttributes(XMLStreamWriter writer, XMLStreamReader reader) throws XMLStreamException {
		for (int i = 0; i < reader.getAttributeCount(); i++)
			writeAttribute(writer, reader.getAttributeName(i), reader.getAttributeValue(i));
	}
	
	public static void writeAttributes(XMLStreamWriter writer, Map attributes) throws XMLStreamException {
		for (Map.Entry attr : attributes.entrySet())
			writeAttribute(writer, attr);
	}
	
	public static void writeCData(XMLStreamWriter writer, XMLStreamReader reader) throws XMLStreamException {
		writer.writeCData(reader.getText());
	}
	
	public static void writeCharacters(XMLStreamWriter writer, Node text) throws XMLStreamException {
		writer.writeCharacters(text.getNodeValue());
	}
	
	public static void writeCharacters(XMLStreamWriter writer, XMLStreamReader reader) throws XMLStreamException {
		writer.writeCharacters(reader.getText());
	}
	
	public static void writeComment(XMLStreamWriter writer, Node node) throws XMLStreamException {
		writer.writeComment(node.getNodeValue());
	}
	
	public static void writeComment(XMLStreamWriter writer, XMLStreamReader reader) throws XMLStreamException {
		writer.writeComment(reader.getText());
	}
	
	public static void writeDocument(XMLStreamWriter writer, XMLStreamReader reader) throws XMLStreamException {
		writer.writeStartDocument();
	  loop: while (true)
			try {
				int event = reader.next();
				switch (event) {
				case START_DOCUMENT:
					break;
				case END_DOCUMENT:
					break loop;
				case START_ELEMENT:
					writeElement(writer, reader);
					break;
				default:
					writeEvent(writer, event, reader);
				}
			} catch (NoSuchElementException e) {
				break;
			}
		writer.writeEndDocument();
	}
	
	public static void writeElement(XMLStreamWriter writer, XMLStreamReader reader) throws XMLStreamException {
		writeStartElement(writer, reader.getName());
		writeAttributes(writer, reader);
		int depth = 0;
		while (true)
			try {
				int event = reader.next();
				switch (event) {
				case START_ELEMENT:
					writeStartElement(writer, reader);
					writeAttributes(writer, reader);
					depth++;
					break;
				case END_ELEMENT:
					writer.writeEndElement();
					depth--;
					if (depth < 0)
						return;
					break;
				default:
					writeEvent(writer, event, reader); }}
			catch (NoSuchElementException e) {
				throw new RuntimeException("coding error"); }
	}
	
	public static void writeEvent(XMLStreamWriter writer, int event, XMLStreamReader reader) throws XMLStreamException {
		switch (event) {
		case START_DOCUMENT:
			writer.writeStartDocument();
			break;
		case END_DOCUMENT:
			writer.writeEndDocument();
			break;
		case START_ELEMENT:
			writeStartElement(writer, reader);
			break;
		case END_ELEMENT:
			writer.writeEndElement();
			break;
		case SPACE:
		case CHARACTERS:
			writeCharacters(writer, reader);
			break;
		case PROCESSING_INSTRUCTION:
			writeProcessingInstruction(writer, reader);
			break;
		case CDATA:
			writeCData(writer, reader);
			break;
		case COMMENT:
			writeComment(writer, reader);
			break;
		}
	}
	
	public static void writeProcessingInstruction(XMLStreamWriter writer, Node pi) throws XMLStreamException {
		writer.writeProcessingInstruction(pi.getLocalName(), pi.getNodeValue());
	}
	
	public static void writeProcessingInstruction(XMLStreamWriter writer, XMLStreamReader reader) throws XMLStreamException {
		String target = reader.getPITarget();
		String data = reader.getPIData();
		if (data == null)
			writer.writeProcessingInstruction(target);
		else
			writer.writeProcessingInstruction(target, data);
	}
	
	public static void writeStartElement(XMLStreamWriter writer, QName name) throws XMLStreamException {
		String prefix = name.getPrefix();
		String ns = name.getNamespaceURI();
		String localPart = name.getLocalPart();
		if (prefix != null)
			writer.writeStartElement(prefix, localPart, ns);
		else
			writer.writeStartElement(ns, localPart);
	}
	
	public static void writeStartElement(XMLStreamWriter writer, XMLStreamReader reader) throws XMLStreamException {
		writeStartElement(writer, reader.getName());
	}
	
	public static void writeStartElement(XMLStreamWriter writer, Element element) throws XMLStreamException {
		writeStartElement(writer, element, false, false, false);
	}
	
	public static void writeStartElement(XMLStreamWriter writer, Element element,
	                                     boolean copyAttributes, boolean copyNamespaceNodes, boolean copyBaseURI)
			throws XMLStreamException {
		String prefix = element.getPrefix();
		String ns = element.getNamespaceURI();
		String localPart = element.getLocalName();
		if (prefix != null)
			writer.writeStartElement(prefix, localPart, ns);
		else if (ns != null)
			writer.writeStartElement(ns, localPart);
		else
			writer.writeStartElement(localPart);
		if (copyAttributes) {
			writeAttributes(writer, element, copyNamespaceNodes);
		}
		if (copyBaseURI) {
			if (writer instanceof BaseURIAwareXMLStreamWriter) {
				String baseURI = element.getBaseURI();
				((BaseURIAwareXMLStreamWriter)writer).setBaseURI(baseURI == null ? null : URI.create(baseURI));
			} else
				throw new IllegalArgumentException();
		}
	}
	
	public interface WriterEvent {
		public void writeTo(XMLStreamWriter writer) throws XMLStreamException;
	}
	
	public interface FutureWriterEvent extends WriterEvent {
		public boolean isReady();
	}
	
	public static class BufferedXMLStreamWriter implements BaseURIAwareXMLStreamWriter {
		
		private final BaseURIAwareXMLStreamWriter zuper;
		
		public BufferedXMLStreamWriter(BaseURIAwareXMLStreamWriter zuper) {
			this.zuper = zuper;
		}
		
		private Queue queue = new LinkedList<>();
		
		public void writeEvent(FutureWriterEvent event) throws XMLStreamException {
			queue.add(event);
			flushQueue();
		}
		
		private boolean isQueueEmpty() {
			return queue == null || queue.isEmpty();
		}
		
		private boolean flushQueue() throws XMLStreamException {
			if (queue == null)
				return true;
			List todo = null;
			while (!queue.isEmpty()) {
				WriterEvent event = queue.peek();
				if (event instanceof FutureWriterEvent && !((FutureWriterEvent)event).isReady())
					break;
				if (todo == null)
					todo = new ArrayList();
				todo.add(event);
				queue.remove(); }
			Queue tmp = queue;
			queue = null;
			if (todo != null)
				for (WriterEvent event : todo)
					event.writeTo(this);
			queue = tmp;
			return queue.isEmpty();
		}

		@Override
		public void flush() throws XMLStreamException {
			if (!flushQueue())
				throw new XMLStreamException("not ready");
			zuper.flush();
		}

		@Override
		public void close() throws XMLStreamException {
			throw new UnsupportedOperationException();
		}

		@Override
		public URI getBaseURI() throws XMLStreamException {
			return zuper.getBaseURI();
		}
		
		@Override
		public NamespaceContext getNamespaceContext() {
			throw new UnsupportedOperationException();
		}

		@Override
		public String getPrefix(String uri) throws XMLStreamException {
			if (!isQueueEmpty())
				throw new IllegalStateException();
			return zuper.getPrefix(uri);
		}

		@Override
		public Object getProperty(String name) throws IllegalArgumentException {
			throw new UnsupportedOperationException();
		}

		@Override
		public void setBaseURI(URI baseURI) throws XMLStreamException {
			zuper.setBaseURI(baseURI);
		}

		@Override
		public void setDefaultNamespace(String uri) throws XMLStreamException {
			throw new UnsupportedOperationException();
		}

		@Override
		public void setNamespaceContext(NamespaceContext context) throws XMLStreamException {
			throw new UnsupportedOperationException();
		}

		@Override
		public void setPrefix(String prefix, String uri) {
			throw new UnsupportedOperationException();
		}
		
		@Override
		public void writeAttribute(String localName, String value) throws XMLStreamException {
			if (flushQueue())
				zuper.writeAttribute(localName, value);
			else
				queue.add(w -> w.writeAttribute(localName, value));
		}

		@Override
		public void writeAttribute(String prefix, String namespaceURI, String localName, String value) throws XMLStreamException {
			if (flushQueue())
				zuper.writeAttribute(prefix, namespaceURI, localName, value);
			else
				queue.add(w -> w.writeAttribute(prefix, namespaceURI, localName, value));
		}

		@Override
		public void writeAttribute(String namespaceURI, String localName, String value) throws XMLStreamException {
			if (flushQueue())
				zuper.writeAttribute(namespaceURI, localName, value);
			else
				queue.add(w -> w.writeAttribute(namespaceURI, localName, value));
		}
		
		@Override
		public void writeCData(String text) throws XMLStreamException {
			if (flushQueue())
				zuper.writeCData(text);
			else
				queue.add(w -> w.writeCData(text));
		}

		@Override
		public void writeCharacters(String text) throws XMLStreamException {
			if (flushQueue())
				zuper.writeCharacters(text);
			else
				queue.add(w -> w.writeCharacters(text));
		}

		@Override
		public void writeCharacters(char[] text, int start, int len) throws XMLStreamException {
			throw new UnsupportedOperationException();
		}
		
		@Override
		public void writeComment(String text) throws XMLStreamException {
			if (flushQueue())
				zuper.writeComment(text);
			else
				queue.add(w -> w.writeComment(text));
		}

		@Override
		public void writeDefaultNamespace(String namespaceURI) throws XMLStreamException {
			if (flushQueue())
				zuper.writeDefaultNamespace(namespaceURI);
			else
				queue.add(w -> w.writeDefaultNamespace(namespaceURI));
		}

		@Override
		public void writeDTD(String dtd) throws XMLStreamException {
			throw new UnsupportedOperationException();
		}

		@Override
		public void writeEmptyElement(String localName) throws XMLStreamException {
			throw new UnsupportedOperationException();
		}

		@Override
		public void writeEmptyElement(String namespaceURI, String localName) throws XMLStreamException {
			throw new UnsupportedOperationException();
		}

		@Override
		public void writeEmptyElement(String prefix, String localName, String namespaceURI) throws XMLStreamException {
			throw new UnsupportedOperationException();
		}
		
		@Override
		public void writeEndElement() throws XMLStreamException {
			if (flushQueue())
				zuper.writeEndElement();
			else
				queue.add(w -> w.writeEndElement());
		}
		
		@Override
		public void writeEndDocument() throws XMLStreamException {
			if (flushQueue())
				zuper.writeEndDocument();
			else
				queue.add(w -> w.writeEndDocument());
		}

		@Override
		public void writeEntityRef(String name) throws XMLStreamException {
			throw new UnsupportedOperationException();
		}
		
		@Override
		public void writeNamespace(String prefix, String namespaceURI) throws XMLStreamException {
			if (flushQueue())
				zuper.writeNamespace(prefix, namespaceURI);
			else
				queue.add(w -> w.writeNamespace(prefix, namespaceURI));
		}
		
		@Override
		public void writeProcessingInstruction(String target) throws XMLStreamException {
			if (flushQueue())
				zuper.writeProcessingInstruction(target);
			else
				queue.add(w -> w.writeProcessingInstruction(target));
		}

		@Override
		public void writeProcessingInstruction(String target, String data) throws XMLStreamException {
			if (flushQueue())
				zuper.writeProcessingInstruction(target, data);
			else
				queue.add(w -> w.writeProcessingInstruction(target, data));
		}
		
		@Override
		public void writeStartDocument() throws XMLStreamException {
			if (flushQueue())
				zuper.writeStartDocument();
			else
				queue.add(w -> w.writeStartDocument());
		}

		@Override
		public void writeStartDocument(String version) throws XMLStreamException {
			if (flushQueue())
				zuper.writeStartDocument(version);
			else
				queue.add(w -> w.writeStartDocument(version));
		}

		@Override
		public void writeStartDocument(String encoding, String version) throws XMLStreamException {
			if (flushQueue())
				zuper.writeStartDocument(encoding, version);
			else
				queue.add(w -> w.writeStartDocument(encoding, version));
		}
		
		@Override
		public void writeStartElement(String localName) throws XMLStreamException {
			if (flushQueue())
				zuper.writeStartElement(localName);
			else
				queue.add(w -> w.writeStartElement(localName));
		}

		@Override
		public void writeStartElement(String namespaceURI, String localName) throws XMLStreamException {
			if (flushQueue())
				zuper.writeStartElement(namespaceURI, localName);
			else
				queue.add(w -> w.writeStartElement(namespaceURI, localName));
		}

		@Override
		public void writeStartElement(String prefix, String localName, String namespaceURI) throws XMLStreamException {
			if (flushQueue())
				zuper.writeStartElement(prefix, localName, namespaceURI);
			else
				queue.add(w -> w.writeStartElement(prefix, localName, namespaceURI));
		}
	}
	
	public static class ToStringWriter implements BaseURIAwareXMLStreamWriter {
		
		private StringBuilder b = new StringBuilder();
		
		private Stack elements = new Stack();
		private boolean startTagOpen = false;
		
		@Override
		public String toString() {
			return b.toString();
		}

		@Override
		public void close() throws XMLStreamException {
			throw new UnsupportedOperationException();
		}

		@Override
		public void flush() throws XMLStreamException {
			throw new UnsupportedOperationException();
		}

		@Override
		public URI getBaseURI() throws XMLStreamException {
			throw new UnsupportedOperationException();
		}
		
		@Override
		public NamespaceContext getNamespaceContext() {
			throw new UnsupportedOperationException();
		}

		@Override
		public String getPrefix(String uri) throws XMLStreamException {
			throw new UnsupportedOperationException();
		}

		@Override
		public Object getProperty(String name) throws IllegalArgumentException {
			throw new UnsupportedOperationException();
		}

		@Override
		public void setBaseURI(URI baseURI) throws XMLStreamException {
		}

		@Override
		public void setDefaultNamespace(String uri) throws XMLStreamException {
			throw new UnsupportedOperationException();
		}

		@Override
		public void setNamespaceContext(NamespaceContext context) throws XMLStreamException {
			throw new UnsupportedOperationException();
		}

		@Override
		public void setPrefix(String prefix, String uri) throws XMLStreamException {
			throw new UnsupportedOperationException();
		}

		@Override
		public void writeAttribute(String localName, String value) throws XMLStreamException {
			writeAttribute(null, localName, value);
		}

		@Override
		public void writeAttribute(String prefix, String namespaceURI, String localName, String value) throws XMLStreamException {
			b.append(" ").append(localName).append("='").append(value).append("'");
		}

		@Override
		public void writeAttribute(String namespaceURI, String localName, String value) throws XMLStreamException {
			writeAttribute(null, namespaceURI, localName, value);
		}

		@Override
		public void writeCData(String data) throws XMLStreamException {
			throw new UnsupportedOperationException();
		}
		
		@Override
		public void writeCharacters(String text) throws XMLStreamException {
			if (startTagOpen) {
				b.append(">");
				startTagOpen = false; }
			b.append(text);
		}

		@Override
		public void writeCharacters(char[] text, int start, int len) throws XMLStreamException {
			throw new UnsupportedOperationException();
		}

		@Override
		public void writeComment(String data) throws XMLStreamException {
			throw new UnsupportedOperationException();
		}

		@Override
		public void writeDefaultNamespace(String namespaceURI) throws XMLStreamException {
			throw new UnsupportedOperationException();
		}

		@Override
		public void writeDTD(String dtd) throws XMLStreamException {
			throw new UnsupportedOperationException();
		}

		@Override
		public void writeEmptyElement(String localName) throws XMLStreamException {
			throw new UnsupportedOperationException();
		}

		@Override
		public void writeEmptyElement(String namespaceURI, String localName) throws XMLStreamException {
			throw new UnsupportedOperationException();
		}

		@Override
		public void writeEmptyElement(String prefix, String localName, String namespaceURI) throws XMLStreamException {
			throw new UnsupportedOperationException();
		}

		@Override
		public void writeEndDocument() throws XMLStreamException {
			throw new UnsupportedOperationException();
		}

		@Override
		public void writeEndElement() throws XMLStreamException {
			if (startTagOpen) {
				b.append("/>");
				startTagOpen = false;
				elements.pop(); }
			else
				b.append("");
		}

		@Override
		public void writeEntityRef(String name) throws XMLStreamException {
			throw new UnsupportedOperationException();
		}

		@Override
		public void writeNamespace(String prefix, String namespaceURI) throws XMLStreamException {
		}

		@Override
		public void writeProcessingInstruction(String target) throws XMLStreamException {
			throw new UnsupportedOperationException();
		}

		@Override
		public void writeProcessingInstruction(String target, String data) throws XMLStreamException {
			throw new UnsupportedOperationException();
		}

		@Override
		public void writeStartDocument() throws XMLStreamException {
			throw new UnsupportedOperationException();
		}

		@Override
		public void writeStartDocument(String version) throws XMLStreamException {
			throw new UnsupportedOperationException();
		}

		@Override
		public void writeStartDocument(String encoding, String version) throws XMLStreamException {
			throw new UnsupportedOperationException();
		}
		
		@Override
		public void writeStartElement(String localName) throws XMLStreamException {
			writeStartElement(null, localName);
		}

		@Override
		public void writeStartElement(String namespaceURI, String localName) throws XMLStreamException {
			writeStartElement(null, namespaceURI, localName);
		}

		@Override
		public void writeStartElement(String prefix, String localName, String namespaceURI) throws XMLStreamException {
			if (startTagOpen) {
				b.append(">");
				startTagOpen = false; }
			elements.push(localName);
			b.append("<").append(localName);
			startTagOpen = true;
		}
	}
	
	private XMLStreamWriterHelper() {
		// no instantiation
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy