0001: /*
0002: * Copyright 1999-2005 The Apache Software Foundation.
0003: *
0004: * Licensed under the Apache License, Version 2.0 (the "License");
0005: * you may not use this file except in compliance with the License.
0006: * You may obtain a copy of the License at
0007: *
0008: * http://www.apache.org/licenses/LICENSE-2.0
0009: *
0010: * Unless required by applicable law or agreed to in writing, software
0011: * distributed under the License is distributed on an "AS IS" BASIS,
0012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013: * See the License for the specific language governing permissions and
0014: * limitations under the License.
0015: */
0016: /*
0017: * $Id: SAX2DTM.java,v 1.39 2005/01/27 15:17:41 zongaro Exp $
0018: */
0019: package org.apache.xml.dtm.ref.sax2dtm;
0020:
0021: import java.util.Hashtable;
0022: import java.util.Vector;
0023: import javax.xml.transform.Source;
0024: import javax.xml.transform.SourceLocator;
0025:
0026: import org.apache.xml.dtm.*;
0027: import org.apache.xml.dtm.ref.*;
0028: import org.apache.xml.utils.StringVector;
0029: import org.apache.xml.utils.IntVector;
0030: import org.apache.xml.utils.FastStringBuffer;
0031: import org.apache.xml.utils.IntStack;
0032: import org.apache.xml.utils.SuballocatedIntVector;
0033: import org.apache.xml.utils.SystemIDResolver;
0034: import org.apache.xml.utils.WrappedRuntimeException;
0035: import org.apache.xml.utils.XMLString;
0036: import org.apache.xml.utils.XMLStringFactory;
0037: import org.apache.xml.res.XMLErrorResources;
0038: import org.apache.xml.res.XMLMessages;
0039: import org.xml.sax.*;
0040: import org.xml.sax.ext.*;
0041:
0042: /**
0043: * This class implements a DTM that tends to be optimized more for speed than
0044: * for compactness, that is constructed via SAX2 ContentHandler events.
0045: */
0046: public class SAX2DTM extends DTMDefaultBaseIterators implements
0047: EntityResolver, DTDHandler, ContentHandler, ErrorHandler,
0048: DeclHandler, LexicalHandler {
0049: /** Set true to monitor SAX events and similar diagnostic info. */
0050: private static final boolean DEBUG = false;
0051:
0052: /**
0053: * If we're building the model incrementally on demand, we need to
0054: * be able to tell the source when to send us more data.
0055: *
0056: * Note that if this has not been set, and you attempt to read ahead
0057: * of the current build point, we'll probably throw a null-pointer
0058: * exception. We could try to wait-and-retry instead, as a very poor
0059: * fallback, but that has all the known problems with multithreading
0060: * on multiprocessors and we Don't Want to Go There.
0061: *
0062: * @see setIncrementalSAXSource
0063: */
0064: private IncrementalSAXSource m_incrementalSAXSource = null;
0065:
0066: /**
0067: * All the character content, including attribute values, are stored in
0068: * this buffer.
0069: *
0070: * %REVIEW% Should this have an option of being shared across DTMs?
0071: * Sequentially only; not threadsafe... Currently, I think not.
0072: *
0073: * %REVIEW% Initial size was pushed way down to reduce weight of RTFs.
0074: * pending reduction in number of RTF DTMs. Now that we're sharing a DTM
0075: * between RTFs, and tail-pruning... consider going back to the larger/faster.
0076: *
0077: * Made protected rather than private so SAX2RTFDTM can access it.
0078: */
0079: //private FastStringBuffer m_chars = new FastStringBuffer(13, 13);
0080: protected FastStringBuffer m_chars;
0081:
0082: /** This vector holds offset and length data.
0083: */
0084: protected SuballocatedIntVector m_data;
0085:
0086: /** The parent stack, needed only for construction.
0087: * Made protected rather than private so SAX2RTFDTM can access it.
0088: */
0089: transient protected IntStack m_parents;
0090:
0091: /** The current previous node, needed only for construction time.
0092: * Made protected rather than private so SAX2RTFDTM can access it.
0093: */
0094: transient protected int m_previous = 0;
0095:
0096: /** Namespace support, only relevent at construction time.
0097: * Made protected rather than private so SAX2RTFDTM can access it.
0098: */
0099: transient protected java.util.Vector m_prefixMappings = new java.util.Vector();
0100:
0101: /** Namespace support, only relevent at construction time.
0102: * Made protected rather than private so SAX2RTFDTM can access it.
0103: */
0104: transient protected IntStack m_contextIndexes;
0105:
0106: /** Type of next characters() event within text block in prgress. */
0107: transient protected int m_textType = DTM.TEXT_NODE;
0108:
0109: /**
0110: * Type of coalesced text block. See logic in the characters()
0111: * method.
0112: */
0113: transient protected int m_coalescedTextType = DTM.TEXT_NODE;
0114:
0115: /** The SAX Document locator */
0116: transient protected Locator m_locator = null;
0117:
0118: /** The SAX Document system-id */
0119: transient private String m_systemId = null;
0120:
0121: /** We are inside the DTD. This is used for ignoring comments. */
0122: transient protected boolean m_insideDTD = false;
0123:
0124: /** Tree Walker for dispatchToEvents. */
0125: protected DTMTreeWalker m_walker = new DTMTreeWalker();
0126:
0127: /** pool of string values that come as strings. */
0128: protected DTMStringPool m_valuesOrPrefixes;
0129:
0130: /** End document has been reached.
0131: * Made protected rather than private so SAX2RTFDTM can access it.
0132: */
0133: protected boolean m_endDocumentOccured = false;
0134:
0135: /** Data or qualified name values, one array element for each node. */
0136: protected SuballocatedIntVector m_dataOrQName;
0137:
0138: /**
0139: * This table holds the ID string to node associations, for
0140: * XML IDs.
0141: */
0142: protected Hashtable m_idAttributes = new Hashtable();
0143:
0144: /**
0145: * fixed dom-style names.
0146: */
0147: private static final String[] m_fixednames = { null, null, // nothing, Element
0148: null, "#text", // Attr, Text
0149: "#cdata_section", null, // CDATA, EntityReference
0150: null, null, // Entity, PI
0151: "#comment", "#document", // Comment, Document
0152: null, "#document-fragment", // Doctype, DocumentFragment
0153: null }; // Notation
0154:
0155: /**
0156: * Vector of entities. Each record is composed of four Strings:
0157: * publicId, systemID, notationName, and name.
0158: */
0159: private Vector m_entities = null;
0160:
0161: /** m_entities public ID offset. */
0162: private static final int ENTITY_FIELD_PUBLICID = 0;
0163:
0164: /** m_entities system ID offset. */
0165: private static final int ENTITY_FIELD_SYSTEMID = 1;
0166:
0167: /** m_entities notation name offset. */
0168: private static final int ENTITY_FIELD_NOTATIONNAME = 2;
0169:
0170: /** m_entities name offset. */
0171: private static final int ENTITY_FIELD_NAME = 3;
0172:
0173: /** Number of entries per record for m_entities. */
0174: private static final int ENTITY_FIELDS_PER = 4;
0175:
0176: /**
0177: * The starting offset within m_chars for the text or
0178: * CDATA_SECTION node currently being acumulated,
0179: * or -1 if there is no text node in progress
0180: */
0181: protected int m_textPendingStart = -1;
0182:
0183: /**
0184: * Describes whether information about document source location
0185: * should be maintained or not.
0186: *
0187: * Made protected for access by SAX2RTFDTM.
0188: */
0189: protected boolean m_useSourceLocationProperty = false;
0190:
0191: /** Made protected for access by SAX2RTFDTM.
0192: */
0193: protected StringVector m_sourceSystemId;
0194: /** Made protected for access by SAX2RTFDTM.
0195: */
0196: protected IntVector m_sourceLine;
0197: /** Made protected for access by SAX2RTFDTM.
0198: */
0199: protected IntVector m_sourceColumn;
0200:
0201: /**
0202: * Construct a SAX2DTM object using the default block size.
0203: *
0204: * @param mgr The DTMManager who owns this DTM.
0205: * @param source the JAXP 1.1 Source object for this DTM.
0206: * @param dtmIdentity The DTM identity ID for this DTM.
0207: * @param whiteSpaceFilter The white space filter for this DTM, which may
0208: * be null.
0209: * @param xstringfactory XMLString factory for creating character content.
0210: * @param doIndexing true if the caller considers it worth it to use
0211: * indexing schemes.
0212: */
0213: public SAX2DTM(DTMManager mgr, Source source, int dtmIdentity,
0214: DTMWSFilter whiteSpaceFilter,
0215: XMLStringFactory xstringfactory, boolean doIndexing) {
0216:
0217: this (mgr, source, dtmIdentity, whiteSpaceFilter,
0218: xstringfactory, doIndexing, DEFAULT_BLOCKSIZE, true,
0219: false);
0220: }
0221:
0222: /**
0223: * Construct a SAX2DTM object ready to be constructed from SAX2
0224: * ContentHandler events.
0225: *
0226: * @param mgr The DTMManager who owns this DTM.
0227: * @param source the JAXP 1.1 Source object for this DTM.
0228: * @param dtmIdentity The DTM identity ID for this DTM.
0229: * @param whiteSpaceFilter The white space filter for this DTM, which may
0230: * be null.
0231: * @param xstringfactory XMLString factory for creating character content.
0232: * @param doIndexing true if the caller considers it worth it to use
0233: * indexing schemes.
0234: * @param blocksize The block size of the DTM.
0235: * @param usePrevsib true if we want to build the previous sibling node array.
0236: * @param newNameTable true if we want to use a new ExpandedNameTable for this DTM.
0237: */
0238: public SAX2DTM(DTMManager mgr, Source source, int dtmIdentity,
0239: DTMWSFilter whiteSpaceFilter,
0240: XMLStringFactory xstringfactory, boolean doIndexing,
0241: int blocksize, boolean usePrevsib, boolean newNameTable) {
0242:
0243: super (mgr, source, dtmIdentity, whiteSpaceFilter,
0244: xstringfactory, doIndexing, blocksize, usePrevsib,
0245: newNameTable);
0246:
0247: // %OPT% Use smaller sizes for all internal storage units when
0248: // the blocksize is small. This reduces the cost of creating an RTF.
0249: if (blocksize <= 64) {
0250: m_data = new SuballocatedIntVector(blocksize,
0251: DEFAULT_NUMBLOCKS_SMALL);
0252: m_dataOrQName = new SuballocatedIntVector(blocksize,
0253: DEFAULT_NUMBLOCKS_SMALL);
0254: m_valuesOrPrefixes = new DTMStringPool(16);
0255: m_chars = new FastStringBuffer(7, 10);
0256: m_contextIndexes = new IntStack(4);
0257: m_parents = new IntStack(4);
0258: } else {
0259: m_data = new SuballocatedIntVector(blocksize,
0260: DEFAULT_NUMBLOCKS);
0261: m_dataOrQName = new SuballocatedIntVector(blocksize,
0262: DEFAULT_NUMBLOCKS);
0263: m_valuesOrPrefixes = new DTMStringPool();
0264: m_chars = new FastStringBuffer(10, 13);
0265: m_contextIndexes = new IntStack();
0266: m_parents = new IntStack();
0267: }
0268:
0269: // %REVIEW% Initial size pushed way down to reduce weight of RTFs
0270: // (I'm not entirely sure 0 would work, so I'm playing it safe for now.)
0271: //m_data = new SuballocatedIntVector(doIndexing ? (1024*2) : 512, 1024);
0272: //m_data = new SuballocatedIntVector(blocksize);
0273:
0274: m_data.addElement(0); // Need placeholder in case index into here must be <0.
0275:
0276: //m_dataOrQName = new SuballocatedIntVector(blocksize);
0277:
0278: // m_useSourceLocationProperty=org.apache.xalan.processor.TransformerFactoryImpl.m_source_location;
0279: m_useSourceLocationProperty = mgr.getSource_location();
0280: m_sourceSystemId = (m_useSourceLocationProperty) ? new StringVector()
0281: : null;
0282: m_sourceLine = (m_useSourceLocationProperty) ? new IntVector()
0283: : null;
0284: m_sourceColumn = (m_useSourceLocationProperty) ? new IntVector()
0285: : null;
0286: }
0287:
0288: /**
0289: * Set whether information about document source location
0290: * should be maintained or not.
0291: */
0292: public void setUseSourceLocation(boolean useSourceLocation) {
0293: m_useSourceLocationProperty = useSourceLocation;
0294: }
0295:
0296: /**
0297: * Get the data or qualified name for the given node identity.
0298: *
0299: * @param identity The node identity.
0300: *
0301: * @return The data or qualified name, or DTM.NULL.
0302: */
0303: protected int _dataOrQName(int identity) {
0304:
0305: if (identity < m_size)
0306: return m_dataOrQName.elementAt(identity);
0307:
0308: // Check to see if the information requested has been processed, and,
0309: // if not, advance the iterator until we the information has been
0310: // processed.
0311: while (true) {
0312: boolean isMore = nextNode();
0313:
0314: if (!isMore)
0315: return NULL;
0316: else if (identity < m_size)
0317: return m_dataOrQName.elementAt(identity);
0318: }
0319: }
0320:
0321: /**
0322: * Ask the CoRoutine parser to doTerminate and clear the reference.
0323: */
0324: public void clearCoRoutine() {
0325: clearCoRoutine(true);
0326: }
0327:
0328: /**
0329: * Ask the CoRoutine parser to doTerminate and clear the reference. If
0330: * the CoRoutine parser has already been cleared, this will have no effect.
0331: *
0332: * @param callDoTerminate true of doTerminate should be called on the
0333: * coRoutine parser.
0334: */
0335: public void clearCoRoutine(boolean callDoTerminate) {
0336:
0337: if (null != m_incrementalSAXSource) {
0338: if (callDoTerminate)
0339: m_incrementalSAXSource.deliverMoreNodes(false);
0340:
0341: m_incrementalSAXSource = null;
0342: }
0343: }
0344:
0345: /**
0346: * Bind a IncrementalSAXSource to this DTM. If we discover we need nodes
0347: * that have not yet been built, we will ask this object to send us more
0348: * events, and it will manage interactions with its data sources.
0349: *
0350: * Note that we do not actually build the IncrementalSAXSource, since we don't
0351: * know what source it's reading from, what thread that source will run in,
0352: * or when it will run.
0353: *
0354: * @param incrementalSAXSource The parser that we want to recieve events from
0355: * on demand.
0356: */
0357: public void setIncrementalSAXSource(
0358: IncrementalSAXSource incrementalSAXSource) {
0359:
0360: // Establish coroutine link so we can request more data
0361: //
0362: // Note: It's possible that some versions of IncrementalSAXSource may
0363: // not actually use a CoroutineManager, and hence may not require
0364: // that we obtain an Application Coroutine ID. (This relies on the
0365: // coroutine transaction details having been encapsulated in the
0366: // IncrementalSAXSource.do...() methods.)
0367: m_incrementalSAXSource = incrementalSAXSource;
0368:
0369: // Establish SAX-stream link so we can receive the requested data
0370: incrementalSAXSource.setContentHandler(this );
0371: incrementalSAXSource.setLexicalHandler(this );
0372: incrementalSAXSource.setDTDHandler(this );
0373:
0374: // Are the following really needed? incrementalSAXSource doesn't yet
0375: // support them, and they're mostly no-ops here...
0376: //incrementalSAXSource.setErrorHandler(this);
0377: //incrementalSAXSource.setDeclHandler(this);
0378: }
0379:
0380: /**
0381: * getContentHandler returns "our SAX builder" -- the thing that
0382: * someone else should send SAX events to in order to extend this
0383: * DTM model.
0384: *
0385: * %REVIEW% Should this return null if constrution already done/begun?
0386: *
0387: * @return null if this model doesn't respond to SAX events,
0388: * "this" if the DTM object has a built-in SAX ContentHandler,
0389: * the IncrementalSAXSource if we're bound to one and should receive
0390: * the SAX stream via it for incremental build purposes...
0391: */
0392: public ContentHandler getContentHandler() {
0393:
0394: if (m_incrementalSAXSource instanceof IncrementalSAXSource_Filter)
0395: return (ContentHandler) m_incrementalSAXSource;
0396: else
0397: return this ;
0398: }
0399:
0400: /**
0401: * Return this DTM's lexical handler.
0402: *
0403: * %REVIEW% Should this return null if constrution already done/begun?
0404: *
0405: * @return null if this model doesn't respond to lexical SAX events,
0406: * "this" if the DTM object has a built-in SAX ContentHandler,
0407: * the IncrementalSAXSource if we're bound to one and should receive
0408: * the SAX stream via it for incremental build purposes...
0409: */
0410: public LexicalHandler getLexicalHandler() {
0411:
0412: if (m_incrementalSAXSource instanceof IncrementalSAXSource_Filter)
0413: return (LexicalHandler) m_incrementalSAXSource;
0414: else
0415: return this ;
0416: }
0417:
0418: /**
0419: * Return this DTM's EntityResolver.
0420: *
0421: * @return null if this model doesn't respond to SAX entity ref events.
0422: */
0423: public EntityResolver getEntityResolver() {
0424: return this ;
0425: }
0426:
0427: /**
0428: * Return this DTM's DTDHandler.
0429: *
0430: * @return null if this model doesn't respond to SAX dtd events.
0431: */
0432: public DTDHandler getDTDHandler() {
0433: return this ;
0434: }
0435:
0436: /**
0437: * Return this DTM's ErrorHandler.
0438: *
0439: * @return null if this model doesn't respond to SAX error events.
0440: */
0441: public ErrorHandler getErrorHandler() {
0442: return this ;
0443: }
0444:
0445: /**
0446: * Return this DTM's DeclHandler.
0447: *
0448: * @return null if this model doesn't respond to SAX Decl events.
0449: */
0450: public DeclHandler getDeclHandler() {
0451: return this ;
0452: }
0453:
0454: /**
0455: * @return true iff we're building this model incrementally (eg
0456: * we're partnered with a IncrementalSAXSource) and thus require that the
0457: * transformation and the parse run simultaneously. Guidance to the
0458: * DTMManager.
0459: */
0460: public boolean needsTwoThreads() {
0461: return null != m_incrementalSAXSource;
0462: }
0463:
0464: /**
0465: * Directly call the
0466: * characters method on the passed ContentHandler for the
0467: * string-value of the given node (see http://www.w3.org/TR/xpath#data-model
0468: * for the definition of a node's string-value). Multiple calls to the
0469: * ContentHandler's characters methods may well occur for a single call to
0470: * this method.
0471: *
0472: * @param nodeHandle The node ID.
0473: * @param ch A non-null reference to a ContentHandler.
0474: * @param normalize true if the content should be normalized according to
0475: * the rules for the XPath
0476: * <a href="http://www.w3.org/TR/xpath#function-normalize-space">normalize-space</a>
0477: * function.
0478: *
0479: * @throws SAXException
0480: */
0481: public void dispatchCharactersEvents(int nodeHandle,
0482: ContentHandler ch, boolean normalize) throws SAXException {
0483:
0484: int identity = makeNodeIdentity(nodeHandle);
0485:
0486: if (identity == DTM.NULL)
0487: return;
0488:
0489: int type = _type(identity);
0490:
0491: if (isTextType(type)) {
0492: int dataIndex = m_dataOrQName.elementAt(identity);
0493: int offset = m_data.elementAt(dataIndex);
0494: int length = m_data.elementAt(dataIndex + 1);
0495:
0496: if (normalize)
0497: m_chars.sendNormalizedSAXcharacters(ch, offset, length);
0498: else
0499: m_chars.sendSAXcharacters(ch, offset, length);
0500: } else {
0501: int firstChild = _firstch(identity);
0502:
0503: if (DTM.NULL != firstChild) {
0504: int offset = -1;
0505: int length = 0;
0506: int startNode = identity;
0507:
0508: identity = firstChild;
0509:
0510: do {
0511: type = _type(identity);
0512:
0513: if (isTextType(type)) {
0514: int dataIndex = _dataOrQName(identity);
0515:
0516: if (-1 == offset) {
0517: offset = m_data.elementAt(dataIndex);
0518: }
0519:
0520: length += m_data.elementAt(dataIndex + 1);
0521: }
0522:
0523: identity = getNextNodeIdentity(identity);
0524: } while (DTM.NULL != identity
0525: && (_parent(identity) >= startNode));
0526:
0527: if (length > 0) {
0528: if (normalize)
0529: m_chars.sendNormalizedSAXcharacters(ch, offset,
0530: length);
0531: else
0532: m_chars.sendSAXcharacters(ch, offset, length);
0533: }
0534: } else if (type != DTM.ELEMENT_NODE) {
0535: int dataIndex = _dataOrQName(identity);
0536:
0537: if (dataIndex < 0) {
0538: dataIndex = -dataIndex;
0539: dataIndex = m_data.elementAt(dataIndex + 1);
0540: }
0541:
0542: String str = m_valuesOrPrefixes
0543: .indexToString(dataIndex);
0544:
0545: if (normalize)
0546: FastStringBuffer.sendNormalizedSAXcharacters(str
0547: .toCharArray(), 0, str.length(), ch);
0548: else
0549: ch.characters(str.toCharArray(), 0, str.length());
0550: }
0551: }
0552: }
0553:
0554: /**
0555: * Given a node handle, return its DOM-style node name. This will
0556: * include names such as #text or #document.
0557: *
0558: * @param nodeHandle the id of the node.
0559: * @return String Name of this node, which may be an empty string.
0560: * %REVIEW% Document when empty string is possible...
0561: * %REVIEW-COMMENT% It should never be empty, should it?
0562: */
0563: public String getNodeName(int nodeHandle) {
0564:
0565: int expandedTypeID = getExpandedTypeID(nodeHandle);
0566: // If just testing nonzero, no need to shift...
0567: int namespaceID = m_expandedNameTable
0568: .getNamespaceID(expandedTypeID);
0569:
0570: if (0 == namespaceID) {
0571: // Don't retrieve name until/unless needed
0572: // String name = m_expandedNameTable.getLocalName(expandedTypeID);
0573: int type = getNodeType(nodeHandle);
0574:
0575: if (type == DTM.NAMESPACE_NODE) {
0576: if (null == m_expandedNameTable
0577: .getLocalName(expandedTypeID))
0578: return "xmlns";
0579: else
0580: return "xmlns:"
0581: + m_expandedNameTable
0582: .getLocalName(expandedTypeID);
0583: } else if (0 == m_expandedNameTable
0584: .getLocalNameID(expandedTypeID)) {
0585: return m_fixednames[type];
0586: } else
0587: return m_expandedNameTable.getLocalName(expandedTypeID);
0588: } else {
0589: int qnameIndex = m_dataOrQName
0590: .elementAt(makeNodeIdentity(nodeHandle));
0591:
0592: if (qnameIndex < 0) {
0593: qnameIndex = -qnameIndex;
0594: qnameIndex = m_data.elementAt(qnameIndex);
0595: }
0596:
0597: return m_valuesOrPrefixes.indexToString(qnameIndex);
0598: }
0599: }
0600:
0601: /**
0602: * Given a node handle, return the XPath node name. This should be
0603: * the name as described by the XPath data model, NOT the DOM-style
0604: * name.
0605: *
0606: * @param nodeHandle the id of the node.
0607: * @return String Name of this node, which may be an empty string.
0608: */
0609: public String getNodeNameX(int nodeHandle) {
0610:
0611: int expandedTypeID = getExpandedTypeID(nodeHandle);
0612: int namespaceID = m_expandedNameTable
0613: .getNamespaceID(expandedTypeID);
0614:
0615: if (0 == namespaceID) {
0616: String name = m_expandedNameTable
0617: .getLocalName(expandedTypeID);
0618:
0619: if (name == null)
0620: return "";
0621: else
0622: return name;
0623: } else {
0624: int qnameIndex = m_dataOrQName
0625: .elementAt(makeNodeIdentity(nodeHandle));
0626:
0627: if (qnameIndex < 0) {
0628: qnameIndex = -qnameIndex;
0629: qnameIndex = m_data.elementAt(qnameIndex);
0630: }
0631:
0632: return m_valuesOrPrefixes.indexToString(qnameIndex);
0633: }
0634: }
0635:
0636: /**
0637: * 5. [specified] A flag indicating whether this attribute was actually
0638: * specified in the start-tag of its element, or was defaulted from the
0639: * DTD.
0640: *
0641: * @param attributeHandle Must be a valid handle to an attribute node.
0642: * @return <code>true</code> if the attribute was specified;
0643: * <code>false</code> if it was defaulted.
0644: */
0645: public boolean isAttributeSpecified(int attributeHandle) {
0646:
0647: // I'm not sure if I want to do anything with this...
0648: return true; // ??
0649: }
0650:
0651: /**
0652: * A document type declaration information item has the following properties:
0653: *
0654: * 1. [system identifier] The system identifier of the external subset, if
0655: * it exists. Otherwise this property has no value.
0656: *
0657: * @return the system identifier String object, or null if there is none.
0658: */
0659: public String getDocumentTypeDeclarationSystemIdentifier() {
0660:
0661: /** @todo: implement this org.apache.xml.dtm.DTMDefaultBase abstract method */
0662: error(XMLMessages.createXMLMessage(
0663: XMLErrorResources.ER_METHOD_NOT_SUPPORTED, null));//"Not yet supported!");
0664:
0665: return null;
0666: }
0667:
0668: /**
0669: * Get the next node identity value in the list, and call the iterator
0670: * if it hasn't been added yet.
0671: *
0672: * @param identity The node identity (index).
0673: * @return identity+1, or DTM.NULL.
0674: */
0675: protected int getNextNodeIdentity(int identity) {
0676:
0677: identity += 1;
0678:
0679: while (identity >= m_size) {
0680: if (null == m_incrementalSAXSource)
0681: return DTM.NULL;
0682:
0683: nextNode();
0684: }
0685:
0686: return identity;
0687: }
0688:
0689: /**
0690: * Directly create SAX parser events from a subtree.
0691: *
0692: * @param nodeHandle The node ID.
0693: * @param ch A non-null reference to a ContentHandler.
0694: *
0695: * @throws org.xml.sax.SAXException
0696: */
0697: public void dispatchToEvents(int nodeHandle,
0698: org.xml.sax.ContentHandler ch)
0699: throws org.xml.sax.SAXException {
0700:
0701: DTMTreeWalker treeWalker = m_walker;
0702: ContentHandler prevCH = treeWalker.getcontentHandler();
0703:
0704: if (null != prevCH) {
0705: treeWalker = new DTMTreeWalker();
0706: }
0707:
0708: treeWalker.setcontentHandler(ch);
0709: treeWalker.setDTM(this );
0710:
0711: try {
0712: treeWalker.traverse(nodeHandle);
0713: } finally {
0714: treeWalker.setcontentHandler(null);
0715: }
0716: }
0717:
0718: /**
0719: * Get the number of nodes that have been added.
0720: *
0721: * @return The number of that are currently in the tree.
0722: */
0723: public int getNumberOfNodes() {
0724: return m_size;
0725: }
0726:
0727: /**
0728: * This method should try and build one or more nodes in the table.
0729: *
0730: * @return The true if a next node is found or false if
0731: * there are no more nodes.
0732: */
0733: protected boolean nextNode() {
0734:
0735: if (null == m_incrementalSAXSource)
0736: return false;
0737:
0738: if (m_endDocumentOccured) {
0739: clearCoRoutine();
0740:
0741: return false;
0742: }
0743:
0744: Object gotMore = m_incrementalSAXSource.deliverMoreNodes(true);
0745:
0746: // gotMore may be a Boolean (TRUE if still parsing, FALSE if
0747: // EOF) or an exception if IncrementalSAXSource malfunctioned
0748: // (code error rather than user error).
0749: //
0750: // %REVIEW% Currently the ErrorHandlers sketched herein are
0751: // no-ops, so I'm going to initially leave this also as a
0752: // no-op.
0753: if (!(gotMore instanceof Boolean)) {
0754: if (gotMore instanceof RuntimeException) {
0755: throw (RuntimeException) gotMore;
0756: } else if (gotMore instanceof Exception) {
0757: throw new WrappedRuntimeException((Exception) gotMore);
0758: }
0759: // for now...
0760: clearCoRoutine();
0761:
0762: return false;
0763:
0764: // %TBD%
0765: }
0766:
0767: if (gotMore != Boolean.TRUE) {
0768:
0769: // EOF reached without satisfying the request
0770: clearCoRoutine(); // Drop connection, stop trying
0771:
0772: // %TBD% deregister as its listener?
0773: }
0774:
0775: return true;
0776: }
0777:
0778: /**
0779: * Bottleneck determination of text type.
0780: *
0781: * @param type oneof DTM.XXX_NODE.
0782: *
0783: * @return true if this is a text or cdata section.
0784: */
0785: private final boolean isTextType(int type) {
0786: return (DTM.TEXT_NODE == type || DTM.CDATA_SECTION_NODE == type);
0787: }
0788:
0789: // /**
0790: // * Ensure that the size of the information arrays can hold another entry
0791: // * at the given index.
0792: // *
0793: // * @param on exit from this function, the information arrays sizes must be
0794: // * at least index+1.
0795: // *
0796: // * NEEDSDOC @param index
0797: // */
0798: // protected void ensureSize(int index)
0799: // {
0800: // // dataOrQName is an SuballocatedIntVector and hence self-sizing.
0801: // // But DTMDefaultBase may need fixup.
0802: // super.ensureSize(index);
0803: // }
0804:
0805: /**
0806: * Construct the node map from the node.
0807: *
0808: * @param type raw type ID, one of DTM.XXX_NODE.
0809: * @param expandedTypeID The expended type ID.
0810: * @param parentIndex The current parent index.
0811: * @param previousSibling The previous sibling index.
0812: * @param dataOrPrefix index into m_data table, or string handle.
0813: * @param canHaveFirstChild true if the node can have a first child, false
0814: * if it is atomic.
0815: *
0816: * @return The index identity of the node that was added.
0817: */
0818: protected int addNode(int type, int expandedTypeID,
0819: int parentIndex, int previousSibling, int dataOrPrefix,
0820: boolean canHaveFirstChild) {
0821: // Common to all nodes:
0822: int nodeIndex = m_size++;
0823:
0824: // Have we overflowed a DTM Identity's addressing range?
0825: if (m_dtmIdent.size() == (nodeIndex >>> DTMManager.IDENT_DTM_NODE_BITS)) {
0826: addNewDTMID(nodeIndex);
0827: }
0828:
0829: m_firstch.addElement(canHaveFirstChild ? NOTPROCESSED
0830: : DTM.NULL);
0831: m_nextsib.addElement(NOTPROCESSED);
0832: m_parent.addElement(parentIndex);
0833: m_exptype.addElement(expandedTypeID);
0834: m_dataOrQName.addElement(dataOrPrefix);
0835:
0836: if (m_prevsib != null) {
0837: m_prevsib.addElement(previousSibling);
0838: }
0839:
0840: if (DTM.NULL != previousSibling) {
0841: m_nextsib.setElementAt(nodeIndex, previousSibling);
0842: }
0843:
0844: if (m_locator != null && m_useSourceLocationProperty) {
0845: setSourceLocation();
0846: }
0847:
0848: // Note that nextSibling is not processed until charactersFlush()
0849: // is called, to handle successive characters() events.
0850:
0851: // Special handling by type: Declare namespaces, attach first child
0852: switch (type) {
0853: case DTM.NAMESPACE_NODE:
0854: declareNamespaceInContext(parentIndex, nodeIndex);
0855: break;
0856: case DTM.ATTRIBUTE_NODE:
0857: break;
0858: default:
0859: if (DTM.NULL == previousSibling && DTM.NULL != parentIndex) {
0860: m_firstch.setElementAt(nodeIndex, parentIndex);
0861: }
0862: break;
0863: }
0864:
0865: return nodeIndex;
0866: }
0867:
0868: /**
0869: * Get a new DTM ID beginning at the specified node index.
0870: * @param nodeIndex The node identity at which the new DTM ID will begin
0871: * addressing.
0872: */
0873: protected void addNewDTMID(int nodeIndex) {
0874: try {
0875: if (m_mgr == null)
0876: throw new ClassCastException();
0877:
0878: // Handle as Extended Addressing
0879: DTMManagerDefault mgrD = (DTMManagerDefault) m_mgr;
0880: int id = mgrD.getFirstFreeDTMID();
0881: mgrD.addDTM(this , id, nodeIndex);
0882: m_dtmIdent.addElement(id << DTMManager.IDENT_DTM_NODE_BITS);
0883: } catch (ClassCastException e) {
0884: // %REVIEW% Wrong error message, but I've been told we're trying
0885: // not to add messages right not for I18N reasons.
0886: // %REVIEW% Should this be a Fatal Error?
0887: error(XMLMessages.createXMLMessage(
0888: XMLErrorResources.ER_NO_DTMIDS_AVAIL, null));//"No more DTM IDs are available";
0889: }
0890: }
0891:
0892: /**
0893: * Migrate a DTM built with an old DTMManager to a new DTMManager.
0894: * After the migration, the new DTMManager will treat the DTM as
0895: * one that is built by itself.
0896: * This is used to support DTM sharing between multiple transformations.
0897: * @param manager the DTMManager
0898: */
0899: public void migrateTo(DTMManager manager) {
0900: super .migrateTo(manager);
0901:
0902: // We have to reset the information in m_dtmIdent and
0903: // register the DTM with the new manager.
0904: int numDTMs = m_dtmIdent.size();
0905: int dtmId = m_mgrDefault.getFirstFreeDTMID();
0906: int nodeIndex = 0;
0907: for (int i = 0; i < numDTMs; i++) {
0908: m_dtmIdent.setElementAt(
0909: dtmId << DTMManager.IDENT_DTM_NODE_BITS, i);
0910: m_mgrDefault.addDTM(this , dtmId, nodeIndex);
0911: dtmId++;
0912: nodeIndex += (1 << DTMManager.IDENT_DTM_NODE_BITS);
0913: }
0914: }
0915:
0916: /**
0917: * Store the source location of the current node. This method must be called
0918: * as every node is added to the DTM or for no node.
0919: */
0920: protected void setSourceLocation() {
0921: m_sourceSystemId.addElement(m_locator.getSystemId());
0922: m_sourceLine.addElement(m_locator.getLineNumber());
0923: m_sourceColumn.addElement(m_locator.getColumnNumber());
0924:
0925: //%REVIEW% %BUG% Prevent this from arising in the first place
0926: // by not allowing the enabling conditions to change after we start
0927: // building the document.
0928: if (m_sourceSystemId.size() != m_size) {
0929: String msg = "CODING ERROR in Source Location: " + m_size
0930: + " != " + m_sourceSystemId.size();
0931: System.err.println(msg);
0932: throw new RuntimeException(msg);
0933: }
0934: }
0935:
0936: /**
0937: * Given a node handle, return its node value. This is mostly
0938: * as defined by the DOM, but may ignore some conveniences.
0939: * <p>
0940: *
0941: * @param nodeHandle The node id.
0942: * @return String Value of this node, or null if not
0943: * meaningful for this node type.
0944: */
0945: public String getNodeValue(int nodeHandle) {
0946:
0947: int identity = makeNodeIdentity(nodeHandle);
0948: int type = _type(identity);
0949:
0950: if (isTextType(type)) {
0951: int dataIndex = _dataOrQName(identity);
0952: int offset = m_data.elementAt(dataIndex);
0953: int length = m_data.elementAt(dataIndex + 1);
0954:
0955: // %OPT% We should cache this, I guess.
0956: return m_chars.getString(offset, length);
0957: } else if (DTM.ELEMENT_NODE == type
0958: || DTM.DOCUMENT_FRAGMENT_NODE == type
0959: || DTM.DOCUMENT_NODE == type) {
0960: return null;
0961: } else {
0962: int dataIndex = _dataOrQName(identity);
0963:
0964: if (dataIndex < 0) {
0965: dataIndex = -dataIndex;
0966: dataIndex = m_data.elementAt(dataIndex + 1);
0967: }
0968:
0969: return m_valuesOrPrefixes.indexToString(dataIndex);
0970: }
0971: }
0972:
0973: /**
0974: * Given a node handle, return its XPath-style localname.
0975: * (As defined in Namespaces, this is the portion of the name after any
0976: * colon character).
0977: *
0978: * @param nodeHandle the id of the node.
0979: * @return String Local name of this node.
0980: */
0981: public String getLocalName(int nodeHandle) {
0982: return m_expandedNameTable
0983: .getLocalName(_exptype(makeNodeIdentity(nodeHandle)));
0984: }
0985:
0986: /**
0987: * The getUnparsedEntityURI function returns the URI of the unparsed
0988: * entity with the specified name in the same document as the context
0989: * node (see [3.3 Unparsed Entities]). It returns the empty string if
0990: * there is no such entity.
0991: * <p>
0992: * XML processors may choose to use the System Identifier (if one
0993: * is provided) to resolve the entity, rather than the URI in the
0994: * Public Identifier. The details are dependent on the processor, and
0995: * we would have to support some form of plug-in resolver to handle
0996: * this properly. Currently, we simply return the System Identifier if
0997: * present, and hope that it a usable URI or that our caller can
0998: * map it to one.
0999: * TODO: Resolve Public Identifiers... or consider changing function name.
1000: * <p>
1001: * If we find a relative URI
1002: * reference, XML expects it to be resolved in terms of the base URI
1003: * of the document. The DOM doesn't do that for us, and it isn't
1004: * entirely clear whether that should be done here; currently that's
1005: * pushed up to a higher level of our application. (Note that DOM Level
1006: * 1 didn't store the document's base URI.)
1007: * TODO: Consider resolving Relative URIs.
1008: * <p>
1009: * (The DOM's statement that "An XML processor may choose to
1010: * completely expand entities before the structure model is passed
1011: * to the DOM" refers only to parsed entities, not unparsed, and hence
1012: * doesn't affect this function.)
1013: *
1014: * @param name A string containing the Entity Name of the unparsed
1015: * entity.
1016: *
1017: * @return String containing the URI of the Unparsed Entity, or an
1018: * empty string if no such entity exists.
1019: */
1020: public String getUnparsedEntityURI(String name) {
1021:
1022: String url = "";
1023:
1024: if (null == m_entities)
1025: return url;
1026:
1027: int n = m_entities.size();
1028:
1029: for (int i = 0; i < n; i += ENTITY_FIELDS_PER) {
1030: String ename = (String) m_entities.elementAt(i
1031: + ENTITY_FIELD_NAME);
1032:
1033: if (null != ename && ename.equals(name)) {
1034: String nname = (String) m_entities.elementAt(i
1035: + ENTITY_FIELD_NOTATIONNAME);
1036:
1037: if (null != nname) {
1038:
1039: // The draft says: "The XSLT processor may use the public
1040: // identifier to generate a URI for the entity instead of the URI
1041: // specified in the system identifier. If the XSLT processor does
1042: // not use the public identifier to generate the URI, it must use
1043: // the system identifier; if the system identifier is a relative
1044: // URI, it must be resolved into an absolute URI using the URI of
1045: // the resource containing the entity declaration as the base
1046: // URI [RFC2396]."
1047: // So I'm falling a bit short here.
1048: url = (String) m_entities.elementAt(i
1049: + ENTITY_FIELD_SYSTEMID);
1050:
1051: if (null == url) {
1052: url = (String) m_entities.elementAt(i
1053: + ENTITY_FIELD_PUBLICID);
1054: }
1055: }
1056:
1057: break;
1058: }
1059: }
1060:
1061: return url;
1062: }
1063:
1064: /**
1065: * Given a namespace handle, return the prefix that the namespace decl is
1066: * mapping.
1067: * Given a node handle, return the prefix used to map to the namespace.
1068: *
1069: * <p> %REVIEW% Are you sure you want "" for no prefix? </p>
1070: * <p> %REVIEW-COMMENT% I think so... not totally sure. -sb </p>
1071: *
1072: * @param nodeHandle the id of the node.
1073: * @return String prefix of this node's name, or "" if no explicit
1074: * namespace prefix was given.
1075: */
1076: public String getPrefix(int nodeHandle) {
1077:
1078: int identity = makeNodeIdentity(nodeHandle);
1079: int type = _type(identity);
1080:
1081: if (DTM.ELEMENT_NODE == type) {
1082: int prefixIndex = _dataOrQName(identity);
1083:
1084: if (0 == prefixIndex)
1085: return "";
1086: else {
1087: String qname = m_valuesOrPrefixes
1088: .indexToString(prefixIndex);
1089:
1090: return getPrefix(qname, null);
1091: }
1092: } else if (DTM.ATTRIBUTE_NODE == type) {
1093: int prefixIndex = _dataOrQName(identity);
1094:
1095: if (prefixIndex < 0) {
1096: prefixIndex = m_data.elementAt(-prefixIndex);
1097:
1098: String qname = m_valuesOrPrefixes
1099: .indexToString(prefixIndex);
1100:
1101: return getPrefix(qname, null);
1102: }
1103: }
1104:
1105: return "";
1106: }
1107:
1108: /**
1109: * Retrieves an attribute node by by qualified name and namespace URI.
1110: *
1111: * @param nodeHandle int Handle of the node upon which to look up this attribute..
1112: * @param namespaceURI The namespace URI of the attribute to
1113: * retrieve, or null.
1114: * @param name The local name of the attribute to
1115: * retrieve.
1116: * @return The attribute node handle with the specified name (
1117: * <code>nodeName</code>) or <code>DTM.NULL</code> if there is no such
1118: * attribute.
1119: */
1120: public int getAttributeNode(int nodeHandle, String namespaceURI,
1121: String name) {
1122:
1123: for (int attrH = getFirstAttribute(nodeHandle); DTM.NULL != attrH; attrH = getNextAttribute(attrH)) {
1124: String attrNS = getNamespaceURI(attrH);
1125: String attrName = getLocalName(attrH);
1126: boolean nsMatch = namespaceURI == attrNS
1127: || (namespaceURI != null && namespaceURI
1128: .equals(attrNS));
1129:
1130: if (nsMatch && name.equals(attrName))
1131: return attrH;
1132: }
1133:
1134: return DTM.NULL;
1135: }
1136:
1137: /**
1138: * Return the public identifier of the external subset,
1139: * normalized as described in 4.2.2 External Entities [XML]. If there is
1140: * no external subset or if it has no public identifier, this property
1141: * has no value.
1142: *
1143: * @return the public identifier String object, or null if there is none.
1144: */
1145: public String getDocumentTypeDeclarationPublicIdentifier() {
1146:
1147: /** @todo: implement this org.apache.xml.dtm.DTMDefaultBase abstract method */
1148: error(XMLMessages.createXMLMessage(
1149: XMLErrorResources.ER_METHOD_NOT_SUPPORTED, null));//"Not yet supported!");
1150:
1151: return null;
1152: }
1153:
1154: /**
1155: * Given a node handle, return its DOM-style namespace URI
1156: * (As defined in Namespaces, this is the declared URI which this node's
1157: * prefix -- or default in lieu thereof -- was mapped to.)
1158: *
1159: * <p>%REVIEW% Null or ""? -sb</p>
1160: *
1161: * @param nodeHandle the id of the node.
1162: * @return String URI value of this node's namespace, or null if no
1163: * namespace was resolved.
1164: */
1165: public String getNamespaceURI(int nodeHandle) {
1166:
1167: return m_expandedNameTable
1168: .getNamespace(_exptype(makeNodeIdentity(nodeHandle)));
1169: }
1170:
1171: /**
1172: * Get the string-value of a node as a String object
1173: * (see http://www.w3.org/TR/xpath#data-model
1174: * for the definition of a node's string-value).
1175: *
1176: * @param nodeHandle The node ID.
1177: *
1178: * @return A string object that represents the string-value of the given node.
1179: */
1180: public XMLString getStringValue(int nodeHandle) {
1181: int identity = makeNodeIdentity(nodeHandle);
1182: int type;
1183: if (identity == DTM.NULL) // Separate lines because I wanted to breakpoint it
1184: type = DTM.NULL;
1185: else
1186: type = _type(identity);
1187:
1188: if (isTextType(type)) {
1189: int dataIndex = _dataOrQName(identity);
1190: int offset = m_data.elementAt(dataIndex);
1191: int length = m_data.elementAt(dataIndex + 1);
1192:
1193: return m_xstrf.newstr(m_chars, offset, length);
1194: } else {
1195: int firstChild = _firstch(identity);
1196:
1197: if (DTM.NULL != firstChild) {
1198: int offset = -1;
1199: int length = 0;
1200: int startNode = identity;
1201:
1202: identity = firstChild;
1203:
1204: do {
1205: type = _type(identity);
1206:
1207: if (isTextType(type)) {
1208: int dataIndex = _dataOrQName(identity);
1209:
1210: if (-1 == offset) {
1211: offset = m_data.elementAt(dataIndex);
1212: }
1213:
1214: length += m_data.elementAt(dataIndex + 1);
1215: }
1216:
1217: identity = getNextNodeIdentity(identity);
1218: } while (DTM.NULL != identity
1219: && (_parent(identity) >= startNode));
1220:
1221: if (length > 0) {
1222: return m_xstrf.newstr(m_chars, offset, length);
1223: }
1224: } else if (type != DTM.ELEMENT_NODE) {
1225: int dataIndex = _dataOrQName(identity);
1226:
1227: if (dataIndex < 0) {
1228: dataIndex = -dataIndex;
1229: dataIndex = m_data.elementAt(dataIndex + 1);
1230: }
1231: return m_xstrf.newstr(m_valuesOrPrefixes
1232: .indexToString(dataIndex));
1233: }
1234: }
1235:
1236: return m_xstrf.emptystr();
1237: }
1238:
1239: /**
1240: * Determine if the string-value of a node is whitespace
1241: *
1242: * @param nodeHandle The node Handle.
1243: *
1244: * @return Return true if the given node is whitespace.
1245: */
1246: public boolean isWhitespace(int nodeHandle) {
1247: int identity = makeNodeIdentity(nodeHandle);
1248: int type;
1249: if (identity == DTM.NULL) // Separate lines because I wanted to breakpoint it
1250: type = DTM.NULL;
1251: else
1252: type = _type(identity);
1253:
1254: if (isTextType(type)) {
1255: int dataIndex = _dataOrQName(identity);
1256: int offset = m_data.elementAt(dataIndex);
1257: int length = m_data.elementAt(dataIndex + 1);
1258:
1259: return m_chars.isWhitespace(offset, length);
1260: }
1261: return false;
1262: }
1263:
1264: /**
1265: * Returns the <code>Element</code> whose <code>ID</code> is given by
1266: * <code>elementId</code>. If no such element exists, returns
1267: * <code>DTM.NULL</code>. Behavior is not defined if more than one element
1268: * has this <code>ID</code>. Attributes (including those
1269: * with the name "ID") are not of type ID unless so defined by DTD/Schema
1270: * information available to the DTM implementation.
1271: * Implementations that do not know whether attributes are of type ID or
1272: * not are expected to return <code>DTM.NULL</code>.
1273: *
1274: * <p>%REVIEW% Presumably IDs are still scoped to a single document,
1275: * and this operation searches only within a single document, right?
1276: * Wouldn't want collisions between DTMs in the same process.</p>
1277: *
1278: * @param elementId The unique <code>id</code> value for an element.
1279: * @return The handle of the matching element.
1280: */
1281: public int getElementById(String elementId) {
1282:
1283: Integer intObj;
1284: boolean isMore = true;
1285:
1286: do {
1287: intObj = (Integer) m_idAttributes.get(elementId);
1288:
1289: if (null != intObj)
1290: return makeNodeHandle(intObj.intValue());
1291:
1292: if (!isMore || m_endDocumentOccured)
1293: break;
1294:
1295: isMore = nextNode();
1296: } while (null == intObj);
1297:
1298: return DTM.NULL;
1299: }
1300:
1301: /**
1302: * Get a prefix either from the qname or from the uri mapping, or just make
1303: * one up!
1304: *
1305: * @param qname The qualified name, which may be null.
1306: * @param uri The namespace URI, which may be null.
1307: *
1308: * @return The prefix if there is one, or null.
1309: */
1310: public String getPrefix(String qname, String uri) {
1311:
1312: String prefix;
1313: int uriIndex = -1;
1314:
1315: if (null != uri && uri.length() > 0) {
1316:
1317: do {
1318: uriIndex = m_prefixMappings.indexOf(uri, ++uriIndex);
1319: } while ((uriIndex & 0x01) == 0);
1320:
1321: if (uriIndex >= 0) {
1322: prefix = (String) m_prefixMappings
1323: .elementAt(uriIndex - 1);
1324: } else if (null != qname) {
1325: int indexOfNSSep = qname.indexOf(':');
1326:
1327: if (qname.equals("xmlns"))
1328: prefix = "";
1329: else if (qname.startsWith("xmlns:"))
1330: prefix = qname.substring(indexOfNSSep + 1);
1331: else
1332: prefix = (indexOfNSSep > 0) ? qname.substring(0,
1333: indexOfNSSep) : null;
1334: } else {
1335: prefix = null;
1336: }
1337: } else if (null != qname) {
1338: int indexOfNSSep = qname.indexOf(':');
1339:
1340: if (indexOfNSSep > 0) {
1341: if (qname.startsWith("xmlns:"))
1342: prefix = qname.substring(indexOfNSSep + 1);
1343: else
1344: prefix = qname.substring(0, indexOfNSSep);
1345: } else {
1346: if (qname.equals("xmlns"))
1347: prefix = "";
1348: else
1349: prefix = null;
1350: }
1351: } else {
1352: prefix = null;
1353: }
1354:
1355: return prefix;
1356: }
1357:
1358: /**
1359: * Get a prefix either from the uri mapping, or just make
1360: * one up!
1361: *
1362: * @param uri The namespace URI, which may be null.
1363: *
1364: * @return The prefix if there is one, or null.
1365: */
1366: public int getIdForNamespace(String uri) {
1367:
1368: return m_valuesOrPrefixes.stringToIndex(uri);
1369:
1370: }
1371:
1372: /**
1373: * Get a prefix either from the qname or from the uri mapping, or just make
1374: * one up!
1375: *
1376: * @return The prefix if there is one, or null.
1377: */
1378: public String getNamespaceURI(String prefix) {
1379:
1380: String uri = "";
1381: int prefixIndex = m_contextIndexes.peek() - 1;
1382:
1383: if (null == prefix)
1384: prefix = "";
1385:
1386: do {
1387: prefixIndex = m_prefixMappings.indexOf(prefix,
1388: ++prefixIndex);
1389: } while ((prefixIndex >= 0) && (prefixIndex & 0x01) == 0x01);
1390:
1391: if (prefixIndex > -1) {
1392: uri = (String) m_prefixMappings.elementAt(prefixIndex + 1);
1393: }
1394:
1395: return uri;
1396: }
1397:
1398: /**
1399: * Set an ID string to node association in the ID table.
1400: *
1401: * @param id The ID string.
1402: * @param elem The associated element handle.
1403: */
1404: public void setIDAttribute(String id, int elem) {
1405: m_idAttributes.put(id, new Integer(elem));
1406: }
1407:
1408: /**
1409: * Check whether accumulated text should be stripped; if not,
1410: * append the appropriate flavor of text/cdata node.
1411: */
1412: protected void charactersFlush() {
1413:
1414: if (m_textPendingStart >= 0) // -1 indicates no-text-in-progress
1415: {
1416: int length = m_chars.size() - m_textPendingStart;
1417: boolean doStrip = false;
1418:
1419: if (getShouldStripWhitespace()) {
1420: doStrip = m_chars.isWhitespace(m_textPendingStart,
1421: length);
1422: }
1423:
1424: if (doStrip) {
1425: m_chars.setLength(m_textPendingStart); // Discard accumulated text
1426: } else {
1427: // Guard against characters/ignorableWhitespace events that
1428: // contained no characters. They should not result in a node.
1429: if (length > 0) {
1430: int exName = m_expandedNameTable
1431: .getExpandedTypeID(DTM.TEXT_NODE);
1432: int dataIndex = m_data.size();
1433:
1434: m_previous = addNode(m_coalescedTextType, exName,
1435: m_parents.peek(), m_previous, dataIndex,
1436: false);
1437:
1438: m_data.addElement(m_textPendingStart);
1439: m_data.addElement(length);
1440: }
1441: }
1442:
1443: // Reset for next text block
1444: m_textPendingStart = -1;
1445: m_textType = m_coalescedTextType = DTM.TEXT_NODE;
1446: }
1447: }
1448:
1449: ////////////////////////////////////////////////////////////////////
1450: // Implementation of the EntityResolver interface.
1451: ////////////////////////////////////////////////////////////////////
1452:
1453: /**
1454: * Resolve an external entity.
1455: *
1456: * <p>Always return null, so that the parser will use the system
1457: * identifier provided in the XML document. This method implements
1458: * the SAX default behaviour: application writers can override it
1459: * in a subclass to do special translations such as catalog lookups
1460: * or URI redirection.</p>
1461: *
1462: * @param publicId The public identifer, or null if none is
1463: * available.
1464: * @param systemId The system identifier provided in the XML
1465: * document.
1466: * @return The new input source, or null to require the
1467: * default behaviour.
1468: * @throws SAXException Any SAX exception, possibly
1469: * wrapping another exception.
1470: * @see org.xml.sax.EntityResolver#resolveEntity
1471: *
1472: * @throws SAXException
1473: */
1474: public InputSource resolveEntity(String publicId, String systemId)
1475: throws SAXException {
1476: return null;
1477: }
1478:
1479: ////////////////////////////////////////////////////////////////////
1480: // Implementation of DTDHandler interface.
1481: ////////////////////////////////////////////////////////////////////
1482:
1483: /**
1484: * Receive notification of a notation declaration.
1485: *
1486: * <p>By default, do nothing. Application writers may override this
1487: * method in a subclass if they wish to keep track of the notations
1488: * declared in a document.</p>
1489: *
1490: * @param name The notation name.
1491: * @param publicId The notation public identifier, or null if not
1492: * available.
1493: * @param systemId The notation system identifier.
1494: * @throws SAXException Any SAX exception, possibly
1495: * wrapping another exception.
1496: * @see org.xml.sax.DTDHandler#notationDecl
1497: *
1498: * @throws SAXException
1499: */
1500: public void notationDecl(String name, String publicId,
1501: String systemId) throws SAXException {
1502:
1503: // no op
1504: }
1505:
1506: /**
1507: * Receive notification of an unparsed entity declaration.
1508: *
1509: * <p>By default, do nothing. Application writers may override this
1510: * method in a subclass to keep track of the unparsed entities
1511: * declared in a document.</p>
1512: *
1513: * @param name The entity name.
1514: * @param publicId The entity public identifier, or null if not
1515: * available.
1516: * @param systemId The entity system identifier.
1517: * @param notationName The name of the associated notation.
1518: * @throws SAXException Any SAX exception, possibly
1519: * wrapping another exception.
1520: * @see org.xml.sax.DTDHandler#unparsedEntityDecl
1521: *
1522: * @throws SAXException
1523: */
1524: public void unparsedEntityDecl(String name, String publicId,
1525: String systemId, String notationName) throws SAXException {
1526:
1527: if (null == m_entities) {
1528: m_entities = new Vector();
1529: }
1530:
1531: try {
1532: systemId = SystemIDResolver.getAbsoluteURI(systemId,
1533: getDocumentBaseURI());
1534: } catch (Exception e) {
1535: throw new org.xml.sax.SAXException(e);
1536: }
1537:
1538: // private static final int ENTITY_FIELD_PUBLICID = 0;
1539: m_entities.addElement(publicId);
1540:
1541: // private static final int ENTITY_FIELD_SYSTEMID = 1;
1542: m_entities.addElement(systemId);
1543:
1544: // private static final int ENTITY_FIELD_NOTATIONNAME = 2;
1545: m_entities.addElement(notationName);
1546:
1547: // private static final int ENTITY_FIELD_NAME = 3;
1548: m_entities.addElement(name);
1549: }
1550:
1551: ////////////////////////////////////////////////////////////////////
1552: // Implementation of ContentHandler interface.
1553: ////////////////////////////////////////////////////////////////////
1554:
1555: /**
1556: * Receive a Locator object for document events.
1557: *
1558: * <p>By default, do nothing. Application writers may override this
1559: * method in a subclass if they wish to store the locator for use
1560: * with other document events.</p>
1561: *
1562: * @param locator A locator for all SAX document events.
1563: * @see org.xml.sax.ContentHandler#setDocumentLocator
1564: * @see org.xml.sax.Locator
1565: */
1566: public void setDocumentLocator(Locator locator) {
1567: m_locator = locator;
1568: m_systemId = locator.getSystemId();
1569: }
1570:
1571: /**
1572: * Receive notification of the beginning of the document.
1573: *
1574: * @throws SAXException Any SAX exception, possibly
1575: * wrapping another exception.
1576: * @see org.xml.sax.ContentHandler#startDocument
1577: */
1578: public void startDocument() throws SAXException {
1579: if (DEBUG)
1580: System.out.println("startDocument");
1581:
1582: int doc = addNode(DTM.DOCUMENT_NODE, m_expandedNameTable
1583: .getExpandedTypeID(DTM.DOCUMENT_NODE), DTM.NULL,
1584: DTM.NULL, 0, true);
1585:
1586: m_parents.push(doc);
1587: m_previous = DTM.NULL;
1588:
1589: m_contextIndexes.push(m_prefixMappings.size()); // for the next element.
1590: }
1591:
1592: /**
1593: * Receive notification of the end of the document.
1594: *
1595: * @throws SAXException Any SAX exception, possibly
1596: * wrapping another exception.
1597: * @see org.xml.sax.ContentHandler#endDocument
1598: */
1599: public void endDocument() throws SAXException {
1600: if (DEBUG)
1601: System.out.println("endDocument");
1602:
1603: charactersFlush();
1604:
1605: m_nextsib.setElementAt(NULL, 0);
1606:
1607: if (m_firstch.elementAt(0) == NOTPROCESSED)
1608: m_firstch.setElementAt(NULL, 0);
1609:
1610: if (DTM.NULL != m_previous)
1611: m_nextsib.setElementAt(DTM.NULL, m_previous);
1612:
1613: m_parents = null;
1614: m_prefixMappings = null;
1615: m_contextIndexes = null;
1616:
1617: m_endDocumentOccured = true;
1618:
1619: // Bugzilla 4858: throw away m_locator. we cache m_systemId
1620: m_locator = null;
1621: }
1622:
1623: /**
1624: * Receive notification of the start of a Namespace mapping.
1625: *
1626: * <p>By default, do nothing. Application writers may override this
1627: * method in a subclass to take specific actions at the start of
1628: * each Namespace prefix scope (such as storing the prefix mapping).</p>
1629: *
1630: * @param prefix The Namespace prefix being declared.
1631: * @param uri The Namespace URI mapped to the prefix.
1632: * @throws SAXException Any SAX exception, possibly
1633: * wrapping another exception.
1634: * @see org.xml.sax.ContentHandler#startPrefixMapping
1635: */
1636: public void startPrefixMapping(String prefix, String uri)
1637: throws SAXException {
1638:
1639: if (DEBUG)
1640: System.out.println("startPrefixMapping: prefix: " + prefix
1641: + ", uri: " + uri);
1642:
1643: if (null == prefix)
1644: prefix = "";
1645: m_prefixMappings.addElement(prefix); // JDK 1.1.x compat -sc
1646: m_prefixMappings.addElement(uri); // JDK 1.1.x compat -sc
1647: }
1648:
1649: /**
1650: * Receive notification of the end of a Namespace mapping.
1651: *
1652: * <p>By default, do nothing. Application writers may override this
1653: * method in a subclass to take specific actions at the end of
1654: * each prefix mapping.</p>
1655: *
1656: * @param prefix The Namespace prefix being declared.
1657: * @throws SAXException Any SAX exception, possibly
1658: * wrapping another exception.
1659: * @see org.xml.sax.ContentHandler#endPrefixMapping
1660: */
1661: public void endPrefixMapping(String prefix) throws SAXException {
1662: if (DEBUG)
1663: System.out.println("endPrefixMapping: prefix: " + prefix);
1664:
1665: if (null == prefix)
1666: prefix = "";
1667:
1668: int index = m_contextIndexes.peek() - 1;
1669:
1670: do {
1671: index = m_prefixMappings.indexOf(prefix, ++index);
1672: } while ((index >= 0) && ((index & 0x01) == 0x01));
1673:
1674: if (index > -1) {
1675: m_prefixMappings.setElementAt("%@$#^@#", index);
1676: m_prefixMappings.setElementAt("%@$#^@#", index + 1);
1677: }
1678:
1679: // no op
1680: }
1681:
1682: /**
1683: * Check if a declaration has already been made for a given prefix.
1684: *
1685: * @param prefix non-null prefix string.
1686: *
1687: * @return true if the declaration has already been declared in the
1688: * current context.
1689: */
1690: protected boolean declAlreadyDeclared(String prefix) {
1691:
1692: int startDecls = m_contextIndexes.peek();
1693: java.util.Vector prefixMappings = m_prefixMappings;
1694: int nDecls = prefixMappings.size();
1695:
1696: for (int i = startDecls; i < nDecls; i += 2) {
1697: String prefixDecl = (String) prefixMappings.elementAt(i);
1698:
1699: if (prefixDecl == null)
1700: continue;
1701:
1702: if (prefixDecl.equals(prefix))
1703: return true;
1704: }
1705:
1706: return false;
1707: }
1708:
1709: boolean m_pastFirstElement = false;
1710:
1711: /**
1712: * Receive notification of the start of an element.
1713: *
1714: * <p>By default, do nothing. Application writers may override this
1715: * method in a subclass to take specific actions at the start of
1716: * each element (such as allocating a new tree node or writing
1717: * output to a file).</p>
1718: *
1719: * @param uri The Namespace URI, or the empty string if the
1720: * element has no Namespace URI or if Namespace
1721: * processing is not being performed.
1722: * @param localName The local name (without prefix), or the
1723: * empty string if Namespace processing is not being
1724: * performed.
1725: * @param qName The qualified name (with prefix), or the
1726: * empty string if qualified names are not available.
1727: * @param attributes The specified or defaulted attributes.
1728: * @throws SAXException Any SAX exception, possibly
1729: * wrapping another exception.
1730: * @see org.xml.sax.ContentHandler#startElement
1731: */
1732: public void startElement(String uri, String localName,
1733: String qName, Attributes attributes) throws SAXException {
1734: if (DEBUG) {
1735: System.out.println("startElement: uri: " + uri
1736: + ", localname: " + localName + ", qname: " + qName
1737: + ", atts: " + attributes);
1738:
1739: boolean DEBUG_ATTRS = true;
1740: if (DEBUG_ATTRS & attributes != null) {
1741: int n = attributes.getLength();
1742: if (n == 0)
1743: System.out.println("\tempty attribute list");
1744: else
1745: for (int i = 0; i < n; i++)
1746: System.out.println("\t attr: uri: "
1747: + attributes.getURI(i)
1748: + ", localname: "
1749: + attributes.getLocalName(i)
1750: + ", qname: " + attributes.getQName(i)
1751: + ", type: " + attributes.getType(i)
1752: + ", value: " + attributes.getValue(i));
1753: }
1754: }
1755:
1756: charactersFlush();
1757:
1758: int exName = m_expandedNameTable.getExpandedTypeID(uri,
1759: localName, DTM.ELEMENT_NODE);
1760: String prefix = getPrefix(qName, uri);
1761: int prefixIndex = (null != prefix) ? m_valuesOrPrefixes
1762: .stringToIndex(qName) : 0;
1763:
1764: int elemNode = addNode(DTM.ELEMENT_NODE, exName, m_parents
1765: .peek(), m_previous, prefixIndex, true);
1766:
1767: if (m_indexing)
1768: indexNode(exName, elemNode);
1769:
1770: m_parents.push(elemNode);
1771:
1772: int startDecls = m_contextIndexes.peek();
1773: int nDecls = m_prefixMappings.size();
1774: int prev = DTM.NULL;
1775:
1776: if (!m_pastFirstElement) {
1777: // SPECIAL CASE: Implied declaration at root element
1778: prefix = "xml";
1779: String declURL = "http://www.w3.org/XML/1998/namespace";
1780: exName = m_expandedNameTable.getExpandedTypeID(null,
1781: prefix, DTM.NAMESPACE_NODE);
1782: int val = m_valuesOrPrefixes.stringToIndex(declURL);
1783: prev = addNode(DTM.NAMESPACE_NODE, exName, elemNode, prev,
1784: val, false);
1785: m_pastFirstElement = true;
1786: }
1787:
1788: for (int i = startDecls; i < nDecls; i += 2) {
1789: prefix = (String) m_prefixMappings.elementAt(i);
1790:
1791: if (prefix == null)
1792: continue;
1793:
1794: String declURL = (String) m_prefixMappings.elementAt(i + 1);
1795:
1796: exName = m_expandedNameTable.getExpandedTypeID(null,
1797: prefix, DTM.NAMESPACE_NODE);
1798:
1799: int val = m_valuesOrPrefixes.stringToIndex(declURL);
1800:
1801: prev = addNode(DTM.NAMESPACE_NODE, exName, elemNode, prev,
1802: val, false);
1803: }
1804:
1805: int n = attributes.getLength();
1806:
1807: for (int i = 0; i < n; i++) {
1808: String attrUri = attributes.getURI(i);
1809: String attrQName = attributes.getQName(i);
1810: String valString = attributes.getValue(i);
1811:
1812: prefix = getPrefix(attrQName, attrUri);
1813:
1814: int nodeType;
1815:
1816: String attrLocalName = attributes.getLocalName(i);
1817:
1818: if ((null != attrQName)
1819: && (attrQName.equals("xmlns") || attrQName
1820: .startsWith("xmlns:"))) {
1821: if (declAlreadyDeclared(prefix))
1822: continue; // go to the next attribute.
1823:
1824: nodeType = DTM.NAMESPACE_NODE;
1825: } else {
1826: nodeType = DTM.ATTRIBUTE_NODE;
1827:
1828: if (attributes.getType(i).equalsIgnoreCase("ID"))
1829: setIDAttribute(valString, elemNode);
1830: }
1831:
1832: // Bit of a hack... if somehow valString is null, stringToIndex will
1833: // return -1, which will make things very unhappy.
1834: if (null == valString)
1835: valString = "";
1836:
1837: int val = m_valuesOrPrefixes.stringToIndex(valString);
1838: //String attrLocalName = attributes.getLocalName(i);
1839:
1840: if (null != prefix) {
1841:
1842: prefixIndex = m_valuesOrPrefixes
1843: .stringToIndex(attrQName);
1844:
1845: int dataIndex = m_data.size();
1846:
1847: m_data.addElement(prefixIndex);
1848: m_data.addElement(val);
1849:
1850: val = -dataIndex;
1851: }
1852:
1853: exName = m_expandedNameTable.getExpandedTypeID(attrUri,
1854: attrLocalName, nodeType);
1855: prev = addNode(nodeType, exName, elemNode, prev, val, false);
1856: }
1857:
1858: if (DTM.NULL != prev)
1859: m_nextsib.setElementAt(DTM.NULL, prev);
1860:
1861: if (null != m_wsfilter) {
1862: short wsv = m_wsfilter.getShouldStripSpace(
1863: makeNodeHandle(elemNode), this );
1864: boolean shouldStrip = (DTMWSFilter.INHERIT == wsv) ? getShouldStripWhitespace()
1865: : (DTMWSFilter.STRIP == wsv);
1866:
1867: pushShouldStripWhitespace(shouldStrip);
1868: }
1869:
1870: m_previous = DTM.NULL;
1871:
1872: m_contextIndexes.push(m_prefixMappings.size()); // for the children.
1873: }
1874:
1875: /**
1876: * Receive notification of the end of an element.
1877: *
1878: * <p>By default, do nothing. Application writers may override this
1879: * method in a subclass to take specific actions at the end of
1880: * each element (such as finalising a tree node or writing
1881: * output to a file).</p>
1882: *
1883: * @param uri The Namespace URI, or the empty string if the
1884: * element has no Namespace URI or if Namespace
1885: * processing is not being performed.
1886: * @param localName The local name (without prefix), or the
1887: * empty string if Namespace processing is not being
1888: * performed.
1889: * @param qName The qualified XML 1.0 name (with prefix), or the
1890: * empty string if qualified names are not available.
1891: * @throws SAXException Any SAX exception, possibly
1892: * wrapping another exception.
1893: * @see org.xml.sax.ContentHandler#endElement
1894: */
1895: public void endElement(String uri, String localName, String qName)
1896: throws SAXException {
1897: if (DEBUG)
1898: System.out
1899: .println("endElement: uri: " + uri
1900: + ", localname: " + localName + ", qname: "
1901: + qName);
1902:
1903: charactersFlush();
1904:
1905: // If no one noticed, startPrefixMapping is a drag.
1906: // Pop the context for the last child (the one pushed by startElement)
1907: m_contextIndexes.quickPop(1);
1908:
1909: // Do it again for this one (the one pushed by the last endElement).
1910: int topContextIndex = m_contextIndexes.peek();
1911: if (topContextIndex != m_prefixMappings.size()) {
1912: m_prefixMappings.setSize(topContextIndex);
1913: }
1914:
1915: int lastNode = m_previous;
1916:
1917: m_previous = m_parents.pop();
1918:
1919: // If lastNode is still DTM.NULL, this element had no children
1920: if (DTM.NULL == lastNode)
1921: m_firstch.setElementAt(DTM.NULL, m_previous);
1922: else
1923: m_nextsib.setElementAt(DTM.NULL, lastNode);
1924:
1925: popShouldStripWhitespace();
1926: }
1927:
1928: /**
1929: * Receive notification of character data inside an element.
1930: *
1931: * <p>By default, do nothing. Application writers may override this
1932: * method to take specific actions for each chunk of character data
1933: * (such as adding the data to a node or buffer, or printing it to
1934: * a file).</p>
1935: *
1936: * @param ch The characters.
1937: * @param start The start position in the character array.
1938: * @param length The number of characters to use from the
1939: * character array.
1940: * @throws SAXException Any SAX exception, possibly
1941: * wrapping another exception.
1942: * @see org.xml.sax.ContentHandler#characters
1943: */
1944: public void characters(char ch[], int start, int length)
1945: throws SAXException {
1946: if (m_textPendingStart == -1) // First one in this block
1947: {
1948: m_textPendingStart = m_chars.size();
1949: m_coalescedTextType = m_textType;
1950: }
1951: // Type logic: If all adjacent text is CDATASections, the
1952: // concatentated text is treated as a single CDATASection (see
1953: // initialization above). If any were ordinary Text, the whole
1954: // thing is treated as Text. This may be worth %REVIEW%ing.
1955: else if (m_textType == DTM.TEXT_NODE) {
1956: m_coalescedTextType = DTM.TEXT_NODE;
1957: }
1958:
1959: m_chars.append(ch, start, length);
1960: }
1961:
1962: /**
1963: * Receive notification of ignorable whitespace in element content.
1964: *
1965: * <p>By default, do nothing. Application writers may override this
1966: * method to take specific actions for each chunk of ignorable
1967: * whitespace (such as adding data to a node or buffer, or printing
1968: * it to a file).</p>
1969: *
1970: * @param ch The whitespace characters.
1971: * @param start The start position in the character array.
1972: * @param length The number of characters to use from the
1973: * character array.
1974: * @throws SAXException Any SAX exception, possibly
1975: * wrapping another exception.
1976: * @see org.xml.sax.ContentHandler#ignorableWhitespace
1977: */
1978: public void ignorableWhitespace(char ch[], int start, int length)
1979: throws SAXException {
1980:
1981: // %OPT% We can probably take advantage of the fact that we know this
1982: // is whitespace.
1983: characters(ch, start, length);
1984: }
1985:
1986: /**
1987: * Receive notification of a processing instruction.
1988: *
1989: * <p>By default, do nothing. Application writers may override this
1990: * method in a subclass to take specific actions for each
1991: * processing instruction, such as setting status variables or
1992: * invoking other methods.</p>
1993: *
1994: * @param target The processing instruction target.
1995: * @param data The processing instruction data, or null if
1996: * none is supplied.
1997: * @throws SAXException Any SAX exception, possibly
1998: * wrapping another exception.
1999: * @see org.xml.sax.ContentHandler#processingInstruction
2000: */
2001: public void processingInstruction(String target, String data)
2002: throws SAXException {
2003: if (DEBUG)
2004: System.out.println("processingInstruction: target: "
2005: + target + ", data: " + data);
2006:
2007: charactersFlush();
2008:
2009: int exName = m_expandedNameTable.getExpandedTypeID(null,
2010: target, DTM.PROCESSING_INSTRUCTION_NODE);
2011: int dataIndex = m_valuesOrPrefixes.stringToIndex(data);
2012:
2013: m_previous = addNode(DTM.PROCESSING_INSTRUCTION_NODE, exName,
2014: m_parents.peek(), m_previous, dataIndex, false);
2015: }
2016:
2017: /**
2018: * Receive notification of a skipped entity.
2019: *
2020: * <p>By default, do nothing. Application writers may override this
2021: * method in a subclass to take specific actions for each
2022: * processing instruction, such as setting status variables or
2023: * invoking other methods.</p>
2024: *
2025: * @param name The name of the skipped entity.
2026: * @throws SAXException Any SAX exception, possibly
2027: * wrapping another exception.
2028: * @see org.xml.sax.ContentHandler#processingInstruction
2029: */
2030: public void skippedEntity(String name) throws SAXException {
2031:
2032: // %REVIEW% What should be done here?
2033: // no op
2034: }
2035:
2036: ////////////////////////////////////////////////////////////////////
2037: // Implementation of the ErrorHandler interface.
2038: ////////////////////////////////////////////////////////////////////
2039:
2040: /**
2041: * Receive notification of a parser warning.
2042: *
2043: * <p>The default implementation does nothing. Application writers
2044: * may override this method in a subclass to take specific actions
2045: * for each warning, such as inserting the message in a log file or
2046: * printing it to the console.</p>
2047: *
2048: * @param e The warning information encoded as an exception.
2049: * @throws SAXException Any SAX exception, possibly
2050: * wrapping another exception.
2051: * @see org.xml.sax.ErrorHandler#warning
2052: * @see org.xml.sax.SAXParseException
2053: */
2054: public void warning(SAXParseException e) throws SAXException {
2055:
2056: // %REVIEW% Is there anyway to get the JAXP error listener here?
2057: System.err.println(e.getMessage());
2058: }
2059:
2060: /**
2061: * Receive notification of a recoverable parser error.
2062: *
2063: * <p>The default implementation does nothing. Application writers
2064: * may override this method in a subclass to take specific actions
2065: * for each error, such as inserting the message in a log file or
2066: * printing it to the console.</p>
2067: *
2068: * @param e The warning information encoded as an exception.
2069: * @throws SAXException Any SAX exception, possibly
2070: * wrapping another exception.
2071: * @see org.xml.sax.ErrorHandler#warning
2072: * @see org.xml.sax.SAXParseException
2073: */
2074: public void error(SAXParseException e) throws SAXException {
2075: throw e;
2076: }
2077:
2078: /**
2079: * Report a fatal XML parsing error.
2080: *
2081: * <p>The default implementation throws a SAXParseException.
2082: * Application writers may override this method in a subclass if
2083: * they need to take specific actions for each fatal error (such as
2084: * collecting all of the errors into a single report): in any case,
2085: * the application must stop all regular processing when this
2086: * method is invoked, since the document is no longer reliable, and
2087: * the parser may no longer report parsing events.</p>
2088: *
2089: * @param e The error information encoded as an exception.
2090: * @throws SAXException Any SAX exception, possibly
2091: * wrapping another exception.
2092: * @see org.xml.sax.ErrorHandler#fatalError
2093: * @see org.xml.sax.SAXParseException
2094: */
2095: public void fatalError(SAXParseException e) throws SAXException {
2096: throw e;
2097: }
2098:
2099: ////////////////////////////////////////////////////////////////////
2100: // Implementation of the DeclHandler interface.
2101: ////////////////////////////////////////////////////////////////////
2102:
2103: /**
2104: * Report an element type declaration.
2105: *
2106: * <p>The content model will consist of the string "EMPTY", the
2107: * string "ANY", or a parenthesised group, optionally followed
2108: * by an occurrence indicator. The model will be normalized so
2109: * that all whitespace is removed,and will include the enclosing
2110: * parentheses.</p>
2111: *
2112: * @param name The element type name.
2113: * @param model The content model as a normalized string.
2114: * @throws SAXException The application may raise an exception.
2115: */
2116: public void elementDecl(String name, String model)
2117: throws SAXException {
2118:
2119: // no op
2120: }
2121:
2122: /**
2123: * Report an attribute type declaration.
2124: *
2125: * <p>Only the effective (first) declaration for an attribute will
2126: * be reported. The type will be one of the strings "CDATA",
2127: * "ID", "IDREF", "IDREFS", "NMTOKEN", "NMTOKENS", "ENTITY",
2128: * "ENTITIES", or "NOTATION", or a parenthesized token group with
2129: * the separator "|" and all whitespace removed.</p>
2130: *
2131: * @param eName The name of the associated element.
2132: * @param aName The name of the attribute.
2133: * @param type A string representing the attribute type.
2134: * @param valueDefault A string representing the attribute default
2135: * ("#IMPLIED", "#REQUIRED", or "#FIXED") or null if
2136: * none of these applies.
2137: * @param value A string representing the attribute's default value,
2138: * or null if there is none.
2139: * @throws SAXException The application may raise an exception.
2140: */
2141: public void attributeDecl(String eName, String aName, String type,
2142: String valueDefault, String value) throws SAXException {
2143:
2144: // no op
2145: }
2146:
2147: /**
2148: * Report an internal entity declaration.
2149: *
2150: * <p>Only the effective (first) declaration for each entity
2151: * will be reported.</p>
2152: *
2153: * @param name The name of the entity. If it is a parameter
2154: * entity, the name will begin with '%'.
2155: * @param value The replacement text of the entity.
2156: * @throws SAXException The application may raise an exception.
2157: * @see #externalEntityDecl
2158: * @see org.xml.sax.DTDHandler#unparsedEntityDecl
2159: */
2160: public void internalEntityDecl(String name, String value)
2161: throws SAXException {
2162:
2163: // no op
2164: }
2165:
2166: /**
2167: * Report a parsed external entity declaration.
2168: *
2169: * <p>Only the effective (first) declaration for each entity
2170: * will be reported.</p>
2171: *
2172: * @param name The name of the entity. If it is a parameter
2173: * entity, the name will begin with '%'.
2174: * @param publicId The declared public identifier of the entity, or
2175: * null if none was declared.
2176: * @param systemId The declared system identifier of the entity.
2177: * @throws SAXException The application may raise an exception.
2178: * @see #internalEntityDecl
2179: * @see org.xml.sax.DTDHandler#unparsedEntityDecl
2180: */
2181: public void externalEntityDecl(String name, String publicId,
2182: String systemId) throws SAXException {
2183:
2184: // no op
2185: }
2186:
2187: ////////////////////////////////////////////////////////////////////
2188: // Implementation of the LexicalHandler interface.
2189: ////////////////////////////////////////////////////////////////////
2190:
2191: /**
2192: * Report the start of DTD declarations, if any.
2193: *
2194: * <p>Any declarations are assumed to be in the internal subset
2195: * unless otherwise indicated by a {@link #startEntity startEntity}
2196: * event.</p>
2197: *
2198: * <p>Note that the start/endDTD events will appear within
2199: * the start/endDocument events from ContentHandler and
2200: * before the first startElement event.</p>
2201: *
2202: * @param name The document type name.
2203: * @param publicId The declared public identifier for the
2204: * external DTD subset, or null if none was declared.
2205: * @param systemId The declared system identifier for the
2206: * external DTD subset, or null if none was declared.
2207: * @throws SAXException The application may raise an
2208: * exception.
2209: * @see #endDTD
2210: * @see #startEntity
2211: */
2212: public void startDTD(String name, String publicId, String systemId)
2213: throws SAXException {
2214:
2215: m_insideDTD = true;
2216: }
2217:
2218: /**
2219: * Report the end of DTD declarations.
2220: *
2221: * @throws SAXException The application may raise an exception.
2222: * @see #startDTD
2223: */
2224: public void endDTD() throws SAXException {
2225:
2226: m_insideDTD = false;
2227: }
2228:
2229: /**
2230: * Report the beginning of an entity in content.
2231: *
2232: * <p><strong>NOTE:</entity> entity references in attribute
2233: * values -- and the start and end of the document entity --
2234: * are never reported.</p>
2235: *
2236: * <p>The start and end of the external DTD subset are reported
2237: * using the pseudo-name "[dtd]". All other events must be
2238: * properly nested within start/end entity events.</p>
2239: *
2240: * <p>Note that skipped entities will be reported through the
2241: * {@link org.xml.sax.ContentHandler#skippedEntity skippedEntity}
2242: * event, which is part of the ContentHandler interface.</p>
2243: *
2244: * @param name The name of the entity. If it is a parameter
2245: * entity, the name will begin with '%'.
2246: * @throws SAXException The application may raise an exception.
2247: * @see #endEntity
2248: * @see org.xml.sax.ext.DeclHandler#internalEntityDecl
2249: * @see org.xml.sax.ext.DeclHandler#externalEntityDecl
2250: */
2251: public void startEntity(String name) throws SAXException {
2252:
2253: // no op
2254: }
2255:
2256: /**
2257: * Report the end of an entity.
2258: *
2259: * @param name The name of the entity that is ending.
2260: * @throws SAXException The application may raise an exception.
2261: * @see #startEntity
2262: */
2263: public void endEntity(String name) throws SAXException {
2264:
2265: // no op
2266: }
2267:
2268: /**
2269: * Report the start of a CDATA section.
2270: *
2271: * <p>The contents of the CDATA section will be reported through
2272: * the regular {@link org.xml.sax.ContentHandler#characters
2273: * characters} event.</p>
2274: *
2275: * @throws SAXException The application may raise an exception.
2276: * @see #endCDATA
2277: */
2278: public void startCDATA() throws SAXException {
2279: m_textType = DTM.CDATA_SECTION_NODE;
2280: }
2281:
2282: /**
2283: * Report the end of a CDATA section.
2284: *
2285: * @throws SAXException The application may raise an exception.
2286: * @see #startCDATA
2287: */
2288: public void endCDATA() throws SAXException {
2289: m_textType = DTM.TEXT_NODE;
2290: }
2291:
2292: /**
2293: * Report an XML comment anywhere in the document.
2294: *
2295: * <p>This callback will be used for comments inside or outside the
2296: * document element, including comments in the external DTD
2297: * subset (if read).</p>
2298: *
2299: * @param ch An array holding the characters in the comment.
2300: * @param start The starting position in the array.
2301: * @param length The number of characters to use from the array.
2302: * @throws SAXException The application may raise an exception.
2303: */
2304: public void comment(char ch[], int start, int length)
2305: throws SAXException {
2306:
2307: if (m_insideDTD) // ignore comments if we're inside the DTD
2308: return;
2309:
2310: charactersFlush();
2311:
2312: int exName = m_expandedNameTable
2313: .getExpandedTypeID(DTM.COMMENT_NODE);
2314:
2315: // For now, treat comments as strings... I guess we should do a
2316: // seperate FSB buffer instead.
2317: int dataIndex = m_valuesOrPrefixes.stringToIndex(new String(ch,
2318: start, length));
2319:
2320: m_previous = addNode(DTM.COMMENT_NODE, exName,
2321: m_parents.peek(), m_previous, dataIndex, false);
2322: }
2323:
2324: /**
2325: * Set a run time property for this DTM instance.
2326: *
2327: * %REVIEW% Now that we no longer use this method to support
2328: * getSourceLocatorFor, can we remove it?
2329: *
2330: * @param property a <code>String</code> value
2331: * @param value an <code>Object</code> value
2332: */
2333: public void setProperty(String property, Object value) {
2334: }
2335:
2336: /** Retrieve the SourceLocator associated with a specific node.
2337: * This is only meaningful if the XalanProperties.SOURCE_LOCATION flag was
2338: * set True using setProperty; if it was never set, or was set false, we
2339: * will return null.
2340: *
2341: * (We _could_ return a locator with the document's base URI and bogus
2342: * line/column information. Trying that; see the else clause.)
2343: * */
2344: public SourceLocator getSourceLocatorFor(int node) {
2345: if (m_useSourceLocationProperty) {
2346:
2347: node = makeNodeIdentity(node);
2348:
2349: return new NodeLocator(null, m_sourceSystemId
2350: .elementAt(node), m_sourceLine.elementAt(node),
2351: m_sourceColumn.elementAt(node));
2352: } else if (m_locator != null) {
2353: return new NodeLocator(null, m_locator.getSystemId(), -1,
2354: -1);
2355: } else if (m_systemId != null) {
2356: return new NodeLocator(null, m_systemId, -1, -1);
2357: }
2358: return null;
2359: }
2360:
2361: public String getFixedNames(int type) {
2362: return m_fixednames[type];
2363: }
2364: }
|