Improve XML parsing to handle attributes as well.
[cfb.git] / prod / net / jaekl / qd / xml / ParseResult.java
index 6c2c25f6e9c2e7b22567cbaf388038a9cc2cb685..f653b368c81f17f4dee94e8211410e334050f058 100644 (file)
@@ -8,6 +8,7 @@
 
 package net.jaekl.qd.xml;
 
+import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -19,6 +20,8 @@ import org.xml.sax.helpers.AttributesImpl;
 
 public abstract class ParseResult
 {
+       public static final String TAG_FIELD_NAME = "TAG";
+       
        Stack<CurrentInfo> m_current;                                                           // Name of the element that we're currently inside
        StringBuilder m_chars;                                                                          // character content of m_current.peek()
        ArrayList<ParseResult> m_childParsers;                                          // Set of all child parsers
@@ -65,17 +68,35 @@ public abstract class ParseResult
                }
        }
 
-       public abstract void endContents(String uri, String localName, String qName, String chars, Attributes attr) throws XmlParseException;
+       public abstract void endContents(String uri, String localName, String qName, String chars) throws XmlParseException;
        public abstract void endExternal(String uri, String localName, String qName) throws XmlParseException;
+
+       // Called once for this tag itself
+       public void handleMainAttributes(Attributes attr) throws MissingAttributeException {
+               // Default action is to do nothing.
+               // Override this if you want to process tag attributes.
+       }
+       
+       // Called once for each internally-handled subtag
+       public void handleInternalAttributes(String tagName, Attributes attr) throws MissingAttributeException {
+               // Default action is to do nothing.
+               // Override this if you want to process tag attributes.
+       }
        
        public String getTagName() { return m_tagName; }
-       public boolean haveSeenMyTag() { return m_haveSeenMyTag; }
 
        public void characters(char[] ch, int start, int length) throws XmlParseException
        {
                m_chars.append(ch, start, length);
        }
        
+       // Dump human-readable text describing this tag and its children.
+       // Default implemenation:  print the tag name (only)
+       public void dump(PrintWriter pw, int indent) {
+               String margin = String.format("%"+indent+"s", "");
+               pw.println(margin + getTagName());
+       }
+       
        protected ParseResult[] collectParsedChildren(Class<? extends ParseResult> cls) {
                ArrayList<ParseResult> collection = new ArrayList<ParseResult>();
                Iterator<ParseResult> iter = m_childParsers.iterator();
@@ -90,9 +111,9 @@ public abstract class ParseResult
                ParseResult[] result = new ParseResult[collection.size()];
                return collection.toArray(result);
        }
-
+       
        // returns true if this ParseResult's context has ended with this endElement() call
-       public boolean endElement(String uri, String localName, String qName) throws XmlParseException
+       protected boolean endElement(String uri, String localName, String qName) throws XmlParseException
        {
                assert (null != localName);
                
@@ -120,13 +141,13 @@ public abstract class ParseResult
                }
                
                String chars = m_chars.toString();
-               endContents(uri, localName, qName, chars, info.getAttributes());
+               endContents(uri, localName, qName, chars);
                
                return false;
        }
        
        // returns either itself, or a new ParseResult-derived object, whichever should handle parsing the inside of this element
-       public ParseResult startElement(String uri, String localName, String qName, Attributes attributes) 
+       public ParseResult startElement(String uri, String localName, String qName, Attributes attrs) 
                        throws XmlParseException
        {
                assert (null != localName);
@@ -138,6 +159,7 @@ public abstract class ParseResult
                        
                        if (m_tagName.equals(localName)) {
                                m_haveSeenMyTag = true;
+                               handleMainAttributes(attrs);
                                return this;
                        }
                        else {
@@ -150,7 +172,8 @@ public abstract class ParseResult
                }
 
                if (m_internal.contains(localName)) {
-                       CurrentInfo info = new CurrentInfo(localName, attributes);
+                       handleInternalAttributes(localName, attrs);
+                       CurrentInfo info = new CurrentInfo(localName, attrs);
                        m_current.push(info);
                        return this;
                }
@@ -160,7 +183,7 @@ public abstract class ParseResult
                        try {
                                ParseResult childParser = (ParseResult) parserClass.newInstance();
                                m_childParsers.add(childParser);
-                               return childParser.startElement(uri, localName, qName, attributes);
+                               return childParser.startElement(uri, localName, qName, attrs);
                        }
                        catch (IllegalAccessException iae) {
                                throw new XmlParseException(iae);
@@ -179,5 +202,25 @@ public abstract class ParseResult
                // Default implementation is a no-op.
                // Override if you want to validate on endElement()
        }
+       
+       protected String getRequiredAttr(String tagName, Attributes attr, String attrName)
+               throws MissingAttributeException
+       {
+               String result = attr.getValue(attrName);
+               if (null == result) {
+                       throw new MissingAttributeException(tagName, attrName);
+               }
+               return result;
+       }
+       
+       protected String getOptionalAttr(Attributes attr, String attrName, String defaultValue)
+       {
+               String value = attr.getValue(attrName);
+               if (null == value) {
+                       return defaultValue;
+               }
+               return value;
+       }
+
 }