| /* 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(); |
| } |
| |
| |
| } |