/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * $Id: SAX2DTM.java 468653 2006-10-28 07:07:05Z minchau $ */ package org.apache.xml.dtm.ref.sax2dtm; import java.util.Hashtable; import java.util.Vector; import javax.xml.transform.Source; import javax.xml.transform.SourceLocator; import org.apache.xml.dtm.*; import org.apache.xml.dtm.ref.*; import org.apache.xml.utils.StringVector; import org.apache.xml.utils.IntVector; import org.apache.xml.utils.FastStringBuffer; import org.apache.xml.utils.IntStack; import org.apache.xml.utils.SuballocatedIntVector; import org.apache.xml.utils.SystemIDResolver; import org.apache.xml.utils.WrappedRuntimeException; import org.apache.xml.utils.XMLString; import org.apache.xml.utils.XMLStringFactory; import org.apache.xml.res.XMLErrorResources; import org.apache.xml.res.XMLMessages; import org.xml.sax.*; import org.xml.sax.ext.*; /** * This class implements a DTM that tends to be optimized more for speed than * for compactness, that is constructed via SAX2 ContentHandler events. */ public class SAX2DTM extends DTMDefaultBaseIterators implements EntityResolver, DTDHandler, ContentHandler, ErrorHandler, DeclHandler, LexicalHandler { /** Set true to monitor SAX events and similar diagnostic info. */ private static final boolean DEBUG = false; /** * If we're building the model incrementally on demand, we need to * be able to tell the source when to send us more data. * * Note that if this has not been set, and you attempt to read ahead * of the current build point, we'll probably throw a null-pointer * exception. We could try to wait-and-retry instead, as a very poor * fallback, but that has all the known problems with multithreading * on multiprocessors and we Don't Want to Go There. * * @see setIncrementalSAXSource */ private IncrementalSAXSource m_incrementalSAXSource = null; /** * All the character content, including attribute values, are stored in * this buffer. * * %REVIEW% Should this have an option of being shared across DTMs? * Sequentially only; not threadsafe... Currently, I think not. * * %REVIEW% Initial size was pushed way down to reduce weight of RTFs. * pending reduction in number of RTF DTMs. Now that we're sharing a DTM * between RTFs, and tail-pruning... consider going back to the larger/faster. * * Made protected rather than private so SAX2RTFDTM can access it. */ //private FastStringBuffer m_chars = new FastStringBuffer(13, 13); protected FastStringBuffer m_chars; /** This vector holds offset and length data. */ protected SuballocatedIntVector m_data; /** The parent stack, needed only for construction. * Made protected rather than private so SAX2RTFDTM can access it. */ transient protected IntStack m_parents; /** The current previous node, needed only for construction time. * Made protected rather than private so SAX2RTFDTM can access it. */ transient protected int m_previous = 0; /** Namespace support, only relevent at construction time. * Made protected rather than private so SAX2RTFDTM can access it. */ transient protected java.util.Vector m_prefixMappings = new java.util.Vector(); /** Namespace support, only relevent at construction time. * Made protected rather than private so SAX2RTFDTM can access it. */ transient protected IntStack m_contextIndexes; /** Type of next characters() event within text block in prgress. */ transient protected int m_textType = DTM.TEXT_NODE; /** * Type of coalesced text block. See logic in the characters() * method. */ transient protected int m_coalescedTextType = DTM.TEXT_NODE; /** The SAX Document locator */ transient protected Locator m_locator = null; /** The SAX Document system-id */ transient private String m_systemId = null; /** We are inside the DTD. This is used for ignoring comments. */ transient protected boolean m_insideDTD = false; /** Tree Walker for dispatchToEvents. */ protected DTMTreeWalker m_walker = new DTMTreeWalker(); /** pool of string values that come as strings. */ protected DTMStringPool m_valuesOrPrefixes; /** End document has been reached. * Made protected rather than private so SAX2RTFDTM can access it. */ protected boolean m_endDocumentOccured = false; /** Data or qualified name values, one array element for each node. */ protected SuballocatedIntVector m_dataOrQName; /** * This table holds the ID string to node associations, for * XML IDs. */ protected Hashtable m_idAttributes = new Hashtable(); /** * fixed dom-style names. */ private static final String[] m_fixednames = { null, null, // nothing, Element null, "#text", // Attr, Text "#cdata_section", null, // CDATA, EntityReference null, null, // Entity, PI "#comment", "#document", // Comment, Document null, "#document-fragment", // Doctype, DocumentFragment null }; // Notation /** * Vector of entities. Each record is composed of four Strings: * publicId, systemID, notationName, and name. */ private Vector m_entities = null; /** m_entities public ID offset. */ private static final int ENTITY_FIELD_PUBLICID = 0; /** m_entities system ID offset. */ private static final int ENTITY_FIELD_SYSTEMID = 1; /** m_entities notation name offset. */ private static final int ENTITY_FIELD_NOTATIONNAME = 2; /** m_entities name offset. */ private static final int ENTITY_FIELD_NAME = 3; /** Number of entries per record for m_entities. */ private static final int ENTITY_FIELDS_PER = 4; /** * The starting offset within m_chars for the text or * CDATA_SECTION node currently being acumulated, * or -1 if there is no text node in progress */ protected int m_textPendingStart = -1; /** * Describes whether information about document source location * should be maintained or not. * * Made protected for access by SAX2RTFDTM. */ protected boolean m_useSourceLocationProperty = false; /** Made protected for access by SAX2RTFDTM. */ protected StringVector m_sourceSystemId; /** Made protected for access by SAX2RTFDTM. */ protected IntVector m_sourceLine; /** Made protected for access by SAX2RTFDTM. */ protected IntVector m_sourceColumn; /** * Construct a SAX2DTM object using the default block size. * * @param mgr The DTMManager who owns this DTM. * @param source the JAXP 1.1 Source object for this DTM. * @param dtmIdentity The DTM identity ID for this DTM. * @param whiteSpaceFilter The white space filter for this DTM, which may * be null. * @param xstringfactory XMLString factory for creating character content. * @param doIndexing true if the caller considers it worth it to use * indexing schemes. */ public SAX2DTM(DTMManager mgr, Source source, int dtmIdentity, DTMWSFilter whiteSpaceFilter, XMLStringFactory xstringfactory, boolean doIndexing) { this(mgr, source, dtmIdentity, whiteSpaceFilter, xstringfactory, doIndexing, DEFAULT_BLOCKSIZE, true, false); } /** * Construct a SAX2DTM object ready to be constructed from SAX2 * ContentHandler events. * * @param mgr The DTMManager who owns this DTM. * @param source the JAXP 1.1 Source object for this DTM. * @param dtmIdentity The DTM identity ID for this DTM. * @param whiteSpaceFilter The white space filter for this DTM, which may * be null. * @param xstringfactory XMLString factory for creating character content. * @param doIndexing true if the caller considers it worth it to use * indexing schemes. * @param blocksize The block size of the DTM. * @param usePrevsib true if we want to build the previous sibling node array. * @param newNameTable true if we want to use a new ExpandedNameTable for this DTM. */ public SAX2DTM(DTMManager mgr, Source source, int dtmIdentity, DTMWSFilter whiteSpaceFilter, XMLStringFactory xstringfactory, boolean doIndexing, int blocksize, boolean usePrevsib, boolean newNameTable) { super(mgr, source, dtmIdentity, whiteSpaceFilter, xstringfactory, doIndexing, blocksize, usePrevsib, newNameTable); // %OPT% Use smaller sizes for all internal storage units when // the blocksize is small. This reduces the cost of creating an RTF. if (blocksize <= 64) { m_data = new SuballocatedIntVector(blocksize, DEFAULT_NUMBLOCKS_SMALL); m_dataOrQName = new SuballocatedIntVector(blocksize, DEFAULT_NUMBLOCKS_SMALL); m_valuesOrPrefixes = new DTMStringPool(16); m_chars = new FastStringBuffer(7, 10); m_contextIndexes = new IntStack(4); m_parents = new IntStack(4); } else { m_data = new SuballocatedIntVector(blocksize, DEFAULT_NUMBLOCKS); m_dataOrQName = new SuballocatedIntVector(blocksize, DEFAULT_NUMBLOCKS); m_valuesOrPrefixes = new DTMStringPool(); m_chars = new FastStringBuffer(10, 13); m_contextIndexes = new IntStack(); m_parents = new IntStack(); } // %REVIEW% Initial size pushed way down to reduce weight of RTFs // (I'm not entirely sure 0 would work, so I'm playing it safe for now.) //m_data = new SuballocatedIntVector(doIndexing ? (1024*2) : 512, 1024); //m_data = new SuballocatedIntVector(blocksize); m_data.addElement(0); // Need placeholder in case index into here must be <0. //m_dataOrQName = new SuballocatedIntVector(blocksize); // m_useSourceLocationProperty=org.apache.xalan.processor.TransformerFactoryImpl.m_source_location; m_useSourceLocationProperty = mgr.getSource_location(); m_sourceSystemId = (m_useSourceLocationProperty) ? new StringVector() : null; m_sourceLine = (m_useSourceLocationProperty) ? new IntVector() : null; m_sourceColumn = (m_useSourceLocationProperty) ? new IntVector() : null; } /** * Set whether information about document source location * should be maintained or not. */ public void setUseSourceLocation(boolean useSourceLocation) { m_useSourceLocationProperty = useSourceLocation; } /** * Get the data or qualified name for the given node identity. * * @param identity The node identity. * * @return The data or qualified name, or DTM.NULL. */ protected int _dataOrQName(int identity) { if (identity < m_size) return m_dataOrQName.elementAt(identity); // Check to see if the information requested has been processed, and, // if not, advance the iterator until we the information has been // processed. while (true) { boolean isMore = nextNode(); if (!isMore) return NULL; else if (identity < m_size) return m_dataOrQName.elementAt(identity); } } /** * Ask the CoRoutine parser to doTerminate and clear the reference. */ public void clearCoRoutine() { clearCoRoutine(true); } /** * Ask the CoRoutine parser to doTerminate and clear the reference. If * the CoRoutine parser has already been cleared, this will have no effect. * * @param callDoTerminate true of doTerminate should be called on the * coRoutine parser. */ public void clearCoRoutine(boolean callDoTerminate) { if (null != m_incrementalSAXSource) { if (callDoTerminate) m_incrementalSAXSource.deliverMoreNodes(false); m_incrementalSAXSource = null; } } /** * Bind a IncrementalSAXSource to this DTM. If we discover we need nodes * that have not yet been built, we will ask this object to send us more * events, and it will manage interactions with its data sources. * * Note that we do not actually build the IncrementalSAXSource, since we don't * know what source it's reading from, what thread that source will run in, * or when it will run. * * @param incrementalSAXSource The parser that we want to recieve events from * on demand. */ public void setIncrementalSAXSource(IncrementalSAXSource incrementalSAXSource) { // Establish coroutine link so we can request more data // // Note: It's possible that some versions of IncrementalSAXSource may // not actually use a CoroutineManager, and hence may not require // that we obtain an Application Coroutine ID. (This relies on the // coroutine transaction details having been encapsulated in the // IncrementalSAXSource.do...() methods.) m_incrementalSAXSource = incrementalSAXSource; // Establish SAX-stream link so we can receive the requested data incrementalSAXSource.setContentHandler(this); incrementalSAXSource.setLexicalHandler(this); incrementalSAXSource.setDTDHandler(this); // Are the following really needed? incrementalSAXSource doesn't yet // support them, and they're mostly no-ops here... //incrementalSAXSource.setErrorHandler(this); //incrementalSAXSource.setDeclHandler(this); } /** * getContentHandler returns "our SAX builder" -- the thing that * someone else should send SAX events to in order to extend this * DTM model. * * %REVIEW% Should this return null if constrution already done/begun? * * @return null if this model doesn't respond to SAX events, * "this" if the DTM object has a built-in SAX ContentHandler, * the IncrementalSAXSource if we're bound to one and should receive * the SAX stream via it for incremental build purposes... */ public ContentHandler getContentHandler() { if (m_incrementalSAXSource instanceof IncrementalSAXSource_Filter) return (ContentHandler) m_incrementalSAXSource; else return this; } /** * Return this DTM's lexical handler. * * %REVIEW% Should this return null if constrution already done/begun? * * @return null if this model doesn't respond to lexical SAX events, * "this" if the DTM object has a built-in SAX ContentHandler, * the IncrementalSAXSource if we're bound to one and should receive * the SAX stream via it for incremental build purposes... */ public LexicalHandler getLexicalHandler() { if (m_incrementalSAXSource instanceof IncrementalSAXSource_Filter) return (LexicalHandler) m_incrementalSAXSource; else return this; } /** * Return this DTM's EntityResolver. * * @return null if this model doesn't respond to SAX entity ref events. */ public EntityResolver getEntityResolver() { return this; } /** * Return this DTM's DTDHandler. * * @return null if this model doesn't respond to SAX dtd events. */ public DTDHandler getDTDHandler() { return this; } /** * Return this DTM's ErrorHandler. * * @return null if this model doesn't respond to SAX error events. */ public ErrorHandler getErrorHandler() { return this; } /** * Return this DTM's DeclHandler. * * @return null if this model doesn't respond to SAX Decl events. */ public DeclHandler getDeclHandler() { return this; } /** * @return true iff we're building this model incrementally (eg * we're partnered with a IncrementalSAXSource) and thus require that the * transformation and the parse run simultaneously. Guidance to the * DTMManager. */ public boolean needsTwoThreads() { return null != m_incrementalSAXSource; } /** * Directly call the * characters method on the passed ContentHandler for the * string-value of the given node (see http://www.w3.org/TR/xpath#data-model * for the definition of a node's string-value). Multiple calls to the * ContentHandler's characters methods may well occur for a single call to * this method. * * @param nodeHandle The node ID. * @param ch A non-null reference to a ContentHandler. * @param normalize true if the content should be normalized according to * the rules for the XPath * normalize-space * function. * * @throws SAXException */ public void dispatchCharactersEvents(int nodeHandle, ContentHandler ch, boolean normalize) throws SAXException { int identity = makeNodeIdentity(nodeHandle); if (identity == DTM.NULL) return; int type = _type(identity); if (isTextType(type)) { int dataIndex = m_dataOrQName.elementAt(identity); int offset = m_data.elementAt(dataIndex); int length = m_data.elementAt(dataIndex + 1); if(normalize) m_chars.sendNormalizedSAXcharacters(ch, offset, length); else m_chars.sendSAXcharacters(ch, offset, length); } else { int firstChild = _firstch(identity); if (DTM.NULL != firstChild) { int offset = -1; int length = 0; int startNode = identity; identity = firstChild; do { type = _type(identity); if (isTextType(type)) { int dataIndex = _dataOrQName(identity); if (-1 == offset) { offset = m_data.elementAt(dataIndex); } length += m_data.elementAt(dataIndex + 1); } identity = getNextNodeIdentity(identity); } while (DTM.NULL != identity && (_parent(identity) >= startNode)); if (length > 0) { if(normalize) m_chars.sendNormalizedSAXcharacters(ch, offset, length); else m_chars.sendSAXcharacters(ch, offset, length); } } else if(type != DTM.ELEMENT_NODE) { int dataIndex = _dataOrQName(identity); if (dataIndex < 0) { dataIndex = -dataIndex; dataIndex = m_data.elementAt(dataIndex + 1); } String str = m_valuesOrPrefixes.indexToString(dataIndex); if(normalize) FastStringBuffer.sendNormalizedSAXcharacters(str.toCharArray(), 0, str.length(), ch); else ch.characters(str.toCharArray(), 0, str.length()); } } } /** * Given a node handle, return its DOM-style node name. This will * include names such as #text or #document. * * @param nodeHandle the id of the node. * @return String Name of this node, which may be an empty string. * %REVIEW% Document when empty string is possible... * %REVIEW-COMMENT% It should never be empty, should it? */ public String getNodeName(int nodeHandle) { int expandedTypeID = getExpandedTypeID(nodeHandle); // If just testing nonzero, no need to shift... int namespaceID = m_expandedNameTable.getNamespaceID(expandedTypeID); if (0 == namespaceID) { // Don't retrieve name until/unless needed // String name = m_expandedNameTable.getLocalName(expandedTypeID); int type = getNodeType(nodeHandle); if (type == DTM.NAMESPACE_NODE) { if (null == m_expandedNameTable.getLocalName(expandedTypeID)) return "xmlns"; else return "xmlns:" + m_expandedNameTable.getLocalName(expandedTypeID); } else if (0 == m_expandedNameTable.getLocalNameID(expandedTypeID)) { return m_fixednames[type]; } else return m_expandedNameTable.getLocalName(expandedTypeID); } else { int qnameIndex = m_dataOrQName.elementAt(makeNodeIdentity(nodeHandle)); if (qnameIndex < 0) { qnameIndex = -qnameIndex; qnameIndex = m_data.elementAt(qnameIndex); } return m_valuesOrPrefixes.indexToString(qnameIndex); } } /** * Given a node handle, return the XPath node name. This should be * the name as described by the XPath data model, NOT the DOM-style * name. * * @param nodeHandle the id of the node. * @return String Name of this node, which may be an empty string. */ public String getNodeNameX(int nodeHandle) { int expandedTypeID = getExpandedTypeID(nodeHandle); int namespaceID = m_expandedNameTable.getNamespaceID(expandedTypeID); if (0 == namespaceID) { String name = m_expandedNameTable.getLocalName(expandedTypeID); if (name == null) return ""; else return name; } else { int qnameIndex = m_dataOrQName.elementAt(makeNodeIdentity(nodeHandle)); if (qnameIndex < 0) { qnameIndex = -qnameIndex; qnameIndex = m_data.elementAt(qnameIndex); } return m_valuesOrPrefixes.indexToString(qnameIndex); } } /** * 5. [specified] A flag indicating whether this attribute was actually * specified in the start-tag of its element, or was defaulted from the * DTD. * * @param attributeHandle Must be a valid handle to an attribute node. * @return true if the attribute was specified; * false if it was defaulted. */ public boolean isAttributeSpecified(int attributeHandle) { // I'm not sure if I want to do anything with this... return true; // ?? } /** * A document type declaration information item has the following properties: * * 1. [system identifier] The system identifier of the external subset, if * it exists. Otherwise this property has no value. * * @return the system identifier String object, or null if there is none. */ public String getDocumentTypeDeclarationSystemIdentifier() { /** @todo: implement this org.apache.xml.dtm.DTMDefaultBase abstract method */ error(XMLMessages.createXMLMessage(XMLErrorResources.ER_METHOD_NOT_SUPPORTED, null));//"Not yet supported!"); return null; } /** * Get the next node identity value in the list, and call the iterator * if it hasn't been added yet. * * @param identity The node identity (index). * @return identity+1, or DTM.NULL. */ protected int getNextNodeIdentity(int identity) { identity += 1; while (identity >= m_size) { if (null == m_incrementalSAXSource) return DTM.NULL; nextNode(); } return identity; } /** * Directly create SAX parser events from a subtree. * * @param nodeHandle The node ID. * @param ch A non-null reference to a ContentHandler. * * @throws org.xml.sax.SAXException */ public void dispatchToEvents(int nodeHandle, org.xml.sax.ContentHandler ch) throws org.xml.sax.SAXException { DTMTreeWalker treeWalker = m_walker; ContentHandler prevCH = treeWalker.getcontentHandler(); if (null != prevCH) { treeWalker = new DTMTreeWalker(); } treeWalker.setcontentHandler(ch); treeWalker.setDTM(this); try { treeWalker.traverse(nodeHandle); } finally { treeWalker.setcontentHandler(null); } } /** * Get the number of nodes that have been added. * * @return The number of that are currently in the tree. */ public int getNumberOfNodes() { return m_size; } /** * This method should try and build one or more nodes in the table. * * @return The true if a next node is found or false if * there are no more nodes. */ protected boolean nextNode() { if (null == m_incrementalSAXSource) return false; if (m_endDocumentOccured) { clearCoRoutine(); return false; } Object gotMore = m_incrementalSAXSource.deliverMoreNodes(true); // gotMore may be a Boolean (TRUE if still parsing, FALSE if // EOF) or an exception if IncrementalSAXSource malfunctioned // (code error rather than user error). // // %REVIEW% Currently the ErrorHandlers sketched herein are // no-ops, so I'm going to initially leave this also as a // no-op. if (!(gotMore instanceof Boolean)) { if(gotMore instanceof RuntimeException) { throw (RuntimeException)gotMore; } else if(gotMore instanceof Exception) { throw new WrappedRuntimeException((Exception)gotMore); } // for now... clearCoRoutine(); return false; // %TBD% } if (gotMore != Boolean.TRUE) { // EOF reached without satisfying the request clearCoRoutine(); // Drop connection, stop trying // %TBD% deregister as its listener? } return true; } /** * Bottleneck determination of text type. * * @param type oneof DTM.XXX_NODE. * * @return true if this is a text or cdata section. */ private final boolean isTextType(int type) { return (DTM.TEXT_NODE == type || DTM.CDATA_SECTION_NODE == type); } // /** // * Ensure that the size of the information arrays can hold another entry // * at the given index. // * // * @param on exit from this function, the information arrays sizes must be // * at least index+1. // * // * NEEDSDOC @param index // */ // protected void ensureSize(int index) // { // // dataOrQName is an SuballocatedIntVector and hence self-sizing. // // But DTMDefaultBase may need fixup. // super.ensureSize(index); // } /** * Construct the node map from the node. * * @param type raw type ID, one of DTM.XXX_NODE. * @param expandedTypeID The expended type ID. * @param parentIndex The current parent index. * @param previousSibling The previous sibling index. * @param dataOrPrefix index into m_data table, or string handle. * @param canHaveFirstChild true if the node can have a first child, false * if it is atomic. * * @return The index identity of the node that was added. */ protected int addNode(int type, int expandedTypeID, int parentIndex, int previousSibling, int dataOrPrefix, boolean canHaveFirstChild) { // Common to all nodes: int nodeIndex = m_size++; // Have we overflowed a DTM Identity's addressing range? if(m_dtmIdent.size() == (nodeIndex>>>DTMManager.IDENT_DTM_NODE_BITS)) { addNewDTMID(nodeIndex); } m_firstch.addElement(canHaveFirstChild ? NOTPROCESSED : DTM.NULL); m_nextsib.addElement(NOTPROCESSED); m_parent.addElement(parentIndex); m_exptype.addElement(expandedTypeID); m_dataOrQName.addElement(dataOrPrefix); if (m_prevsib != null) { m_prevsib.addElement(previousSibling); } if (DTM.NULL != previousSibling) { m_nextsib.setElementAt(nodeIndex,previousSibling); } if (m_locator != null && m_useSourceLocationProperty) { setSourceLocation(); } // Note that nextSibling is not processed until charactersFlush() // is called, to handle successive characters() events. // Special handling by type: Declare namespaces, attach first child switch(type) { case DTM.NAMESPACE_NODE: declareNamespaceInContext(parentIndex,nodeIndex); break; case DTM.ATTRIBUTE_NODE: break; default: if (DTM.NULL == previousSibling && DTM.NULL != parentIndex) { m_firstch.setElementAt(nodeIndex,parentIndex); } break; } return nodeIndex; } /** * Get a new DTM ID beginning at the specified node index. * @param nodeIndex The node identity at which the new DTM ID will begin * addressing. */ protected void addNewDTMID(int nodeIndex) { try { if(m_mgr==null) throw new ClassCastException(); // Handle as Extended Addressing DTMManagerDefault mgrD=(DTMManagerDefault)m_mgr; int id=mgrD.getFirstFreeDTMID(); mgrD.addDTM(this,id,nodeIndex); m_dtmIdent.addElement(id< %REVIEW% Are you sure you want "" for no prefix?

*

%REVIEW-COMMENT% I think so... not totally sure. -sb

* * @param nodeHandle the id of the node. * @return String prefix of this node's name, or "" if no explicit * namespace prefix was given. */ public String getPrefix(int nodeHandle) { int identity = makeNodeIdentity(nodeHandle); int type = _type(identity); if (DTM.ELEMENT_NODE == type) { int prefixIndex = _dataOrQName(identity); if (0 == prefixIndex) return ""; else { String qname = m_valuesOrPrefixes.indexToString(prefixIndex); return getPrefix(qname, null); } } else if (DTM.ATTRIBUTE_NODE == type) { int prefixIndex = _dataOrQName(identity); if (prefixIndex < 0) { prefixIndex = m_data.elementAt(-prefixIndex); String qname = m_valuesOrPrefixes.indexToString(prefixIndex); return getPrefix(qname, null); } } return ""; } /** * Retrieves an attribute node by by qualified name and namespace URI. * * @param nodeHandle int Handle of the node upon which to look up this attribute.. * @param namespaceURI The namespace URI of the attribute to * retrieve, or null. * @param name The local name of the attribute to * retrieve. * @return The attribute node handle with the specified name ( * nodeName) or DTM.NULL if there is no such * attribute. */ public int getAttributeNode(int nodeHandle, String namespaceURI, String name) { for (int attrH = getFirstAttribute(nodeHandle); DTM.NULL != attrH; attrH = getNextAttribute(attrH)) { String attrNS = getNamespaceURI(attrH); String attrName = getLocalName(attrH); boolean nsMatch = namespaceURI == attrNS || (namespaceURI != null && namespaceURI.equals(attrNS)); if (nsMatch && name.equals(attrName)) return attrH; } return DTM.NULL; } /** * Return the public identifier of the external subset, * normalized as described in 4.2.2 External Entities [XML]. If there is * no external subset or if it has no public identifier, this property * has no value. * * @return the public identifier String object, or null if there is none. */ public String getDocumentTypeDeclarationPublicIdentifier() { /** @todo: implement this org.apache.xml.dtm.DTMDefaultBase abstract method */ error(XMLMessages.createXMLMessage(XMLErrorResources.ER_METHOD_NOT_SUPPORTED, null));//"Not yet supported!"); return null; } /** * Given a node handle, return its DOM-style namespace URI * (As defined in Namespaces, this is the declared URI which this node's * prefix -- or default in lieu thereof -- was mapped to.) * *

%REVIEW% Null or ""? -sb

* * @param nodeHandle the id of the node. * @return String URI value of this node's namespace, or null if no * namespace was resolved. */ public String getNamespaceURI(int nodeHandle) { return m_expandedNameTable.getNamespace(_exptype(makeNodeIdentity(nodeHandle))); } /** * Get the string-value of a node as a String object * (see http://www.w3.org/TR/xpath#data-model * for the definition of a node's string-value). * * @param nodeHandle The node ID. * * @return A string object that represents the string-value of the given node. */ public XMLString getStringValue(int nodeHandle) { int identity = makeNodeIdentity(nodeHandle); int type; if(identity==DTM.NULL) // Separate lines because I wanted to breakpoint it type = DTM.NULL; else type= _type(identity); if (isTextType(type)) { int dataIndex = _dataOrQName(identity); int offset = m_data.elementAt(dataIndex); int length = m_data.elementAt(dataIndex + 1); return m_xstrf.newstr(m_chars, offset, length); } else { int firstChild = _firstch(identity); if (DTM.NULL != firstChild) { int offset = -1; int length = 0; int startNode = identity; identity = firstChild; do { type = _type(identity); if (isTextType(type)) { int dataIndex = _dataOrQName(identity); if (-1 == offset) { offset = m_data.elementAt(dataIndex); } length += m_data.elementAt(dataIndex + 1); } identity = getNextNodeIdentity(identity); } while (DTM.NULL != identity && (_parent(identity) >= startNode)); if (length > 0) { return m_xstrf.newstr(m_chars, offset, length); } } else if(type != DTM.ELEMENT_NODE) { int dataIndex = _dataOrQName(identity); if (dataIndex < 0) { dataIndex = -dataIndex; dataIndex = m_data.elementAt(dataIndex + 1); } return m_xstrf.newstr(m_valuesOrPrefixes.indexToString(dataIndex)); } } return m_xstrf.emptystr(); } /** * Determine if the string-value of a node is whitespace * * @param nodeHandle The node Handle. * * @return Return true if the given node is whitespace. */ public boolean isWhitespace(int nodeHandle) { int identity = makeNodeIdentity(nodeHandle); int type; if(identity==DTM.NULL) // Separate lines because I wanted to breakpoint it type = DTM.NULL; else type= _type(identity); if (isTextType(type)) { int dataIndex = _dataOrQName(identity); int offset = m_data.elementAt(dataIndex); int length = m_data.elementAt(dataIndex + 1); return m_chars.isWhitespace(offset, length); } return false; } /** * Returns the Element whose ID is given by * elementId. If no such element exists, returns * DTM.NULL. Behavior is not defined if more than one element * has this ID. Attributes (including those * with the name "ID") are not of type ID unless so defined by DTD/Schema * information available to the DTM implementation. * Implementations that do not know whether attributes are of type ID or * not are expected to return DTM.NULL. * *

%REVIEW% Presumably IDs are still scoped to a single document, * and this operation searches only within a single document, right? * Wouldn't want collisions between DTMs in the same process.

* * @param elementId The unique id value for an element. * @return The handle of the matching element. */ public int getElementById(String elementId) { Integer intObj; boolean isMore = true; do { intObj = (Integer) m_idAttributes.get(elementId); if (null != intObj) return makeNodeHandle(intObj.intValue()); if (!isMore || m_endDocumentOccured) break; isMore = nextNode(); } while (null == intObj); return DTM.NULL; } /** * Get a prefix either from the qname or from the uri mapping, or just make * one up! * * @param qname The qualified name, which may be null. * @param uri The namespace URI, which may be null. * * @return The prefix if there is one, or null. */ public String getPrefix(String qname, String uri) { String prefix; int uriIndex = -1; if (null != uri && uri.length() > 0) { do { uriIndex = m_prefixMappings.indexOf(uri, ++uriIndex); } while ( (uriIndex & 0x01) == 0); if (uriIndex >= 0) { prefix = (String) m_prefixMappings.elementAt(uriIndex - 1); } else if (null != qname) { int indexOfNSSep = qname.indexOf(':'); if (qname.equals("xmlns")) prefix = ""; else if (qname.startsWith("xmlns:")) prefix = qname.substring(indexOfNSSep + 1); else prefix = (indexOfNSSep > 0) ? qname.substring(0, indexOfNSSep) : null; } else { prefix = null; } } else if (null != qname) { int indexOfNSSep = qname.indexOf(':'); if (indexOfNSSep > 0) { if (qname.startsWith("xmlns:")) prefix = qname.substring(indexOfNSSep + 1); else prefix = qname.substring(0, indexOfNSSep); } else { if (qname.equals("xmlns")) prefix = ""; else prefix = null; } } else { prefix = null; } return prefix; } /** * Get a prefix either from the uri mapping, or just make * one up! * * @param uri The namespace URI, which may be null. * * @return The prefix if there is one, or null. */ public int getIdForNamespace(String uri) { return m_valuesOrPrefixes.stringToIndex(uri); } /** * Get a prefix either from the qname or from the uri mapping, or just make * one up! * * @return The prefix if there is one, or null. */ public String getNamespaceURI(String prefix) { String uri = ""; int prefixIndex = m_contextIndexes.peek() - 1 ; if(null == prefix) prefix = ""; do { prefixIndex = m_prefixMappings.indexOf(prefix, ++prefixIndex); } while ( (prefixIndex >= 0) && (prefixIndex & 0x01) == 0x01); if (prefixIndex > -1) { uri = (String) m_prefixMappings.elementAt(prefixIndex + 1); } return uri; } /** * Set an ID string to node association in the ID table. * * @param id The ID string. * @param elem The associated element handle. */ public void setIDAttribute(String id, int elem) { m_idAttributes.put(id, new Integer(elem)); } /** * Check whether accumulated text should be stripped; if not, * append the appropriate flavor of text/cdata node. */ protected void charactersFlush() { if (m_textPendingStart >= 0) // -1 indicates no-text-in-progress { int length = m_chars.size() - m_textPendingStart; boolean doStrip = false; if (getShouldStripWhitespace()) { doStrip = m_chars.isWhitespace(m_textPendingStart, length); } if (doStrip) { m_chars.setLength(m_textPendingStart); // Discard accumulated text } else { // Guard against characters/ignorableWhitespace events that // contained no characters. They should not result in a node. if (length > 0) { int exName = m_expandedNameTable.getExpandedTypeID(DTM.TEXT_NODE); int dataIndex = m_data.size(); m_previous = addNode(m_coalescedTextType, exName, m_parents.peek(), m_previous, dataIndex, false); m_data.addElement(m_textPendingStart); m_data.addElement(length); } } // Reset for next text block m_textPendingStart = -1; m_textType = m_coalescedTextType = DTM.TEXT_NODE; } } //////////////////////////////////////////////////////////////////// // Implementation of the EntityResolver interface. //////////////////////////////////////////////////////////////////// /** * Resolve an external entity. * *

Always return null, so that the parser will use the system * identifier provided in the XML document. This method implements * the SAX default behaviour: application writers can override it * in a subclass to do special translations such as catalog lookups * or URI redirection.

* * @param publicId The public identifer, or null if none is * available. * @param systemId The system identifier provided in the XML * document. * @return The new input source, or null to require the * default behaviour. * @throws SAXException Any SAX exception, possibly * wrapping another exception. * @see org.xml.sax.EntityResolver#resolveEntity * * @throws SAXException */ public InputSource resolveEntity(String publicId, String systemId) throws SAXException { return null; } //////////////////////////////////////////////////////////////////// // Implementation of DTDHandler interface. //////////////////////////////////////////////////////////////////// /** * Receive notification of a notation declaration. * *

By default, do nothing. Application writers may override this * method in a subclass if they wish to keep track of the notations * declared in a document.

* * @param name The notation name. * @param publicId The notation public identifier, or null if not * available. * @param systemId The notation system identifier. * @throws SAXException Any SAX exception, possibly * wrapping another exception. * @see org.xml.sax.DTDHandler#notationDecl * * @throws SAXException */ public void notationDecl(String name, String publicId, String systemId) throws SAXException { // no op } /** * Receive notification of an unparsed entity declaration. * *

By default, do nothing. Application writers may override this * method in a subclass to keep track of the unparsed entities * declared in a document.

* * @param name The entity name. * @param publicId The entity public identifier, or null if not * available. * @param systemId The entity system identifier. * @param notationName The name of the associated notation. * @throws SAXException Any SAX exception, possibly * wrapping another exception. * @see org.xml.sax.DTDHandler#unparsedEntityDecl * * @throws SAXException */ public void unparsedEntityDecl( String name, String publicId, String systemId, String notationName) throws SAXException { if (null == m_entities) { m_entities = new Vector(); } try { systemId = SystemIDResolver.getAbsoluteURI(systemId, getDocumentBaseURI()); } catch (Exception e) { throw new org.xml.sax.SAXException(e); } // private static final int ENTITY_FIELD_PUBLICID = 0; m_entities.addElement(publicId); // private static final int ENTITY_FIELD_SYSTEMID = 1; m_entities.addElement(systemId); // private static final int ENTITY_FIELD_NOTATIONNAME = 2; m_entities.addElement(notationName); // private static final int ENTITY_FIELD_NAME = 3; m_entities.addElement(name); } //////////////////////////////////////////////////////////////////// // Implementation of ContentHandler interface. //////////////////////////////////////////////////////////////////// /** * Receive a Locator object for document events. * *

By default, do nothing. Application writers may override this * method in a subclass if they wish to store the locator for use * with other document events.

* * @param locator A locator for all SAX document events. * @see org.xml.sax.ContentHandler#setDocumentLocator * @see org.xml.sax.Locator */ public void setDocumentLocator(Locator locator) { m_locator = locator; m_systemId = locator.getSystemId(); } /** * Receive notification of the beginning of the document. * * @throws SAXException Any SAX exception, possibly * wrapping another exception. * @see org.xml.sax.ContentHandler#startDocument */ public void startDocument() throws SAXException { if (DEBUG) System.out.println("startDocument"); int doc = addNode(DTM.DOCUMENT_NODE, m_expandedNameTable.getExpandedTypeID(DTM.DOCUMENT_NODE), DTM.NULL, DTM.NULL, 0, true); m_parents.push(doc); m_previous = DTM.NULL; m_contextIndexes.push(m_prefixMappings.size()); // for the next element. } /** * Receive notification of the end of the document. * * @throws SAXException Any SAX exception, possibly * wrapping another exception. * @see org.xml.sax.ContentHandler#endDocument */ public void endDocument() throws SAXException { if (DEBUG) System.out.println("endDocument"); charactersFlush(); m_nextsib.setElementAt(NULL,0); if (m_firstch.elementAt(0) == NOTPROCESSED) m_firstch.setElementAt(NULL,0); if (DTM.NULL != m_previous) m_nextsib.setElementAt(DTM.NULL,m_previous); m_parents = null; m_prefixMappings = null; m_contextIndexes = null; m_endDocumentOccured = true; // Bugzilla 4858: throw away m_locator. we cache m_systemId m_locator = null; } /** * Receive notification of the start of a Namespace mapping. * *

By default, do nothing. Application writers may override this * method in a subclass to take specific actions at the start of * each Namespace prefix scope (such as storing the prefix mapping).

* * @param prefix The Namespace prefix being declared. * @param uri The Namespace URI mapped to the prefix. * @throws SAXException Any SAX exception, possibly * wrapping another exception. * @see org.xml.sax.ContentHandler#startPrefixMapping */ public void startPrefixMapping(String prefix, String uri) throws SAXException { if (DEBUG) System.out.println("startPrefixMapping: prefix: " + prefix + ", uri: " + uri); if(null == prefix) prefix = ""; m_prefixMappings.addElement(prefix); // JDK 1.1.x compat -sc m_prefixMappings.addElement(uri); // JDK 1.1.x compat -sc } /** * Receive notification of the end of a Namespace mapping. * *

By default, do nothing. Application writers may override this * method in a subclass to take specific actions at the end of * each prefix mapping.

* * @param prefix The Namespace prefix being declared. * @throws SAXException Any SAX exception, possibly * wrapping another exception. * @see org.xml.sax.ContentHandler#endPrefixMapping */ public void endPrefixMapping(String prefix) throws SAXException { if (DEBUG) System.out.println("endPrefixMapping: prefix: " + prefix); if(null == prefix) prefix = ""; int index = m_contextIndexes.peek() - 1; do { index = m_prefixMappings.indexOf(prefix, ++index); } while ( (index >= 0) && ((index & 0x01) == 0x01) ); if (index > -1) { m_prefixMappings.setElementAt("%@$#^@#", index); m_prefixMappings.setElementAt("%@$#^@#", index + 1); } // no op } /** * Check if a declaration has already been made for a given prefix. * * @param prefix non-null prefix string. * * @return true if the declaration has already been declared in the * current context. */ protected boolean declAlreadyDeclared(String prefix) { int startDecls = m_contextIndexes.peek(); java.util.Vector prefixMappings = m_prefixMappings; int nDecls = prefixMappings.size(); for (int i = startDecls; i < nDecls; i += 2) { String prefixDecl = (String) prefixMappings.elementAt(i); if (prefixDecl == null) continue; if (prefixDecl.equals(prefix)) return true; } return false; } boolean m_pastFirstElement=false; /** * Receive notification of the start of an element. * *

By default, do nothing. Application writers may override this * method in a subclass to take specific actions at the start of * each element (such as allocating a new tree node or writing * output to a file).

* * @param uri The Namespace URI, or the empty string if the * element has no Namespace URI or if Namespace * processing is not being performed. * @param localName The local name (without prefix), or the * empty string if Namespace processing is not being * performed. * @param qName The qualified name (with prefix), or the * empty string if qualified names are not available. * @param attributes The specified or defaulted attributes. * @throws SAXException Any SAX exception, possibly * wrapping another exception. * @see org.xml.sax.ContentHandler#startElement */ public void startElement( String uri, String localName, String qName, Attributes attributes) throws SAXException { if (DEBUG) { System.out.println("startElement: uri: " + uri + ", localname: " + localName + ", qname: "+qName+", atts: " + attributes); boolean DEBUG_ATTRS=true; if(DEBUG_ATTRS & attributes!=null) { int n = attributes.getLength(); if(n==0) System.out.println("\tempty attribute list"); else for (int i = 0; i < n; i++) System.out.println("\t attr: uri: " + attributes.getURI(i) + ", localname: " + attributes.getLocalName(i) + ", qname: " + attributes.getQName(i) + ", type: " + attributes.getType(i) + ", value: " + attributes.getValue(i) ); } } charactersFlush(); int exName = m_expandedNameTable.getExpandedTypeID(uri, localName, DTM.ELEMENT_NODE); String prefix = getPrefix(qName, uri); int prefixIndex = (null != prefix) ? m_valuesOrPrefixes.stringToIndex(qName) : 0; int elemNode = addNode(DTM.ELEMENT_NODE, exName, m_parents.peek(), m_previous, prefixIndex, true); if(m_indexing) indexNode(exName, elemNode); m_parents.push(elemNode); int startDecls = m_contextIndexes.peek(); int nDecls = m_prefixMappings.size(); int prev = DTM.NULL; if(!m_pastFirstElement) { // SPECIAL CASE: Implied declaration at root element prefix="xml"; String declURL = "http://www.w3.org/XML/1998/namespace"; exName = m_expandedNameTable.getExpandedTypeID(null, prefix, DTM.NAMESPACE_NODE); int val = m_valuesOrPrefixes.stringToIndex(declURL); prev = addNode(DTM.NAMESPACE_NODE, exName, elemNode, prev, val, false); m_pastFirstElement=true; } for (int i = startDecls; i < nDecls; i += 2) { prefix = (String) m_prefixMappings.elementAt(i); if (prefix == null) continue; String declURL = (String) m_prefixMappings.elementAt(i + 1); exName = m_expandedNameTable.getExpandedTypeID(null, prefix, DTM.NAMESPACE_NODE); int val = m_valuesOrPrefixes.stringToIndex(declURL); prev = addNode(DTM.NAMESPACE_NODE, exName, elemNode, prev, val, false); } int n = attributes.getLength(); for (int i = 0; i < n; i++) { String attrUri = attributes.getURI(i); String attrQName = attributes.getQName(i); String valString = attributes.getValue(i); prefix = getPrefix(attrQName, attrUri); int nodeType; String attrLocalName = attributes.getLocalName(i); if ((null != attrQName) && (attrQName.equals("xmlns") || attrQName.startsWith("xmlns:"))) { if (declAlreadyDeclared(prefix)) continue; // go to the next attribute. nodeType = DTM.NAMESPACE_NODE; } else { nodeType = DTM.ATTRIBUTE_NODE; if (attributes.getType(i).equalsIgnoreCase("ID")) setIDAttribute(valString, elemNode); } // Bit of a hack... if somehow valString is null, stringToIndex will // return -1, which will make things very unhappy. if(null == valString) valString = ""; int val = m_valuesOrPrefixes.stringToIndex(valString); //String attrLocalName = attributes.getLocalName(i); if (null != prefix) { prefixIndex = m_valuesOrPrefixes.stringToIndex(attrQName); int dataIndex = m_data.size(); m_data.addElement(prefixIndex); m_data.addElement(val); val = -dataIndex; } exName = m_expandedNameTable.getExpandedTypeID(attrUri, attrLocalName, nodeType); prev = addNode(nodeType, exName, elemNode, prev, val, false); } if (DTM.NULL != prev) m_nextsib.setElementAt(DTM.NULL,prev); if (null != m_wsfilter) { short wsv = m_wsfilter.getShouldStripSpace(makeNodeHandle(elemNode), this); boolean shouldStrip = (DTMWSFilter.INHERIT == wsv) ? getShouldStripWhitespace() : (DTMWSFilter.STRIP == wsv); pushShouldStripWhitespace(shouldStrip); } m_previous = DTM.NULL; m_contextIndexes.push(m_prefixMappings.size()); // for the children. } /** * Receive notification of the end of an element. * *

By default, do nothing. Application writers may override this * method in a subclass to take specific actions at the end of * each element (such as finalising a tree node or writing * output to a file).

* * @param uri The Namespace URI, or the empty string if the * element has no Namespace URI or if Namespace * processing is not being performed. * @param localName The local name (without prefix), or the * empty string if Namespace processing is not being * performed. * @param qName The qualified XML 1.0 name (with prefix), or the * empty string if qualified names are not available. * @throws SAXException Any SAX exception, possibly * wrapping another exception. * @see org.xml.sax.ContentHandler#endElement */ public void endElement(String uri, String localName, String qName) throws SAXException { if (DEBUG) System.out.println("endElement: uri: " + uri + ", localname: " + localName + ", qname: "+qName); charactersFlush(); // If no one noticed, startPrefixMapping is a drag. // Pop the context for the last child (the one pushed by startElement) m_contextIndexes.quickPop(1); // Do it again for this one (the one pushed by the last endElement). int topContextIndex = m_contextIndexes.peek(); if (topContextIndex != m_prefixMappings.size()) { m_prefixMappings.setSize(topContextIndex); } int lastNode = m_previous; m_previous = m_parents.pop(); // If lastNode is still DTM.NULL, this element had no children if (DTM.NULL == lastNode) m_firstch.setElementAt(DTM.NULL,m_previous); else m_nextsib.setElementAt(DTM.NULL,lastNode); popShouldStripWhitespace(); } /** * Receive notification of character data inside an element. * *

By default, do nothing. Application writers may override this * method to take specific actions for each chunk of character data * (such as adding the data to a node or buffer, or printing it to * a file).

* * @param ch The characters. * @param start The start position in the character array. * @param length The number of characters to use from the * character array. * @throws SAXException Any SAX exception, possibly * wrapping another exception. * @see org.xml.sax.ContentHandler#characters */ public void characters(char ch[], int start, int length) throws SAXException { if (m_textPendingStart == -1) // First one in this block { m_textPendingStart = m_chars.size(); m_coalescedTextType = m_textType; } // Type logic: If all adjacent text is CDATASections, the // concatentated text is treated as a single CDATASection (see // initialization above). If any were ordinary Text, the whole // thing is treated as Text. This may be worth %REVIEW%ing. else if (m_textType == DTM.TEXT_NODE) { m_coalescedTextType = DTM.TEXT_NODE; } m_chars.append(ch, start, length); } /** * Receive notification of ignorable whitespace in element content. * *

By default, do nothing. Application writers may override this * method to take specific actions for each chunk of ignorable * whitespace (such as adding data to a node or buffer, or printing * it to a file).

* * @param ch The whitespace characters. * @param start The start position in the character array. * @param length The number of characters to use from the * character array. * @throws SAXException Any SAX exception, possibly * wrapping another exception. * @see org.xml.sax.ContentHandler#ignorableWhitespace */ public void ignorableWhitespace(char ch[], int start, int length) throws SAXException { // %OPT% We can probably take advantage of the fact that we know this // is whitespace. characters(ch, start, length); } /** * Receive notification of a processing instruction. * *

By default, do nothing. Application writers may override this * method in a subclass to take specific actions for each * processing instruction, such as setting status variables or * invoking other methods.

* * @param target The processing instruction target. * @param data The processing instruction data, or null if * none is supplied. * @throws SAXException Any SAX exception, possibly * wrapping another exception. * @see org.xml.sax.ContentHandler#processingInstruction */ public void processingInstruction(String target, String data) throws SAXException { if (DEBUG) System.out.println("processingInstruction: target: " + target +", data: "+data); charactersFlush(); int exName = m_expandedNameTable.getExpandedTypeID(null, target, DTM.PROCESSING_INSTRUCTION_NODE); int dataIndex = m_valuesOrPrefixes.stringToIndex(data); m_previous = addNode(DTM.PROCESSING_INSTRUCTION_NODE, exName, m_parents.peek(), m_previous, dataIndex, false); } /** * Receive notification of a skipped entity. * *

By default, do nothing. Application writers may override this * method in a subclass to take specific actions for each * processing instruction, such as setting status variables or * invoking other methods.

* * @param name The name of the skipped entity. * @throws SAXException Any SAX exception, possibly * wrapping another exception. * @see org.xml.sax.ContentHandler#processingInstruction */ public void skippedEntity(String name) throws SAXException { // %REVIEW% What should be done here? // no op } //////////////////////////////////////////////////////////////////// // Implementation of the ErrorHandler interface. //////////////////////////////////////////////////////////////////// /** * Receive notification of a parser warning. * *

The default implementation does nothing. Application writers * may override this method in a subclass to take specific actions * for each warning, such as inserting the message in a log file or * printing it to the console.

* * @param e The warning information encoded as an exception. * @throws SAXException Any SAX exception, possibly * wrapping another exception. * @see org.xml.sax.ErrorHandler#warning * @see org.xml.sax.SAXParseException */ public void warning(SAXParseException e) throws SAXException { // %REVIEW% Is there anyway to get the JAXP error listener here? System.err.println(e.getMessage()); } /** * Receive notification of a recoverable parser error. * *

The default implementation does nothing. Application writers * may override this method in a subclass to take specific actions * for each error, such as inserting the message in a log file or * printing it to the console.

* * @param e The warning information encoded as an exception. * @throws SAXException Any SAX exception, possibly * wrapping another exception. * @see org.xml.sax.ErrorHandler#warning * @see org.xml.sax.SAXParseException */ public void error(SAXParseException e) throws SAXException { throw e; } /** * Report a fatal XML parsing error. * *

The default implementation throws a SAXParseException. * Application writers may override this method in a subclass if * they need to take specific actions for each fatal error (such as * collecting all of the errors into a single report): in any case, * the application must stop all regular processing when this * method is invoked, since the document is no longer reliable, and * the parser may no longer report parsing events.

* * @param e The error information encoded as an exception. * @throws SAXException Any SAX exception, possibly * wrapping another exception. * @see org.xml.sax.ErrorHandler#fatalError * @see org.xml.sax.SAXParseException */ public void fatalError(SAXParseException e) throws SAXException { throw e; } //////////////////////////////////////////////////////////////////// // Implementation of the DeclHandler interface. //////////////////////////////////////////////////////////////////// /** * Report an element type declaration. * *

The content model will consist of the string "EMPTY", the * string "ANY", or a parenthesised group, optionally followed * by an occurrence indicator. The model will be normalized so * that all whitespace is removed,and will include the enclosing * parentheses.

* * @param name The element type name. * @param model The content model as a normalized string. * @throws SAXException The application may raise an exception. */ public void elementDecl(String name, String model) throws SAXException { // no op } /** * Report an attribute type declaration. * *

Only the effective (first) declaration for an attribute will * be reported. The type will be one of the strings "CDATA", * "ID", "IDREF", "IDREFS", "NMTOKEN", "NMTOKENS", "ENTITY", * "ENTITIES", or "NOTATION", or a parenthesized token group with * the separator "|" and all whitespace removed.

* * @param eName The name of the associated element. * @param aName The name of the attribute. * @param type A string representing the attribute type. * @param valueDefault A string representing the attribute default * ("#IMPLIED", "#REQUIRED", or "#FIXED") or null if * none of these applies. * @param value A string representing the attribute's default value, * or null if there is none. * @throws SAXException The application may raise an exception. */ public void attributeDecl( String eName, String aName, String type, String valueDefault, String value) throws SAXException { // no op } /** * Report an internal entity declaration. * *

Only the effective (first) declaration for each entity * will be reported.

* * @param name The name of the entity. If it is a parameter * entity, the name will begin with '%'. * @param value The replacement text of the entity. * @throws SAXException The application may raise an exception. * @see #externalEntityDecl * @see org.xml.sax.DTDHandler#unparsedEntityDecl */ public void internalEntityDecl(String name, String value) throws SAXException { // no op } /** * Report a parsed external entity declaration. * *

Only the effective (first) declaration for each entity * will be reported.

* * @param name The name of the entity. If it is a parameter * entity, the name will begin with '%'. * @param publicId The declared public identifier of the entity, or * null if none was declared. * @param systemId The declared system identifier of the entity. * @throws SAXException The application may raise an exception. * @see #internalEntityDecl * @see org.xml.sax.DTDHandler#unparsedEntityDecl */ public void externalEntityDecl( String name, String publicId, String systemId) throws SAXException { // no op } //////////////////////////////////////////////////////////////////// // Implementation of the LexicalHandler interface. //////////////////////////////////////////////////////////////////// /** * Report the start of DTD declarations, if any. * *

Any declarations are assumed to be in the internal subset * unless otherwise indicated by a {@link #startEntity startEntity} * event.

* *

Note that the start/endDTD events will appear within * the start/endDocument events from ContentHandler and * before the first startElement event.

* * @param name The document type name. * @param publicId The declared public identifier for the * external DTD subset, or null if none was declared. * @param systemId The declared system identifier for the * external DTD subset, or null if none was declared. * @throws SAXException The application may raise an * exception. * @see #endDTD * @see #startEntity */ public void startDTD(String name, String publicId, String systemId) throws SAXException { m_insideDTD = true; } /** * Report the end of DTD declarations. * * @throws SAXException The application may raise an exception. * @see #startDTD */ public void endDTD() throws SAXException { m_insideDTD = false; } /** * Report the beginning of an entity in content. * *

NOTE: entity references in attribute * values -- and the start and end of the document entity -- * are never reported.

* *

The start and end of the external DTD subset are reported * using the pseudo-name "[dtd]". All other events must be * properly nested within start/end entity events.

* *

Note that skipped entities will be reported through the * {@link org.xml.sax.ContentHandler#skippedEntity skippedEntity} * event, which is part of the ContentHandler interface.

* * @param name The name of the entity. If it is a parameter * entity, the name will begin with '%'. * @throws SAXException The application may raise an exception. * @see #endEntity * @see org.xml.sax.ext.DeclHandler#internalEntityDecl * @see org.xml.sax.ext.DeclHandler#externalEntityDecl */ public void startEntity(String name) throws SAXException { // no op } /** * Report the end of an entity. * * @param name The name of the entity that is ending. * @throws SAXException The application may raise an exception. * @see #startEntity */ public void endEntity(String name) throws SAXException { // no op } /** * Report the start of a CDATA section. * *

The contents of the CDATA section will be reported through * the regular {@link org.xml.sax.ContentHandler#characters * characters} event.

* * @throws SAXException The application may raise an exception. * @see #endCDATA */ public void startCDATA() throws SAXException { m_textType = DTM.CDATA_SECTION_NODE; } /** * Report the end of a CDATA section. * * @throws SAXException The application may raise an exception. * @see #startCDATA */ public void endCDATA() throws SAXException { m_textType = DTM.TEXT_NODE; } /** * Report an XML comment anywhere in the document. * *

This callback will be used for comments inside or outside the * document element, including comments in the external DTD * subset (if read).

* * @param ch An array holding the characters in the comment. * @param start The starting position in the array. * @param length The number of characters to use from the array. * @throws SAXException The application may raise an exception. */ public void comment(char ch[], int start, int length) throws SAXException { if (m_insideDTD) // ignore comments if we're inside the DTD return; charactersFlush(); int exName = m_expandedNameTable.getExpandedTypeID(DTM.COMMENT_NODE); // For now, treat comments as strings... I guess we should do a // seperate FSB buffer instead. int dataIndex = m_valuesOrPrefixes.stringToIndex(new String(ch, start, length)); m_previous = addNode(DTM.COMMENT_NODE, exName, m_parents.peek(), m_previous, dataIndex, false); } /** * Set a run time property for this DTM instance. * * %REVIEW% Now that we no longer use this method to support * getSourceLocatorFor, can we remove it? * * @param property a String value * @param value an Object value */ public void setProperty(String property, Object value) { } /** Retrieve the SourceLocator associated with a specific node. * This is only meaningful if the XalanProperties.SOURCE_LOCATION flag was * set True using setProperty; if it was never set, or was set false, we * will return null. * * (We _could_ return a locator with the document's base URI and bogus * line/column information. Trying that; see the else clause.) * */ public SourceLocator getSourceLocatorFor(int node) { if (m_useSourceLocationProperty) { node = makeNodeIdentity(node); return new NodeLocator(null, m_sourceSystemId.elementAt(node), m_sourceLine.elementAt(node), m_sourceColumn.elementAt(node)); } else if(m_locator!=null) { return new NodeLocator(null,m_locator.getSystemId(),-1,-1); } else if(m_systemId!=null) { return new NodeLocator(null,m_systemId,-1,-1); } return null; } public String getFixedNames(int type){ return m_fixednames[type]; } }