Mercurial > repos > pfrommolt > ngsrich
diff NGSrich_0.5.5/src/org/jdom/input/SAXHandler.java @ 0:89ad0a9cca52 default tip
Uploaded
author | pfrommolt |
---|---|
date | Mon, 21 Nov 2011 08:12:19 -0500 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/NGSrich_0.5.5/src/org/jdom/input/SAXHandler.java Mon Nov 21 08:12:19 2011 -0500 @@ -0,0 +1,1018 @@ +/*-- + + $Id: SAXHandler.java,v 1.73 2007/11/10 05:29:00 jhunter Exp $ + + Copyright (C) 2000-2007 Jason Hunter & Brett McLaughlin. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions, and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions, and the disclaimer that follows + these conditions in the documentation and/or other materials + provided with the distribution. + + 3. The name "JDOM" must not be used to endorse or promote products + derived from this software without prior written permission. For + written permission, please contact <request_AT_jdom_DOT_org>. + + 4. Products derived from this software may not be called "JDOM", nor + may "JDOM" appear in their name, without prior written permission + from the JDOM Project Management <request_AT_jdom_DOT_org>. + + In addition, we request (but do not require) that you include in the + end-user documentation provided with the redistribution and/or in the + software itself an acknowledgement equivalent to the following: + "This product includes software developed by the + JDOM Project (http://www.jdom.org/)." + Alternatively, the acknowledgment may be graphical using the logos + available at http://www.jdom.org/images/logos. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + + This software consists of voluntary contributions made by many + individuals on behalf of the JDOM Project and was originally + created by Jason Hunter <jhunter_AT_jdom_DOT_org> and + Brett McLaughlin <brett_AT_jdom_DOT_org>. For more information + on the JDOM Project, please see <http://www.jdom.org/>. + + */ + +package org.jdom.input; + +import java.util.*; + +import org.jdom.*; +import org.xml.sax.*; +import org.xml.sax.ext.*; +import org.xml.sax.helpers.*; + +/** + * A support class for {@link SAXBuilder}. + * + * @version $Revision: 1.73 $, $Date: 2007/11/10 05:29:00 $ + * @author Brett McLaughlin + * @author Jason Hunter + * @author Philip Nelson + * @author Bradley S. Huffman + * @author phil@triloggroup.com + */ +public class SAXHandler extends DefaultHandler implements LexicalHandler, + DeclHandler, + DTDHandler { + + private static final String CVS_ID = + "@(#) $RCSfile: SAXHandler.java,v $ $Revision: 1.73 $ $Date: 2007/11/10 05:29:00 $ $Name: jdom_1_1_1 $"; + + /** Hash table to map SAX attribute type names to JDOM attribute types. */ + private static final Map attrNameToTypeMap = new HashMap(13); + + /** <code>Document</code> object being built */ + private Document document; + + /** <code>Element</code> object being built */ + private Element currentElement; + + /** Indicator of where in the document we are */ + private boolean atRoot; + + /** Indicator of whether we are in the DocType. Note that the DTD consists + * of both the internal subset (inside the <!DOCTYPE> tag) and the + * external subset (in a separate .dtd file). */ + private boolean inDTD = false; + + /** Indicator of whether we are in the internal subset */ + private boolean inInternalSubset = false; + + /** Indicator of whether we previously were in a CDATA */ + private boolean previousCDATA = false; + + /** Indicator of whether we are in a CDATA */ + private boolean inCDATA = false; + + /** Indicator of whether we should expand entities */ + private boolean expand = true; + + /** Indicator of whether we are actively suppressing (non-expanding) a + current entity */ + private boolean suppress = false; + + /** How many nested entities we're currently within */ + private int entityDepth = 0; // XXX may not be necessary anymore? + + /** Temporary holder for namespaces that have been declared with + * startPrefixMapping, but are not yet available on the element */ + private List declaredNamespaces; + + /** Temporary holder for the internal subset */ + private StringBuffer internalSubset = new StringBuffer(); + + /** Temporary holder for Text and CDATA */ + private TextBuffer textBuffer = new TextBuffer(); + + /** The external entities defined in this document */ + private Map externalEntities; + + /** The JDOMFactory used for JDOM object creation */ + private JDOMFactory factory; + + /** Whether to ignore ignorable whitespace */ + private boolean ignoringWhite = false; + + /** Whether to ignore text containing all whitespace */ + private boolean ignoringBoundaryWhite = false; + + /** The SAX Locator object provided by the parser */ + private Locator locator; + + /** + * Class initializer: Populate a table to translate SAX attribute + * type names into JDOM attribute type value (integer). + * <p> + * <b>Note that all the mappings defined below are compliant with + * the SAX 2.0 specification exception for "ENUMERATION" with is + * specific to Crimson 1.1.X and Xerces 2.0.0-betaX which report + * attributes of enumerated types with a type "ENUMERATION" + * instead of the expected "NMTOKEN". + * </p> + * <p> + * Note also that Xerces 1.4.X is not SAX 2.0 compliant either + * but handling its case requires + * {@link #getAttributeType specific code}. + * </p> + */ + static { + attrNameToTypeMap.put("CDATA", + new Integer(Attribute.CDATA_TYPE)); + attrNameToTypeMap.put("ID", + new Integer(Attribute.ID_TYPE)); + attrNameToTypeMap.put("IDREF", + new Integer(Attribute.IDREF_TYPE)); + attrNameToTypeMap.put("IDREFS", + new Integer(Attribute.IDREFS_TYPE)); + attrNameToTypeMap.put("ENTITY", + new Integer(Attribute.ENTITY_TYPE)); + attrNameToTypeMap.put("ENTITIES", + new Integer(Attribute.ENTITIES_TYPE)); + attrNameToTypeMap.put("NMTOKEN", + new Integer(Attribute.NMTOKEN_TYPE)); + attrNameToTypeMap.put("NMTOKENS", + new Integer(Attribute.NMTOKENS_TYPE)); + attrNameToTypeMap.put("NOTATION", + new Integer(Attribute.NOTATION_TYPE)); + attrNameToTypeMap.put("ENUMERATION", + new Integer(Attribute.ENUMERATED_TYPE)); + } + + /** + * This will create a new <code>SAXHandler</code> that listens to SAX + * events and creates a JDOM Document. The objects will be constructed + * using the default factory. + */ + public SAXHandler() { + this(null); + } + + /** + * This will create a new <code>SAXHandler</code> that listens to SAX + * events and creates a JDOM Document. The objects will be constructed + * using the provided factory. + * + * @param factory <code>JDOMFactory</code> to be used for constructing + * objects + */ + public SAXHandler(JDOMFactory factory) { + if (factory != null) { + this.factory = factory; + } else { + this.factory = new DefaultJDOMFactory(); + } + + atRoot = true; + declaredNamespaces = new ArrayList(); + externalEntities = new HashMap(); + + document = this.factory.document(null); + } + + /** + * Pushes an element onto the tree under construction. Allows subclasses + * to put content under a dummy root element which is useful for building + * content that would otherwise be a non-well formed document. + * + * @param element root element under which content will be built + */ + protected void pushElement(Element element) { + if (atRoot) { + document.setRootElement(element); // XXX should we use a factory call? + atRoot = false; + } + else { + factory.addContent(currentElement, element); + } + currentElement = element; + } + + /** + * Returns the document. Should be called after parsing is complete. + * + * @return <code>Document</code> - Document that was built + */ + public Document getDocument() { + return document; + } + + /** + * Returns the factory used for constructing objects. + * + * @return <code>JDOMFactory</code> - the factory used for + * constructing objects. + * + * @see #SAXHandler(org.jdom.JDOMFactory) + */ + public JDOMFactory getFactory() { + return factory; + } + + /** + * This sets whether or not to expand entities during the build. + * A true means to expand entities as normal content. A false means to + * leave entities unexpanded as <code>EntityRef</code> objects. The + * default is true. + * + * @param expand <code>boolean</code> indicating whether entity expansion + * should occur. + */ + public void setExpandEntities(boolean expand) { + this.expand = expand; + } + + /** + * Returns whether or not entities will be expanded during the + * build. + * + * @return <code>boolean</code> - whether entity expansion + * will occur during build. + * + * @see #setExpandEntities + */ + public boolean getExpandEntities() { + return expand; + } + + /** + * Specifies whether or not the parser should elminate whitespace in + * element content (sometimes known as "ignorable whitespace") when + * building the document. Only whitespace which is contained within + * element content that has an element only content model will be + * eliminated (see XML Rec 3.2.1). For this setting to take effect + * requires that validation be turned on. The default value of this + * setting is <code>false</code>. + * + * @param ignoringWhite Whether to ignore ignorable whitespace + */ + public void setIgnoringElementContentWhitespace(boolean ignoringWhite) { + this.ignoringWhite = ignoringWhite; + } + + /** + * Specifies whether or not the parser should elminate text() nodes + * containing only whitespace when building the document. See + * {@link SAXBuilder#setIgnoringBoundaryWhitespace(boolean)}. + * + * @param ignoringBoundaryWhite Whether to ignore only whitespace content + */ + public void setIgnoringBoundaryWhitespace(boolean ignoringBoundaryWhite) { + this.ignoringBoundaryWhite = ignoringBoundaryWhite; + } + + /** + * Returns whether or not the parser will elminate element content + * containing only whitespace. + * + * @return <code>boolean</code> - whether only whitespace content will + * be ignored during build. + * + * @see #setIgnoringBoundaryWhitespace + */ + public boolean getIgnoringBoundaryWhitespace() { + return ignoringBoundaryWhite; + } + + /** + * Returns whether or not the parser will elminate whitespace in + * element content (sometimes known as "ignorable whitespace") when + * building the document. + * + * @return <code>boolean</code> - whether ignorable whitespace will + * be ignored during build. + * + * @see #setIgnoringElementContentWhitespace + */ + public boolean getIgnoringElementContentWhitespace() { + return ignoringWhite; + } + + public void startDocument() { + if (locator != null) { + document.setBaseURI(locator.getSystemId()); + } + } + + /** + * This is called when the parser encounters an external entity + * declaration. + * + * @param name entity name + * @param publicID public id + * @param systemID system id + * @throws SAXException when things go wrong + */ + public void externalEntityDecl(String name, + String publicID, String systemID) + throws SAXException { + // Store the public and system ids for the name + externalEntities.put(name, new String[]{publicID, systemID}); + + if (!inInternalSubset) return; + + internalSubset.append(" <!ENTITY ") + .append(name); + appendExternalId(publicID, systemID); + internalSubset.append(">\n"); + } + + /** + * This handles an attribute declaration in the internal subset. + * + * @param eName <code>String</code> element name of attribute + * @param aName <code>String</code> attribute name + * @param type <code>String</code> attribute type + * @param valueDefault <code>String</code> default value of attribute + * @param value <code>String</code> value of attribute + * @throws SAXException + */ + public void attributeDecl(String eName, String aName, String type, + String valueDefault, String value) + throws SAXException { + + if (!inInternalSubset) return; + + internalSubset.append(" <!ATTLIST ") + .append(eName) + .append(' ') + .append(aName) + .append(' ') + .append(type) + .append(' '); + if (valueDefault != null) { + internalSubset.append(valueDefault); + } else { + internalSubset.append('\"') + .append(value) + .append('\"'); + } + if ((valueDefault != null) && (valueDefault.equals("#FIXED"))) { + internalSubset.append(" \"") + .append(value) + .append('\"'); + } + internalSubset.append(">\n"); + } + + /** + * Handle an element declaration in a DTD. + * + * @param name <code>String</code> name of element + * @param model <code>String</code> model of the element in DTD syntax + * @throws SAXException + */ + public void elementDecl(String name, String model) throws SAXException { + // Skip elements that come from the external subset + if (!inInternalSubset) return; + + internalSubset.append(" <!ELEMENT ") + .append(name) + .append(' ') + .append(model) + .append(">\n"); + } + + /** + * Handle an internal entity declaration in a DTD. + * + * @param name <code>String</code> name of entity + * @param value <code>String</code> value of the entity + * @throws SAXException + */ + public void internalEntityDecl(String name, String value) + throws SAXException { + + // Skip entities that come from the external subset + if (!inInternalSubset) return; + + internalSubset.append(" <!ENTITY "); + if (name.startsWith("%")) { + internalSubset.append("% ").append(name.substring(1)); + } else { + internalSubset.append(name); + } + internalSubset.append(" \"") + .append(value) + .append("\">\n"); + } + + /** + * This will indicate that a processing instruction has been encountered. + * (The XML declaration is not a processing instruction and will not + * be reported.) + * + * @param target <code>String</code> target of PI + * @param data <code>String</code> containing all data sent to the PI. + * This typically looks like one or more attribute value + * pairs. + * @throws SAXException when things go wrong + */ + public void processingInstruction(String target, String data) + throws SAXException { + + if (suppress) return; + + flushCharacters(); + + if (atRoot) { + factory.addContent(document, factory.processingInstruction(target, data)); + } else { + factory.addContent(getCurrentElement(), + factory.processingInstruction(target, data)); + } + } + + /** + * This indicates that an unresolvable entity reference has been + * encountered, normally because the external DTD subset has not been + * read. + * + * @param name <code>String</code> name of entity + * @throws SAXException when things go wrong + */ + public void skippedEntity(String name) + throws SAXException { + + // We don't handle parameter entity references. + if (name.startsWith("%")) return; + + flushCharacters(); + + factory.addContent(getCurrentElement(), factory.entityRef(name)); + } + + /** + * This will add the prefix mapping to the JDOM + * <code>Document</code> object. + * + * @param prefix <code>String</code> namespace prefix. + * @param uri <code>String</code> namespace URI. + */ + public void startPrefixMapping(String prefix, String uri) + throws SAXException { + + if (suppress) return; + + Namespace ns = Namespace.getNamespace(prefix, uri); + declaredNamespaces.add(ns); + } + + /** + * This reports the occurrence of an actual element. It will include + * the element's attributes, with the exception of XML vocabulary + * specific attributes, such as + * <code>xmlns:[namespace prefix]</code> and + * <code>xsi:schemaLocation</code>. + * + * @param namespaceURI <code>String</code> namespace URI this element + * is associated with, or an empty + * <code>String</code> + * @param localName <code>String</code> name of element (with no + * namespace prefix, if one is present) + * @param qName <code>String</code> XML 1.0 version of element name: + * [namespace prefix]:[localName] + * @param atts <code>Attributes</code> list for this element + * @throws SAXException when things go wrong + */ + public void startElement(String namespaceURI, String localName, + String qName, Attributes atts) + throws SAXException { + if (suppress) return; + + Element element = null; + + if ((namespaceURI != null) && (!namespaceURI.equals(""))) { + String prefix = ""; + + // Determine any prefix on the Element + if (!qName.equals(localName)) { + int split = qName.indexOf(":"); + prefix = qName.substring(0, split); + } + Namespace elementNamespace = + Namespace.getNamespace(prefix, namespaceURI); + element = factory.element(localName, elementNamespace); + } else { + element = factory.element(localName); + } + + // Take leftover declared namespaces and add them to this element's + // map of namespaces + if (declaredNamespaces.size() > 0) { + transferNamespaces(element); + } + + // Handle attributes + for (int i=0, len=atts.getLength(); i<len; i++) { + Attribute attribute = null; + + String attLocalName = atts.getLocalName(i); + String attQName = atts.getQName(i); + int attType = getAttributeType(atts.getType(i)); + + // Bypass any xmlns attributes which might appear, as we got + // them already in startPrefixMapping(). + // This is sometimes necessary when SAXHandler is used with + // another source than SAXBuilder, as with JDOMResult. + if (attQName.startsWith("xmlns:") || attQName.equals("xmlns")) { + continue; + } + + // First clause per http://markmail.org/message/2p245ggcjst27xe6 + // patch from Mattias Jiderhamn + if ("".equals(attLocalName) && attQName.indexOf(":") == -1) { + attribute = factory.attribute(attQName, atts.getValue(i), attType); + } else if (!attQName.equals(attLocalName)) { + String attPrefix = attQName.substring(0, attQName.indexOf(":")); + Namespace attNs = Namespace.getNamespace(attPrefix, + atts.getURI(i)); + + attribute = factory.attribute(attLocalName, atts.getValue(i), + attType, attNs); + } else { + attribute = factory.attribute(attLocalName, atts.getValue(i), + attType); + } + factory.setAttribute(element, attribute); + } + + flushCharacters(); + + if (atRoot) { + document.setRootElement(element); // XXX should we use a factory call? + atRoot = false; + } else { + factory.addContent(getCurrentElement(), element); + } + currentElement = element; + } + + /** + * This will take the supplied <code>{@link Element}</code> and + * transfer its namespaces to the global namespace storage. + * + * @param element <code>Element</code> to read namespaces from. + */ + private void transferNamespaces(Element element) { + Iterator i = declaredNamespaces.iterator(); + while (i.hasNext()) { + Namespace ns = (Namespace)i.next(); + if (ns != element.getNamespace()) { + element.addNamespaceDeclaration(ns); + } + } + declaredNamespaces.clear(); + } + + /** + * This will report character data (within an element). + * + * @param ch <code>char[]</code> character array with character data + * @param start <code>int</code> index in array where data starts. + * @param length <code>int</code> length of data. + * @throws SAXException + */ + public void characters(char[] ch, int start, int length) + throws SAXException { + + if (suppress || (length == 0)) + return; + + if (previousCDATA != inCDATA) { + flushCharacters(); + } + + textBuffer.append(ch, start, length); + } + + /** + * Capture ignorable whitespace as text. If + * setIgnoringElementContentWhitespace(true) has been called then this + * method does nothing. + * + * @param ch <code>[]</code> - char array of ignorable whitespace + * @param start <code>int</code> - starting position within array + * @param length <code>int</code> - length of whitespace after start + * @throws SAXException when things go wrong + */ + public void ignorableWhitespace(char[] ch, int start, int length) + throws SAXException { + if (!ignoringWhite) { + characters(ch, start, length); + } + } + + /** + * This will flush any characters from SAX character calls we've + * been buffering. + * + * @throws SAXException when things go wrong + */ + protected void flushCharacters() throws SAXException { + if (ignoringBoundaryWhite) { + if (!textBuffer.isAllWhitespace()) { + flushCharacters(textBuffer.toString()); + } + } + else { + flushCharacters(textBuffer.toString()); + } + textBuffer.clear(); + } + + /** + * Flush the given string into the document. This is a protected method + * so subclassers can control text handling without knowledge of the + * internals of this class. + * + * @param data string to flush + */ + protected void flushCharacters(String data) throws SAXException { + if (data.length() == 0) { + previousCDATA = inCDATA; + return; + } + +/** + * This is commented out because of some problems with + * the inline DTDs that Xerces seems to have. +if (!inDTD) { + if (inEntity) { + getCurrentElement().setContent(factory.text(data)); + } else { + getCurrentElement().addContent(factory.text(data)); +} +*/ + + if (previousCDATA) { + factory.addContent(getCurrentElement(), factory.cdata(data)); + } + else { + factory.addContent(getCurrentElement(), factory.text(data)); + } + + previousCDATA = inCDATA; + } + + /** + * Indicates the end of an element + * (<code></[element name]></code>) is reached. Note that + * the parser does not distinguish between empty + * elements and non-empty elements, so this will occur uniformly. + * + * @param namespaceURI <code>String</code> URI of namespace this + * element is associated with + * @param localName <code>String</code> name of element without prefix + * @param qName <code>String</code> name of element in XML 1.0 form + * @throws SAXException when things go wrong + */ + public void endElement(String namespaceURI, String localName, + String qName) throws SAXException { + + if (suppress) return; + + flushCharacters(); + + if (!atRoot) { + Parent p = currentElement.getParent(); + if (p instanceof Document) { + atRoot = true; + } + else { + currentElement = (Element) p; + } + } + else { + throw new SAXException( + "Ill-formed XML document (missing opening tag for " + + localName + ")"); + } + } + + /** + * This will signify that a DTD is being parsed, and can be + * used to ensure that comments and other lexical structures + * in the DTD are not added to the JDOM <code>Document</code> + * object. + * + * @param name <code>String</code> name of element listed in DTD + * @param publicID <code>String</code> public ID of DTD + * @param systemID <code>String</code> system ID of DTD + */ + public void startDTD(String name, String publicID, String systemID) + throws SAXException { + + flushCharacters(); // Is this needed here? + + factory.addContent(document, factory.docType(name, publicID, systemID)); + inDTD = true; + inInternalSubset = true; + } + + /** + * This signifies that the reading of the DTD is complete. + * + * @throws SAXException + */ + public void endDTD() throws SAXException { + + document.getDocType().setInternalSubset(internalSubset.toString()); + inDTD = false; + inInternalSubset = false; + } + + public void startEntity(String name) throws SAXException { + entityDepth++; + + if (expand || entityDepth > 1) { + // Short cut out if we're expanding or if we're nested + return; + } + + // A "[dtd]" entity indicates the beginning of the external subset + if (name.equals("[dtd]")) { + inInternalSubset = false; + return; + } + + // Ignore DTD references, and translate the standard 5 + if ((!inDTD) && + (!name.equals("amp")) && + (!name.equals("lt")) && + (!name.equals("gt")) && + (!name.equals("apos")) && + (!name.equals("quot"))) { + + if (!expand) { + String pub = null; + String sys = null; + String[] ids = (String[]) externalEntities.get(name); + if (ids != null) { + pub = ids[0]; // may be null, that's OK + sys = ids[1]; // may be null, that's OK + } + /** + * if no current element, this entity belongs to an attribute + * in these cases, it is an error on the part of the parser + * to call startEntity but this will help in some cases. + * See org/xml/sax/ext/LexicalHandler.html#startEntity(java.lang.String) + * for more information + */ + if (!atRoot) { + flushCharacters(); + EntityRef entity = factory.entityRef(name, pub, sys); + + // no way to tell if the entity was from an attribute or element so just assume element + factory.addContent(getCurrentElement(), entity); + } + suppress = true; + } + } + } + + public void endEntity(String name) throws SAXException { + entityDepth--; + if (entityDepth == 0) { + // No way are we suppressing if not in an entity, + // regardless of the "expand" value + suppress = false; + } + if (name.equals("[dtd]")) { + inInternalSubset = true; + } + } + + /** + * Report a CDATA section + * + * @throws SAXException + */ + public void startCDATA() throws SAXException { + if (suppress) return; + + inCDATA = true; + } + + /** + * Report a CDATA section + */ + public void endCDATA() throws SAXException { + if (suppress) return; + + previousCDATA = true; + inCDATA = false; + } + + /** + * This reports that a comments is parsed. If not in the + * DTD, this comment is added to the current JDOM + * <code>Element</code>, or the <code>Document</code> itself + * if at that level. + * + * @param ch <code>ch[]</code> array of comment characters. + * @param start <code>int</code> index to start reading from. + * @param length <code>int</code> length of data. + * @throws SAXException + */ + public void comment(char[] ch, int start, int length) + throws SAXException { + + if (suppress) return; + + flushCharacters(); + + String commentText = new String(ch, start, length); + if (inDTD && inInternalSubset && (expand == false)) { + internalSubset.append(" <!--") + .append(commentText) + .append("-->\n"); + return; + } + if ((!inDTD) && (!commentText.equals(""))) { + if (atRoot) { + factory.addContent(document, factory.comment(commentText)); + } else { + factory.addContent(getCurrentElement(), factory.comment(commentText)); + } + } + } + + /** + * Handle the declaration of a Notation in a DTD + * + * @param name name of the notation + * @param publicID the public ID of the notation + * @param systemID the system ID of the notation + */ + public void notationDecl(String name, String publicID, String systemID) + throws SAXException { + + if (!inInternalSubset) return; + + internalSubset.append(" <!NOTATION ") + .append(name); + appendExternalId(publicID, systemID); + internalSubset.append(">\n"); + } + + /** + * Handler for unparsed entity declarations in the DTD + * + * @param name <code>String</code> of the unparsed entity decl + * @param publicID <code>String</code> of the unparsed entity decl + * @param systemID <code>String</code> of the unparsed entity decl + * @param notationName <code>String</code> of the unparsed entity decl + */ + public void unparsedEntityDecl(String name, String publicID, + String systemID, String notationName) + throws SAXException { + + if (!inInternalSubset) return; + + internalSubset.append(" <!ENTITY ") + .append(name); + appendExternalId(publicID, systemID); + internalSubset.append(" NDATA ") + .append(notationName); + internalSubset.append(">\n"); + } + + /** + * Appends an external ID to the internal subset buffer. Either publicID + * or systemID may be null, but not both. + * + * @param publicID the public ID + * @param systemID the system ID + */ + private void appendExternalId(String publicID, String systemID) { + if (publicID != null) { + internalSubset.append(" PUBLIC \"") + .append(publicID) + .append('\"'); + } + if (systemID != null) { + if (publicID == null) { + internalSubset.append(" SYSTEM "); + } + else { + internalSubset.append(' '); + } + internalSubset.append('\"') + .append(systemID) + .append('\"'); + } + } + + /** + * Returns the being-parsed element. + * + * @return <code>Element</code> - element being built. + * @throws SAXException + */ + public Element getCurrentElement() throws SAXException { + if (currentElement == null) { + throw new SAXException( + "Ill-formed XML document (multiple root elements detected)"); + } + return currentElement; + } + + /** + * Returns the the JDOM Attribute type value from the SAX 2.0 + * attribute type string provided by the parser. + * + * @param typeName <code>String</code> the SAX 2.0 attribute + * type string. + * + * @return <code>int</code> the JDOM attribute type. + * + * @see Attribute#setAttributeType + * @see Attributes#getType + */ + private static int getAttributeType(String typeName) { + Integer type = (Integer)(attrNameToTypeMap.get(typeName)); + if (type == null) { + if (typeName != null && typeName.length() > 0 && + typeName.charAt(0) == '(') { + // Xerces 1.4.X reports attributes of enumerated type with + // a type string equals to the enumeration definition, i.e. + // starting with a parenthesis. + return Attribute.ENUMERATED_TYPE; + } + else { + return Attribute.UNDECLARED_TYPE; + } + } else { + return type.intValue(); + } + } + + /** + * Receives an object for locating the origin of SAX document + * events. This method is invoked by the SAX parser. + * <p> + * {@link org.jdom.JDOMFactory} implementations can use the + * {@link #getDocumentLocator} method to get access to the + * {@link Locator} during parse. + * </p> + * + * @param locator <code>Locator</code> an object that can return + * the location of any SAX document event. + */ + public void setDocumentLocator(Locator locator) { + this.locator = locator; + } + + /** + * Provides access to the {@link Locator} object provided by the + * SAX parser. + * + * @return <code>Locator</code> an object that can return + * the location of any SAX document event. + */ + public Locator getDocumentLocator() { + return locator; + } +}