/* Stax2 API extension for Streaming Api for Xml processing (StAX).
*
* Copyright (c) 2006- Tatu Saloranta, tatu.saloranta@iki.fi
*
* 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.stream.*;
import org.codehaus.stax2.*;
import org.codehaus.stax2.validation.*;
/**
* This is a partial base implementation of {@link XMLStreamWriter2},
* the extended stream writer that is part of Stax2.
*/
public abstract class
Stax2WriterImpl
implements
XMLStreamWriter2 /* From Stax2 */
,
XMLStreamConstants
{
/*
///////////////////////////////////////////////////////////
// Life-cycle methods
///////////////////////////////////////////////////////////
*/
protected
Stax2WriterImpl() { }
/*
///////////////////////////////////////////////////////////
// XMLStreamWriter2 (StAX2) implementation
///////////////////////////////////////////////////////////
*/
public boolean
isPropertySupported(
String name)
{
/* No base properties (or should we have something for impl
* name, version?)
*/
return false;
}
public boolean
setProperty(
String name,
Object value)
{
throw new
IllegalArgumentException("No settable property '"+
name+"'");
}
public abstract
XMLStreamLocation2 getLocation();
public abstract
String getEncoding();
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("<!DOCTYPE");
sb.
append(
rootName);
if (
systemId != null) {
if (
publicId != null) {
sb.
append(" PUBLIC \"");
sb.
append(
publicId);
sb.
append("\" \"");
} else {
sb.
append(" SYSTEM \"");
}
sb.
append(
systemId);
sb.
append('"');
}
// Hmmh. Should we output empty internal subset?
if (
internalSubset != null &&
internalSubset.
length() > 0) {
sb.
append(" [");
sb.
append(
internalSubset);
sb.
append(']');
}
sb.
append('>');
writeDTD(
sb.
toString());
}
public void
writeFullEndElement()
throws
XMLStreamException
{
/* This should work with base Stax 1.0 implementations.
* Sub-classes are, however, encouraged to implement it
* more directly, if possible.
*/
writeCharacters("");
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 abstract void
writeStartDocument(
String version,
String encoding,
boolean
standAlone)
throws
XMLStreamException;
/*
///////////////////////////////////////////////////////////
// Stax2, Pass-through methods
///////////////////////////////////////////////////////////
*/
public void
writeRaw(
String text)
throws
XMLStreamException
{
writeRaw(
text, 0,
text.
length());
}
public abstract void
writeRaw(
String text, int
offset, int
len)
throws
XMLStreamException;
public abstract void
writeRaw(char[]
text, int
offset, int
length)
throws
XMLStreamException;
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
{
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
///////////////////////////////////////////////////////////
*/
/**
* Basic implementation of copy operation. It is likely that
* sub-classes can implement more efficient copy operations: if so,
* they should do so.
*/
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));
}
}
}
}