src.java.org.codehaus.stax2.ri.Stax2WriterAdapter Maven / Gradle / Ivy
/* Stax2 API extension for Streaming Api for Xml processing (StAX).
*
* Copyright (c) 2006- Tatu Saloranta, [email protected]
*
* Licensed under the License specified in file LICENSE, included with
* the source code.
* You may not use this file except in compliance with the License.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.codehaus.stax2.ri;
import javax.xml.namespace.NamespaceContext;
import javax.xml.stream.*;
import org.codehaus.stax2.*;
import org.codehaus.stax2.validation.ValidationProblemHandler;
import org.codehaus.stax2.validation.XMLValidationSchema;
import org.codehaus.stax2.validation.XMLValidator;
/**
* This adapter implements parts of {@link XMLStreamWriter2}, the
* extended stream writer defined by Stax2 extension, by wrapping
* a vanilla Stax 1.0 {@link XMLStreamReader} implementation.
*
* Note: the implementation is incomplete as-is, since not all
* features needed are accessible via basic Stax 1.0 interface.
* As such, two main use cases for this wrapper are:
*
* - Serve as convenient base class for a complete implementation,
* which can use native accessors provided by the wrapped Stax
* implementation
*
* - To be used for tasks that make limited use of Stax2 API, such
* that missing parts are not needed
*
*
*/
public final class Stax2WriterAdapter
//extends StreamWriterDelegate // such a thing doesn't exist... doh
implements XMLStreamWriter2 /* From Stax2 */
,XMLStreamConstants
{
/**
* Underlying Stax 1.0 compliant stream writer.
*/
final XMLStreamWriter mDelegate;
/**
* Encoding we have determined to be used, according to method
* calls (write start document etc.)
*/
String mEncoding;
/*
////////////////////////////////////////////////////
// Life-cycle methods
////////////////////////////////////////////////////
*/
private Stax2WriterAdapter(XMLStreamWriter sw)
{
mDelegate = sw;
}
/**
* Method that should be used to add dynamic support for
* {@link XMLStreamWriter2}. Method will check whether the
* stream reader passed happens to be a {@link XMLStreamWriter2};
* and if it is, return it properly cast. If not, it will create
* necessary wrapper to support features needed by StaxMate,
* using vanilla Stax 1.0 interface.
*/
public static XMLStreamWriter2 wrapIfNecessary(XMLStreamWriter sw)
{
if (sw instanceof XMLStreamWriter2) {
return (XMLStreamWriter2) sw;
}
return new Stax2WriterAdapter(sw);
}
/*
////////////////////////////////////////////////////
// Stax 1.0 delegation
////////////////////////////////////////////////////
*/
public void close()
throws XMLStreamException
{
mDelegate.close();
}
public void flush()
throws XMLStreamException
{
mDelegate.flush();
}
public NamespaceContext getNamespaceContext()
{
return mDelegate.getNamespaceContext();
}
public String getPrefix(String uri)
throws XMLStreamException
{
return mDelegate.getPrefix(uri);
}
public Object getProperty(String name)
{
return mDelegate.getProperty(name);
}
public void setDefaultNamespace(String uri)
throws XMLStreamException
{
mDelegate.setDefaultNamespace(uri);
}
public void setNamespaceContext(NamespaceContext context)
throws XMLStreamException
{
mDelegate.setNamespaceContext(context);
}
public void setPrefix(String prefix, String uri)
throws XMLStreamException
{
mDelegate.setPrefix(prefix, uri);
}
public void writeAttribute(String localName, String value)
throws XMLStreamException
{
mDelegate.writeAttribute(localName, value);
}
public void writeAttribute(String namespaceURI, String localName, String value)
throws XMLStreamException
{
mDelegate.writeAttribute(namespaceURI, localName, value);
}
public void writeAttribute(String prefix, String namespaceURI, String localName, String value)
throws XMLStreamException
{
mDelegate.writeAttribute(prefix, namespaceURI, localName, value);
}
public void writeCData(String data)
throws XMLStreamException
{
mDelegate.writeCData(data);
}
public void writeCharacters(char[] text, int start, int len)
throws XMLStreamException
{
mDelegate.writeCharacters(text, start, len);
}
public void writeCharacters(String text)
throws XMLStreamException
{
mDelegate.writeCharacters(text);
}
public void writeComment(String data)
throws XMLStreamException
{
mDelegate.writeComment(data);
}
public void writeDefaultNamespace(String namespaceURI)
throws XMLStreamException
{
mDelegate.writeDefaultNamespace(namespaceURI);
}
public void writeDTD(String dtd)
throws XMLStreamException
{
mDelegate.writeDTD(dtd);
}
public void writeEmptyElement(String localName)
throws XMLStreamException
{
mDelegate.writeEmptyElement(localName);
}
public void writeEmptyElement(String namespaceURI, String localName)
throws XMLStreamException
{
mDelegate.writeEmptyElement(namespaceURI, localName);
}
public void writeEmptyElement(String prefix, String localName, String namespaceURI)
throws XMLStreamException
{
mDelegate.writeEmptyElement(prefix, localName, namespaceURI);
}
public void writeEndDocument()
throws XMLStreamException
{
mDelegate.writeEndDocument();
}
public void writeEndElement()
throws XMLStreamException
{
mDelegate.writeEndElement();
}
public void writeEntityRef(String name)
throws XMLStreamException
{
mDelegate.writeEntityRef(name);
}
public void writeNamespace(String prefix, String namespaceURI)
throws XMLStreamException
{
mDelegate.writeNamespace(prefix, namespaceURI);
}
public void writeProcessingInstruction(String target)
throws XMLStreamException
{
mDelegate.writeProcessingInstruction(target);
}
public void writeProcessingInstruction(String target, String data)
throws XMLStreamException
{
mDelegate.writeProcessingInstruction(target, data);
}
public void writeStartDocument()
throws XMLStreamException
{
mDelegate.writeStartDocument();
}
public void writeStartDocument(String version)
throws XMLStreamException
{
mDelegate.writeStartDocument(version);
}
public void writeStartDocument(String encoding, String version)
throws XMLStreamException
{
mEncoding = encoding;
mDelegate.writeStartDocument(encoding, version);
}
public void writeStartElement(String localName)
throws XMLStreamException
{
mDelegate.writeStartElement(localName);
}
public void writeStartElement(String namespaceURI, String localName)
throws XMLStreamException
{
mDelegate.writeStartElement(namespaceURI, localName);
}
public void writeStartElement(String prefix, String localName, String namespaceURI)
throws XMLStreamException
{
mDelegate.writeStartElement(prefix, localName, namespaceURI);
}
/*
////////////////////////////////////////////////////
// XMLStreamWriter2 (StAX2) implementation
////////////////////////////////////////////////////
*/
public boolean isPropertySupported(String name)
{
/* No real clean way to check this, so let's just fake by
* claiming nothing is supported
*/
return false;
}
public boolean setProperty(String name, Object value)
{
throw new IllegalArgumentException("No settable property '"+name+"'");
}
public XMLStreamLocation2 getLocation()
{
// No easy way to keep track of it, without impl support
return null;
}
public String getEncoding()
{
// We may have been able to infer it... if so:
return mEncoding;
}
public void writeCData(char[] text, int start, int len)
throws XMLStreamException
{
writeCData(new String(text, start, len));
}
public void writeDTD(String rootName, String systemId, String publicId,
String internalSubset)
throws XMLStreamException
{
/* This may or may not work... depending on how well underlying
* implementation follows stax 1.0 spec (it should work)
*/
StringBuffer sb = new StringBuffer();
sb.append(" 0) {
sb.append(" [");
sb.append(internalSubset);
sb.append(']');
}
sb.append('>');
writeDTD(sb.toString());
}
public void writeFullEndElement()
throws XMLStreamException
{
/* It may be possible to fake it, by pretending to write
* character output, which in turn should prevent writing of
* an empty element...
*/
mDelegate.writeCharacters("");
mDelegate.writeEndElement();
}
public void writeSpace(String text)
throws XMLStreamException
{
/* Hmmh. Two choices: either try to write as regular characters,
* or output as is via raw calls. Latter would be safer, if we
* had access to it; former may escape incorrectly.
* While this may not be optimal, let's try former
*/
writeRaw(text);
}
public void writeSpace(char[] text, int offset, int length)
throws XMLStreamException
{
// See comments above...
writeRaw(text, offset, length);
}
public void writeStartDocument(String version, String encoding,
boolean standAlone)
throws XMLStreamException
{
// No good way to do it, so let's do what we can...
writeStartDocument(encoding, version);
}
/*
///////////////////////////////
// Stax2, Pass-through methods
///////////////////////////////
*/
public void writeRaw(String text)
throws XMLStreamException
{
writeRaw(text, 0, text.length());
}
public void writeRaw(String text, int offset, int len)
throws XMLStreamException
{
// There is no clean way to implement this via Stax 1.0, alas...
throw new UnsupportedOperationException("Not implemented");
}
public void writeRaw(char[] text, int offset, int length)
throws XMLStreamException
{
writeRaw(new String(text, offset, length));
}
public void copyEventFromReader(XMLStreamReader2 sr, boolean preserveEventData)
throws XMLStreamException
{
switch (sr.getEventType()) {
case START_DOCUMENT:
{
String version = sr.getVersion();
/* No real declaration? If so, we don't want to output
* anything, to replicate as closely as possible the
* source document
*/
if (version == null || version.length() == 0) {
; // no output if no real input
} else {
if (sr.standaloneSet()) {
writeStartDocument(sr.getVersion(),
sr.getCharacterEncodingScheme(),
sr.isStandalone());
} else {
writeStartDocument(sr.getCharacterEncodingScheme(),
sr.getVersion());
}
}
}
return;
case END_DOCUMENT:
writeEndDocument();
return;
// Element start/end events:
case START_ELEMENT:
/* Start element is bit trickier to output since there
* may be differences between repairing/non-repairing
* writers. But let's try a generic handling here.
*/
copyStartElement(sr);
return;
case END_ELEMENT:
writeEndElement();
return;
case SPACE:
writeSpace(sr.getTextCharacters(), sr.getTextStart(), sr.getTextLength());
return;
case CDATA:
writeCData(sr.getTextCharacters(), sr.getTextStart(), sr.getTextLength());
return;
case CHARACTERS:
writeCharacters(sr.getTextCharacters(), sr.getTextStart(), sr.getTextLength());
return;
case COMMENT:
writeComment(sr.getText());
return;
case PROCESSING_INSTRUCTION:
writeProcessingInstruction(sr.getPITarget(), sr.getPIData());
return;
case DTD:
{
DTDInfo info = sr.getDTDInfo();
if (info == null) {
/* Hmmmh. Can this happen for non-DTD-aware readers?
* And if so, what should we do?
*/
throw new XMLStreamException("Current state DOCTYPE, but not DTDInfo Object returned -- reader doesn't support DTDs?");
}
writeDTD(info.getDTDRootName(), info.getDTDSystemId(),
info.getDTDPublicId(), info.getDTDInternalSubset());
}
return;
case ENTITY_REFERENCE:
writeEntityRef(sr.getLocalName());
return;
case ATTRIBUTE:
case NAMESPACE:
case ENTITY_DECLARATION:
case NOTATION_DECLARATION:
// Let's just fall back to throw the exception
}
throw new XMLStreamException("Unrecognized event type ("
+sr.getEventType()+"); not sure how to copy");
}
/*
///////////////////////////////
// Stax2, validation
///////////////////////////////
*/
public XMLValidator validateAgainst(XMLValidationSchema schema)
throws XMLStreamException
{
// !!! TODO: try to implement?
throw new UnsupportedOperationException("Not yet implemented");
}
public XMLValidator stopValidatingAgainst(XMLValidationSchema schema)
throws XMLStreamException
{
return null;
}
public XMLValidator stopValidatingAgainst(XMLValidator validator)
throws XMLStreamException
{
return null;
}
public ValidationProblemHandler setValidationProblemHandler(ValidationProblemHandler h)
{
/* Not a real problem: although we can't do anything with it
* (without real validator integration)
*/
return null;
}
/*
///////////////////////////////
// Helper methods
///////////////////////////////
*/
protected void copyStartElement(XMLStreamReader sr)
throws XMLStreamException
{
// Any namespace declarations/bindings?
int nsCount = sr.getNamespaceCount();
if (nsCount > 0) { // yup, got some...
/* First, need to (or at least, should?) add prefix bindings:
* (may not be 100% required, but probably a good thing to do,
* just so that app code has access to prefixes then)
*/
for (int i = 0; i < nsCount; ++i) {
String prefix = sr.getNamespacePrefix(i);
String uri = sr.getNamespaceURI(i);
if (prefix == null || prefix.length() == 0) { // default NS
setDefaultNamespace(uri);
} else {
setPrefix(prefix, uri);
}
}
}
writeStartElement(sr.getPrefix(), sr.getLocalName(), sr.getNamespaceURI());
if (nsCount > 0) {
// And then output actual namespace declarations:
for (int i = 0; i < nsCount; ++i) {
String prefix = sr.getNamespacePrefix(i);
String uri = sr.getNamespaceURI(i);
if (prefix == null || prefix.length() == 0) { // default NS
writeDefaultNamespace(uri);
} else {
writeNamespace(prefix, uri);
}
}
}
/* And then let's just output attributes. But should we copy the
* implicit attributes (created via attribute defaulting?)
*/
int attrCount = sr.getAttributeCount();
if (attrCount > 0) {
for (int i = 0; i < attrCount; ++i) {
writeAttribute(sr.getAttributePrefix(i),
sr.getAttributeNamespace(i),
sr.getAttributeLocalName(i),
sr.getAttributeValue(i));
}
}
}
}