0001: /*
0002: Copyright (c) 2002-2007, Dennis M. Sosnoski.
0003: All rights reserved.
0004:
0005: Redistribution and use in source and binary forms, with or without modification,
0006: are permitted provided that the following conditions are met:
0007:
0008: * Redistributions of source code must retain the above copyright notice, this
0009: list of conditions and the following disclaimer.
0010: * Redistributions in binary form must reproduce the above copyright notice,
0011: this list of conditions and the following disclaimer in the documentation
0012: and/or other materials provided with the distribution.
0013: * Neither the name of JiBX nor the names of its contributors may be used
0014: to endorse or promote products derived from this software without specific
0015: prior written permission.
0016:
0017: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
0018: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
0019: WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
0020: DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
0021: ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
0022: (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
0023: LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
0024: ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
0025: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
0026: SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0027: */
0028:
0029: package org.jibx.runtime.impl;
0030:
0031: import java.io.InputStream;
0032: import java.io.Reader;
0033: import java.lang.reflect.InvocationTargetException;
0034: import java.lang.reflect.Method;
0035: import java.util.ArrayList;
0036: import java.util.Date;
0037: import java.util.HashMap;
0038:
0039: import org.jibx.runtime.IBindingFactory;
0040: import org.jibx.runtime.IUnmarshaller;
0041: import org.jibx.runtime.IUnmarshallingContext;
0042: import org.jibx.runtime.IXMLReader;
0043: import org.jibx.runtime.JiBXException;
0044: import org.jibx.runtime.Utility;
0045:
0046: /**
0047: * Pull parser wrapper supplying convenience methods for access. Most of
0048: * these methods are designed for use in code generated by the binding
0049: * generator.
0050: *
0051: * @author Dennis M. Sosnoski
0052: */
0053: public class UnmarshallingContext implements IUnmarshallingContext {
0054: /** Starting size for object stack. */
0055: private static final int INITIAL_STACK_SIZE = 20;
0056:
0057: /** Empty array of strings. */
0058: private static final String[] EMPTY_STRING_ARRAY = new String[0];
0059:
0060: /** Factory for creating XML readers. */
0061: private static final IXMLReaderFactory s_readerFactory;
0062: static {
0063: String prop = System
0064: .getProperty("org.jibx.runtime.impl.parser");
0065: if (prop == null) {
0066:
0067: // try XMLPull parser factory first
0068: IXMLReaderFactory fact = null;
0069: try {
0070: fact = createReaderFactory("org.jibx.runtime.impl.XMLPullReaderFactory");
0071: } catch (Throwable e) {
0072: fact = createReaderFactory("org.jibx.runtime.impl.StAXReaderFactory");
0073: }
0074: s_readerFactory = fact;
0075:
0076: } else {
0077:
0078: // try loading factory class specified by property
0079: s_readerFactory = createReaderFactory(prop);
0080: }
0081: }
0082:
0083: /** Binding factory used to create this unmarshaller. */
0084: private IBindingFactory m_factory;
0085:
0086: /** Parser in use. */
0087: private IXMLReader m_reader;
0088:
0089: //
0090: // Structures organized by mapping index number. Each unmarshaller in the
0091: // binding definition is assigned a unique index number by the binding
0092: // compiler. This includes both generated unmarshallers (from non-abstract
0093: // <mapping> definitions) and user-defined unmarshallers. Instances of
0094: // the unmarshaller classes are created as needed. The indexes for the
0095: // unmarshallers corresponding to named mappings always precede those for
0096: // internal mappings in the list.
0097:
0098: /** Unmarshaller classes for mapping definition (<code>null</code> for
0099: mappings out of context). */
0100: protected String[] m_unmarshallerClasses;
0101:
0102: /** Unmarshallers for classes in mapping definition (lazy create of actual
0103: unmarshaller instances) */
0104: protected IUnmarshaller[] m_unmarshallers;
0105:
0106: //
0107: // Structures organized by mapping
0108:
0109: /** Namespaces for elements associated with class mappings. */
0110: protected String[] m_namespaces;
0111:
0112: /** Names for elements associated with class mappings. */
0113: protected String[] m_names;
0114:
0115: /** Number of classes with global unmarshallers. */
0116: protected int m_globalCount;
0117:
0118: /** ID maps for finding references. */
0119: protected HashMap[] m_idMaps;
0120:
0121: /** Class names of referenced types (<code>null</code> unless class-specific
0122: IDs used). */
0123: protected String[] m_idClasses;
0124:
0125: /** Current unmarshalling stack depth. */
0126: protected int m_stackDepth;
0127:
0128: /** Stack of objects being unmarshalled. */
0129: protected Object[] m_objectStack;
0130:
0131: /** Mapping from element name to class index. If only a single namespace
0132: is defined for a particular local name the value for that name in
0133: this table is the Integer index of the associated class. If multiple
0134: namespaces are defined using the same local name the value is an
0135: ArrayList of Integer indexes. This is a high-overhead construct, so
0136: lazy construction is used - it's built the first time needed, then kept
0137: up to date thereafter. */
0138: protected HashMap m_unmarshalMap;
0139:
0140: /** Wrapped index values used with unmarshalling map. */
0141: protected Integer[] m_indexes;
0142:
0143: /** Last IDREF value parsed. */
0144: protected String m_idref;
0145:
0146: /** User context object (not used by JiBX, only for user convenience). */
0147: protected Object m_userContext;
0148:
0149: /**
0150: * Parser factory class loader method. This is used during initialization to
0151: * check that a particular factory class is usable.
0152: *
0153: * @param cname class name
0154: * @return reader factory instance
0155: * @throws RuntimeException on error creating class instance
0156: */
0157: private static IXMLReaderFactory createReaderFactory(String cname) {
0158:
0159: // try loading factory class from context loader
0160: Class clas = null;
0161: ClassLoader loader = Thread.currentThread()
0162: .getContextClassLoader();
0163: if (loader != null) {
0164: try {
0165: clas = loader.loadClass(cname);
0166: } catch (ClassNotFoundException e) { /* deliberately empty */
0167: }
0168: }
0169: if (clas == null) {
0170:
0171: // next try the class loader that loaded the unmarshaller interface
0172: try {
0173: loader = IUnmarshallingContext.class.getClassLoader();
0174: clas = loader.loadClass(cname);
0175: } catch (ClassNotFoundException e) {
0176: throw new RuntimeException(
0177: "Unable to specified parser factory class "
0178: + cname);
0179: }
0180: }
0181: if (!(IXMLReaderFactory.class.isAssignableFrom(clas))) {
0182: throw new RuntimeException(
0183: "Specified parser factory class "
0184: + cname
0185: + " does not implement IXMLReaderFactory interface");
0186: }
0187:
0188: // use static method to create parser factory class instance
0189: try {
0190: Method meth = clas.getMethod("getInstance", null);
0191: return (IXMLReaderFactory) meth.invoke(null, null);
0192: } catch (NoSuchMethodException e) {
0193: throw new RuntimeException(
0194: "Specified parser factory class "
0195: + cname
0196: + " does not define static getInstance() method");
0197: } catch (IllegalAccessException e) {
0198: throw new RuntimeException("Error on parser factory class "
0199: + cname + " getInstance() method call: "
0200: + e.getMessage());
0201: } catch (InvocationTargetException e) {
0202: throw new RuntimeException("Error on parser factory class "
0203: + cname + " getInstance() method call: "
0204: + e.getMessage());
0205: }
0206: }
0207:
0208: /**
0209: * Constructor. Builds the actual parser and initializes internal data
0210: * structures.
0211: *
0212: * @param nmap number of mapping definitions included
0213: * @param umcs names of unmarshaller classes for indexes with fixed
0214: * unmarshallers (as opposed to mapping slots, which may be overridden;
0215: * reference kept, must be constant)
0216: * @param nss namespaces for elements of classes with global definitions
0217: * @param names names for elements of classes with global definitions
0218: * @param idcs array of class names with IDs (<code>null</code> if no IDs or
0219: * global IDs)
0220: * @param ifact binding factory creating this unmarshaller
0221: */
0222: public UnmarshallingContext(int nmap, String[] umcs, String[] nss,
0223: String[] names, String[] idcs, IBindingFactory ifact) {
0224:
0225: // initialize internal unmarshaller state
0226: m_globalCount = nss.length;
0227: m_unmarshallerClasses = new String[nmap];
0228: System
0229: .arraycopy(umcs, 0, m_unmarshallerClasses, 0,
0230: umcs.length);
0231: m_unmarshallers = new IUnmarshaller[nmap];
0232: m_namespaces = new String[nmap];
0233: System.arraycopy(nss, 0, m_namespaces, 0, nss.length);
0234: m_names = new String[nmap];
0235: System.arraycopy(names, 0, m_names, 0, names.length);
0236: m_idClasses = idcs;
0237: int size = idcs == null ? 1 : idcs.length;
0238: m_idMaps = new HashMap[size];
0239: m_objectStack = new Object[INITIAL_STACK_SIZE];
0240: m_factory = ifact;
0241: }
0242:
0243: /**
0244: * Default constructor. This can be used for creating a context outside of
0245: * the generated code for special purposes.
0246: */
0247: public UnmarshallingContext() {
0248: this (0, EMPTY_STRING_ARRAY, EMPTY_STRING_ARRAY,
0249: EMPTY_STRING_ARRAY, EMPTY_STRING_ARRAY, null);
0250: }
0251:
0252: /**
0253: * Build name with optional namespace. Just returns the appropriate
0254: * name format.
0255: *
0256: * @param ns namespace URI of name
0257: * @param name local name part of name
0258: * @return formatted name string
0259: */
0260: public static String buildNameString(String ns, String name) {
0261: if (ns == null || "".equals(ns)) {
0262: return "\"" + name + "\"";
0263: } else {
0264: return "\"{" + ns + "}" + name + "\"";
0265: }
0266: }
0267:
0268: /**
0269: * Build current element name, with optional namespace.
0270: *
0271: * @return formatted name string
0272: */
0273: public String currentNameString() {
0274: return buildNameString(m_reader.getNamespace(), m_reader
0275: .getName());
0276: }
0277:
0278: /**
0279: * Build current parse input position description.
0280: *
0281: * @return text description of current parse position
0282: */
0283: public String buildPositionString() {
0284: return m_reader.buildPositionString();
0285: }
0286:
0287: /**
0288: * Throw exception for expected element start tag not found.
0289: *
0290: * @param ns namespace URI of name
0291: * @param name local name part of name
0292: * @exception JiBXException always thrown
0293: */
0294: public void throwStartTagNameError(String ns, String name)
0295: throws JiBXException {
0296: throw new JiBXException("Expected " + buildNameString(ns, name)
0297: + " start tag, found " + currentNameString()
0298: + " start tag " + buildPositionString());
0299: }
0300:
0301: /**
0302: * Throw exception for expected element end tag not found.
0303: *
0304: * @param ns namespace URI of name
0305: * @param name local name part of name
0306: * @exception JiBXException always thrown
0307: */
0308: public void throwEndTagNameError(String ns, String name)
0309: throws JiBXException {
0310: throw new JiBXException("Expected " + buildNameString(ns, name)
0311: + " end tag, found " + currentNameString()
0312: + " end tag " + buildPositionString());
0313: }
0314:
0315: /**
0316: * Throw exception including a name and position information.
0317: *
0318: * @param msg leading message text
0319: * @param ns namespace URI of name
0320: * @param name local name part of name
0321: * @exception JiBXException always thrown
0322: */
0323: public void throwNameException(String msg, String ns, String name)
0324: throws JiBXException {
0325: throw new JiBXException(msg + buildNameString(ns, name)
0326: + buildPositionString());
0327: }
0328:
0329: /**
0330: * Advance to next parse item. This wraps the base parser call in order to
0331: * catch and handle exceptions.
0332: *
0333: * @exception JiBXException on any error (possibly wrapping other exception)
0334: */
0335: private void advance() throws JiBXException {
0336: m_reader.nextToken();
0337: }
0338:
0339: /**
0340: * Verify namespace. This is a simple utility method that allows multiple
0341: * representations for the empty namespace as a convenience for generated
0342: * code.
0343: *
0344: * @param ns namespace URI expected (may be <code>null</code>
0345: * or the empty string for the empty namespace)
0346: * @return <code>true</code> if the current namespace matches that
0347: * expected, <code>false</code> if not
0348: */
0349: private boolean verifyNamespace(String ns) {
0350: if (ns == null || "".equals(ns)) {
0351: return m_reader.getNamespace().length() == 0;
0352: } else {
0353: return ns.equals(m_reader.getNamespace());
0354: }
0355: }
0356:
0357: /**
0358: * Get attribute value from parser.
0359: *
0360: * @param ns namespace URI for expected attribute (may be <code>null</code>
0361: * or the empty string for the empty namespace)
0362: * @param name attribute name expected
0363: * @return attribute value text, or <code>null</code> if missing
0364: */
0365: private String getAttributeValue(String ns, String name) {
0366: return m_reader.getAttributeValue(ns, name);
0367: }
0368:
0369: /**
0370: * Set document to be parsed from stream. This call is not part of the
0371: * interface definition, but is supplied to allow direct control of the
0372: * namespace processing by the compiler. The option of disabling namespaces
0373: * should be considered experimental and may not be supported in the future.
0374: *
0375: * @param ins stream supplying document data
0376: * @param name document name (<code>null</code> if unknown)
0377: * @param enc document input encoding, or <code>null</code> if to be
0378: * determined by parser
0379: * @param nsa enable namespace processing for parser flag
0380: * @throws JiBXException if error creating parser
0381: */
0382: public void setDocument(InputStream ins, String name, String enc,
0383: boolean nsa) throws JiBXException {
0384: if (m_reader == null) {
0385: m_reader = s_readerFactory
0386: .createReader(ins, name, enc, nsa);
0387: } else {
0388: m_reader = s_readerFactory.recycleReader(m_reader, ins,
0389: name, enc);
0390: }
0391: reset();
0392: }
0393:
0394: /**
0395: * Set document to be parsed from stream.
0396: *
0397: * @param ins stream supplying document data
0398: * @param enc document input encoding, or <code>null</code> if to be
0399: * determined by parser
0400: * @throws JiBXException if error creating parser
0401: */
0402: public void setDocument(InputStream ins, String enc)
0403: throws JiBXException {
0404: setDocument(ins, null, enc, true);
0405: }
0406:
0407: /**
0408: * Set document to be parsed from reader. This call is not part of the
0409: * interface definition, but is supplied to allow direct control of the
0410: * namespace processing by the compiler. The option of disabling namespaces
0411: * should be considered experimental and may not be supported in the future.
0412: *
0413: * @param rdr reader supplying document data
0414: * @param name document name (<code>null</code> if unknown)
0415: * @param nsa enable namespace processing for parser flag
0416: * @throws JiBXException if error creating parser
0417: */
0418: public void setDocument(Reader rdr, String name, boolean nsa)
0419: throws JiBXException {
0420: if (m_reader == null) {
0421: m_reader = s_readerFactory.createReader(rdr, name, nsa);
0422: } else {
0423: m_reader = s_readerFactory.recycleReader(m_reader, rdr,
0424: name);
0425: }
0426: reset();
0427: }
0428:
0429: /**
0430: * Set document to be parsed from reader.
0431: *
0432: * @param rdr reader supplying document data
0433: * @throws JiBXException if error creating parser
0434: */
0435: public void setDocument(Reader rdr) throws JiBXException {
0436: setDocument(rdr, null, true);
0437: }
0438:
0439: /**
0440: * Set named document to be parsed from stream.
0441: *
0442: * @param ins stream supplying document data
0443: * @param name document name
0444: * @param enc document input encoding, or <code>null</code> if to be
0445: * determined by parser
0446: * @throws JiBXException if error creating parser
0447: */
0448: public void setDocument(InputStream ins, String name, String enc)
0449: throws JiBXException {
0450: setDocument(ins, name, enc, true);
0451: }
0452:
0453: /**
0454: * Set named document to be parsed from reader.
0455: *
0456: * @param rdr reader supplying document data
0457: * @param name document name
0458: * @throws JiBXException if error creating parser
0459: */
0460: public void setDocument(Reader rdr, String name)
0461: throws JiBXException {
0462: setDocument(rdr, name, true);
0463: }
0464:
0465: /**
0466: * Set input document parse source directly.
0467: *
0468: * @param rdr document parse event reader
0469: */
0470: public void setDocument(IXMLReader rdr) {
0471: m_reader = rdr;
0472: }
0473:
0474: /**
0475: * Initializes the context to use the same parser and document as another
0476: * unmarshalling context. This method is designed for use when an initial
0477: * context needs to create and invoke a secondary context in the course of
0478: * an unmarshalling operation.
0479: *
0480: * @param parent context supplying parser and document to be unmarshalled
0481: */
0482: public void setFromContext(UnmarshallingContext parent) {
0483: m_factory = parent.m_factory;
0484: m_reader = parent.m_reader;
0485: }
0486:
0487: /**
0488: * Reset unmarshalling information. This releases all references to
0489: * unmarshalled objects and prepares the context for potential reuse.
0490: * It is automatically called when input is set.
0491: */
0492: public void reset() {
0493: for (int i = 0; i < m_idMaps.length; i++) {
0494: m_idMaps[i] = null;
0495: }
0496: for (int i = m_globalCount; i < m_unmarshallers.length; i++) {
0497: m_namespaces[i] = null;
0498: m_names[i] = null;
0499: m_unmarshallers[i] = null;
0500: }
0501: m_unmarshalMap = null;
0502: m_idref = null;
0503: for (int i = 0; i < m_objectStack.length; i++) {
0504: m_objectStack[i] = null;
0505: }
0506: m_stackDepth = 0;
0507: m_userContext = null;
0508: }
0509:
0510: /**
0511: * Parse to start tag. Ignores character data seen prior to a start tag, but
0512: * throws exception if an end tag or the end of the document is seen before
0513: * a start tag. Leaves the parser positioned at the start tag.
0514: *
0515: * @return element name of start tag found
0516: * @throws JiBXException on any error (possibly wrapping other exception)
0517: */
0518: public String toStart() throws JiBXException {
0519: if (m_reader.getEventType() == IXMLReader.START_TAG) {
0520: return m_reader.getName();
0521: }
0522: while (true) {
0523: m_reader.next();
0524: switch (m_reader.getEventType()) {
0525:
0526: case IXMLReader.START_TAG:
0527: return m_reader.getName();
0528:
0529: case IXMLReader.END_TAG:
0530: throw new JiBXException("Expected start tag, "
0531: + "found end tag " + currentNameString() + " "
0532: + buildPositionString());
0533:
0534: case IXMLReader.END_DOCUMENT:
0535: throw new JiBXException("Expected start tag, "
0536: + "found end of document "
0537: + buildPositionString());
0538:
0539: }
0540: }
0541: }
0542:
0543: /**
0544: * Parse to end tag. Ignores character data seen prior to an end tag, but
0545: * throws exception if a start tag or the end of the document is seen before
0546: * an end tag. Leaves the parser positioned at the end tag.
0547: *
0548: * @return element name of end tag found
0549: * @throws JiBXException on any error (possibly wrapping other exception)
0550: */
0551: public String toEnd() throws JiBXException {
0552: if (m_reader.getEventType() == IXMLReader.END_TAG) {
0553: return m_reader.getName();
0554: }
0555: while (true) {
0556: m_reader.next();
0557: switch (m_reader.getEventType()) {
0558:
0559: case IXMLReader.START_TAG:
0560: throw new JiBXException("Expected end tag, "
0561: + "found start tag " + currentNameString()
0562: + " " + buildPositionString());
0563:
0564: case IXMLReader.END_TAG:
0565: return m_reader.getName();
0566:
0567: case IXMLReader.END_DOCUMENT:
0568: throw new JiBXException("Expected end tag, "
0569: + "found end of document "
0570: + buildPositionString());
0571:
0572: }
0573: }
0574: }
0575:
0576: /**
0577: * Parse to start or end tag. If not currently positioned at a start or end
0578: * tag this first advances the parse to the next start or end tag.
0579: *
0580: * @return parser event type for start tag or end tag
0581: * @throws JiBXException on any error (possibly wrapping other exception)
0582: */
0583: public int toTag() throws JiBXException {
0584: int type = m_reader.getEventType();
0585: while (type != IXMLReader.START_TAG
0586: && type != IXMLReader.END_TAG) {
0587: type = m_reader.next();
0588: }
0589: return m_reader.getEventType();
0590: }
0591:
0592: /**
0593: * Check if next tag is start of element. If not currently positioned at a
0594: * start or end tag this first advances the parse to the next start or end
0595: * tag.
0596: *
0597: * @param ns namespace URI for expected element (may be <code>null</code>
0598: * or the empty string for the empty namespace)
0599: * @param name element name expected
0600: * @return <code>true</code> if at start of element with supplied name,
0601: * <code>false</code> if not
0602: * @throws JiBXException on any error (possibly wrapping other exception)
0603: */
0604: public boolean isAt(String ns, String name) throws JiBXException {
0605: int type = m_reader.getEventType();
0606: while (type != IXMLReader.START_TAG
0607: && type != IXMLReader.END_TAG) {
0608: type = m_reader.next();
0609: }
0610: return m_reader.getEventType() == IXMLReader.START_TAG
0611: && m_reader.getName().equals(name)
0612: && verifyNamespace(ns);
0613: }
0614:
0615: /**
0616: * Check if attribute is present on current start tag. Throws an exception
0617: * if not currently positioned on a start tag.
0618: *
0619: * @param ns namespace URI for expected attribute (may be <code>null</code>
0620: * or the empty string for the empty namespace)
0621: * @param name attribute name expected
0622: * @return <code>true</code> if named attribute is present,
0623: * <code>false</code> if not
0624: * @throws JiBXException on any error (possibly wrapping other exception)
0625: */
0626: public boolean hasAttribute(String ns, String name)
0627: throws JiBXException {
0628: if (m_reader.getEventType() == IXMLReader.START_TAG) {
0629: return getAttributeValue(ns, name) != null;
0630: } else {
0631: throw new JiBXException("Error parsing document "
0632: + buildPositionString());
0633: }
0634: }
0635:
0636: /**
0637: * Check if any of several attributes is present on current start tag.
0638: * Throws an exception if not currently positioned on a start tag.
0639: *
0640: * @param nss namespace URIs for expected attributes (each may be
0641: * <code>null</code> or the empty string for the empty namespace)
0642: * @param names attribute names expected
0643: * @return <code>true</code> if at least one of the named attributes is
0644: * present, <code>false</code> if not
0645: * @throws JiBXException on any error (possibly wrapping other exception)
0646: */
0647: public boolean hasAnyAttribute(String[] nss, String[] names)
0648: throws JiBXException {
0649: if (m_reader.getEventType() == IXMLReader.START_TAG) {
0650: for (int i = 0; i < names.length; i++) {
0651: if (getAttributeValue(nss[i], names[i]) != null) {
0652: return true;
0653: }
0654: }
0655: return false;
0656: } else {
0657: throw new JiBXException("Error parsing document "
0658: + buildPositionString());
0659: }
0660: }
0661:
0662: /**
0663: * Check that only allowed attributes are present on current start tag.
0664: * Throws an exception if not currently positioned on a start tag, or if
0665: * an attribute is present which is not in the list.
0666: *
0667: * @param nss namespace URIs for allowed attributes (each may be
0668: * <code>null</code> or the empty string for the empty namespace)
0669: * @param names alphabetical list of attribute names expected (duplicates
0670: * names are ordered by namespace URI)
0671: * @throws JiBXException on any error (possibly wrapping other exception)
0672: */
0673: public void checkAllowedAttributes(String[] nss, String[] names)
0674: throws JiBXException {
0675: if (m_reader.getEventType() == IXMLReader.START_TAG) {
0676: int count = m_reader.getAttributeCount();
0677: loop: for (int i = 0; i < count; i++) {
0678: String name = m_reader.getAttributeName(i);
0679: String ns = m_reader.getAttributeNamespace(i);
0680: int base = 0;
0681: int limit = names.length - 1;
0682: while (base <= limit) {
0683: int cur = (base + limit) >> 1;
0684: int diff = name.compareTo(names[cur]);
0685: if (diff == 0) {
0686: String comp = nss[cur];
0687: if (comp == null) {
0688: diff = ns.compareTo("");
0689: } else {
0690: diff = ns.compareTo(comp);
0691: }
0692: if (diff == 0) {
0693: continue loop;
0694: }
0695: }
0696: if (diff < 0) {
0697: limit = cur - 1;
0698: } else if (diff > 0) {
0699: base = cur + 1;
0700: }
0701: }
0702: throwStartTagException("Illegal attribute "
0703: + buildNameString(ns, name));
0704: }
0705: } else {
0706: throw new JiBXException("Error parsing document "
0707: + buildPositionString());
0708: }
0709: }
0710:
0711: /**
0712: * Internal parse to expected start tag. Ignores character data seen prior
0713: * to a start tag, but throws exception if an end tag or the end of the
0714: * document is seen before a start tag. Leaves the parser positioned at the
0715: * start tag.
0716: *
0717: * @param ns namespace URI for expected element (may be <code>null</code>
0718: * or the empty string for the empty namespace)
0719: * @param name element name expected
0720: * @throws JiBXException on any error (possibly wrapping other exception)
0721: */
0722: private void matchStart(String ns, String name)
0723: throws JiBXException {
0724: if (toTag() == IXMLReader.START_TAG) {
0725: if (!m_reader.getName().equals(name)
0726: || !verifyNamespace(ns)) {
0727: throwStartTagNameError(ns, name);
0728: }
0729: } else {
0730: throw new JiBXException("Expected "
0731: + buildNameString(ns, name) + " start tag, found "
0732: + currentNameString() + " end tag "
0733: + buildPositionString());
0734: }
0735: }
0736:
0737: /**
0738: * Parse to start of element. Ignores character data to next start or end
0739: * tag, but throws exception if an end tag is seen before a start tag, or if
0740: * the start tag seen does not match the expected name. Leaves the parse
0741: * positioned at the start tag.
0742: *
0743: * @param ns namespace URI for expected element (may be <code>null</code>
0744: * or the empty string for the empty namespace)
0745: * @param name element name expected
0746: * @throws JiBXException on any error (possibly wrapping other exception)
0747: */
0748: public void parseToStartTag(String ns, String name)
0749: throws JiBXException {
0750: matchStart(ns, name);
0751: }
0752:
0753: /**
0754: * Parse past start of element. Ignores character data to next start or end
0755: * tag, but throws exception if an end tag is seen before a start tag, or if
0756: * the start tag seen does not match the expected name. Leaves the parse
0757: * positioned following the start tag.
0758: *
0759: * @param ns namespace URI for expected element (may be <code>null</code>
0760: * or the empty string for the empty namespace)
0761: * @param name element name expected
0762: * @throws JiBXException on any error (possibly wrapping other exception)
0763: */
0764: public void parsePastStartTag(String ns, String name)
0765: throws JiBXException {
0766: matchStart(ns, name);
0767: advance();
0768: }
0769:
0770: /**
0771: * Parse past start of element. Ignores character data to next start or end
0772: * tag, but throws exception if an end tag is seen before a start tag, or if
0773: * the start tag seen does not match the expected name. Leaves the parse
0774: * positioned following the start tag.
0775: *
0776: * @param ns namespace URI for expected element (may be <code>null</code>
0777: * or the empty string for the empty namespace)
0778: * @param name element name expected
0779: * @throws JiBXException on any error (possibly wrapping other exception)
0780: */
0781: public boolean parseIfStartTag(String ns, String name)
0782: throws JiBXException {
0783: if (isAt(ns, name)) {
0784: advance();
0785: return true;
0786: } else {
0787: return false;
0788: }
0789: }
0790:
0791: /**
0792: * Parse past current end of element. Ignores character data to next start
0793: * or end tag, but throws exception if a start tag is seen before a end tag,
0794: * or if the end tag seen does not match the expected name. Leaves the parse
0795: * positioned following the end tag.
0796: *
0797: * @param ns namespace URI for expected element (may be <code>null</code>
0798: * or the empty string for the empty namespace)
0799: * @param name element name expected
0800: * @throws JiBXException on any error (possibly wrapping other exception)
0801: */
0802: public void parsePastCurrentEndTag(String ns, String name)
0803: throws JiBXException {
0804:
0805: // move parse to start or end tag
0806: int event = toTag();
0807:
0808: // check for match on expected end tag
0809: if (event == IXMLReader.END_TAG) {
0810: if (m_reader.getName().equals(name) && verifyNamespace(ns)) {
0811: advance();
0812: } else {
0813: throwEndTagNameError(ns, name);
0814: }
0815: } else {
0816: throw new JiBXException("Expected "
0817: + buildNameString(ns, name) + " end tag, found "
0818: + currentNameString() + " start tag "
0819: + buildPositionString());
0820: }
0821: }
0822:
0823: /**
0824: * Parse past end of element. If currently at a start tag parses past that
0825: * start tag, then ignores character data to next start or end tag, and
0826: * throws exception if a start tag is seen before a end tag, or if
0827: * the end tag seen does not match the expected name. Leaves the parse
0828: * positioned following the end tag.
0829: *
0830: * @param ns namespace URI for expected element (may be <code>null</code>
0831: * or the empty string for the empty namespace)
0832: * @param name element name expected
0833: * @throws JiBXException on any error (possibly wrapping other exception)
0834: */
0835: public void parsePastEndTag(String ns, String name)
0836: throws JiBXException {
0837:
0838: // most past current tag if start
0839: int event = m_reader.getEventType();
0840: if (event == IXMLReader.START_TAG) {
0841: advance();
0842: }
0843:
0844: // handle as current tag
0845: parsePastCurrentEndTag(ns, name);
0846: }
0847:
0848: /**
0849: * Check if next tag is a start tag. If not currently positioned at a
0850: * start or end tag this first advances the parse to the next start or
0851: * end tag.
0852: *
0853: * @return <code>true</code> if at start of element, <code>false</code> if
0854: * at end
0855: * @throws JiBXException on any error (possibly wrapping other exception)
0856: */
0857: public boolean isStart() throws JiBXException {
0858: int type = m_reader.getEventType();
0859: while (type != IXMLReader.START_TAG
0860: && type != IXMLReader.END_TAG) {
0861: type = m_reader.next();
0862: }
0863: return m_reader.getEventType() == IXMLReader.START_TAG;
0864: }
0865:
0866: /**
0867: * Check if next tag is an end tag. If not currently positioned at a
0868: * start or end tag this first advances the parse to the next start or
0869: * end tag.
0870: *
0871: * @return <code>true</code> if at end of element, <code>false</code> if
0872: * at start
0873: * @throws JiBXException on any error (possibly wrapping other exception)
0874: */
0875: public boolean isEnd() throws JiBXException {
0876: int type = m_reader.getEventType();
0877: while (type != IXMLReader.START_TAG
0878: && type != IXMLReader.END_TAG) {
0879: type = m_reader.next();
0880: }
0881: return m_reader.getEventType() == IXMLReader.END_TAG;
0882: }
0883:
0884: /**
0885: * Accumulate text content. This skips past comments and processing
0886: * instructions, and consolidates text and entities to a single string. Any
0887: * unexpanded entity references found are treated as errors.
0888: *
0889: * @return consolidated text string (empty string if no text components)
0890: * @exception JiBXException on error in unmarshalling
0891: */
0892: public String accumulateText() throws JiBXException {
0893: String text = null;
0894: StringBuffer buff = null;
0895: loop: while (true) {
0896: switch (m_reader.getEventType()) {
0897:
0898: case IXMLReader.ENTITY_REF:
0899: if (m_reader.getText() == null) {
0900: throw new JiBXException(
0901: "Unexpanded entity reference in text at "
0902: + buildPositionString());
0903: }
0904: // fall through into text accumulation
0905:
0906: case IXMLReader.CDSECT:
0907: case IXMLReader.TEXT:
0908: if (text == null) {
0909: text = m_reader.getText();
0910: } else {
0911: if (buff == null) {
0912: buff = new StringBuffer(text);
0913: }
0914: buff.append(m_reader.getText());
0915: }
0916: break;
0917:
0918: case IXMLReader.END_TAG:
0919: case IXMLReader.START_TAG:
0920: case IXMLReader.END_DOCUMENT:
0921: break loop;
0922:
0923: default:
0924: break;
0925:
0926: }
0927: m_reader.nextToken();
0928: }
0929: if (buff == null) {
0930: return (text == null) ? "" : text;
0931: } else {
0932: return buff.toString();
0933: }
0934: }
0935:
0936: /**
0937: * Parse required text content. Assumes the parse is already positioned at
0938: * the text content, so just returns the text.
0939: *
0940: * @return content text found
0941: * @throws JiBXException on any error (possible wrapping other exception)
0942: */
0943: public String parseContentText() throws JiBXException {
0944: return accumulateText();
0945: }
0946:
0947: /**
0948: * Parse past end of element, returning optional text content. Assumes
0949: * you've already parsed past the start tag of the element, so it just looks
0950: * for text content followed by the end tag, and returns with the parser
0951: * positioned after the end tag.
0952: *
0953: * @param ns namespace URI for expected element (may be <code>null</code>
0954: * or the empty string for the empty namespace)
0955: * @param tag element name expected
0956: * @return content text from element
0957: * @throws JiBXException on any error (possible wrapping other exception)
0958: */
0959: public String parseContentText(String ns, String tag)
0960: throws JiBXException {
0961: String text = accumulateText();
0962: switch (m_reader.getEventType()) {
0963:
0964: case IXMLReader.END_TAG:
0965: if (m_reader.getName().equals(tag) && verifyNamespace(ns)) {
0966: m_reader.nextToken();
0967: return text;
0968: } else {
0969: throwEndTagNameError(ns, tag);
0970: }
0971:
0972: case IXMLReader.START_TAG:
0973: throw new JiBXException("Expected "
0974: + buildNameString(ns, tag) + " end tag, "
0975: + "found " + currentNameString() + " start tag "
0976: + buildPositionString());
0977:
0978: case IXMLReader.END_DOCUMENT:
0979: throw new JiBXException("Expected "
0980: + buildNameString(ns, tag) + " end tag, "
0981: + "found end of document " + buildPositionString());
0982:
0983: }
0984: return null;
0985: }
0986:
0987: /**
0988: * Parse past end of element, returning integer value of
0989: * content. Assumes you've already parsed past the start tag of the
0990: * element, so it just looks for text content followed by the end tag.
0991: *
0992: * @param ns namespace URI for expected element (may be <code>null</code>
0993: * or the empty string for the empty namespace)
0994: * @param tag element name expected
0995: * @return converted value from element text
0996: * @throws JiBXException on any error (possible wrapping other exception)
0997: */
0998: public int parseContentInt(String ns, String tag)
0999: throws JiBXException {
1000: String text = parseContentText(ns, tag);
1001: try {
1002: return Utility.parseInt(text);
1003: } catch (JiBXException ex) {
1004: throw new JiBXException(ex.getMessage() + ' '
1005: + buildPositionString(), ex.getRootCause());
1006: }
1007: }
1008:
1009: /**
1010: * Parse entire element, returning text content.
1011: * Expects to find the element start tag, text content, and end tag,
1012: * in that order, and returns with the parser positioned following
1013: * the end tag.
1014: *
1015: * @param ns namespace URI for expected element (may be <code>null</code>
1016: * or the empty string for the empty namespace)
1017: * @param tag element name expected
1018: * @return content text from element
1019: * @throws JiBXException on any error (possible wrapping other exception)
1020: */
1021: public String parseElementText(String ns, String tag)
1022: throws JiBXException {
1023: parsePastStartTag(ns, tag);
1024: return parseContentText(ns, tag);
1025: }
1026:
1027: /**
1028: * Parse entire element, returning optional text content.
1029: * Expects to find the element start tag, text content, and end tag,
1030: * in that order, and returns with the parser positioned following
1031: * the end tag. Returns the default text if the element is not found.
1032: *
1033: * @param ns namespace URI for expected element (may be <code>null</code>
1034: * or the empty string for the empty namespace)
1035: * @param tag element name expected
1036: * @param dflt default text value
1037: * @return content text from element
1038: * @throws JiBXException on any error (possible wrapping other exception)
1039: */
1040: public String parseElementText(String ns, String tag, String dflt)
1041: throws JiBXException {
1042: if (parseIfStartTag(ns, tag)) {
1043: return parseContentText(ns, tag);
1044: } else {
1045: return dflt;
1046: }
1047: }
1048:
1049: /**
1050: * Get text value of attribute from current start tag.
1051: * Throws an exception if the attribute value is not found in the start
1052: * tag.
1053: *
1054: * @param ns namespace URI for expected attribute (may be <code>null</code>
1055: * or the empty string for the empty namespace)
1056: * @param name attribute name expected
1057: * @return attribute value text
1058: * @throws JiBXException if attribute not present
1059: */
1060: public String attributeText(String ns, String name)
1061: throws JiBXException {
1062: String value = getAttributeValue(ns, name);
1063: if (value == null) {
1064: throw new JiBXException("Missing required attribute "
1065: + buildNameString(ns, name) + " "
1066: + buildPositionString());
1067: } else {
1068: return value;
1069: }
1070: }
1071:
1072: /**
1073: * Get text value of optional attribute from current start
1074: * tag. If the attribute is not present the supplied default value is
1075: * returned instead.
1076: *
1077: * @param ns namespace URI for expected attribute (may be <code>null</code>
1078: * or the empty string for the empty namespace)
1079: * @param name attribute name expected
1080: * @param dflt value to be returned if attribute is not present
1081: * @return attribute value text
1082: */
1083: public String attributeText(String ns, String name, String dflt) {
1084: String value = getAttributeValue(ns, name);
1085: if (value == null) {
1086: return dflt;
1087: } else {
1088: return value;
1089: }
1090: }
1091:
1092: /**
1093: * Find the object corresponding to an ID. This method just handles the
1094: * lookup and checks the object type.
1095: *
1096: * @param id ID text
1097: * @param index expected reference type index
1098: * @return object corresponding to IDREF, or <code>null</code> if not
1099: * yet defined
1100: * @throws JiBXException on any error
1101: */
1102: public Object findID(String id, int index) throws JiBXException {
1103: HashMap map = m_idMaps[index];
1104: if (map != null) {
1105: Object obj = map.get(id);
1106: if (obj == null || obj instanceof BackFillHolder) {
1107: return null;
1108: } else if (m_idClasses == null
1109: || m_idClasses[index].equals(obj.getClass()
1110: .getName())) {
1111: return obj;
1112: } else {
1113: throwStartTagException("IDREF element content mapped to wrong type");
1114: }
1115: }
1116: return null;
1117: }
1118:
1119: /**
1120: * Find previously defined object corresponding to an ID. This does the
1121: * lookup and checks that the referenced object has been defined.
1122: *
1123: * @param id ID text
1124: * @param index expected reference type index
1125: * @return object corresponding to IDREF
1126: * @throws JiBXException on any error
1127: */
1128: public Object findDefinedID(String id, int index)
1129: throws JiBXException {
1130: Object obj = findID(id, index);
1131: if (obj == null) {
1132: throwStartTagException("ID " + id + " not defined");
1133: }
1134: return obj;
1135: }
1136:
1137: /**
1138: * Parse entire element, returning object (if defined yet) corresponding
1139: * to content interpreted as IDREF. Expects to find the element start tag,
1140: * text content, and end tag, in that order, and returns with the parser
1141: * positioned following the end tag.
1142: *
1143: * @param ns namespace URI for expected element (may be <code>null</code>
1144: * or the empty string for the empty namespace)
1145: * @param tag attribute name expected
1146: * @param index expected reference type index
1147: * @return object corresponding to IDREF, or <code>null</code> if not
1148: * yet defined
1149: * @throws JiBXException on any error (possibly wrapping other exception)
1150: */
1151: public Object parseElementForwardIDREF(String ns, String tag,
1152: int index) throws JiBXException {
1153: parsePastStartTag(ns, tag);
1154: m_idref = parseContentText(ns, tag);
1155: return findID(m_idref, index);
1156: }
1157:
1158: /**
1159: * Get object (if defined yet) corresponding to IDREF attribute from
1160: * current start tag.
1161: *
1162: * @param ns namespace URI for expected attribute (may be <code>null</code>
1163: * or the empty string for the empty namespace)
1164: * @param name attribute name expected
1165: * @param index expected reference type index
1166: * @return object corresponding to IDREF, or <code>null</code> if not
1167: * yet defined
1168: * @throws JiBXException if attribute not present, or ID mapped to a
1169: * different type of object than expected
1170: */
1171: public Object attributeForwardIDREF(String ns, String name,
1172: int index) throws JiBXException {
1173: m_idref = attributeText(ns, name);
1174: return findID(m_idref, index);
1175: }
1176:
1177: /**
1178: * Parse entire element, returning previously defined object corresponding
1179: * to content interpreted as IDREF. Expects to find the element start tag,
1180: * text content, and end tag, in that order, and returns with the parser
1181: * positioned following the end tag.
1182: *
1183: * @param ns namespace URI for expected element (may be <code>null</code>
1184: * or the empty string for the empty namespace)
1185: * @param tag attribute name expected
1186: * @param index expected reference type index
1187: * @return object corresponding to IDREF
1188: * @throws JiBXException if attribute not present, ID not defined, or
1189: * mapped to a different type of object than expected
1190: */
1191: public Object parseElementExistingIDREF(String ns, String tag,
1192: int index) throws JiBXException {
1193: parsePastStartTag(ns, tag);
1194: m_idref = parseContentText(ns, tag);
1195: return findDefinedID(m_idref, index);
1196: }
1197:
1198: /**
1199: * Get previously defined object corresponding to IDREF attribute from
1200: * current start tag.
1201: *
1202: * @param ns namespace URI for expected attribute (may be <code>null</code>
1203: * or the empty string for the empty namespace)
1204: * @param name attribute name expected
1205: * @param index expected reference type index
1206: * @return object corresponding to IDREF
1207: * @throws JiBXException if attribute not present, ID not defined, or
1208: * mapped to a different type of object than expected
1209: */
1210: public Object attributeExistingIDREF(String ns, String name,
1211: int index) throws JiBXException {
1212: m_idref = attributeText(ns, name);
1213: return findDefinedID(m_idref, index);
1214: }
1215:
1216: /**
1217: * Get integer value of attribute from current start tag.
1218: * Throws an exception if the attribute is not found in the start
1219: * tag, or if it is not a valid integer value.
1220: *
1221: * @param ns namespace URI for expected attribute (may be <code>null</code>
1222: * or the empty string for the empty namespace)
1223: * @param name attribute name expected
1224: * @return attribute integer value
1225: * @throws JiBXException if attribute not present or not a valid integer
1226: * value
1227: */
1228: public int attributeInt(String ns, String name)
1229: throws JiBXException {
1230: String text = attributeText(ns, name);
1231: try {
1232: return Utility.parseInt(text);
1233: } catch (JiBXException ex) {
1234: throw new JiBXException(ex.getMessage() + ' '
1235: + buildPositionString(), ex.getRootCause());
1236: }
1237: }
1238:
1239: /**
1240: * Get integer value of optional attribute from current
1241: * start tag. If the attribute is not present the supplied default value
1242: * is returned instead.
1243: *
1244: * @param ns namespace URI for expected attribute (may be <code>null</code>
1245: * or the empty string for the empty namespace)
1246: * @param name attribute name expected
1247: * @param dflt value to be returned if attribute is not present
1248: * @return attribute integer value
1249: * @throws JiBXException if attribute value is not a valid integer
1250: */
1251: public int attributeInt(String ns, String name, int dflt)
1252: throws JiBXException {
1253: String value = getAttributeValue(ns, name);
1254: if (value == null) {
1255: return dflt;
1256: } else {
1257: try {
1258: return Utility.parseInt(value);
1259: } catch (JiBXException ex) {
1260: throw new JiBXException(ex.getMessage() + ' '
1261: + buildPositionString(), ex.getRootCause());
1262: }
1263: }
1264: }
1265:
1266: /**
1267: * Parse entire element, returning integer value of content.
1268: * Expects to find the element start tag, text content, and end tag,
1269: * in that order, and returns with the parser positioned following
1270: * the end tag.
1271: *
1272: * @param ns namespace URI for expected element (may be <code>null</code>
1273: * or the empty string for the empty namespace)
1274: * @param tag element name expected
1275: * @return content text from element
1276: * @throws JiBXException on any error (possibly wrapping other exception)
1277: */
1278: public int parseElementInt(String ns, String tag)
1279: throws JiBXException {
1280: parsePastStartTag(ns, tag);
1281: return parseContentInt(ns, tag);
1282: }
1283:
1284: /**
1285: * Parse entire optional element, returning integer value of content.
1286: * Expects to find the element start tag, text content, and end tag,
1287: * in that order, and returns with the parser positioned following
1288: * the end tag. Returns the default value if the element is missing or
1289: * has no content.
1290: *
1291: * @param ns namespace URI for expected element (may be <code>null</code>
1292: * or the empty string for the empty namespace)
1293: * @param tag element name expected
1294: * @param dflt default value
1295: * @return content text from element
1296: * @throws JiBXException on any error (possibly wrapping other exception)
1297: */
1298: public int parseElementInt(String ns, String tag, int dflt)
1299: throws JiBXException {
1300: if (parseIfStartTag(ns, tag)) {
1301: return parseContentInt(ns, tag);
1302: } else {
1303: return dflt;
1304: }
1305: }
1306:
1307: /**
1308: * Find required text value in enumeration. Looks up and returns the
1309: * enumeration value corresponding to the target text.
1310: *
1311: * @param target text to be found in enumeration
1312: * @param enums ordered array of texts included in enumeration
1313: * @param vals array of values to be returned for corresponding text match
1314: * positions (position returned directly if this is <code>null</code>)
1315: * @return enumeration value for target text
1316: * @throws JiBXException if target text not found in enumeration
1317: */
1318: public int convertEnum(String target, String[] enums, int[] vals)
1319: throws JiBXException {
1320: if (target == null) {
1321: throwStartTagException("Missing required enumeration value");
1322: }
1323: try {
1324: return Utility.enumValue(target, enums, vals);
1325: } catch (JiBXException ex) {
1326: throw new JiBXException(ex.getMessage() + ' '
1327: + buildPositionString());
1328: }
1329: }
1330:
1331: /**
1332: * Find optional text value in enumeration. Looks up and returns the
1333: * enumeration value corresponding to the target text, or the default
1334: * value if the text is <code>null</code>.
1335: *
1336: * @param target text to be found in enumeration (may be <code>null</code>)
1337: * @param enums ordered array of texts included in enumeration
1338: * @param vals array of values to be returned for corresponding text match
1339: * positions (position returned directly if this is <code>null</code>)
1340: * @param dflt default value returned if target text is <code>null</code>
1341: * @return enumeration value for target text
1342: * @throws JiBXException if target text not found in enumeration
1343: */
1344: public int convertEnum(String target, String[] enums, int[] vals,
1345: int dflt) throws JiBXException {
1346: if (target == null) {
1347: return dflt;
1348: }
1349: try {
1350: return Utility.enumValue(target, enums, vals);
1351: } catch (JiBXException ex) {
1352: throw new JiBXException(ex.getMessage() + ' '
1353: + buildPositionString());
1354: }
1355: }
1356:
1357: /**
1358: * Get enumeration attribute value from current start tag.
1359: * Throws an exception if the attribute value is not found in the start
1360: * tag or the text does not match a value defined in the enumeration table.
1361: *
1362: * @param ns namespace URI for expected attribute (may be <code>null</code>
1363: * or the empty string for the empty namespace)
1364: * @param name attribute name expected
1365: * @param enums ordered array of texts included in enumeration
1366: * @param vals array of values to be returned for corresponding text match
1367: * positions (position returned directly if this is <code>null</code>)
1368: * @return enumeration value for target text
1369: * @throws JiBXException if attribute not present or value not found in
1370: * enumeration list
1371: */
1372: public int attributeEnumeration(String ns, String name,
1373: String[] enums, int[] vals) throws JiBXException {
1374: return convertEnum(getAttributeValue(ns, name), enums, vals);
1375: }
1376:
1377: /**
1378: * Get optional enumeration attribute value from current start tag.
1379: * Throws an exception if the attribute value is present but does not match
1380: * a value defined in the enumeration table.
1381: *
1382: * @param ns namespace URI for expected attribute (may be <code>null</code>
1383: * or the empty string for the empty namespace)
1384: * @param name attribute name expected
1385: * @param enums ordered array of texts included in enumeration
1386: * @param vals array of values to be returned for corresponding text match
1387: * positions (position returned directly if this is <code>null</code>)
1388: * @param dflt default value returned if attribute is not present
1389: * @return enumeration value for target text
1390: * @throws JiBXException if attribute not present or value not found in
1391: * enumeration list
1392: */
1393: public int attributeEnumeration(String ns, String name,
1394: String[] enums, int[] vals, int dflt) throws JiBXException {
1395: return convertEnum(getAttributeValue(ns, name), enums, vals,
1396: dflt);
1397: }
1398:
1399: /**
1400: * Parse past end of element, returning enumeration value of content.
1401: * Assumes you've already parsed past the start tag of the element, so it
1402: * just looks for text content followed by the end tag, and returns with the
1403: * parser positioned after the end tag.
1404: *
1405: * @param ns namespace URI for expected element (may be <code>null</code>
1406: * or the empty string for the empty namespace)
1407: * @param tag element name expected
1408: * @param enums ordered array of texts included in enumeration
1409: * @param vals array of values to be returned for corresponding text match
1410: * positions (position returned directly if this is <code>null</code>)
1411: * @return enumeration value for element text
1412: * @throws JiBXException on any error (possible wrapping other exception)
1413: */
1414: public int parseContentEnumeration(String ns, String tag,
1415: String[] enums, int[] vals) throws JiBXException {
1416: return convertEnum(parseContentText(ns, tag), enums, vals);
1417: }
1418:
1419: /**
1420: * Parse entire element, returning enumeration value of optional content.
1421: * Expects to find the element start tag, text content, and end tag,
1422: * in that order, and returns with the parser positioned following
1423: * the end tag. Returns the default value if no content is present.
1424: *
1425: * @param ns namespace URI for expected element (may be <code>null</code>
1426: * or the empty string for the empty namespace)
1427: * @param tag element name expected
1428: * @param enums ordered array of texts included in enumeration
1429: * @param vals array of values to be returned for corresponding text match
1430: * positions (position returned directly if this is <code>null</code>)
1431: * @param dflt default value
1432: * @return enumeration value for element text
1433: * @throws JiBXException on any error (possibly wrapping other exception)
1434: */
1435: public int parseElementEnumeration(String ns, String tag,
1436: String[] enums, int[] vals, int dflt) throws JiBXException {
1437: if (parseIfStartTag(ns, tag)) {
1438: String text = parseContentText(ns, tag);
1439: return convertEnum(text, enums, vals, dflt);
1440: } else {
1441: return dflt;
1442: }
1443: }
1444:
1445: /**
1446: * Convert byte value with exception wrapper. This internal method is used
1447: * by all the byte unmarshalling calls. It adds position information to
1448: * any exceptions that occur.
1449: *
1450: * @param text text for value to be converted
1451: * @return converted byte value
1452: * @throws JiBXException if not a valid byte value
1453: */
1454: public byte convertByte(String text) throws JiBXException {
1455: try {
1456: return Utility.parseByte(text);
1457: } catch (JiBXException ex) {
1458: throw new JiBXException(ex.getMessage() + ' '
1459: + buildPositionString(), ex.getRootCause());
1460: }
1461: }
1462:
1463: /**
1464: * Get byte value of attribute from current start tag. Throws an exception
1465: * if the attribute is not found in the start tag, or if it is not a valid
1466: * integer value.
1467: *
1468: * @param ns namespace URI for expected attribute (may be <code>null</code>
1469: * or the empty string for the empty namespace)
1470: * @param name attribute name expected
1471: * @return attribute byte value
1472: * @throws JiBXException if attribute not present or not a valid byte value
1473: */
1474: public byte attributeByte(String ns, String name)
1475: throws JiBXException {
1476: return convertByte(attributeText(ns, name));
1477: }
1478:
1479: /**
1480: * Get byte value of optional attribute from current start tag. If the
1481: * attribute is not present the supplied default value is returned instead.
1482: *
1483: * @param ns namespace URI for expected attribute (may be <code>null</code>
1484: * or the empty string for the empty namespace)
1485: * @param name attribute name expected
1486: * @param dflt value to be returned if attribute is not present
1487: * @return attribute byte value
1488: * @throws JiBXException if attribute value is not a valid byte
1489: */
1490: public byte attributeByte(String ns, String name, byte dflt)
1491: throws JiBXException {
1492: String text = getAttributeValue(ns, name);
1493: if (text == null) {
1494: return dflt;
1495: } else {
1496: return convertByte(text);
1497: }
1498: }
1499:
1500: /**
1501: * Parse past end of element, returning byte value of content. Assumes
1502: * you've already parsed past the start tag of the element, so it just looks
1503: * for text content followed by the end tag, and returns with the parser
1504: * positioned after the end tag.
1505: *
1506: * @param ns namespace URI for expected element (may be <code>null</code>
1507: * or the empty string for the empty namespace)
1508: * @param tag element name expected
1509: * @return converted value from element text
1510: * @throws JiBXException on any error (possible wrapping other exception)
1511: */
1512: public byte parseContentByte(String ns, String tag)
1513: throws JiBXException {
1514: return convertByte(parseContentText(ns, tag));
1515: }
1516:
1517: /**
1518: * Parse entire element, returning byte value of content.
1519: * Expects to find the element start tag, text content, and end tag,
1520: * in that order, and returns with the parser positioned following
1521: * the end tag.
1522: *
1523: * @param ns namespace URI for expected element (may be <code>null</code>
1524: * or the empty string for the empty namespace)
1525: * @param tag element name expected
1526: * @return content text from element
1527: * @throws JiBXException on any error (possibly wrapping other exception)
1528: */
1529: public byte parseElementByte(String ns, String tag)
1530: throws JiBXException {
1531: parsePastStartTag(ns, tag);
1532: return parseContentByte(ns, tag);
1533: }
1534:
1535: /**
1536: * Parse entire element, returning byte value of optional content.
1537: * Expects to find the element start tag, text content, and end tag,
1538: * in that order, and returns with the parser positioned following
1539: * the end tag. Returns the default value if no content is present.
1540: *
1541: * @param ns namespace URI for expected element (may be <code>null</code>
1542: * or the empty string for the empty namespace)
1543: * @param tag element name expected
1544: * @param dflt default value
1545: * @return content text from element
1546: * @throws JiBXException on any error (possibly wrapping other exception)
1547: */
1548: public byte parseElementByte(String ns, String tag, byte dflt)
1549: throws JiBXException {
1550: if (parseIfStartTag(ns, tag)) {
1551: return convertByte(parseContentText(ns, tag));
1552: } else {
1553: return dflt;
1554: }
1555: }
1556:
1557: /**
1558: * Convert short value with exception wrapper. This internal method is used
1559: * by all the short unmarshalling calls. It adds position information to
1560: * any exceptions that occur.
1561: *
1562: * @param text text for value to be converted
1563: * @return converted short value
1564: * @throws JiBXException if not a valid short value
1565: */
1566: public short convertShort(String text) throws JiBXException {
1567: try {
1568: return Utility.parseShort(text);
1569: } catch (JiBXException ex) {
1570: throw new JiBXException(ex.getMessage() + ' '
1571: + buildPositionString(), ex.getRootCause());
1572: }
1573: }
1574:
1575: /**
1576: * Get short value of attribute from current start tag. Throws an exception
1577: * if the attribute is not found in the start tag, or if it is not a valid
1578: * integer value.
1579: *
1580: * @param ns namespace URI for expected attribute (may be <code>null</code>
1581: * or the empty string for the empty namespace)
1582: * @param name attribute name expected
1583: * @return attribute short value
1584: * @throws JiBXException if attribute not present or not a valid short value
1585: */
1586: public short attributeShort(String ns, String name)
1587: throws JiBXException {
1588: return convertShort(attributeText(ns, name));
1589: }
1590:
1591: /**
1592: * Get short value of optional attribute from current start tag. If the
1593: * attribute is not present the supplied default value is returned instead.
1594: *
1595: * @param ns namespace URI for expected attribute (may be <code>null</code>
1596: * or the empty string for the empty namespace)
1597: * @param name attribute name expected
1598: * @param dflt value to be returned if attribute is not present
1599: * @return attribute short value
1600: * @throws JiBXException if attribute value is not a valid short
1601: */
1602: public short attributeShort(String ns, String name, short dflt)
1603: throws JiBXException {
1604: String text = getAttributeValue(ns, name);
1605: if (text == null) {
1606: return dflt;
1607: } else {
1608: return convertShort(text);
1609: }
1610: }
1611:
1612: /**
1613: * Parse past end of element, returning short value of content. Assumes
1614: * you've already parsed past the start tag of the element, so it just looks
1615: * for text content followed by the end tag, and returns with the parser
1616: * positioned after the end tag.
1617: *
1618: * @param ns namespace URI for expected element (may be <code>null</code>
1619: * or the empty string for the empty namespace)
1620: * @param tag element name expected
1621: * @return converted value from element text
1622: * @throws JiBXException on any error (possible wrapping other exception)
1623: */
1624: public short parseContentShort(String ns, String tag)
1625: throws JiBXException {
1626: return convertShort(parseContentText(ns, tag));
1627: }
1628:
1629: /**
1630: * Parse entire element, returning short value of content.
1631: * Expects to find the element start tag, text content, and end tag,
1632: * in that order, and returns with the parser positioned following
1633: * the end tag.
1634: *
1635: * @param ns namespace URI for expected element (may be <code>null</code>
1636: * or the empty string for the empty namespace)
1637: * @param tag element name expected
1638: * @return content text from element
1639: * @throws JiBXException on any error (possibly wrapping other exception)
1640: */
1641: public short parseElementShort(String ns, String tag)
1642: throws JiBXException {
1643: parsePastStartTag(ns, tag);
1644: return parseContentShort(ns, tag);
1645: }
1646:
1647: /**
1648: * Parse entire element, returning short value of optional content.
1649: * Expects to find the element start tag, text content, and end tag,
1650: * in that order, and returns with the parser positioned following
1651: * the end tag. Returns the default value if no content is present.
1652: *
1653: * @param ns namespace URI for expected element (may be <code>null</code>
1654: * or the empty string for the empty namespace)
1655: * @param tag element name expected
1656: * @param dflt default value
1657: * @return content text from element
1658: * @throws JiBXException on any error (possibly wrapping other exception)
1659: */
1660: public short parseElementShort(String ns, String tag, short dflt)
1661: throws JiBXException {
1662: if (parseIfStartTag(ns, tag)) {
1663: return convertShort(parseContentText(ns, tag));
1664: } else {
1665: return dflt;
1666: }
1667: }
1668:
1669: /**
1670: * Convert char value with exception wrapper. This internal method is used
1671: * by all the char unmarshalling calls. It adds position information to
1672: * any exceptions that occur.
1673: *
1674: * @param text text for value to be converted
1675: * @return converted char value
1676: * @throws JiBXException if not a valid char value
1677: */
1678: public char convertChar(String text) throws JiBXException {
1679: try {
1680: return Utility.parseChar(text);
1681: } catch (JiBXException ex) {
1682: throw new JiBXException(ex.getMessage() + ' '
1683: + buildPositionString(), ex.getRootCause());
1684: }
1685: }
1686:
1687: /**
1688: * Get char value of attribute from current start tag. Throws an exception
1689: * if the attribute is not found in the start tag, or if it is not a valid
1690: * integer value.
1691: *
1692: * @param ns namespace URI for expected attribute (may be <code>null</code>
1693: * or the empty string for the empty namespace)
1694: * @param name attribute name expected
1695: * @return attribute char value
1696: * @throws JiBXException if attribute not present or not a valid char value
1697: */
1698: public char attributeChar(String ns, String name)
1699: throws JiBXException {
1700: return convertChar(attributeText(ns, name));
1701: }
1702:
1703: /**
1704: * Get char value of optional attribute from current start tag. If the
1705: * attribute is not present the supplied default value is returned instead.
1706: *
1707: * @param ns namespace URI for expected attribute (may be <code>null</code>
1708: * or the empty string for the empty namespace)
1709: * @param name attribute name expected
1710: * @param dflt value to be returned if attribute is not present
1711: * @return attribute char value
1712: * @throws JiBXException if attribute value is not a valid char
1713: */
1714: public char attributeChar(String ns, String name, char dflt)
1715: throws JiBXException {
1716: String text = getAttributeValue(ns, name);
1717: if (text == null) {
1718: return dflt;
1719: } else {
1720: return convertChar(text);
1721: }
1722: }
1723:
1724: /**
1725: * Parse past end of element, returning char value of content. Assumes
1726: * you've already parsed past the start tag of the element, so it just looks
1727: * for text content followed by the end tag, and returns with the parser
1728: * positioned after the end tag.
1729: *
1730: * @param ns namespace URI for expected element (may be <code>null</code>
1731: * or the empty string for the empty namespace)
1732: * @param tag element name expected
1733: * @return converted value from element text
1734: * @throws JiBXException on any error (possible wrapping other exception)
1735: */
1736: public char parseContentChar(String ns, String tag)
1737: throws JiBXException {
1738: return convertChar(parseContentText(ns, tag));
1739: }
1740:
1741: /**
1742: * Parse entire element, returning char value of content.
1743: * Expects to find the element start tag, text content, and end tag,
1744: * in that order, and returns with the parser positioned following
1745: * the end tag.
1746: *
1747: * @param ns namespace URI for expected element (may be <code>null</code>
1748: * or the empty string for the empty namespace)
1749: * @param tag element name expected
1750: * @return content text from element
1751: * @throws JiBXException on any error (possibly wrapping other exception)
1752: */
1753: public char parseElementChar(String ns, String tag)
1754: throws JiBXException {
1755: parsePastStartTag(ns, tag);
1756: return parseContentChar(ns, tag);
1757: }
1758:
1759: /**
1760: * Parse entire element, returning char value of optional content.
1761: * Expects to find the element start tag, text content, and end tag,
1762: * in that order, and returns with the parser positioned following
1763: * the end tag. Returns the default value if the element is not present.
1764: *
1765: * @param ns namespace URI for expected element (may be <code>null</code>
1766: * or the empty string for the empty namespace)
1767: * @param tag element name expected
1768: * @param dflt default value
1769: * @return content text from element
1770: * @throws JiBXException on any error (possibly wrapping other exception)
1771: */
1772: public char parseElementChar(String ns, String tag, char dflt)
1773: throws JiBXException {
1774: if (parseIfStartTag(ns, tag)) {
1775: return convertChar(parseContentText(ns, tag));
1776: } else {
1777: return dflt;
1778: }
1779: }
1780:
1781: /**
1782: * Convert long value with exception wrapper. This internal method is used
1783: * by all the long unmarshalling calls. It adds position information to
1784: * any exceptions that occur.
1785: *
1786: * @param text text for value to be converted
1787: * @return converted long value
1788: * @throws JiBXException if not a valid long value
1789: */
1790: public long convertLong(String text) throws JiBXException {
1791: try {
1792: return Utility.parseLong(text);
1793: } catch (JiBXException ex) {
1794: throw new JiBXException(ex.getMessage() + ' '
1795: + buildPositionString(), ex.getRootCause());
1796: }
1797: }
1798:
1799: /**
1800: * Get long value of attribute from current start tag. Throws an exception
1801: * if the attribute is not found in the start tag, or if it is not a valid
1802: * integer value.
1803: *
1804: * @param ns namespace URI for expected attribute (may be <code>null</code>
1805: * or the empty string for the empty namespace)
1806: * @param name attribute name expected
1807: * @return attribute long value
1808: * @throws JiBXException if attribute not present or not a valid long value
1809: */
1810: public long attributeLong(String ns, String name)
1811: throws JiBXException {
1812: return convertLong(attributeText(ns, name));
1813: }
1814:
1815: /**
1816: * Get long value of optional attribute from current start tag. If the
1817: * attribute is not present the supplied default value is returned instead.
1818: *
1819: * @param ns namespace URI for expected attribute (may be <code>null</code>
1820: * or the empty string for the empty namespace)
1821: * @param name attribute name expected
1822: * @param dflt value to be returned if attribute is not present
1823: * @return attribute long value
1824: * @throws JiBXException if attribute value is not a valid long
1825: */
1826: public long attributeLong(String ns, String name, long dflt)
1827: throws JiBXException {
1828: String text = getAttributeValue(ns, name);
1829: if (text == null) {
1830: return dflt;
1831: } else {
1832: return convertLong(text);
1833: }
1834: }
1835:
1836: /**
1837: * Parse past end of element, returning long value of content.
1838: * Expects to find the element start tag, text content, and end tag,
1839: * in that order, and returns with the parser positioned following
1840: * the end tag.
1841: *
1842: * @param ns namespace URI for expected element (may be <code>null</code>
1843: * or the empty string for the empty namespace)
1844: * @param tag element name expected
1845: * @return converted value from element text
1846: * @throws JiBXException on any error (possible wrapping other exception)
1847: */
1848: public long parseElementLong(String ns, String tag)
1849: throws JiBXException {
1850: parsePastStartTag(ns, tag);
1851: return convertLong(parseContentText(ns, tag));
1852: }
1853:
1854: /**
1855: * Parse entire element, returning long value of optional content.
1856: * Expects to find the element start tag, text content, and end tag,
1857: * in that order, and returns with the parser positioned following
1858: * the end tag. Returns the default value if the element is not present.
1859: *
1860: * @param ns namespace URI for expected element (may be <code>null</code>
1861: * or the empty string for the empty namespace)
1862: * @param tag element name expected
1863: * @param dflt default value
1864: * @return content text from element
1865: * @throws JiBXException on any error (possibly wrapping other exception)
1866: */
1867: public long parseElementLong(String ns, String tag, long dflt)
1868: throws JiBXException {
1869: if (parseIfStartTag(ns, tag)) {
1870: return convertLong(parseContentText(ns, tag));
1871: } else {
1872: return dflt;
1873: }
1874: }
1875:
1876: /**
1877: * Convert boolean value. This internal method is used by all the boolean
1878: * unmarshalling calls. It accepts "true" or "1" as equivalent, and "false"
1879: * or "0" as equivalent, and throws exceptions for anything else.
1880: *
1881: * @param text text for value to be converted
1882: * @return converted boolean value
1883: * @throws JiBXException if not a valid boolean value
1884: */
1885: public boolean convertBoolean(String text) throws JiBXException {
1886: if ("true".equals(text) || "1".equals(text)) {
1887: return true;
1888: } else if ("false".equals(text) || "0".equals(text)) {
1889: return false;
1890: }
1891: throw new JiBXException("Invalid boolean value "
1892: + buildPositionString());
1893: }
1894:
1895: /**
1896: * Get boolean value of attribute from current start tag. Throws an
1897: * exception if the attribute is not found in the start tag, or if it is
1898: * not a valid integer value.
1899: *
1900: * @param ns namespace URI for expected attribute (may be <code>null</code>
1901: * or the empty string for the empty namespace)
1902: * @param name attribute name expected
1903: * @return attribute boolean value
1904: * @throws JiBXException if attribute not present or not a valid boolean
1905: * value
1906: */
1907: public boolean attributeBoolean(String ns, String name)
1908: throws JiBXException {
1909: return convertBoolean(attributeText(ns, name));
1910: }
1911:
1912: /**
1913: * Get boolean value of optional attribute from current start tag. If the
1914: * attribute is not present the supplied default value is returned instead.
1915: *
1916: * @param ns namespace URI for expected attribute (may be <code>null</code>
1917: * or the empty string for the empty namespace)
1918: * @param name attribute name expected
1919: * @param dflt value to be returned if attribute is not present
1920: * @return attribute boolean value
1921: * @throws JiBXException if attribute value is not a valid boolean
1922: */
1923: public boolean attributeBoolean(String ns, String name, boolean dflt)
1924: throws JiBXException {
1925: String text = getAttributeValue(ns, name);
1926: if (text == null) {
1927: return dflt;
1928: } else {
1929: return convertBoolean(text);
1930: }
1931: }
1932:
1933: /**
1934: * Parse entire element, returning boolean value of content.
1935: * Expects to find the element start tag, text content, and end tag,
1936: * in that order, and returns with the parser positioned following
1937: * the end tag.
1938: *
1939: * @param ns namespace URI for expected element (may be <code>null</code>
1940: * or the empty string for the empty namespace)
1941: * @param tag element name expected
1942: * @return converted value from element text
1943: * @throws JiBXException on any error (possible wrapping other exception)
1944: */
1945: public boolean parseElementBoolean(String ns, String tag)
1946: throws JiBXException {
1947: parsePastStartTag(ns, tag);
1948: return convertBoolean(parseContentText(ns, tag));
1949: }
1950:
1951: /**
1952: * Parse entire element, returning boolean value of optional content.
1953: * Expects to find the element start tag, text content, and end tag,
1954: * in that order, and returns with the parser positioned following
1955: * the end tag. Returns the default value if the element is not present.
1956: *
1957: * @param ns namespace URI for expected element (may be <code>null</code>
1958: * or the empty string for the empty namespace)
1959: * @param tag element name expected
1960: * @param dflt default value
1961: * @return content text from element
1962: * @throws JiBXException on any error (possibly wrapping other exception)
1963: */
1964: public boolean parseElementBoolean(String ns, String tag,
1965: boolean dflt) throws JiBXException {
1966: if (parseIfStartTag(ns, tag)) {
1967: return convertBoolean(parseContentText(ns, tag));
1968: } else {
1969: return dflt;
1970: }
1971: }
1972:
1973: /**
1974: * Convert float value with exception wrapper. This internal method is used
1975: * by all the float unmarshalling calls. It adds position information to
1976: * any exceptions that occur.
1977: *
1978: * @param text text for value to be converted
1979: * @return converted float value
1980: * @throws JiBXException if not a valid float value
1981: */
1982: public float convertFloat(String text) throws JiBXException {
1983: try {
1984: return Utility.parseFloat(text);
1985: } catch (JiBXException ex) {
1986: throw new JiBXException(ex.getMessage() + ' '
1987: + buildPositionString(), ex.getRootCause());
1988: }
1989: }
1990:
1991: /**
1992: * Get float value of attribute from current start tag. Throws an exception
1993: * if the attribute is not found in the start tag, or if it is not a valid
1994: * integer value.
1995: *
1996: * @param ns namespace URI for expected attribute (may be <code>null</code>
1997: * or the empty string for the empty namespace)
1998: * @param name attribute name expected
1999: * @return attribute float value
2000: * @throws JiBXException if attribute not present or not a valid float value
2001: */
2002: public float attributeFloat(String ns, String name)
2003: throws JiBXException {
2004: return convertFloat(attributeText(ns, name));
2005: }
2006:
2007: /**
2008: * Get float value of optional attribute from current start tag. If the
2009: * attribute is not present the supplied default value is returned instead.
2010: *
2011: * @param ns namespace URI for expected attribute (may be <code>null</code>
2012: * or the empty string for the empty namespace)
2013: * @param name attribute name expected
2014: * @param dflt value to be returned if attribute is not present
2015: * @return attribute float value
2016: * @throws JiBXException if attribute value is not a valid float
2017: */
2018: public float attributeFloat(String ns, String name, float dflt)
2019: throws JiBXException {
2020: String text = getAttributeValue(ns, name);
2021: if (text == null) {
2022: return dflt;
2023: } else {
2024: return convertFloat(text);
2025: }
2026: }
2027:
2028: /**
2029: * Parse past end of element, returning float value of content.
2030: * Expects to find the element start tag, text content, and end tag,
2031: * in that order, and returns with the parser positioned following
2032: * the end tag.
2033: *
2034: * @param ns namespace URI for expected element (may be <code>null</code>
2035: * or the empty string for the empty namespace)
2036: * @param tag element name expected
2037: * @return converted value from element text
2038: * @throws JiBXException on any error (possible wrapping other exception)
2039: */
2040: public float parseElementFloat(String ns, String tag)
2041: throws JiBXException {
2042: parsePastStartTag(ns, tag);
2043: return convertFloat(parseContentText(ns, tag));
2044: }
2045:
2046: /**
2047: * Parse entire element, returning float value of optional content.
2048: * Expects to find the element start tag, text content, and end tag,
2049: * in that order, and returns with the parser positioned following
2050: * the end tag. Returns the default value if the element is not present.
2051: *
2052: * @param ns namespace URI for expected element (may be <code>null</code>
2053: * or the empty string for the empty namespace)
2054: * @param tag element name expected
2055: * @param dflt default value
2056: * @return content text from element
2057: * @throws JiBXException on any error (possibly wrapping other exception)
2058: */
2059: public float parseElementFloat(String ns, String tag, float dflt)
2060: throws JiBXException {
2061: if (parseIfStartTag(ns, tag)) {
2062: return convertFloat(parseContentText(ns, tag));
2063: } else {
2064: return dflt;
2065: }
2066: }
2067:
2068: /**
2069: * Convert double value with exception wrapper. This internal method is used
2070: * by all the double unmarshalling calls. It adds position information to
2071: * any exceptions that occur.
2072: *
2073: * @param text text for value to be converted
2074: * @return converted double value
2075: * @throws JiBXException if not a valid double value
2076: */
2077: public double convertDouble(String text) throws JiBXException {
2078: try {
2079: return Utility.parseDouble(text);
2080: } catch (JiBXException ex) {
2081: throw new JiBXException(ex.getMessage() + ' '
2082: + buildPositionString(), ex.getRootCause());
2083: }
2084: }
2085:
2086: /**
2087: * Get double value of attribute from current start tag. Throws an exception
2088: * if the attribute is not found in the start tag, or if it is not a valid
2089: * integer value.
2090: *
2091: * @param ns namespace URI for expected attribute (may be <code>null</code>
2092: * or the empty string for the empty namespace)
2093: * @param name attribute name expected
2094: * @return attribute double value
2095: * @throws JiBXException if attribute not present or not a valid double
2096: * value
2097: */
2098: public double attributeDouble(String ns, String name)
2099: throws JiBXException {
2100: return convertDouble(attributeText(ns, name));
2101: }
2102:
2103: /**
2104: * Get double value of optional attribute from current start tag. If the
2105: * attribute is not present the supplied default value is returned instead.
2106: *
2107: * @param ns namespace URI for expected attribute (may be <code>null</code>
2108: * or the empty string for the empty namespace)
2109: * @param name attribute name expected
2110: * @param dflt value to be returned if attribute is not present
2111: * @return attribute double value
2112: * @throws JiBXException if attribute value is not a valid double
2113: */
2114: public double attributeDouble(String ns, String name, double dflt)
2115: throws JiBXException {
2116: String text = getAttributeValue(ns, name);
2117: if (text == null) {
2118: return dflt;
2119: } else {
2120: return convertDouble(text);
2121: }
2122: }
2123:
2124: /**
2125: * Parse past end of element, returning double value of content.
2126: * Expects to find the element start tag, text content, and end tag,
2127: * in that order, and returns with the parser positioned following
2128: * the end tag.
2129: *
2130: * @param ns namespace URI for expected element (may be <code>null</code>
2131: * or the empty string for the empty namespace)
2132: * @param tag element name expected
2133: * @return converted value from element text
2134: * @throws JiBXException on any error (possible wrapping other exception)
2135: */
2136: public double parseElementDouble(String ns, String tag)
2137: throws JiBXException {
2138: parsePastStartTag(ns, tag);
2139: return convertDouble(parseContentText(ns, tag));
2140: }
2141:
2142: /**
2143: * Parse entire element, returning double value of optional content.
2144: * Expects to find the element start tag, text content, and end tag,
2145: * in that order, and returns with the parser positioned following
2146: * the end tag. Returns the default value if the element is not present.
2147: *
2148: * @param ns namespace URI for expected element (may be <code>null</code>
2149: * or the empty string for the empty namespace)
2150: * @param tag element name expected
2151: * @param dflt default value
2152: * @return content text from element
2153: * @throws JiBXException on any error (possibly wrapping other exception)
2154: */
2155: public double parseElementDouble(String ns, String tag, double dflt)
2156: throws JiBXException {
2157: if (parseIfStartTag(ns, tag)) {
2158: return convertDouble(parseContentText(ns, tag));
2159: } else {
2160: return dflt;
2161: }
2162: }
2163:
2164: /**
2165: * Convert <code>java.util.Date</code> value with exception wrapper. This
2166: * internal method is used by all the Date unmarshalling calls. It adds
2167: * position information to any exceptions that occur.
2168: *
2169: * @param text text for value to be converted
2170: * @return converted Date value
2171: * @throws JiBXException if not a valid Date value
2172: */
2173: public Date convertDate(String text) throws JiBXException {
2174: try {
2175: return new Date(Utility.parseDateTime(text));
2176: } catch (JiBXException ex) {
2177: throw new JiBXException(ex.getMessage() + ' '
2178: + buildPositionString(), ex.getRootCause());
2179: }
2180: }
2181:
2182: /**
2183: * Get <code>java.util.Date</code> value of attribute from current start
2184: * tag. Throws an exception if the attribute is not found in the start tag,
2185: * or if it is not a valid integer value.
2186: *
2187: * @param ns namespace URI for expected attribute (may be <code>null</code>
2188: * or the empty string for the empty namespace)
2189: * @param name attribute name expected
2190: * @return attribute Date value
2191: * @throws JiBXException if attribute not present or not a valid Date
2192: * value
2193: */
2194: public Date attributeDate(String ns, String name)
2195: throws JiBXException {
2196: return convertDate(attributeText(ns, name));
2197: }
2198:
2199: /**
2200: * Get <code>java.util.Date</code> value of optional attribute from current
2201: * start tag. If the attribute is not present the supplied default value is
2202: * returned instead.
2203: *
2204: * @param ns namespace URI for expected attribute (may be <code>null</code>
2205: * or the empty string for the empty namespace)
2206: * @param name attribute name expected
2207: * @param dflt value to be returned if attribute is not present
2208: * @return attribute Date value
2209: * @throws JiBXException if attribute value is not a valid Date
2210: */
2211: public Date attributeDate(String ns, String name, Date dflt)
2212: throws JiBXException {
2213: String text = getAttributeValue(ns, name);
2214: if (text == null) {
2215: return dflt;
2216: } else {
2217: return convertDate(text);
2218: }
2219: }
2220:
2221: /**
2222: * Parse past end of element, returning <code>java.util.Date</code> value
2223: * of content. Expects to find the element start tag, text content,
2224: * and end tag, in that order, and returns with the parser positioned
2225: * following the end tag.
2226: *
2227: * @param ns namespace URI for expected element (may be <code>null</code>
2228: * or the empty string for the empty namespace)
2229: * @param tag element name expected
2230: * @return converted value from element text
2231: * @throws JiBXException on any error (possible wrapping other exception)
2232: */
2233: public Date parseElementDate(String ns, String tag)
2234: throws JiBXException {
2235: parsePastStartTag(ns, tag);
2236: return convertDate(parseContentText(ns, tag));
2237: }
2238:
2239: /**
2240: * Parse entire element, returning <code>java.util.Date</code> value of
2241: * optional content. Expects to find the element start tag, text content,
2242: * and end tag, in that order, and returns with the parser positioned
2243: * following the end tag. Returns the default value if the element is not
2244: * present.
2245: *
2246: * @param ns namespace URI for expected element (may be <code>null</code>
2247: * or the empty string for the empty namespace)
2248: * @param tag element name expected
2249: * @param dflt default value
2250: * @return content text from element
2251: * @throws JiBXException on any error (possibly wrapping other exception)
2252: */
2253: public Date parseElementDate(String ns, String tag, Date dflt)
2254: throws JiBXException {
2255: if (parseIfStartTag(ns, tag)) {
2256: return convertDate(parseContentText(ns, tag));
2257: } else {
2258: return dflt;
2259: }
2260: }
2261:
2262: /**
2263: * Register back fill item for undefined ID value. This adds a holder to
2264: * the mapping table if not already present, then adds the back fill item
2265: * to the holder.
2266: *
2267: * @param id target undefined ID value
2268: * @param index target reference type index
2269: * @param fill back fill item
2270: * @throws JiBXException if attribute not present, or ID already defined
2271: */
2272: public void registerBackFill(String id, int index,
2273: BackFillReference fill) throws JiBXException {
2274: HashMap map = m_idMaps[index];
2275: if (map == null) {
2276: m_idMaps[index] = map = new HashMap();
2277: }
2278: Object obj = map.get(id);
2279: if (obj == null) {
2280: String xclass = (m_idClasses == null) ? null
2281: : m_idClasses[index];
2282: BackFillHolder holder = new BackFillHolder(xclass);
2283: map.put(id, holder);
2284: holder.addBackFill(fill);
2285: } else if (obj instanceof BackFillHolder) {
2286: ((BackFillHolder) obj).addBackFill(fill);
2287: } else {
2288: throw new JiBXException(
2289: "Internal operation error (back fill error) "
2290: + buildPositionString());
2291: }
2292: }
2293:
2294: /**
2295: * Register back fill item for last parsed ID value. This adds a holder to
2296: * the mapping table if not already present, then adds the back fill item
2297: * to the holder. This form of call always applies to the last IDREF value
2298: * parsed (from either an element or an attribute).
2299: *
2300: * @param index target reference type index
2301: * @param fill back fill item
2302: * @throws JiBXException if attribute not present, or ID already defined
2303: */
2304: public void registerBackFill(int index, BackFillReference fill)
2305: throws JiBXException {
2306: registerBackFill(m_idref, index, fill);
2307: }
2308:
2309: /**
2310: * Define object for ID. Adds the owning object to a map with the ID
2311: * value as key. Throws an exception if the object class does not match
2312: * that expected from forward references, or if another object has
2313: * previously been registered with the same ID.
2314: *
2315: * @param id text ID value
2316: * @param index ID class index number
2317: * @param obj object corresponding to element
2318: * @throws JiBXException if duplicate ID or wrong class
2319: */
2320: public void defineID(String id, int index, Object obj)
2321: throws JiBXException {
2322: HashMap map = m_idMaps[index];
2323: if (map == null) {
2324: m_idMaps[index] = map = new HashMap();
2325: }
2326: Object prior = map.put(id, obj);
2327: if (prior instanceof BackFillHolder) {
2328: BackFillHolder holder = (BackFillHolder) prior;
2329: String xclass = holder.getExpectedClass();
2330: if (xclass == null
2331: || xclass.equals(obj.getClass().getName())) {
2332: holder.defineValue(obj);
2333: } else {
2334: throw new JiBXException("ID object has wrong type "
2335: + buildPositionString());
2336: }
2337: } else if (prior != null) {
2338: throw new JiBXException("Duplicate ID definition "
2339: + buildPositionString());
2340: }
2341: }
2342:
2343: /**
2344: * Map unmarshalling for element. Adds the entry for a particular class
2345: * index to the unmarshalling map.
2346: *
2347: * @param index class index for unmarshalling definition to be added
2348: */
2349: protected void mapUnmarshalling(int index) {
2350: Object value = m_unmarshalMap.get(m_names[index]);
2351: if (value instanceof Integer) {
2352: ArrayList list = new ArrayList();
2353: list.add(value);
2354: list.add(m_indexes[index]);
2355: m_unmarshalMap.put(m_names[index], list);
2356: } else if (value instanceof ArrayList) {
2357: ArrayList list = (ArrayList) value;
2358: list.add(m_indexes[index]);
2359: } else {
2360: m_unmarshalMap.put(m_names[index], m_indexes[index]);
2361: }
2362: }
2363:
2364: /**
2365: * Define unmarshalling for element. Enables the unmarshalling definition
2366: * linking an element name (including namespace) with a handler. The
2367: * unmarshalling definitions use fixed indexes for each class, allowing
2368: * direct lookup of the unmarshaller when multiple versions are defined.
2369: *
2370: * @param index class index for unmarshalling definition
2371: * @param ns namespace for element (may be <code>null</code>
2372: * or the empty string for the empty namespace)
2373: * @param name name for element
2374: * @param cname name of class created by unmarshaller
2375: */
2376: public void addUnmarshalling(int index, String ns, String name,
2377: String cname) {
2378: m_namespaces[index] = ns;
2379: m_names[index] = name;
2380: m_unmarshallerClasses[index] = cname;
2381: if (m_unmarshalMap != null && name != null) {
2382: mapUnmarshalling(index);
2383: }
2384: }
2385:
2386: /**
2387: * Undefine unmarshalling for element. Disables the unmarshalling
2388: * definition for a particular class index.
2389: *
2390: * @param index class index for unmarshalling definition
2391: */
2392: public void removeUnmarshalling(int index) {
2393: if (m_unmarshalMap != null && m_names[index] != null) {
2394: Object value = m_unmarshalMap.get(m_names[index]);
2395: if (value instanceof Integer) {
2396: m_unmarshalMap.remove(m_names[index]);
2397: } else if (value instanceof ArrayList) {
2398: ArrayList list = (ArrayList) value;
2399: list.remove(list.indexOf(m_indexes[index]));
2400: }
2401: }
2402: m_namespaces[index] = null;
2403: m_names[index] = null;
2404: m_unmarshallers[index] = null;
2405: m_unmarshallerClasses[index] = null;
2406: }
2407:
2408: /**
2409: * Find the unmarshaller for a particular class index in the current
2410: * context.
2411: *
2412: * @param index class index for unmarshalling definition
2413: * @return unmarshalling handler for class
2414: * @throws JiBXException if unable to create unmarshaller
2415: */
2416: public IUnmarshaller getUnmarshaller(int index)
2417: throws JiBXException {
2418: if (m_unmarshallers[index] == null) {
2419:
2420: // load the unmarshaller class and create an instance
2421: String name = m_unmarshallerClasses[index];
2422: if (name == null) {
2423: throw new JiBXException(
2424: "No unmarshaller defined for class at index "
2425: + index);
2426: }
2427: try {
2428:
2429: // first try loading class from binding factory class loader
2430: Class clas = null;
2431: ClassLoader factldr = null;
2432: if (m_factory != null) {
2433: factldr = m_factory.getClass().getClassLoader();
2434: try {
2435: clas = factldr.loadClass(name);
2436: } catch (ClassNotFoundException e) { /* fall through */
2437: }
2438: }
2439: if (clas == null) {
2440:
2441: // next try the context class loader, if set
2442: ClassLoader ctxldr = Thread.currentThread()
2443: .getContextClassLoader();
2444: if (ctxldr != null) {
2445: try {
2446: clas = ctxldr.loadClass(name);
2447: } catch (ClassNotFoundException e) { /* fall through */
2448: }
2449: }
2450: if (clas == null) {
2451:
2452: // not found, try the loader that loaded this class
2453: ClassLoader this ldr = UnmarshallingContext.class
2454: .getClassLoader();
2455: if (this ldr != factldr && this ldr != ctxldr) {
2456: try {
2457: clas = this ldr.loadClass(name);
2458: } catch (ClassNotFoundException e) { /* fall through */
2459: }
2460: }
2461: }
2462: }
2463: if (clas == null) {
2464: throw new JiBXException(
2465: "Unable to load unmarshaller class " + name);
2466: }
2467:
2468: // create an instance of unmarshaller class
2469: IUnmarshaller um = (IUnmarshaller) clas.newInstance();
2470: m_unmarshallers[index] = um;
2471:
2472: } catch (JiBXException e) {
2473: throw e;
2474: } catch (Exception e) {
2475: throw new JiBXException(
2476: "Unable to create unmarshaller of class "
2477: + name + ":", e);
2478: }
2479: }
2480: return m_unmarshallers[index];
2481: }
2482:
2483: /**
2484: * Find the unmarshaller for a particular element name (including
2485: * namespace) in the current context.
2486: *
2487: * @param ns namespace for element (may be <code>null</code>
2488: * or the empty string for the empty namespace)
2489: * @param name name for element
2490: * @return unmarshalling handler for element, or <code>null</code> if none
2491: * found
2492: * @throws JiBXException if unable to create unmarshaller
2493: */
2494: public IUnmarshaller getUnmarshaller(String ns, String name)
2495: throws JiBXException {
2496: if (m_unmarshalMap == null) {
2497: m_unmarshalMap = new HashMap();
2498: m_indexes = new Integer[m_names.length];
2499: for (int i = 0; i < m_names.length; i++) {
2500: m_indexes[i] = new Integer(i);
2501: if (m_names[i] != null) {
2502: mapUnmarshalling(i);
2503: }
2504: }
2505: }
2506: Object value = m_unmarshalMap.get(name);
2507: if (value instanceof Integer) {
2508: int index = ((Integer) value).intValue();
2509: String mns = m_namespaces[index];
2510: if (ns == mns || (ns == null && mns.length() == 0)
2511: || (mns == null && ns.length() == 0)
2512: || (ns != null && ns.equals(mns))) {
2513: return getUnmarshaller(index);
2514: }
2515: } else if (value instanceof ArrayList) {
2516: ArrayList list = (ArrayList) value;
2517: for (int i = 0; i < list.size(); i++) {
2518: int index = ((Integer) list.get(i)).intValue();
2519: String mns = m_namespaces[index];
2520: if (ns == mns || (ns == null && mns.length() == 0)
2521: || (mns == null && ns.length() == 0)
2522: || (ns != null && ns.equals(mns))) {
2523: return getUnmarshaller(index);
2524: }
2525: }
2526: }
2527: return null;
2528: }
2529:
2530: /**
2531: * Unmarshal optional element. If not currently positioned at a start or
2532: * end tag this first advances the parse to the next start or end tag.
2533: *
2534: * @return unmarshalled object from element, or <code>null</code> if end tag
2535: * rather than start tag seen
2536: * @throws JiBXException on any error (possibly wrapping other exception)
2537: */
2538: public Object unmarshalOptionalElement() throws JiBXException {
2539: int type = toTag();
2540: if (type == IXMLReader.START_TAG) {
2541: IUnmarshaller unmarshal = getUnmarshaller(m_reader
2542: .getNamespace(), m_reader.getName());
2543: if (unmarshal != null) {
2544: return unmarshal.unmarshal(null, this );
2545: }
2546: }
2547: return null;
2548: }
2549:
2550: /**
2551: * Unmarshal required element of specified type. If not currently positioned
2552: * at a start or end tag this first advances the parse to the next start or
2553: * end tag. The returned object will always be assignable to the specified
2554: * type.
2555: *
2556: * @param clas expected class of unmarshalled object
2557: * @return unmarshalled object from element
2558: * @throws JiBXException on any error (possibly wrapping other exception)
2559: */
2560: public Object unmarshalElement(Class clas) throws JiBXException {
2561: String name = toStart();
2562: IUnmarshaller unmarshal = getUnmarshaller(m_reader
2563: .getNamespace(), name);
2564: if (unmarshal == null) {
2565: throw new JiBXException("No unmarshaller for element "
2566: + currentNameString() + " " + buildPositionString());
2567: } else {
2568: Object obj = unmarshal.unmarshal(null, this );
2569: if (!clas.isInstance(obj)) {
2570: throw new JiBXException("Element " + name
2571: + " not compatible with expected type "
2572: + clas.getName() + " " + buildPositionString());
2573: }
2574: return obj;
2575: }
2576: }
2577:
2578: /**
2579: * Unmarshal required element. If not currently positioned at a start or
2580: * end tag this first advances the parse to the next start or end tag.
2581: *
2582: * @return unmarshalled object from element
2583: * @throws JiBXException on any error (possibly wrapping other exception)
2584: */
2585: public Object unmarshalElement() throws JiBXException {
2586: String name = toStart();
2587: IUnmarshaller unmarshal = getUnmarshaller(m_reader
2588: .getNamespace(), name);
2589: if (unmarshal == null) {
2590: throw new JiBXException("No unmarshaller for element "
2591: + currentNameString() + " " + buildPositionString());
2592: } else {
2593: return unmarshal.unmarshal(null, this );
2594: }
2595: }
2596:
2597: /**
2598: * Parse past element, ignoring all content. This may be used while
2599: * positioned either before or on the element start tag. It checks if
2600: * currently positioned at the element start tag, and if so advances to the
2601: * next parse event. Then looks for the next end tag, ignoring character
2602: * data and skipping child elements. Leaves the parse positioned following
2603: * the end tag.
2604: *
2605: * @param ns namespace URI for expected element (may be <code>null</code>
2606: * or the empty string for the empty namespace)
2607: * @param tag element name expected
2608: * @throws JiBXException on any error (possible wrapping other exception)
2609: */
2610: public void parsePastElement(String ns, String tag)
2611: throws JiBXException {
2612: parsePastStartTag(ns, tag);
2613: int depth = 0;
2614: while (true) {
2615: switch (m_reader.getEventType()) {
2616:
2617: case IXMLReader.END_TAG:
2618: if (depth == 0) {
2619: if (m_reader.getName().equals(tag)
2620: && verifyNamespace(ns)) {
2621: m_reader.nextToken();
2622: return;
2623: } else {
2624: throwEndTagNameError(ns, tag);
2625: }
2626: } else {
2627: depth--;
2628: }
2629: break;
2630:
2631: case IXMLReader.START_TAG:
2632: depth++;
2633: break;
2634:
2635: default:
2636: break;
2637:
2638: }
2639: m_reader.nextToken();
2640: }
2641: }
2642:
2643: /**
2644: * Returns current element name.
2645: *
2646: * @return local name part of name, or <code>null</code> if not at a start
2647: * or end tag
2648: * @throws JiBXException if error from parser
2649: */
2650: public String getElementName() throws JiBXException {
2651: int type = m_reader.getEventType();
2652: if (type == IXMLReader.START_TAG || type == IXMLReader.END_TAG) {
2653: return m_reader.getName();
2654: } else {
2655: return null;
2656: }
2657: }
2658:
2659: /**
2660: * Returns current element namespace URI.
2661: *
2662: * @return namespace URI of name, or <code>null</code> if not at a start
2663: * or end tag
2664: * @throws JiBXException if error from parser
2665: */
2666: public String getElementNamespace() throws JiBXException {
2667: int type = m_reader.getEventType();
2668: if (type == IXMLReader.START_TAG || type == IXMLReader.END_TAG) {
2669: return m_reader.getNamespace();
2670: } else {
2671: return null;
2672: }
2673: }
2674:
2675: /**
2676: * Throw exception with start tag and position information.
2677: *
2678: * @param msg exception message text
2679: * @exception JiBXException always thrown
2680: */
2681: public void throwStartTagException(String msg) throws JiBXException {
2682: throw new JiBXException(msg + " at tag " + currentNameString()
2683: + buildPositionString());
2684: }
2685:
2686: /**
2687: * Throw exception with start tag, position information, and nested
2688: * exception.
2689: *
2690: * @param msg exception message text
2691: * @param ex nested exception
2692: * @exception JiBXException always thrown
2693: */
2694: public void throwStartTagException(String msg, Exception ex)
2695: throws JiBXException {
2696: throw new JiBXException(msg + " at tag " + currentNameString()
2697: + buildPositionString(), ex);
2698: }
2699:
2700: /**
2701: * Throw exception with position information.
2702: *
2703: * @param msg exception message text
2704: * @exception JiBXException always thrown
2705: */
2706: public void throwException(String msg) throws JiBXException {
2707: throw new JiBXException(msg + " " + buildPositionString());
2708: }
2709:
2710: /**
2711: * Throw exception with position information and nested exception.
2712: *
2713: * @param msg exception message text
2714: * @param ex nested exception
2715: * @exception JiBXException always thrown
2716: */
2717: public void throwException(String msg, Exception ex)
2718: throws JiBXException {
2719: throw new JiBXException(msg + " " + buildPositionString(), ex);
2720: }
2721:
2722: /**
2723: * Unmarshal document from stream to object. The effect of this is the same
2724: * as if {@link #setDocument} were called, followed by {@link
2725: * #unmarshalElement}
2726: *
2727: * @param ins stream supplying document data
2728: * @param enc document input encoding, or <code>null</code> if to be
2729: * determined by parser
2730: * @return unmarshalled object
2731: * @throws JiBXException if error creating parser
2732: */
2733: public Object unmarshalDocument(InputStream ins, String enc)
2734: throws JiBXException {
2735: setDocument(ins, enc);
2736: return unmarshalElement();
2737: }
2738:
2739: /**
2740: * Unmarshal document from reader to object. The effect of this is the same
2741: * as if {@link #setDocument} were called, followed by {@link
2742: * #unmarshalElement}
2743: *
2744: * @param rdr reader supplying document data
2745: * @return unmarshalled object
2746: * @throws JiBXException if error creating parser
2747: */
2748: public Object unmarshalDocument(Reader rdr) throws JiBXException {
2749: setDocument(rdr);
2750: return unmarshalElement();
2751: }
2752:
2753: /**
2754: * Unmarshal named document from stream to object. The effect of this is the
2755: * same as if {@link #setDocument} were called, followed by {@link
2756: * #unmarshalElement}
2757: *
2758: * @param ins stream supplying document data
2759: * @param name document name
2760: * @param enc document input encoding, or <code>null</code> if to be
2761: * determined by parser
2762: * @return unmarshalled object
2763: * @throws JiBXException if error creating parser
2764: */
2765: public Object unmarshalDocument(InputStream ins, String name,
2766: String enc) throws JiBXException {
2767: setDocument(ins, name, enc);
2768: return unmarshalElement();
2769: }
2770:
2771: /**
2772: * Unmarshal named document from reader to object. The effect of this is the
2773: * same as if {@link #setDocument} were called, followed by {@link
2774: * #unmarshalElement}
2775: *
2776: * @param rdr reader supplying document data
2777: * @param name document name
2778: * @return unmarshalled object
2779: * @throws JiBXException if error creating parser
2780: */
2781: public Object unmarshalDocument(Reader rdr, String name)
2782: throws JiBXException {
2783: setDocument(rdr, name);
2784: return unmarshalElement();
2785: }
2786:
2787: /**
2788: * Return the binding factory used to create this unmarshaller.
2789: *
2790: * @return binding factory
2791: */
2792: public IBindingFactory getFactory() {
2793: return m_factory;
2794: }
2795:
2796: /**
2797: * Return the supplied document name.
2798: *
2799: * @return supplied document name (<code>null</code> if none)
2800: */
2801: public String getDocumentName() {
2802: return m_reader.getDocumentName();
2803: }
2804:
2805: /**
2806: * Return the input encoding, if known. This is only valid after parsing of
2807: * a document has been started.
2808: *
2809: * @return input encoding (<code>null</code> if unknown)
2810: */
2811: public String getInputEncoding() {
2812: return m_reader.getInputEncoding();
2813: }
2814:
2815: /**
2816: * Set a user context object. This context object is not used directly by
2817: * JiBX, but can be accessed by all types of user extension methods. The
2818: * context object is automatically cleared by the {@link #reset()} method,
2819: * so to make use of this you need to first call the appropriate version of
2820: * the <code>setDocument()</code> method, then this method, and finally the
2821: * {@link #unmarshalElement} method.
2822: *
2823: * @param obj user context object, or <code>null</code> if clearing existing
2824: * context object
2825: * @see #getUserContext()
2826: */
2827: public void setUserContext(Object obj) {
2828: m_userContext = obj;
2829: }
2830:
2831: /**
2832: * Get the user context object.
2833: *
2834: * @return user context object, or <code>null</code> if no context object
2835: * set
2836: * @see #setUserContext(Object)
2837: */
2838: public Object getUserContext() {
2839: return m_userContext;
2840: }
2841:
2842: /**
2843: * Push created object to unmarshalling stack. This must be called before
2844: * beginning the unmarshalling of the object. It is only called for objects
2845: * with structure, not for those converted directly to and from text.
2846: *
2847: * @param obj object being unmarshalled
2848: */
2849: public void pushObject(Object obj) {
2850: int depth = m_stackDepth;
2851: if (depth >= m_objectStack.length) {
2852: Object[] stack = new Object[depth * 2];
2853: System.arraycopy(m_objectStack, 0, stack, 0, depth);
2854: m_objectStack = stack;
2855: }
2856: m_objectStack[depth] = obj;
2857: m_stackDepth++;
2858: }
2859:
2860: /**
2861: * Push created object to unmarshalling stack with position tracking. If the
2862: * object supports setting source location information, the location is also
2863: * set by this method.
2864: *
2865: * @param obj object being unmarshalled
2866: */
2867: public void pushTrackedObject(Object obj) {
2868: pushObject(obj);
2869: if (obj instanceof ITrackSourceImpl) {
2870: ((ITrackSourceImpl) obj).jibx_setSource(m_reader
2871: .getDocumentName(), m_reader.getLineNumber(),
2872: m_reader.getColumnNumber());
2873: }
2874: }
2875:
2876: /**
2877: * Pop unmarshalled object from stack.
2878: *
2879: * @throws JiBXException if no object on stack
2880: */
2881: public void popObject() throws JiBXException {
2882: if (m_stackDepth > 0) {
2883: --m_stackDepth;
2884: } else {
2885: throw new JiBXException("No object on stack");
2886: }
2887: }
2888:
2889: /**
2890: * Get current unmarshalling object stack depth. This allows tracking
2891: * nested calls to unmarshal one object while in the process of
2892: * unmarshalling another object. The bottom item on the stack is always the
2893: * root object being unmarshalled.
2894: *
2895: * @return number of objects in unmarshalling stack
2896: */
2897: public int getStackDepth() {
2898: return m_stackDepth;
2899: }
2900:
2901: /**
2902: * Get object from unmarshalling stack. This stack allows tracking nested
2903: * calls to unmarshal one object while in the process of unmarshalling
2904: * another object. The bottom item on the stack is always the root object
2905: * being unmarshalled.
2906: *
2907: * @param depth object depth in stack to be retrieved (must be in the range
2908: * of zero to the current depth minus one).
2909: * @return object from unmarshalling stack
2910: */
2911: public Object getStackObject(int depth) {
2912: if (depth >= 0 && depth < m_stackDepth) {
2913: return m_objectStack[m_stackDepth - depth - 1];
2914: } else {
2915: throw new ArrayIndexOutOfBoundsException("Depth " + depth
2916: + " is out of range");
2917: }
2918: }
2919:
2920: /**
2921: * Get top object on unmarshalling stack. This is safe to call even when no
2922: * objects are on the stack.
2923: *
2924: * @return object from unmarshalling stack, or <code>null</code> if none
2925: */
2926: public Object getStackTop() {
2927: if (m_stackDepth > 0) {
2928: return m_objectStack[m_stackDepth - 1];
2929: } else {
2930: return null;
2931: }
2932: }
2933:
2934: /**
2935: * Get count of active namespaces.
2936: *
2937: * @return number of active namespaces in stack
2938: */
2939: public int getActiveNamespaceCount() {
2940: try {
2941: return m_reader.getNamespaceCount(m_reader
2942: .getNestingDepth());
2943: } catch (IllegalArgumentException e) {
2944: throw new IllegalStateException("Internal error: "
2945: + e.getMessage());
2946: }
2947: }
2948:
2949: /**
2950: * Get URI for an active namespace.
2951: *
2952: * @param index index number of namespace to be returned
2953: * @return URI for namespace at position
2954: * @throws IllegalArgumentException if invalid index
2955: */
2956: public String getActiveNamespaceUri(int index) {
2957: return m_reader.getNamespaceUri(index);
2958: }
2959:
2960: /**
2961: * Get prefix for an active namespace.
2962: *
2963: * @param index stack position of namespace to be returned
2964: * @return prefix for namespace at position
2965: * @throws IllegalArgumentException if invalid index
2966: */
2967: public String getActiveNamespacePrefix(int index) {
2968: return m_reader.getNamespacePrefix(index);
2969: }
2970:
2971: /**
2972: * Skip past current element.
2973: *
2974: * @exception JiBXException on any error (possibly wrapping other exception)
2975: */
2976: public void skipElement() throws JiBXException {
2977:
2978: // check positioned at start tag
2979: if (!isEnd()) {
2980:
2981: // skip past the start tag
2982: next();
2983:
2984: // loop until end tag reached
2985: int depth = 1;
2986: while (depth > 0) {
2987: if (isEnd()) {
2988: depth--;
2989: } else {
2990: depth++;
2991: }
2992: next();
2993: }
2994:
2995: }
2996: }
2997:
2998: /**
2999: * Advance to next major parse event. This wraps the base parser call in
3000: * order to catch and handle exceptions, and to preserve a reasonable level
3001: * of parser independence.
3002: *
3003: * @return event type for next major parse event (START_TAG, TEXT, END_TAG,
3004: * or END_DOCUMENT)
3005: * @exception JiBXException on any error (possibly wrapping other exception)
3006: */
3007: public int next() throws JiBXException {
3008: return m_reader.next();
3009: }
3010:
3011: /**
3012: * Advance to next parse event. This wraps the base parser call in order to
3013: * catch and handle exceptions, and to preserve a reasonable level of parser
3014: * independence.
3015: *
3016: * @return event type for next parse event
3017: * @exception JiBXException on any error (possibly wrapping other exception)
3018: */
3019: public int nextToken() throws JiBXException {
3020: return m_reader.nextToken();
3021: }
3022:
3023: /**
3024: * Get the current parse event type. This wraps the base parser call in
3025: * order to catch and handle exceptions, and to preserve a reasonable level
3026: * of parser independence.
3027: *
3028: * @return event type for current parse event
3029: * @exception JiBXException on any error (possibly wrapping other exception)
3030: */
3031: public int currentEvent() throws JiBXException {
3032: return m_reader.getEventType();
3033: }
3034:
3035: /**
3036: * Get name associated with current parse event.
3037: *
3038: * @return name text for name associated with event (START_ELEMENT,
3039: * END_ELEMENT, or ENTITY_REF only)
3040: * @throws IllegalStateException if not at a start or end tag (optional)
3041: */
3042: public String getName() {
3043: return m_reader.getName();
3044: }
3045:
3046: /**
3047: * Get namespace associated with current parse event.
3048: *
3049: * @return URI for namespace associated with event (START_ELEMENT or
3050: * END_ELEMENT only), empty string if none
3051: * @throws IllegalStateException if not at a start or end tag (optional)
3052: */
3053: public String getNamespace() {
3054: return m_reader.getNamespace();
3055: }
3056:
3057: /**
3058: * Get namespace prefix associated with current parse event.
3059: *
3060: * @return prefix for namespace associated with event (START_ELEMENT or
3061: * END_ELEMENT only), <code>null</code> if none
3062: * @throws IllegalStateException if not at a start or end tag (optional)
3063: */
3064: public String getPrefix() {
3065: return m_reader.getPrefix();
3066: }
3067:
3068: /**
3069: * Get number of attributes for current START_ELEMENT event. The results are
3070: * undefined if called when not at a START_ELEMENT event.
3071: *
3072: * @return number of attributes, or <code>-1</code> if not at START_ELEMENT
3073: * @throws IllegalStateException if not at a start tag (optional)
3074: */
3075: public int getAttributeCount() {
3076: return m_reader.getAttributeCount();
3077: }
3078:
3079: /**
3080: * Get attribute name for current START_ELEMENT event. The results are
3081: * undefined if called when not at a START_ELEMENT event.
3082: *
3083: * @param index index number of attribute to be returned
3084: * @return name of attribute at position
3085: * @throws IllegalStateException if not at a start tag or invalid index
3086: */
3087: public String getAttributeName(int index) {
3088: return m_reader.getAttributeName(index);
3089: }
3090:
3091: /**
3092: * Get attribute namespace for current START_ELEMENT event. The results are
3093: * undefined if called when not at a START_ELEMENT event.
3094: *
3095: * @param index index number of attribute to be returned
3096: * @return namespace URI of attribute at position, empty string if none
3097: * @throws IllegalStateException if not at a start tag or invalid index
3098: */
3099: public String getAttributeNamespace(int index) {
3100: return m_reader.getAttributeNamespace(index);
3101: }
3102:
3103: /**
3104: * Get attribute namespace prefix for current START_ELEMENT event. The
3105: * results are undefined if called when not at a START_ELEMENT event.
3106: *
3107: * @param index index number of attribute to be returned
3108: * @return prefix for namespace of attribute at position, <code>null</code>
3109: * if none
3110: * @throws IllegalStateException if not at a start tag or invalid index
3111: */
3112: public String getAttributePrefix(int index) {
3113: return m_reader.getAttributePrefix(index);
3114: }
3115:
3116: /**
3117: * Get attribute value for current START_ELEMENT event. The results are
3118: * undefined if called when not at a START_ELEMENT event.
3119: *
3120: * @param index index number of attribute to be returned
3121: * @return value of attribute at position
3122: * @throws IllegalStateException if not at a start tag or invalid index
3123: */
3124: public String getAttributeValue(int index) {
3125: return m_reader.getAttributeValue(index);
3126: }
3127:
3128: /**
3129: * Get number of namespace declarations for current START_ELEMENT event. The
3130: * results are undefined if called when not at a START_ELEMENT event.
3131: *
3132: * @return number of namespace declarations, or <code>-1</code> if not at
3133: * START_ELEMENT
3134: */
3135: public int getNamespaceCount() {
3136: try {
3137: int level = m_reader.getNestingDepth();
3138: return m_reader.getNamespaceCount(level)
3139: - m_reader.getNamespaceCount(level - 1);
3140: } catch (IllegalArgumentException e) {
3141: throw new IllegalStateException("Internal error: "
3142: + e.getMessage());
3143: }
3144: }
3145:
3146: /**
3147: * Get namespace URI for namespace declaration on current START_ELEMENT
3148: * event. The results are undefined if called when not at a START_ELEMENT
3149: * event.
3150: *
3151: * @param index index number of declaration to be returned
3152: * @return namespace URI for declaration at position
3153: * @throws IllegalArgumentException if invalid index
3154: */
3155: public String getNamespaceUri(int index) {
3156: int base = m_reader.getNamespaceCount(m_reader
3157: .getNestingDepth() - 1);
3158: return m_reader.getNamespaceUri(base + index);
3159: }
3160:
3161: /**
3162: * Get namespace prefix for namespace declaration on current START_ELEMENT
3163: * event. The results are undefined if called when not at a START_ELEMENT
3164: * event.
3165: *
3166: * @param index index number of declaration to be returned
3167: * @return namespace prefix for declaration at position,
3168: * @throws IllegalArgumentException if invalid index
3169: */
3170: public String getNamespacePrefix(int index) {
3171: int base = m_reader.getNamespaceCount(m_reader
3172: .getNestingDepth() - 1);
3173: return m_reader.getNamespacePrefix(base + index);
3174: }
3175:
3176: /**
3177: * Get namespace URI matching prefix.
3178: *
3179: * @param prefix namespace prefix to be matched (<code>null</code> for
3180: * default namespace)
3181: * @return namespace URI for prefix
3182: */
3183: public String getNamespaceUri(String prefix) {
3184: return m_reader.getNamespace(prefix);
3185: }
3186:
3187: /**
3188: * Get text value for current event.
3189: *
3190: * @return text value for event
3191: */
3192: public String getText() {
3193: return m_reader.getText();
3194: }
3195: }
|