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

org.daisy.common.saxon.SaxonOutputValue Maven / Gradle / Ivy

The newest version!
package org.daisy.common.saxon;

import java.net.URI;
import java.util.function.Consumer;

import javax.xml.stream.XMLStreamException;

import net.sf.saxon.Configuration;
import net.sf.saxon.event.NamespaceReducer;
import net.sf.saxon.event.Receiver;
import net.sf.saxon.event.StreamWriterToReceiver;
import net.sf.saxon.s9api.Axis;
import net.sf.saxon.s9api.SaxonApiException;
import net.sf.saxon.s9api.XdmDestination;
import net.sf.saxon.s9api.XdmItem;
import net.sf.saxon.s9api.XdmNode;
import net.sf.saxon.trans.XPathException;

import org.daisy.common.stax.BaseURIAwareXMLStreamWriter;
import org.daisy.common.stax.DelegatingBaseURIAwareXMLStreamWriter;
import org.daisy.common.transform.TransformerException;
import org.daisy.common.transform.XMLOutputValue;

public class SaxonOutputValue extends XMLOutputValue {

	private SaxonOutputValue backingValue = null;
	private final Consumer xdmItemConsumer;

	public SaxonOutputValue(Consumer value, Configuration configuration) {
		super(createXMLStreamWriter(value, configuration));
		xdmItemConsumer = value;
	}

	public SaxonOutputValue(SaxonOutputValue value) {
		super(value);
		backingValue = value;
		xdmItemConsumer = null; // will not be accessed
	}

	public Consumer asXdmItemConsumer() {
		if (backingValue != null)
			return backingValue.asXdmItemConsumer();
		else
			return xdmItemConsumer;
	}

	@Override
	public BaseURIAwareXMLStreamWriter asXMLStreamWriter() {
		return super.asXMLStreamWriter();
	}

	private static BaseURIAwareXMLStreamWriter createXMLStreamWriter(Consumer itemConsumer, Configuration config) {
		return new DelegatingBaseURIAwareXMLStreamWriter() {
			private BaseURIAwareXMLStreamWriter writer = null;
			private Receiver receiver;
			// "An XdmDestination is designed to hold a single tree rooted at a document node."
			private XdmDestination destination;
			private boolean seenStartDocument = false;
			private int elementDepth = 0;
			protected BaseURIAwareXMLStreamWriter delegate() {
				if (writer == null) {
					try {
						destination = new XdmDestination();
						receiver = new NamespaceReducer(destination.getReceiver(config));
						receiver.open();
						writer = new BaseURIAwareStreamWriterToReceiver(receiver);
					} catch (SaxonApiException | XPathException e) {
						throw new TransformerException(e);
					}
				}
				return writer;
			}
			@Override
			public void writeStartDocument() throws XMLStreamException {
				if (elementDepth != 0)
					throw new XMLStreamException();
				if (seenStartDocument)
					throw new XMLStreamException();
				super.writeStartDocument();
				seenStartDocument = true;
			}
			@Override
			public void writeStartDocument(String version) throws XMLStreamException {
				if (elementDepth != 0)
					throw new XMLStreamException();
				if (seenStartDocument)
					throw new XMLStreamException();
				super.writeStartDocument(version);
				seenStartDocument = true;
			}
			@Override
			public void writeStartDocument(String encoding, String version) throws XMLStreamException {
				if (elementDepth != 0)
					throw new XMLStreamException();
				if (seenStartDocument)
					throw new XMLStreamException();
				super.writeStartDocument(encoding, version);
				seenStartDocument = true;
			}
			@Override
			public void writeStartElement(String localName) throws XMLStreamException {
				super.writeStartElement(localName);
				elementDepth++;
			}
			@Override
			public void writeStartElement(String namespaceURI, String localName) throws XMLStreamException {
				super.writeStartElement(namespaceURI, localName);
				elementDepth++;
			}
			@Override
			public void writeStartElement(String prefix, String localName, String namespaceURI) throws XMLStreamException {
				super.writeStartElement(prefix, localName, namespaceURI);
				elementDepth++;
			}
			@Override
			public void writeEndElement() throws XMLStreamException {
				if (elementDepth == 0)
					throw new XMLStreamException();
				super.writeEndElement();
				elementDepth--;
				if (!seenStartDocument && elementDepth == 0) {
					try {
						receiver.close();
						XdmNode doc = destination.getXdmNode();
						itemConsumer.accept(doc.axisIterator(Axis.CHILD).next());
					} catch (XPathException e) {
						throw new XMLStreamException(e);
					}
					seenStartDocument = false;
					writer = null;
				}
			}
			@Override
			public void writeEndDocument() throws XMLStreamException {
				if (elementDepth != 0)
					throw new XMLStreamException();
				if (!seenStartDocument)
					throw new XMLStreamException();
				super.writeEndDocument();
				try {
					receiver.close();
					itemConsumer.accept(destination.getXdmNode());
				} catch (XPathException e) {
					throw new XMLStreamException(e);
				}
				seenStartDocument = false;
				writer = null;
			}
		};
	}

	private static class BaseURIAwareStreamWriterToReceiver extends StreamWriterToReceiver
		implements BaseURIAwareXMLStreamWriter {

		private final Receiver receiver;
		// FIXME: change when xml:base attributes are written
		private URI baseURI = null;
		private boolean seenRoot = false;

		public BaseURIAwareStreamWriterToReceiver(Receiver receiver) {
			super(receiver);
			this.receiver = receiver;
		}

		public URI getBaseURI() throws XMLStreamException {
			return baseURI;
		}

		public void setBaseURI(URI baseURI) throws XMLStreamException {
			if (seenRoot)
				throw new XMLStreamException("Setting base URI not supported after document has started.");
			if (baseURI != null)
				receiver.setSystemId(baseURI.toASCIIString());
			this.baseURI = baseURI;
		}

		@Override
		public void writeStartDocument() throws XMLStreamException {
			super.writeStartDocument();
			seenRoot = true;
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy