blob: 43860e2fe2d7107484668904ea7e20b7b05ffeb7 [file] [log] [blame]
/*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 2003 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache
* XMLBeans", nor may "Apache" appear in their name, without prior
* written permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation and was
* originally based on software copyright (c) 2000-2003 BEA Systems
* Inc., <http://www.bea.com/>. For more information on the Apache Software
* Foundation, please see <http://www.apache.org/>.
*/
package org.apache.xmlbeans.impl.marshal;
import org.apache.xmlbeans.XmlRuntimeException;
import org.apache.xmlbeans.impl.common.XsTypeConverter;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
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";
//more efficient (hopefully) version of XmlStreamReader.getElementText()
//TODO: plenty of room for optimizations here...
static CharSequence getContent(XMLStreamReader reader, Collection errors)
throws XMLStreamException
{
assert reader.isStartElement();
reader.next(); //move past start element
String content = null;
StringBuffer buf = null;
FOL:
for (int state = reader.getEventType(); ; state = reader.next()) {
switch (state) {
case XMLStreamReader.END_DOCUMENT:
throw new XmlRuntimeException("unexpected end of XML");
case XMLStreamReader.END_ELEMENT:
if (content == null) {
content = "";
}
reader.next(); // eat the matching end elem
break FOL;
case XMLStreamReader.START_ELEMENT:
//TODO: better error handling
errors.add("skipping unexpected child element");
skipElement(reader);
break;
case XMLStreamReader.CHARACTERS:
if (content == null) {
content = reader.getText();
} else {
if (buf == null) {
buf = new StringBuffer(content);
}
buf.append(reader.getText());
}
break;
case XMLStreamReader.PROCESSING_INSTRUCTION:
case XMLStreamReader.COMMENT:
break;
default:
throw new AssertionError("unexpected xml state " + state);
}
if (!reader.hasNext()) {
throw new XmlRuntimeException("unexpected end of xml stream");
}
}
if (buf == null) {
assert (content != null) ;
return content;
} else {
return buf.toString();
}
}
/**
* special marker qname object used to indicate that we noticed
* an xsi:nil="true" value while we were looking for an xsi:type attribute
*
* note that such a value would never be returned by getXsiType since
* it is illegal to declare types in the instance namespace.
*/
static QName XSI_NIL_MARKER = new QName(XSI_NS, "unused");
//TODO: REVIEW: reconsider this approach
//and what about the other xsi attributes?
static QName getXsiType(final 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_NIL_ATTR.equals(lname)) {
final String att_val = reader.getAttributeValue(att_idx);
boolean is_nil = XsTypeConverter.lexBoolean(att_val, errors);
if (is_nil) return XSI_NIL_MARKER;
} else 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 and end element,
* otherwise returns true
*
* @param reader
* @return
*/
static boolean advanceToNextStartElement(XMLStreamReader reader)
{
try {
for (int state = reader.getEventType();
reader.hasNext();
state = reader.next()) {
switch (state) {
case XMLStreamReader.END_DOCUMENT:
throw new XmlRuntimeException("unexpected end of XML");
case XMLStreamReader.END_ELEMENT:
return false;
case XMLStreamReader.START_ELEMENT:
return true;
case XMLStreamReader.CHARACTERS:
//TODO: what about mixed content models
case XMLStreamReader.PROCESSING_INSTRUCTION:
case XMLStreamReader.COMMENT:
break;
default:
throw new AssertionError("unexpected xml state " + state);
}
}
}
catch (XMLStreamException e) {
throw new XmlRuntimeException(e);
}
throw new XmlRuntimeException("unexpected end of xml stream");
}
/**
* Skip current element node and all its contents.
* Reader must be on start element.
* Skips to the matching end element (not past it).
* We are just counting start/end -- the parser is
* dealing with well-formedness.
*
* @param reader
*/
static void skipElement(XMLStreamReader reader)
{
assert reader.isStartElement();
int cnt = -1;
//TODO: seem to be rechecking assertion, why not skip one ahead...
try {
for (int state = reader.getEventType(); reader.hasNext();
state = reader.next()) {
switch (state) {
case XMLStreamReader.END_DOCUMENT:
//should not happen for well-formed xml
throw new XmlRuntimeException("unexpected end of xml document");
case XMLStreamReader.END_ELEMENT:
if (cnt == 0) {
return;
} else {
cnt--;
}
break;
case XMLStreamReader.START_ELEMENT:
cnt++;
break;
default:
break;
}
}
}
catch (XMLStreamException e) {
throw new XmlRuntimeException(e);
}
//should not happen for well-formed xml
throw new XmlRuntimeException("unexpected end of xml stream");
}
public static boolean isXsiNilTrue(XMLStreamReader reader,
int att_idx,
Collection errors)
{
final String lname = reader.getAttributeLocalName(att_idx);
System.out.println("lname = " + lname);
if (!XSI_NIL_ATTR.equals(lname))
return false;
if (!XSI_NS.equals(reader.getAttributeNamespace(att_idx)))
return false;
final String att_val = reader.getAttributeValue(att_idx);
return XsTypeConverter.lexBoolean(att_val, errors);
}
}