[jdom-interest] Fw: Code Submission: Refactoring of SAXBuilder

James Strachan james at metastuff.com
Fri Nov 17 09:45:19 PST 2000


The first post didn't seem to make it to the list so I thought I'd repost...
 
----- Original Message ----- 
From: James Strachan <mailto:james at metastuff.com>  
To: jdom-interest at jdom.org <mailto:jdom-interest at jdom.org>  
Sent: Friday, November 17, 2000 11:41 AM
Subject: Code Submission: Refactoring of SAXBuilder

I've attached the patch file for SAXBuilder.java together with a new file,
SAXHandler.java and the new version of SAXBuilder.java.
 
Basically I've split SAXHandler into its own java file. I've also refactored
both SAXBuilder and SAXHandler to implement Factory Method patterns such
that people can quite easily derive from SAXBuilder and SAXHandler to
provide their own derived Element, Attribute et al implementations.
 
Incorporating these changes into CVS should then allow anyone to add any
special applicaiton specific attributes to Element, Attribute or whatever.
Particularly, bob's work on XPath should be quite straightforward, now an
XPathAttribute / XPathElement can be done to store the necessary
relationships (e.g. Attribute to store its owning Element).
 
It should also put to bed the getUserObject() / setUserObject() on Element
discussion. Whether a developer wants to go the getUserObject() route, or
provide a typesafe derivation of Element, should be straightforward through
derivation of the SAX builder classes.
 
Looking at the new refactored code though, I'm now leaning towards further
code refactoring - putting all the factory methods into a new object called
(say) SAXFactory such that a new SAXFactory object can be given to
SAXBuilder. This would allow one simple derivation, MySAXFactory rather than
2 via a MySAXBuilder and a MySAXHandler.
 
Thoughts?
 
J.
 
James Strachan
=============
email: james at metastuff.com <mailto:james at metastuff.com> 
web: http://www.metastuff.com <http://www.metastuff.com> 



If you are not the addressee of this confidential e-mail and any
attachments, please delete it and inform the sender; unauthorised
redistribution or publication is prohibited. Views expressed are those of
the author and do not necessarily represent those of Citria Limited.
      
-------------- next part --------------
Index: SAXBuilder.java
===================================================================
RCS file: /home/cvspublic/jdom/src/java/org/jdom/input/SAXBuilder.java,v
retrieving revision 1.25
diff -u -r1.25 SAXBuilder.java
--- SAXBuilder.java	2000/10/23 17:16:29	1.25
+++ SAXBuilder.java	2000/11/17 11:03:01
@@ -80,6 +80,7 @@
 import org.jdom.ProcessingInstruction;
 
 import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
 import org.xml.sax.DTDHandler;
 import org.xml.sax.EntityResolver;
 import org.xml.sax.ErrorHandler;
@@ -265,8 +266,7 @@
                 parser = saxXMLFilter;
             }
 
-            DefaultHandler contentHandler =
-                new SAXHandler(doc);
+            DefaultHandler contentHandler = createContentHandler( doc );
 
             parser.setContentHandler(contentHandler);
 
@@ -493,419 +493,10 @@
         }
         return new URL("file", "", path);
     }
-}
-
-class SAXHandler extends DefaultHandler implements LexicalHandler {
-
-    /** <code>Document</code> object being built */
-    private Document document;
-
-    /** Element stack */
-    private Stack stack;
-
-    /** Indicator of where in the document we are */
-    private boolean atRoot;
-
-    /** Indicator of whether we are in a DTD */
-    private boolean inDTD;
-
-    /** Indicator of whether we are in a CDATA */
-    private boolean inCDATA;
-
-    /** Indicator of whether we are in an <code>Entity</code> */
-    private boolean inEntity;
-
-    /** Namespaces declared, but not available */
-    private List declaredNamespaces;
-
-    /** Available namespaces */
-    private List availableNamespaces;
-
-    /**
-     * <p>
-     * This will set the <code>Document</code> to use.
-     * </p>
-     *
-     * @param document <code>Document</code> being parsed.
-     * @throws <code>IOException</code> when errors occur.
-     */
-    public SAXHandler(Document document) throws IOException {
-        this.document = document;
-        atRoot = true;
-        stack = new Stack();
-        declaredNamespaces = new LinkedList();
-        availableNamespaces = new LinkedList();
-        availableNamespaces.add(Namespace.XML_NAMESPACE);
-        inEntity = false;
-        inDTD = false;
-        inCDATA = false;
-    }
-
-    /**
-     * <p>
-     * This will indicate that a processing instruction (other than
-     *   the XML declaration) has been encountered.
-     * </p>
-     *
-     * @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 <code>SAXException</code> when things go wrong
-     */
-    public void processingInstruction(String target, String data)
-        throws SAXException {
-
-        if (atRoot) {
-            document.addContent(new ProcessingInstruction(target, data));
-        } else {
-            ((Element)stack.peek()).addContent(new ProcessingInstruction(target, data));
-        }
-    }
-
-    /**
-     * <p>
-     * This will add the prefix mapping to the JDOM
-     *   <code>Document</code> object.
-     * </p>
-     *
-     * @param prefix <code>String</code> namespace prefix.
-     * @param uri <code>String</code> namespace URI.
-     */
-    public void startPrefixMapping(String prefix, String uri)
-        throws SAXException {
-
-        Namespace ns = Namespace.getNamespace(prefix, uri);
-        declaredNamespaces.add(ns);
-    }
-
-    /**
-     * <p>
-     * This will add the prefix mapping to the JDOM
-     *   <code>Document</code> object.
-     * </p>
-     *
-     * @param prefix <code>String</code> namespace prefix.
-     * @param uri <code>String</code> namespace URI.
-     */
-    public void endPrefixMapping(String prefix, String uri)
-        throws SAXException {
-
-        // This removes the namespace for the actual element
-        Namespace ns = Namespace.getNamespace(prefix, uri);
-        availableNamespaces.remove(ns);
-    }
-
-    /**
-     * <p>
-     * 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>.
-     * </p>
-     *
-     * @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 rawName <code>String</code> XML 1.0 version of element name:
-     *                [namespace prefix]:[localName]
-     * @param atts <code>Attributes</code> list for this element
-     * @throws <code>SAXException</code> when things go wrong
-     */
-    public void startElement(String namespaceURI, String localName,
-                             String qName, Attributes atts) throws SAXException {
-
-        Element element = null;
-
-        if ((namespaceURI != null) && (!namespaceURI.equals(""))) {
-            String prefix = "";
-
-            // Determine any prefix on the Element
-            if (localName != qName) {
-                int split = qName.indexOf(":");
-                prefix = qName.substring(0, split);
-            }
-            Namespace elementNamespace = Namespace.getNamespace(prefix, namespaceURI);
-            element = new Element(localName, elementNamespace);
-
-            // We want to remove this namespace from those declared, as we've handled that
-            declaredNamespaces.remove(elementNamespace);
-
-            // We do need to make it available for others to use, though
-            availableNamespaces.add(elementNamespace);
-        } else {
-            element = new Element(localName);
-        }
-
-        // We need to take all declared namespaces and add them to this element
-        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);
-
-            if (attLocalName != attQName) {
-                String attPrefix = attQName.substring(0, attQName.indexOf(":"));
-                attribute = new Attribute(attLocalName, atts.getValue(i), getNamespace(attPrefix));
-            } else {
-                attribute = new Attribute(attLocalName, atts.getValue(i));
-            }
-
-            element.addAttribute(attribute);
-        }
-
-        if (atRoot) {
-            document.setRootElement(element);
-            stack.push(element);
-            atRoot = false;
-        } else {
-            ((Element)stack.peek()).addContent(element);
-            stack.push(element);
-        }
-    }
-
-    private void transferNamespaces(Element element) {
-        Iterator i = declaredNamespaces.iterator();
-        while (i.hasNext()) {
-            Namespace ns = (Namespace)i.next();
-            i.remove();
-            availableNamespaces.add(ns);
-            element.addNamespaceDeclaration(ns);
-        }
-    }
-
-    private Namespace getNamespace(String prefix) {
-        for (int i=availableNamespaces.size(); i>0; i--) {
-            Namespace ns = (Namespace)availableNamespaces.get(i-1);
-            if (prefix.equals(ns.getPrefix())) {
-                return ns;
-            }
-        }
-
-        return Namespace.NO_NAMESPACE;
-    }
-
-    /**
-     * <p>
-     * This will report character data (within an element).
-     * </p>
-     *
-     * @param ch <code>char[]</code> character array with character data
-     * @param start <code>int</code> index in array where data starts.
-     * @param end <code>int</code> index in array where data ends.
-     * @throws <code>SAXException</code> when things go wrong
-     */
-    public void characters(char[] ch, int start, int end)
-        throws SAXException {
-
-        String data = new String(ch, start, end);
-
-        if (inCDATA) {
-            ((Element)stack.peek()).addContent(new CDATA(data));
- 
-        /**
-         * This is commented out because of some problems with
-         *   the inline DTDs that Xerces seems to have.
-        } else if (!inDTD) {
-            if (inEntity) {
-                ((Entity)stack.peek()).setContent(data);
-            } else {
-                Element e = (Element)stack.peek();
-                e.addContent(data);
-            }
-         */
-        } else if (inEntity) {
-            ((Entity)stack.peek()).setContent(data);
-        } else {
-            Element e = (Element)stack.peek();
-            e.addContent(data);
-        }
-    }
-
-    /**
-     * <p>
-     * Indicates the end of an element
-     *   (<code>&lt;/[element name]&gt;</code>) is reached.  Note that
-     *   the parser does not distinguish between empty
-     *   elements and non-empty elements, so this will occur uniformly.
-     * </p>
-     *
-     * @param namespaceURI <code>String</code> URI of namespace this
-     *                     element is associated with
-     * @param localName <code>String</code> name of element without prefix
-     * @param rawName <code>String</code> name of element in XML 1.0 form
-     * @throws <code>SAXException</code> when things go wrong
-     */
-    public void endElement(String namespaceURI, String localName,
-                           String rawName) {
-
-        Element element = (Element)stack.pop();
-        
-        // Remove the namespaces that this element makes available
-        availableNamespaces.remove(element.getAdditionalNamespaces());
-        
-    }
-
-    /**
-     * <p>
-     * This will report an error that has occurred; this indicates
-     *   that a rule was broken, typically in validation, but that
-     *   parsing can reasonably continue.
-     * </p>
-     *
-     * @param exception <code>SAXParseException</code> that occurred.
-     * @throws <code>SAXException</code> when things go wrong
-     */
-    public void error(SAXParseException exception)
-        throws SAXException {
-
-        throw exception;
-    }
-
-    /**
-     * <p>
-     * This will report an error that has occurred; this indicates
-     *   that a rule was broken, typically in validation, but that
-     *   parsing can reasonably continue.
-     * </p>
-     *
-     * @param exception <code>SAXParseException</code> that occurred.
-     * @throws <code>SAXException</code> when things go wrong
-     */
-    public void warning(SAXParseException exception)
-        throws SAXException {
-
-        throw exception;
-    }
-
-    /**
-     * <p>
-     * This will report an error that has occurred; this indicates
-     *   that a rule was broken, typically in validation, but that
-     *   parsing can reasonably continue.
-     * </p>
-     *
-     * @param exception <code>SAXParseException</code> that occurred.
-     * @throws <code>SAXException</code> when things go wrong
-     */
-    public void fatalError(SAXParseException exception)
-        throws SAXException {
-
-        throw exception;
-    }
-
-    /**
-     * <p>
-     * 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.
-     * </p>
-     *
-     * @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> syste ID of DTD
-     */
-    public void startDTD(String name, String publicId, String systemId)
-        throws SAXException {
-
-        document.setDocType(
-            new DocType(name, publicId, systemId));
-        inDTD = true;
-
-        /* Debug
-        System.out.println("startDTD invoked...");
-        */
-    }
-
-    /**
-     * <p>
-     * This signifies that the reading of the DTD is complete.
-     * </p>
-     */
-    public void endDTD() throws SAXException {
-        inDTD = false;
-
-        /* Debug 
-        System.out.println("endDTD invoked...");
-        */
-    }
-
-    public void startEntity(String name)
-        throws SAXException {
-
-        // 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"))) {
-
-            Entity entity = new Entity(name);
-            ((Element)stack.peek()).addContent(entity);
-            stack.push(entity);
-            inEntity = true;
-        }
-    }
-
-    public void endEntity(String name)
-        throws SAXException {
-
-        if (inEntity) {
-            stack.pop();
-            inEntity = false;
-        }
-    }
-
-    /**
-     * <p>
-     * Report a CDATA section - ignored in SAXBuilder.
-     * </p>
-     */
-    public void startCDATA() throws SAXException {
-        inCDATA = true;
-    }
-
-    /**
-     * <p>
-     * Report a CDATA section - ignored in SAXBuilder.
-     * </p>
-     */
-    public void endCDATA() throws SAXException {
-        inCDATA = false;
-    }
-
-    /**
-     * <p>
-     * 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.
-     * </p>
-     *
-     * @param ch <code>ch[]</code> array of comment characters.
-     * @param start <code>int</code> index to start reading from.
-     * @param end <code>int</code> index to end reading at.
-     */
-    public void comment(char[] ch, int start, int end)
-        throws SAXException {
-
-        String commentText = new String(ch, start, end);
-        if ((!inDTD) && (!commentText.equals(""))) {
-            if (stack.empty()) {
-                document.addContent(
-                   new Comment(commentText));
-            } else {
-                ((Element)stack.peek()).addContent(
-                    new Comment(commentText));
-            }
-        }
+    
+    /** Factory Method to allow user derived SAXHandlers to be used
+      */
+    protected DefaultHandler createContentHandler( Document doc ) throws IOException {
+        return new SAXHandler(doc);
     }
 }
-------------- next part --------------
A non-text attachment was scrubbed...
Name: SAXBuilder.java
Type: application/octet-stream
Size: 16421 bytes
Desc: not available
Url : http://jdom.org/pipermail/jdom-interest/attachments/20001117/44141a29/SAXBuilder.obj
-------------- next part --------------
A non-text attachment was scrubbed...
Name: SAXHandler.java
Type: application/octet-stream
Size: 18808 bytes
Desc: not available
Url : http://jdom.org/pipermail/jdom-interest/attachments/20001117/44141a29/SAXHandler.obj


More information about the jdom-interest mailing list