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

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 java.math.BigDecimal;
import java.math.BigInteger;

import javax.xml.namespace.NamespaceContext;
import javax.xml.namespace.QName;
import javax.xml.stream.*;

import org.codehaus.stax2.*;
import org.codehaus.stax2.ri.typed.SimpleValueEncoder;
import org.codehaus.stax2.typed.Base64Variant;
import org.codehaus.stax2.typed.Base64Variants;
// Not from Stax 1.0, but Stax2 does provide it:
import org.codehaus.stax2.util.StreamWriterDelegate;
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 class Stax2WriterAdapter extends StreamWriterDelegate implements XMLStreamWriter2 /* From Stax2 */ ,XMLStreamConstants { /** * Encoding we have determined to be used, according to method * calls (write start document etc.) */ protected String mEncoding; protected SimpleValueEncoder mValueEncoder; protected final boolean mNsRepairing; /* /////////////////////////////////////////////////////////////////////// // Life-cycle methods /////////////////////////////////////////////////////////////////////// */ protected Stax2WriterAdapter(XMLStreamWriter sw) { super(sw); mDelegate = sw; Object value = sw.getProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES); mNsRepairing = (value instanceof Boolean) && ((Boolean) value).booleanValue(); } /** * 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); } /* /////////////////////////////////////////////////////////////////////// // TypedXMLStreamWriter2 implementation // (Typed Access API, Stax v3.0) /////////////////////////////////////////////////////////////////////// */ // // // Typed element content write methods @Override public void writeBoolean(boolean b) throws XMLStreamException { mDelegate.writeCharacters(b ? "true" : "false"); } @Override public void writeInt(int value) throws XMLStreamException { mDelegate.writeCharacters(String.valueOf(value)); } @Override public void writeLong(long value) throws XMLStreamException { mDelegate.writeCharacters(String.valueOf(value)); } @Override public void writeFloat(float value) throws XMLStreamException { mDelegate.writeCharacters(String.valueOf(value)); } @Override public void writeDouble(double value) throws XMLStreamException { mDelegate.writeCharacters(String.valueOf(value)); } @Override public void writeInteger(BigInteger value) throws XMLStreamException { mDelegate.writeCharacters(value.toString()); } @Override public void writeDecimal(BigDecimal value) throws XMLStreamException { mDelegate.writeCharacters(value.toString()); } @Override public void writeQName(QName name) throws XMLStreamException { mDelegate.writeCharacters(serializeQNameValue(name)); } @Override public void writeIntArray(int[] value, int from, int length) throws XMLStreamException { mDelegate.writeCharacters(getValueEncoder().encodeAsString(value, from, length)); } @Override public void writeLongArray(long[] value, int from, int length) throws XMLStreamException { mDelegate.writeCharacters(getValueEncoder().encodeAsString(value, from, length)); } @Override public void writeFloatArray(float[] value, int from, int length) throws XMLStreamException { mDelegate.writeCharacters(getValueEncoder().encodeAsString(value, from, length)); } @Override public void writeDoubleArray(double[] value, int from, int length) throws XMLStreamException { mDelegate.writeCharacters(getValueEncoder().encodeAsString(value, from, length)); } @Override public void writeBinary(Base64Variant v, byte[] value, int from, int length) throws XMLStreamException { mDelegate.writeCharacters(getValueEncoder().encodeAsString(v, value, from, length)); } @Override public void writeBinary(byte[] value, int from, int length) throws XMLStreamException { writeBinary(Base64Variants.getDefaultVariant(), value, from, length); } // // // Typed attribute value write methods @Override public void writeBooleanAttribute(String prefix, String nsURI, String localName, boolean b) throws XMLStreamException { mDelegate.writeAttribute(prefix, nsURI, localName, b ? "true" : "false"); } @Override public void writeIntAttribute(String prefix, String nsURI, String localName, int value) throws XMLStreamException { mDelegate.writeAttribute(prefix, nsURI, localName, String.valueOf(value)); } @Override public void writeLongAttribute(String prefix, String nsURI, String localName, long value) throws XMLStreamException { mDelegate.writeAttribute(prefix, nsURI, localName, String.valueOf(value)); } @Override public void writeFloatAttribute(String prefix, String nsURI, String localName, float value) throws XMLStreamException { mDelegate.writeAttribute(prefix, nsURI, localName, String.valueOf(value)); } @Override public void writeDoubleAttribute(String prefix, String nsURI, String localName, double value) throws XMLStreamException { mDelegate.writeAttribute(prefix, nsURI, localName, String.valueOf(value)); } @Override public void writeIntegerAttribute(String prefix, String nsURI, String localName, BigInteger value) throws XMLStreamException { mDelegate.writeAttribute(prefix, nsURI, localName, value.toString()); } @Override public void writeDecimalAttribute(String prefix, String nsURI, String localName, BigDecimal value) throws XMLStreamException { mDelegate.writeAttribute(prefix, nsURI, localName, value.toString()); } @Override public void writeQNameAttribute(String prefix, String nsURI, String localName, QName name) throws XMLStreamException { mDelegate.writeAttribute(prefix, nsURI, localName, serializeQNameValue(name)); } @Override public void writeIntArrayAttribute(String prefix, String nsURI, String localName, int[] value) throws XMLStreamException { mDelegate.writeAttribute(prefix, nsURI, localName, getValueEncoder().encodeAsString(value, 0, value.length)); } @Override public void writeLongArrayAttribute(String prefix, String nsURI, String localName, long[] value) throws XMLStreamException { mDelegate.writeAttribute(prefix, nsURI, localName, getValueEncoder().encodeAsString(value, 0, value.length)); } @Override public void writeFloatArrayAttribute(String prefix, String nsURI, String localName, float[] value) throws XMLStreamException { mDelegate.writeAttribute(prefix, nsURI, localName, getValueEncoder().encodeAsString(value, 0, value.length)); } @Override public void writeDoubleArrayAttribute(String prefix, String nsURI, String localName, double[] value) throws XMLStreamException { mDelegate.writeAttribute(prefix, nsURI, localName, getValueEncoder().encodeAsString(value, 0, value.length)); } @Override public void writeBinaryAttribute(String prefix, String nsURI, String localName, byte[] value) throws XMLStreamException { writeBinaryAttribute(Base64Variants.getDefaultVariant(), prefix, nsURI, localName, value); } @Override public void writeBinaryAttribute(Base64Variant v, String prefix, String nsURI, String localName, byte[] value) throws XMLStreamException { mDelegate.writeAttribute(prefix, nsURI, localName, getValueEncoder().encodeAsString(v, value, 0, value.length)); } /* /////////////////////////////////////////////////////////////////////// // XMLStreamWriter2 (StAX2) implementation /////////////////////////////////////////////////////////////////////// */ @Override public boolean isPropertySupported(String name) { // No real clean way to check this, so let's just fake by // claiming nothing is supported return false; } @Override public boolean setProperty(String name, Object value) { throw new IllegalArgumentException("No settable property '"+name+"'"); } @Override public XMLStreamLocation2 getLocation() { // No easy way to keep track of it, without impl support return null; } @Override public String getEncoding() { // We may have been able to infer it... if so: return mEncoding; } @Override public void writeCData(char[] text, int start, int len) throws XMLStreamException { writeCData(new String(text, start, len)); } @Override 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()); } @Override 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(); } @Override 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); } @Override public void writeSpace(char[] text, int offset, int length) throws XMLStreamException { // See comments above... writeRaw(text, offset, length); } @Override 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 /////////////////////////////////////////////////////////////////////// */ @Override public void writeRaw(String text) throws XMLStreamException { writeRaw(text, 0, text.length()); } @Override 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"); } @Override public void writeRaw(char[] text, int offset, int length) throws XMLStreamException { writeRaw(new String(text, offset, length)); } @Override 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, output handling /////////////////////////////////////////////////////////////////////// */ @Override public void closeCompletely() throws XMLStreamException { /* 06-Nov-2008, TSa: alas, there is no way to properly implement * this. Should we throw an exception? For now, let's just call * regular close; not quite the same, but better than nothing */ close(); } /* /////////////////////////////////////////////////////////////////////// // Stax2, validation /////////////////////////////////////////////////////////////////////// */ @Override public XMLValidator validateAgainst(XMLValidationSchema schema) throws XMLStreamException { // !!! TODO: try to implement? throw new UnsupportedOperationException("Not yet implemented"); } @Override public XMLValidator stopValidatingAgainst(XMLValidationSchema schema) throws XMLStreamException { return null; } @Override public XMLValidator stopValidatingAgainst(XMLValidator validator) throws XMLStreamException { return null; } @Override 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)); } } } /** * Method called to serialize given qualified name into valid * String serialization, taking into account existing namespace * bindings. */ protected String serializeQNameValue(QName name) throws XMLStreamException { String prefix; // Ok as is? In repairing mode need to ensure it's properly bound if (mNsRepairing) { String uri = name.getNamespaceURI(); // First: let's see if a valid binding already exists: NamespaceContext ctxt = getNamespaceContext(); prefix = (ctxt == null) ? null : ctxt.getPrefix(uri); if (prefix == null) { // nope: need to (try to) bind String origPrefix = name.getPrefix(); if (origPrefix == null || origPrefix.length() == 0) { prefix = ""; /* note: could cause a namespace conflict... but * there is nothing we can do with just stax1 stream * writer */ writeDefaultNamespace(uri); } else { prefix = origPrefix; writeNamespace(prefix, uri); } } } else { // in non-repairing, good as is prefix = name.getPrefix(); } String local = name.getLocalPart(); if (prefix == null || prefix.length() == 0) { return local; } // Not efficient... but should be ok return prefix + ":" + local; } protected SimpleValueEncoder getValueEncoder() { if (mValueEncoder == null) { mValueEncoder = new SimpleValueEncoder(); } return mValueEncoder; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy