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

org.daisy.common.transform.XMLInputValue Maven / Gradle / Ivy

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

import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.function.Supplier;

import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;

import org.daisy.common.stax.BaseURIAwareXMLStreamReader;
import org.daisy.common.stax.DelegatingBaseURIAwareXMLStreamReader;

import org.w3c.dom.Node;

/**
 * A supplier of a XDM value that is a sequence of nodes, or an "external" item that can be
 * marshaled to a sequence of nodes.
 *
 * 

This interface has several sub-interfaces. Instances may implement one or more of them:

*
    *
  • {@link XMLEventReader}
  • *
  • {@link XMLStreamReader}
  • *
  • {@link Iterator}{@code <}{@link Node}{@code >}
  • *
* * {@link #asObject()} will throw a {@link UnsupportedOperationException} unless the value is an * external item. */ public class XMLInputValue extends InputValue { private XMLInputValue backingValue = null; protected BaseURIAwareXMLStreamReader streamReader = null; private boolean streamReaderSupplied = false; private Iterator nodeIterator = null; private boolean nodeIteratorSupplied = false; protected final boolean sequence; public XMLInputValue(BaseURIAwareXMLStreamReader value) { super(); streamReader = value; sequence = true; } public XMLInputValue(Iterator value) { this(value, true); } @SuppressWarnings("unchecked") // safe cast protected XMLInputValue(Iterator value, boolean sequence) { super(); nodeIterator = (Iterator)value; this.sequence = sequence; } protected XMLInputValue(XMLInputValue value, boolean sequence) { super(value); backingValue = value; this.sequence = sequence; } /** * A stream of XML events as a {@link XMLStreamReader}. */ public BaseURIAwareXMLStreamReader asXMLStreamReader() throws UnsupportedOperationException, NoSuchElementException { if (backingValue != null) { if (sequence) return backingValue.asXMLStreamReader(); else return ensureSingleItem(backingValue.asXMLStreamReader()); } else if (streamReader == null) throw new UnsupportedOperationException(); else if (valueSupplied()) throw new NoSuchElementException(); else { streamReaderSupplied = true; if (sequence) return streamReader; else return ensureSingleItem(streamReader); } } /** * A stream of XML events as a {@link XMLEventReader}. */ public XMLEventReader asXMLEventReader() throws UnsupportedOperationException, NoSuchElementException { if (backingValue != null) return backingValue.asXMLEventReader(); else throw new UnsupportedOperationException(); } /** * A sequence of nodes as a {@link Iterator}{@code <}{@link Node}{@code >}. */ public Iterator asNodeIterator() throws UnsupportedOperationException, NoSuchElementException { if (backingValue != null) { if (sequence) return backingValue.asNodeIterator(); else return ensureSingleItem(backingValue.asNodeIterator()); } else if (nodeIterator == null) throw new UnsupportedOperationException(); else if (valueSupplied()) throw new NoSuchElementException(); else { nodeIteratorSupplied = true; if (sequence) return nodeIterator; else return ensureSingleItem(nodeIterator); } } @Override public Mult> mult(int limit) { return new Mult>() { Iterable nodeCache = cache( iteratorOf( new Supplier() { Iterator it = null; public Node get() { if (it == null) it = asNodeIterator(); return it.next(); }}), limit); int supplied = 0; public XMLInputValue get() throws NoSuchElementException { if (supplied >= limit) { nodeCache = null; throw new NoSuchElementException(); } supplied++; return new XMLInputValue(nodeCache.iterator(), sequence); } }; } /** * Ensure that the number of items in the sequence is exactly one. */ public XMLInputValue ensureSingleItem() { if (backingValue != null && !sequence) return this; else return new XMLInputValue(this, false); } @Override protected boolean valueSupplied() { return super.valueSupplied() || streamReaderSupplied || nodeIteratorSupplied; } protected static Iterator ensureSingleItem(Iterator iterator) { if (!iterator.hasNext()) throw new TransformerException(new IllegalArgumentException("expected exactly one input item")); return new Iterator() { public boolean hasNext() { return iterator.hasNext(); } public V next() { V item = iterator.next(); if (iterator.hasNext()) throw new TransformerException(new IllegalArgumentException("expected exactly one input item")); return item; } }; } private static BaseURIAwareXMLStreamReader ensureSingleItem(BaseURIAwareXMLStreamReader reader) { try { if (!reader.hasNext()) throw new TransformerException( new IllegalArgumentException("expected exactly one input node but got an empty sequence")); } catch (XMLStreamException e) { throw new TransformerException(e); } return new DelegatingBaseURIAwareXMLStreamReader() { private boolean seenStartDocument = false; private String firstNode = null; private int elementDepth = 0; { switch (reader.getEventType()) { case START_DOCUMENT: seenStartDocument = true; break; case START_ELEMENT: firstNode = "<" + reader.getName().getLocalPart() + "/>"; elementDepth++; break; default: // the input is assumed to be a sequence of elements or documents throw new IllegalArgumentException(); } } protected BaseURIAwareXMLStreamReader delegate() { return reader; } @Override public int next() throws XMLStreamException, NoSuchElementException { int event = super.next(); switch (event) { case START_DOCUMENT: if (elementDepth != 0) throw new XMLStreamException(); if (seenStartDocument) throw new XMLStreamException(); seenStartDocument = true; break; case START_ELEMENT: if (firstNode == null) firstNode = "<" + reader.getName().getLocalPart() + "/>"; elementDepth++; break; case END_ELEMENT: if (elementDepth == 0) throw new XMLStreamException(); elementDepth--; if (!seenStartDocument && elementDepth == 0) if (super.hasNext()) { String errMsg = "expected exactly one input node"; switch (super.next()) { case START_ELEMENT: String secondNode = "<" + reader.getName().getLocalPart() + "/>"; errMsg += (" but got (" + firstNode + ", " + secondNode + ", ...)"); break; default: errMsg += " but got more than one"; } throw new TransformerException(new IllegalArgumentException(errMsg)); } break; case END_DOCUMENT: if (elementDepth != 0) throw new XMLStreamException(); if (!seenStartDocument) throw new XMLStreamException(); if (firstNode == null) throw new XMLStreamException(); // empty document node, not sure if we should allow this if (super.hasNext()) { String errMsg = "expected exactly one input node"; switch (super.next()) { case START_DOCUMENT: if (super.next() != START_ELEMENT) { errMsg += " but got more than one"; break; } case START_ELEMENT: String secondNode = "<" + reader.getName().getLocalPart() + "/>"; errMsg += (" but got (" + firstNode + ", " + secondNode + ", ...)"); break; default: errMsg += " but got more than one"; } throw new TransformerException(new IllegalArgumentException(errMsg)); } break; default: if (!seenStartDocument && firstNode == null) throw new XMLStreamException(); // not supported for now } return event; } }; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy