blob: b3369fb015c7d647df835d0dced12c8b30227097 [file] [log] [blame]
/* Copyright 2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.apache.xmlbeans.impl.marshal;
import org.apache.xmlbeans.XmlError;
import org.apache.xmlbeans.XmlException;
import org.apache.xmlbeans.impl.common.InvalidLexicalValueException;
import org.apache.xmlbeans.impl.common.XmlWhitespace;
import org.apache.xmlbeans.impl.richParser.XMLStreamReaderExt;
import org.apache.xmlbeans.impl.util.XsTypeConverter;
import javax.xml.namespace.QName;
import javax.xml.stream.Location;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collection;
final class MarshalStreamUtils
{
static final String XSI_NS = "http://www.w3.org/2001/XMLSchema-instance";
static final String XSI_TYPE_ATTR = "type";
static final String XSI_NIL_ATTR = "nil";
static final String XSI_SCHEMA_LOCATION_ATTR = "schemaLocation";
static final String XSI_NO_NS_SCHEMA_LOCATION_ATTR =
"noNamespaceSchemaLocation";
static final QName XSI_NIL_QNAME = new QName(XSI_NS, XSI_NIL_ATTR);
static final QName XSI_TYPE_QNAME = new QName(XSI_NS, XSI_TYPE_ATTR);
static void getXsiAttributes(XsiAttributeHolder holder,
XMLStreamReaderExt reader,
Collection errors)
throws XMLStreamException
{
assert reader.isStartElement();
holder.reset();
final int att_cnt = reader.getAttributeCount();
for (int att_idx = 0; att_idx < att_cnt; att_idx++) {
if (!XSI_NS.equals(reader.getAttributeNamespace(att_idx)))
continue;
try {
final String lname = reader.getAttributeLocalName(att_idx);
if (XSI_TYPE_ATTR.equals(lname)) {
holder.xsiType = reader.getAttributeQNameValue(att_idx);
} else if (XSI_NIL_ATTR.equals(lname)) {
holder.hasXsiNil = reader.getAttributeBooleanValue(att_idx);
} else if (XSI_SCHEMA_LOCATION_ATTR.equals(lname)) {
holder.schemaLocation =
reader.getAttributeStringValue(att_idx,
XmlWhitespace.WS_COLLAPSE);
} else if (XSI_NO_NS_SCHEMA_LOCATION_ATTR.equals(lname)) {
holder.noNamespaceSchemaLocation =
reader.getAttributeStringValue(att_idx,
XmlWhitespace.WS_COLLAPSE);
}
}
//nothing should have been assigned, so keep going
//TODO: use real location (maybe just pass context to this method).
catch (InvalidLexicalValueException ilve) {
addError(errors, ilve.getMessage(),
ilve.getLocation());
}
}
}
static QName getXsiType(XMLStreamReader reader, Collection errors)
{
assert reader.isStartElement();
final int att_cnt = reader.getAttributeCount();
for (int att_idx = 0; att_idx < att_cnt; att_idx++) {
if (!XSI_NS.equals(reader.getAttributeNamespace(att_idx)))
continue;
final String lname = reader.getAttributeLocalName(att_idx);
if (XSI_TYPE_ATTR.equals(lname)) {
final String type_str = reader.getAttributeValue(att_idx);
return XsTypeConverter.lexQName(type_str, errors,
reader.getNamespaceContext());
}
}
return null;
}
/**
* go to next start element. if reader is sitting on a start element
* then no advancing will be done. returns false if we hit an end element,
* or the end of the steam, otherwise returns true
*
* @param reader
* @return
*/
static boolean advanceToNextStartElement(XMLStreamReader reader)
throws XmlException
{
try {
for (int state = reader.getEventType();
reader.hasNext();
state = reader.next()) {
switch (state) {
case XMLStreamReader.START_ELEMENT:
return true;
case XMLStreamReader.END_ELEMENT:
return false;
case XMLStreamReader.END_DOCUMENT:
throw new XmlException("unexpected end of XML");
default:
break;
}
}
}
catch (XMLStreamException xse) {
throw new XmlException(xse);
}
//end of the steam
return false;
}
/**
* Skip current element node and all its contents.
* Reader must be on start element.
* Skips just past the matching end element.
* We are just counting start/end -- the parser is
* dealing with well-formedness.
*
* @param reader
*/
static void skipElement(XMLStreamReader reader)
throws XmlException
{
assert reader.isStartElement();
int cnt = -1;
//TODO: seem to be rechecking assertion, why not skip one ahead...
try {
int event = reader.getEventType();
while (true) {
switch (event) {
case XMLStreamReader.START_ELEMENT:
cnt++;
break;
case XMLStreamReader.END_ELEMENT:
if (cnt == 0) {
if (reader.hasNext())
reader.next(); // move past end element
return;
} else {
cnt--;
}
break;
case XMLStreamReader.END_DOCUMENT:
//should not happen for well-formed xml
throw new XmlException("unexpected end of xml document");
default:
break;
}
if (reader.hasNext()) {
event = reader.next();
} else {
throw new XmlException("unexpected end of xml stream");
}
}
}
catch (XMLStreamException xse) {
throw new XmlException(xse);
}
}
static void advanceToFirstItemOfInterest(XMLStreamReader rdr)
throws XmlException
{
try {
for (int state = rdr.getEventType(); rdr.hasNext(); state = rdr.next()) {
switch (state) {
case XMLStreamReader.START_ELEMENT:
return;
case XMLStreamReader.END_ELEMENT:
throw new XmlException("unexpected end of XML");
case XMLStreamReader.PROCESSING_INSTRUCTION:
break;
case XMLStreamReader.CHARACTERS:
if (rdr.isWhiteSpace()) break;
{
final String text = rdr.getText();
final Location loc = rdr.getLocation();
String msg = "unexpected character data: " + text +
" at line " + loc.getLineNumber() +
" column " + loc.getColumnNumber();
throw new XmlException(msg);
}
case XMLStreamReader.COMMENT:
case XMLStreamReader.SPACE:
case XMLStreamReader.START_DOCUMENT:
break;
case XMLStreamReader.END_DOCUMENT:
throw new XmlException("unexpected end of XML");
case XMLStreamReader.ENTITY_REFERENCE:
break;
case XMLStreamReader.ATTRIBUTE:
throw new AssertionError("NAKED ATTRIBUTE UNIMPLEMENTED");
case XMLStreamReader.DTD:
case XMLStreamReader.CDATA:
case XMLStreamReader.NAMESPACE:
case XMLStreamReader.NOTATION_DECLARATION:
case XMLStreamReader.ENTITY_DECLARATION:
break;
default:
throw new XmlException("unexpected xml state:" + state +
"in" + rdr);
}
}
}
catch (XMLStreamException xse) {
throw new XmlException(xse);
}
throw new XmlException("unexpected end of xml stream");
}
static void addError(Collection errors,
String msg,
Location location)
{
addError(errors, msg, XmlError.SEVERITY_ERROR, location);
}
static void addError(Collection errors,
String msg,
int severity,
Location location)
{
assert location != null;
String systemId = location.getSystemId();
if (systemId == null) {
systemId = "<unknown>"; // without this we get no line numbers
}
final XmlError err =
XmlError.forLocation(msg,
severity,
systemId,
location.getLineNumber(),
location.getColumnNumber(),
location.getCharacterOffset());
errors.add(err);
}
static Object inputStreamToBytes(final InputStream val)
throws IOException
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int b;
while ((b = val.read()) != -1) {
baos.write(b);
}
return baos.toByteArray();
}
}