1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018 |
- /*--
-
- $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 $";
-
- /** 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;
- }
- }
|