You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@maven.apache.org by js...@apache.org on 2003/02/07 13:10:44 UTC

cvs commit: jakarta-turbine-maven/src/plugins-build/jellydoc/src/main/org/apache/maven/jellydoc TagXMLDoclet.java XMLDoclet.java

jstrachan    2003/02/07 04:10:44

  Added:       src/plugins-build/jellydoc plugin.properties project.xml
                        plugin.jelly .cvsignore
               src/plugins-build/jellydoc/xdocs goals.xml index.xml
                        navigation.xml properties.xml .cvsignore
               src/plugins-build/jellydoc/src/plugin-resources
                        maven-jellydoc-plugin.jelly
               src/plugins-build/jellydoc/src/main/org/apache/maven/jellydoc
                        TagXMLDoclet.java XMLDoclet.java
  Log:
  An early implementation of a jellydoc plugin. 
  The idea behind this plugin is to generate javadoc-like documentation for Jelly tags. Now there are various projects which define their own library (or libraries) of Jelly tags. So this code which used to reside inside the Jelly build has now been refactored into a Maven plugin.
  
  To add it to your build just add this to your maven.xml
  
  <preGoal name="site">
      <attainGoal name="jellydoc"/>
  </preGoal>
  
  Its still fairly simple and basic right now. Its using a doclet (rather than xdoclet or qdox) and doesn't handle DynaTag implementations very well - so I'm sure we can improve this over time. However for now this might help other projects (like Maven itself as well as other projects like Latka, Drools, Werkflow etc) create auto-generated documentation for their tags.
  
  Revision  Changes    Path
  1.1                  jakarta-turbine-maven/src/plugins-build/jellydoc/plugin.properties
  
  Index: plugin.properties
  ===================================================================
  # -------------------------------------------------------------------
  # P L U G I N  P R O P E R I E S
  # -------------------------------------------------------------------
  # Activity log plugin.
  # -------------------------------------------------------------------
  
  maven.build.dir = ${basedir}/target
  
  maven.docs.outputencoding = ISO-8859-1
  
  maven.activitylog.range = 30
  
  
  
  1.1                  jakarta-turbine-maven/src/plugins-build/jellydoc/project.xml
  
  Index: project.xml
  ===================================================================
  <?xml version="1.0" encoding="ISO-8859-1"?>
  <project>
    
    <extend>${basedir}/../project.xml</extend>
    <pomVersion>3</pomVersion>
    <id>maven-jellydoc-plugin</id>
    <name>Maven JellyDoc Plug-in</name>
    <currentVersion>1.0-SNAPSHOT</currentVersion>
  
    <!-- Gump integration -->
    <gumpRepositoryId>jakarta</gumpRepositoryId>
  
    <description>
      Creates a JavaDoc like report for any Jelly Tags used in a project.
    </description>
  
    <shortDescription></shortDescription>
  
    <url>http://jakarta.apache.org/turbine/maven/reference/plugins/jellydoc/</url>
    <issueTrackingUrl>http://jira.werken.com/BrowseProject.jspa?id=10030</issueTrackingUrl>
    <siteAddress>jakarta.apache.org</siteAddress>
    <siteDirectory>/www/jakarta.apache.org/turbine/maven/reference/plugins/jellydoc/</siteDirectory>
    <distributionDirectory>/www/jakarta.apache.org/builds/jakarta-turbine-maven/</distributionDirectory>
  
    <developers>
      <developer>
        <name>James Strachan</name>
        <id>jstrachan</id>
        <email>jstrachan@apache.org</email>
        <organization>SpiritSoft, Inc.</organization>
        <roles>
          <role>Java Developer</role>
        </roles>
      </developer>
    </developers>
  
  
    <dependencies>
  
      <dependency>
        <groupId>commons-jelly</groupId>
        <artifactId>commons-jelly-tags-jsl</artifactId>
        <version>SNAPSHOT</version>
        <url>http://jakarta.apache.org/commons/jelly/tags/jsl/</url>
        <properties>
          <classloader>root.maven</classloader>
        </properties>
      </dependency>
  
      <dependency>
        <groupId>commons-jelly</groupId>
        <artifactId>commons-jelly-tags-xml</artifactId>
        <version>SNAPSHOT</version>
        <url>http://jakarta.apache.org/commons/jelly/tags/xml/</url>
        <properties>
          <classloader>root.maven</classloader>
        </properties>
      </dependency>
  
      <dependency>
        <id>javadoc</id>
        <version>1.3</version>
        <properties>
          <classloader>root.maven</classloader>
        </properties>
      </dependency>
  
      <dependency>
        <id>nekohtml</id>
        <version>0.7.1</version>
        <properties>
          <classloader>root.maven</classloader>
        </properties>
      </dependency>
  
  		<!-- core dependencies which i'd have thought Maven introduced -->
      <dependency>
        <id>dom4j</id>
        <version>1.4-dev-8</version>
        <url>http://www.dom4j.org/</url>
      </dependency>
      <dependency>
        <id>xml-apis</id>
        <version>1.0.b2</version>
        <url>http://xml.apache.org/xerces2-j/</url>
      </dependency>
      <dependency>
        <id>xerces</id>
        <version>2.2.1</version>
        <url>http://xml.apache.org/xerces2-j/</url>
      </dependency>
      
    </dependencies>
  
  </project>
  
  
  
  1.1                  jakarta-turbine-maven/src/plugins-build/jellydoc/plugin.jelly
  
  Index: plugin.jelly
  ===================================================================
  <?xml version="1.0"?>
  
  <project
    xmlns:j="jelly:core"
    xmlns:maven="jelly:maven"
    xmlns:m="maven">
  
    <!-- ================================================================== -->
    <!-- GENERATE THE XML DOCUMENTATION                                     -->
    <!-- ================================================================== -->
    <goal name="jellydoc" prereqs="jellydoc:doclet, create-classpath"
  		description="Generates the tag documentation">
  
  		<mkdir dir="${maven.build.dir}/generated-xdocs"/>
  
  		<j:file name="${maven.build.dir}/generated-xdocs/tags.xml">
  			
  			<!-- the following should be way easier - j:include should support files -->
  			<j:new var="file" className="java.io.File">
  				<j:arg value="${plugin.resources}/${plugin.artifactId}.jelly"/>
  			</j:new>
  			
  			<!--
  			<echo>About to include ${file.toURL()}</echo>
  			-->
  			
  			<j:include uri="${file.toURL().toString()}"/>
  		</j:file>
    </goal>
    
    <!-- runs the Tag doclet -->
    <goal name="jellydoc:doclet" prereqs="jellydoc:init"
    	description="A doclet which outputs all the Jelly tag related metadata as XML">
  
  		<j:if test="${context.getVariable('maven.jellydoc.packages') == null}">
  			<j:set var="maven.jellydoc.packages" value="${pom.package}.*"/>
  		</j:if>
  		
  		<echo>Generating jellydoc for packages ${maven.jellydoc.packages}</echo>
  		
      <javadoc
        sourcepath="${pom.build.sourceDirectory}"
        packagenames="${maven.jellydoc.packages}"
        docletpathref="doclet.classpath"
        doclet="org.apache.maven.jellydoc.TagXMLDoclet">
      </javadoc>
  
    </goal>
  
    <!-- runs the XML doclet -->
    <goal name="jellydoc:xml-doclet" prereqs="jellydoc:init"
    	description="Creates an XML representation of the doclet information">
  
      <javadoc
        sourcepath="${pom.build.sourceDirectory}"
        packagenames="${pom.package}.*"
        docletpathref="doclet.classpath"
        doclet="org.apache.maven.jellydoc.XMLDoclet">
      </javadoc>
  
    </goal>
  
  
  	<!-- sets the classpath used for doclet invocations -->
    <goal name="jellydoc:init">
      <path id="doclet.classpath">
        <path refid="maven.dependency.classpath"/>
        <pathelement path="${plugin.dir}"/>
        <pathelement path="${plugin.getDependencyPath('javadoc')}"/>
        <pathelement path="${plugin.getDependencyPath('nekohtml')}"/>
        <pathelement path="${plugin.getDependencyPath('dom4j')}"/>
        <pathelement path="${plugin.getDependencyPath('xerces')}"/>
        <pathelement path="${plugin.getDependencyPath('xml-apis')}"/>
      </path>
    </goal>
  
  
  </project>
  
  
  
  1.1                  jakarta-turbine-maven/src/plugins-build/jellydoc/.cvsignore
  
  Index: .cvsignore
  ===================================================================
  target
  velocity.log
  maven.log
  
  
  
  1.1                  jakarta-turbine-maven/src/plugins-build/jellydoc/xdocs/goals.xml
  
  Index: goals.xml
  ===================================================================
  <?xml version="1.0" encoding="ISO-8859-1"?>
  <document>
  
    <properties>
      <title>JellyDoc Plugin Goals</title>
      <author email="jstrachan@apache.org">James Strachan</author>
    </properties>
  
    <body>
      <section name="Goals">
        <table>
        	<tr><th>Goal</th><th>Description</th></tr>
        	
  				<a name="jellydoc" />
        	<tr>
        	  <td>jellydoc</td>
        	  <td>
        	    The default goal. This goal generates the JellyDoc documentation of
        	    all Jelly tags defined within your code base which can then be styled
        	    into HTML as part of the xdoc goal
        	  </td>
        	</tr>
        	
        </table>
      </section>
    </body>
  </document>
  
  
  
  1.1                  jakarta-turbine-maven/src/plugins-build/jellydoc/xdocs/index.xml
  
  Index: index.xml
  ===================================================================
  <?xml version="1.0"?>
  <document>
  
    <properties>
      <title>Maven JellyDoc Plug-in</title>
      <author email="jstrachan@apache.org">James Strachan</author>
    </properties>
  
    <body>
      <section name="Maven JellyDoc Plug-in">
        <p>
          This plug-in provides JellyDoc reporting documenting all the Jelly 
          Tags defined in your code base using the 
          <code>jellydoc</code> goal as described <a href="goals.html">here</a>.
        </p>
        <p>
          The properties that allow you to customize the execution 
          are documented <a href="properties.html">here</a>.
        </p>
      </section>
   </body>
  </document>
  
  
  
  1.1                  jakarta-turbine-maven/src/plugins-build/jellydoc/xdocs/navigation.xml
  
  Index: navigation.xml
  ===================================================================
  <?xml version="1.0" encoding="ISO-8859-1"?>
  <project name="Maven JellyDoc Plugin">
  
    <title>Maven JellyDoc Plugin</title>
  
    <body>
      <links>
        <item name="Maven"    href="http://jakarta.apache.org/turbine/maven/"/>
        <item name="Jelly"    href="http://jakarta.apache.org/commons/jelly/"/>
      </links>
      <menu name="Overview">
        <item name="Goals"                   href="/goals.html" />
        <item name="Properties"              href="/properties.html" />
      </menu>
    </body>
  </project>
  
  
  
  1.1                  jakarta-turbine-maven/src/plugins-build/jellydoc/xdocs/properties.xml
  
  Index: properties.xml
  ===================================================================
  <?xml version="1.0" encoding="ISO-8859-1"?>
  <document>
  
    <properties>
      <title>JellyDoc Properties</title>
      <author email="jstrachan@apache.org">James Strachan</author>
    </properties>
  
    <body>
      <section name="JellyDoc Settings"> 
        <table>
          <tr><th>Property</th><th>Optional?</th><th>Description</th></tr>
          <tr>
            <td>maven.jellydoc.packages</td>
            <td>Yes</td>
            <td>
              Specifies the packages which contain Jelly tags. 
              By restricting this to a subset of your packages will optimise the
              goal and simplify the documentation. e.g. setting it to org.foo.jelly.*
              The default value is <code>${pom.build.sourceDirectory}.*</code>
            </td>
          </tr>
        </table>
      </section>
    </body>
  </document>
  
  
  
  1.1                  jakarta-turbine-maven/src/plugins-build/jellydoc/xdocs/.cvsignore
  
  Index: .cvsignore
  ===================================================================
  stylesheets
  
  
  
  1.1                  jakarta-turbine-maven/src/plugins-build/jellydoc/src/plugin-resources/maven-jellydoc-plugin.jelly
  
  Index: maven-jellydoc-plugin.jelly
  ===================================================================
  <?xml version="1.0"?>
  <j:jelly 
  	xmlns:j="jelly:core" 
  	xmlns:x="jelly:xml" 
  	xmlns:jsl="jelly:jsl">
  
  <j:new var="file" className="java.io.File">
  	<j:arg value="target/taglib.xml"/>
  </j:new>
  
  <x:parse var="doc" xml="${file}"/>
  <x:set var="libraries" select="$doc/tags/library"/>    	
  
  <!-- lets create a JSL stylesheet that we'll use later -->
  <jsl:stylesheet var="docStylesheet">
  
    <!-- don't output <doc> element but output its contents -->
    <jsl:template match="doc">
    	<jsl:applyTemplates/>	
    </jsl:template>
  
    <!-- ignore javadoc tags-->
    <jsl:template match="authortag"/>
    <jsl:template match="versiontag"/>
    <jsl:template match="tagtag"/>
    <jsl:template match="paramtag"/>
    <jsl:template match="requiredtag"/>
    <jsl:template match="seetag"/>
  
    <!-- let other text and elements pass through via default rules-->
    <jsl:template match="*" trim="false">
      <jsl:copy>
        <jsl:applyTemplates/>
      </jsl:copy>
    </jsl:template>
    
    <jsl:template match="@*"/>
  </jsl:stylesheet>
  
  <document>
  
      <properties>
        <title>Tag Documentation</title>
      </properties>
  
    <body>
      <section name="Tag Documentation">
  
  	  <p>
          [<a href="#Tag Libraries">tag libraries</a>]
          [<a href="#Tags">tags</a>]
        </p>
        <p>
          The following document contains a summary of all the core 
          <a href="http://jakarta.apache.org/commons/sandbox/jelly/">Jelly</a> tag libraries.  
        </p>
        
      </section>
  
      <section name="Tag Libraries">
  	  <p>
          [<a href="#Tag Libraries">tag libraries</a>]
          [<a href="#Tags">tags</a>]
        </p>
        
        <table>
  	<tr>
        <th>Library</th>
        <th>Description</th>
      </tr>
      <x:forEach select="$libraries">
      <x:set var="uri" select="string(@uri)"/>
      <tr>
        <td><a href="#${uri}">${uri}</a></td>
        <td>
        	  <jsl:style stylesheet="${docStylesheet}" select="doc"/>
  	  </td>
      </tr>
      </x:forEach>
      </table>
  
      
      <x:forEach select="$libraries">
      <x:set var="name" select="string(@uri)"/>
      <x:set var="prefix" select="string(@prefix)"/>
    
      <subsection name="${name}">
      <p>
      <jsl:style stylesheet="${docStylesheet}" select="doc"/>
      </p>
        
      <table>
      <tr>
        <th>Tag Name</th>
        <th>Description</th>
      </tr>
      
      <x:forEach select="tag">
      <x:set var="tagName" select="string(@name)"/>
      <x:set var="doc" select="doc"/>
  	<tr>
      	<td><a href="#${prefix}:${tagName}">${tagName}</a></td>
          <td>        
        	  <jsl:style stylesheet="${docStylesheet}" select="$doc"/>
  		</td>
  	</tr>
      </x:forEach>
      </table>
      </subsection>
      
      </x:forEach>
      
      </section>
        
              
  
  	<section name="Tags">	
     	  <p>
          [<a href="#Tag Libraries">tag libraries</a>]
          [<a href="#Tags">tags</a>]
        </p>
      
      <x:forEach select="$libraries">
      <x:set var="prefix" select="string(@prefix)"/>
        <x:forEach select="tag" var="tag">
        <x:set var="tagName" select="string(@name)"/>
  
  	    <subsection name="${prefix}:${tagName}">
  	    <p>
  	      <jsl:style stylesheet="${docStylesheet}" select="$tag/doc"/>
  	    </p>
  	      
  	    <table>
  	    <tr>
  	      <th>Attribute Name</th>
  	      <th>Type</th>
  	      <th>Description</th>
  	    </tr>
  	    
  	    <x:forEach var="attr" select="$tag/attribute">
  		<tr>
  	    	<td><x:expr select="$attr/@name"/></td>
  	    	<td><x:expr select="$attr/@type"/></td>
  	        <td>        
  	      	  <jsl:style stylesheet="${docStylesheet}" select="$attr/doc"/>
  			</td>
  		</tr>
  	    </x:forEach>
  	    </table>
  	    </subsection>
      
      
      
        </x:forEach>
      </x:forEach>
      </section>
    
    </body>
  </document>
  
  </j:jelly>
  
  
  
  
  
  1.1                  jakarta-turbine-maven/src/plugins-build/jellydoc/src/main/org/apache/maven/jellydoc/TagXMLDoclet.java
  
  Index: TagXMLDoclet.java
  ===================================================================
  /*
   * /home/cvs/jakarta-turbine-maven/src/plugins-build/jellydoc/src/main/org/apache/maven/jellydoc/TagXMLDoclet.java,v 1.1 2003/02/07 12:10:44 jstrachan Exp
   * 1.1
   * 2003/02/07 12:10:44
   *
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2002 The Apache Software Foundation.  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 following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Commons", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * 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 APACHE SOFTWARE FOUNDATION OR
   * ITS 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 Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   * 
   * TagXMLDoclet.java,v 1.1 2003/02/07 12:10:44 jstrachan Exp
   */
  
  package org.apache.maven.jellydoc;
  
  import java.beans.Introspector;
  import java.io.FileOutputStream;
  import java.io.IOException;
  import java.io.StringReader;
  
  import org.cyberneko.html.parsers.SAXParser;
  import org.dom4j.io.OutputFormat;
  import org.dom4j.io.XMLWriter;
  import org.xml.sax.Attributes;
  import org.xml.sax.ContentHandler;
  import org.xml.sax.InputSource;
  import org.xml.sax.SAXException;
  import org.xml.sax.helpers.AttributesImpl;
  import org.xml.sax.helpers.DefaultHandler;
  
  import com.sun.javadoc.ClassDoc;
  import com.sun.javadoc.Doc;
  import com.sun.javadoc.Doclet;
  import com.sun.javadoc.MethodDoc;
  import com.sun.javadoc.PackageDoc;
  import com.sun.javadoc.Parameter;
  import com.sun.javadoc.RootDoc;
  import com.sun.javadoc.SeeTag;
  import com.sun.javadoc.Tag;
  
  /**
   * Main Doclet class to generate Tag Library ML.  
   * 
   * @author <a href="mailto:gopi@aztecsoft.com">Gopinath M.R.</a>
   * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
   * @author Rodney Waldhoff
   */
  
  // #### somehow we need to handle taglib inheritence...
  
  public class TagXMLDoclet extends Doclet {
  
      private String xmlns = "jvx";
      private String encodingFormat="UTF-8";
      private String localName = "javadoc";
      private ContentHandler cm = null;
      private String targetFileName="target/taglib.xml";
      private Attributes emptyAtts = new AttributesImpl();
  
      public TagXMLDoclet (RootDoc root) throws Exception {
          FileOutputStream writer = new FileOutputStream(targetFileName);
          OutputFormat format = OutputFormat.createPrettyPrint();
          XMLWriter xmlWriter = new XMLWriter(writer, format);
          try {
              cm = xmlWriter;
              cm.startDocument();
              javadocXML(root);
              cm.endDocument();
              xmlWriter.close();
          } 
          catch (IOException e) {
              xmlWriter.close();
              throw e;
          }
      }
  
      /**
       * Generates the xml for the tag libraries
       */
      private void javadocXML(RootDoc root) throws SAXException {
          cm.startElement(xmlns, localName, "tags", emptyAtts);
          PackageDoc[] packageArray = root.specifiedPackages();
  
          // Generate for packages.
          for (int i = 0; i < packageArray.length; ++i) {
              packageXML(packageArray[i]);
          }
  
          cm.endElement(xmlns, localName, "tags");
      }
  
      /**
       * Generates doc for a tag library
       */
      private void packageXML(PackageDoc packageDoc) throws SAXException {
          ClassDoc[] classArray = packageDoc.ordinaryClasses();
          
          // lets see if we find a Tag
          boolean foundTag = false;
          for (int i = 0; i < classArray.length; ++i) {
              ClassDoc classDoc = classArray[i];
              if ( isTag( classArray[i] ) ) {
                  foundTag = true;
                  break;
              }
          }
          if ( ! foundTag ) {
              return;
          }
          
          AttributesImpl atts = new AttributesImpl();
          atts.addAttribute(xmlns, localName, "name", "String", packageDoc.name());
          
          String name = packageDoc.name();
          int idx = name.lastIndexOf('.');
          if ( idx > 0 ) {
              name = name.substring(idx+1);
          }
          atts.addAttribute(xmlns, localName, "prefix", "String", name);
          
          String uri = "jelly:" + name;
          
          atts.addAttribute(xmlns, localName, "uri", "String", uri );
          cm.startElement(xmlns, localName, "library", atts);
  
          // generate Doc element.
          docXML(packageDoc);
  
          // generate tags
          for (int i = 0; i < classArray.length; ++i) {
              if ( isTag( classArray[i] ) ) {
                  tagXML(classArray[i]);
              }
          }
          cm.endElement(xmlns, localName, "library");
      }
  
      /**
       * @return true if this class is a Jelly Tag
       */
      private boolean isTag(ClassDoc classDoc) {
          ClassDoc[] interfaceArray = classDoc.interfaces();
          for (int i = 0; i < interfaceArray.length; ++i) {
              String name = interfaceArray[i].qualifiedName();
              if ("org.apache.commons.jelly.Tag".equals(name)) {
                  return true;
              }
          }
          ClassDoc base = classDoc.superclass();
          if ( base != null ) {
              return isTag(base);
          }
          return false;
      }
      
      /**
       * Generates doc for a tag
       */
      private void tagXML(ClassDoc classDoc) throws SAXException {
          if (classDoc.isAbstract()) {
              return;
          }
          
          AttributesImpl atts = new AttributesImpl();
          atts.addAttribute(xmlns, localName, "className", "String", classDoc.name());
          String name = classDoc.name();
          if ( name.endsWith( "Tag" ) ) {
              name = name.substring(0, name.length() - 3 );
          }
          name = Introspector.decapitalize(name);
          
          atts.addAttribute(xmlns, localName, "name", "String", name);
          cm.startElement(xmlns, localName, "tag", atts);
  
          // generate "doc" sub-element
          docXML(classDoc);
  
          // generate the attributes
          propertiesXML(classDoc);
          
          // generate "method" sub-elements
          cm.endElement(xmlns, localName, "tag");
      }
  
      /**
       * Generates doc for a tag property
       */
      private void propertiesXML(ClassDoc classDoc) throws SAXException {
          MethodDoc[] methodArray = classDoc.methods();
          for (int i = 0; i < methodArray.length; ++i) {
              propertyXML(methodArray[i]);
          }
          ClassDoc base = classDoc.superclass();
          if ( base != null ) {
              propertiesXML( base );
          }
      }
  
  
      /**
       * Generates doc for a tag property
       */
      private void propertyXML(MethodDoc methodDoc) throws SAXException {
          if ( ! methodDoc.isPublic() || methodDoc.isStatic() ) {
              return;
          }
          String name = methodDoc.name();
          if ( ! name.startsWith( "set" ) ) {
              return;
          }
          Parameter[] parameterArray = methodDoc.parameters();
          if ( parameterArray == null || parameterArray.length != 1 ) {
              return;
          }
          Parameter parameter = parameterArray[0];
          
          name = name.substring(3);
          name = Introspector.decapitalize(name);
          
          if ( name.equals( "body") || name.equals( "context" ) || name.equals( "parent" ) ) {
              return;
          }
          AttributesImpl atts = new AttributesImpl();
          atts.addAttribute(xmlns, localName, "name", "String", name);
          atts.addAttribute(xmlns, localName, "type", "String", parameter.typeName());
          
          cm.startElement(xmlns, localName, "attribute", atts);
  
          // maybe do more semantics, like use custom tags to denote if its required, optional etc.
          
          // generate "doc" sub-element
          docXML(methodDoc);
  
          cm.endElement(xmlns, localName, "attribute");
      }
  
      /**
       * Generates doc for element "doc"
       */
      private void docXML(Doc doc) throws SAXException {
          cm.startElement(xmlns, localName, "doc", emptyAtts);
          // handle the "comment" part, including {@link} tags
          {
              Tag[] tags = doc.inlineTags();
              for(int i=0;i<tags.length;i++) {
                  // if tags[i] is an @link tag
                  if(tags[i] instanceof SeeTag) {                    
                      String label = ((SeeTag)tags[i]).label();
                      // if the label is null or empty, use the class#member part of the link
                      if(null == label || "".equals(label)) { 
                          StringBuffer buf = new StringBuffer();
                          String className = ((SeeTag)tags[i]).referencedClassName();
                          if("".equals(className)) { className = null; }
                          String memberName = ((SeeTag)tags[i]).referencedMemberName();
                          if("".equals(memberName)) { memberName = null; }
                          if(null != className) {
                              buf.append(className);
                              if(null != memberName) {
                                  buf.append(".");
                              }
                          }
                          if(null != memberName) {
                              buf.append(memberName);
                          }
                          label = buf.toString();
                      }
                      parseHTML(label);
                  } else {
                      parseHTML(tags[i].text());
                  }
              }
          }
          // handle the "tags" part
          {
              Tag[] tags = doc.tags();
              for (int i = 0; i < tags.length; ++i) {
                  javadocTagXML(tags[i]);
              }
          }
          cm.endElement(xmlns, localName, "doc");
      }
  
      protected void parseHTML(String text) throws SAXException {
          SAXParser parser = new SAXParser();
          parser.setProperty(
              "http://cyberneko.org/html/properties/names/elems",
              "lower"
          );
          parser.setProperty(
              "http://cyberneko.org/html/properties/names/attrs",
              "lower"
          );
          parser.setContentHandler(
              new DefaultHandler() {
                  public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
                      if ( validDocElementName( localName ) ) {
                          cm.startElement(namespaceURI, localName, qName, atts);
                      }
                  }
                  public void endElement(String namespaceURI, String localName, String qName) throws SAXException {
                      if ( validDocElementName( localName ) ) {
                          cm.endElement(namespaceURI, localName, qName);
                      }
                  }
                  public void characters(char[] ch, int start, int length) throws SAXException {
                      cm.characters(ch, start, length);
                  }
              }
          );
          try {
              parser.parse( new InputSource(new StringReader( text )) );
          }
          catch (IOException e) {
              System.err.println( "This should never happen!" + e );
          }
      }
  
      /**
       * @return true if the given name is a valid HTML markup element.
       */
      protected boolean validDocElementName(String name) {
          return ! name.equalsIgnoreCase( "html" ) && ! name.equalsIgnoreCase( "body" );
      }
      
      /**
       * Generates doc for all tag elements.
       */
      private void javadocTagXML(Tag tag) throws SAXException {
          String name = tag.name().substring(1) + "tag";
          if (! tag.text().equals("")) {
              cm.startElement(xmlns, localName, name, emptyAtts);
              cm.characters(tag.text().toCharArray(), 0, tag.text().length());
              cm.endElement(xmlns, localName, name);
          }
      }
  
      public static boolean start(RootDoc root) {
          try {
              new TagXMLDoclet(root);
              return true;
          } catch (Exception e) {
              e.printStackTrace();
              System.exit(1);
              return false;
          }
      }
  }
  
  
  
  1.1                  jakarta-turbine-maven/src/plugins-build/jellydoc/src/main/org/apache/maven/jellydoc/XMLDoclet.java
  
  Index: XMLDoclet.java
  ===================================================================
  /*
   * /home/cvs/jakarta-turbine-maven/src/plugins-build/jellydoc/src/main/org/apache/maven/jellydoc/XMLDoclet.java,v 1.1 2003/02/07 12:10:44 jstrachan Exp
   * 1.1
   * 2003/02/07 12:10:44
   *
   * ====================================================================
   *
   * The Apache Software License, Version 1.1
   *
   * Copyright (c) 2002 The Apache Software Foundation.  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 following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. The end-user documentation included with the redistribution, if
   *    any, must include the following acknowlegement:
   *       "This product includes software developed by the
   *        Apache Software Foundation (http://www.apache.org/)."
   *    Alternately, this acknowlegement may appear in the software itself,
   *    if and wherever such third-party acknowlegements normally appear.
   *
   * 4. The names "The Jakarta Project", "Commons", and "Apache Software
   *    Foundation" must not be used to endorse or promote products derived
   *    from this software without prior written permission. For written
   *    permission, please contact apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache"
   *    nor may "Apache" appear in their names without prior written
   *    permission of the Apache Group.
   *
   * 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 APACHE SOFTWARE FOUNDATION OR
   * ITS 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 Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <http://www.apache.org/>.
   * 
   * XMLDoclet.java,v 1.1 2003/02/07 12:10:44 jstrachan Exp
   */
  
  package org.apache.maven.jellydoc;
  
  import java.io.*;
  import java.util.*;
  import com.sun.javadoc.*;
  
  import org.dom4j.io.OutputFormat;
  import org.dom4j.io.XMLWriter;
  
  import org.xml.sax.*;
  import org.xml.sax.helpers.*;
  
  /**
   * Main Doclet class to generate JavaDocXML.  This doclet generates the
   * document conforming to DTD specified in javadoc-v04draft.dtd.
   * @author <a href="mailto:gopi@aztecsoft.com">Gopinath M.R.</a>
    * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
   */
  
  public class XMLDoclet extends Doclet {
  
      private String xmlns = "jvx";
      private String encodingFormat="UTF-8";
      private String localName = "javadoc";
      private ContentHandler cm = null;
      private String targetFileName="target/javadoc.xml";
      private Attributes emptyAtts = new AttributesImpl();
  
      public XMLDoclet (RootDoc root) throws Exception {
          FileOutputStream writer = new FileOutputStream(targetFileName);
          OutputFormat format = OutputFormat.createPrettyPrint();
          XMLWriter xmlWriter = new XMLWriter(writer, format);
          try {
              cm = xmlWriter;
              cm.startDocument();
              javadocXML(root);
              cm.endDocument();
              xmlWriter.close();
          } 
          catch (IOException e) {
              xmlWriter.close();
              throw e;
          }
      }
  
      /**
       * Generates the xml data for the top element.
       * <xmp><!ELEMENT javadoc (package*, class*, interface*)></xmp>
       */
      private void javadocXML(RootDoc root) throws SAXException {
          cm.startElement(xmlns, localName, "javadoc", emptyAtts);
          PackageDoc[] packageArray = root.specifiedPackages();
  
          // Generate for packages.
          for (int i = 0; i < packageArray.length; ++i) {
              packageXML(packageArray[i]);
          }
  
          // Generate for classes.
          ClassDoc[] classArray = root.specifiedClasses();
          Vector interfaceVector = new Vector();
          for (int i = 0; i < classArray.length; ++i) {
              if (classArray[i].isInterface()) {
                  interfaceVector.addElement(classArray[i]);
              } else {
                  classXML(classArray[i]);
              }
          }
  
          // Generate for interfaces.
          Enumeration interfaceEnum = interfaceVector.elements();
          if (interfaceEnum.hasMoreElements()) {
              ClassDoc interfaceDoc = (ClassDoc)interfaceEnum.nextElement();
              interfaceXML(interfaceDoc);
          }
          cm.endElement(xmlns, localName, "javadoc");
      }
  
      /**
       * Generates doc for "package".
       * <xmp><!ELEMENT package (doc?, package*, class*, interface*)>
       *<!ATTLIST package
       *              name CDATA #REQUIRED></xmp>
       */
      private void packageXML(PackageDoc packageDoc) throws SAXException {
          AttributesImpl atts = new AttributesImpl();
          atts.addAttribute(xmlns, localName, "name", "String", packageDoc.name());
          cm.startElement(xmlns, localName, "package", atts);
  
          // generate Doc element.
          docXML(packageDoc);
  
          // TODO:generate Package elements.
          // doubt: How package can exist inside a package?
  
          /* Generate for classes. */
          // for ordinary classes.
          ClassDoc[] classArray = packageDoc.ordinaryClasses();
          for (int i = 0; i < classArray.length; ++i) {
              classXML(classArray[i]);
          }
          // for Exception classes.
          classArray = packageDoc.exceptions();
          for (int i = 0; i < classArray.length; ++i) {
              classXML(classArray[i]);
          }
          // for Error classes
          classArray = packageDoc.errors();
          for (int i = 0; i < classArray.length; ++i) {
              classXML(classArray[i]);
          }
  
          /* Generate for interfaces. */
          ClassDoc[] interfaceArray = packageDoc.interfaces();
          for (int i = 0; i < interfaceArray.length; ++i) {
              interfaceXML(interfaceArray[i]);
          }
  
          cm.endElement(xmlns, localName, "package");
      }
  
      /**
       * Generates doc for element "class".
       * <xmp> <!ELEMENT class (doc?,
       *                  extends_class?,
       *                  implements?,
       *                  constructor*,
       *                  method*,
       *                  innerclass*)>
       * <!ATTLIST class
       *     %name;
       *     %extensibility;
       *     %class.access;></xmp>
       */
      private void classXML(ClassDoc classDoc) throws SAXException {
          AttributesImpl atts = new AttributesImpl();
          atts.addAttribute(xmlns, localName, "name", "String", classDoc.name());
  
          String extensibility = "default";
          if (classDoc.isAbstract()) {
              extensibility = "abstract";
          } else if (classDoc.isFinal()) {
              extensibility = "final";
          }
          atts.addAttribute(xmlns, localName, "extensibility", "String", extensibility);
          String access = "package";
          if (classDoc.isPublic()) {
              access = "public";
          }
          atts.addAttribute(xmlns, localName, "access", "String", access);
          cm.startElement(xmlns, localName, "class", atts);
  
          // generate "doc" sub-element
          docXML(classDoc);
  
          // generate "extends_class" sub-element
          extendsXML(classDoc);
  
          // generate "implements" sub-element
          implementsXML(classDoc);
  
          // generate "field" sub-elements
          FieldDoc[] fieldArray = classDoc.fields();
          for (int i = 0; i < fieldArray.length; ++i) {
              fieldXML(fieldArray[i]);
          }
  
          // generate "constructor" sub-elements
          ConstructorDoc[] constructorArray = classDoc.constructors();
          for (int i = 0; i < constructorArray.length; ++i) {
              constructorXML(constructorArray[i]);
          }
  
          // generate "method" sub-elements
          MethodDoc[] methodArray = classDoc.methods();
          for (int i = 0; i < methodArray.length; ++i) {
              methodXML(methodArray[i]);
          }
  
          // generate "innerclass" sub-elements
          ClassDoc[] innerClassArray = classDoc.innerClasses();
          for (int i = 0; i < innerClassArray.length; ++i) {
              innerClassXML(innerClassArray[i]);
          }
  
          cm.endElement(xmlns, localName, "class");
      }
  
      /**
       * Generates doc for element "extends_class"
       * <xmp><!ELEMENT extends_class (classref+)></xmp>
       */
      private void extendsXML(ClassDoc classDoc) throws SAXException {
          if (classDoc.superclass() != null) {
              cm.startElement(xmlns, localName, "extends_class", emptyAtts);
              createRefXML("classref", classDoc.superclass().qualifiedName());
              cm.endElement(xmlns, localName, "extends_class");
          }
      }
  
      /**
       * Generates doc for element "innerclass"
       * <xmp> <!ELEMENT innerclass (doc?,
       *                 extends?,
       *                 implements?,
       *                 field*,
       *                 constructor*,
       *                 method*)>
       * <!ATTLIST innerclass
       *    %name;
       *    %access;
       *    %abstract;
       *    %anonymous;
       *    %final;
       *    %static;></xmp>
       */
      private void innerClassXML(ClassDoc classDoc) throws SAXException {
          AttributesImpl atts = new AttributesImpl();
          atts.addAttribute(xmlns, localName, "name", "String", classDoc.name());
          String access = "package";
          if (classDoc.isPublic()) {
              access = "public";
          }
          atts.addAttribute(xmlns, localName, "access", "String", access);
          atts.addAttribute(xmlns, localName, "abstract", "String", ""+ classDoc.isAbstract());
          String anonymous = "false";
          if (classDoc.name().equals("")) {
              anonymous = "true";
          }
          atts.addAttribute(xmlns, localName, "anonymous", "String", ""+ anonymous);
          atts.addAttribute(xmlns, localName, "final", "String", ""+ "" + classDoc.isFinal());
          atts.addAttribute(xmlns, localName, "static", "String", ""+ "" + classDoc.isStatic());
          cm.startElement(xmlns, localName, "innerclass", atts);
  
          // generate "doc" sub-element
          docXML(classDoc);
  
          // generate "extends" sub-element
          extendsXML(classDoc);
  
          // generate "implements" sub-element
          implementsXML(classDoc);
  
          // generate "field" sub-elements
          FieldDoc[] fieldArray = classDoc.fields();
          for (int i = 0; i < fieldArray.length; ++i) {
              fieldXML(fieldArray[i]);
          }
  
          // generate "constructor" sub-elements
          ConstructorDoc[] constructorArray = classDoc.constructors();
          for (int i = 0; i < constructorArray.length; ++i) {
              constructorXML(constructorArray[i]);
          }
  
          // generate "method" sub-elements
          MethodDoc[] methodArray = classDoc.methods();
          for (int i = 0; i < methodArray.length; ++i) {
              methodXML(methodArray[i]);
          }
  
          cm.endElement(xmlns, localName,"innerclass");
      }
  
      /**
       * Generates doc for element "interface"
       * <xmp><!ELEMENT interface (doc?,
       *               extends_interface?,
       *               field*,
       *               method*)>
       * <!ATTLIST interface
       *             %name;
       *             %access;></xmp>
       */
      private void interfaceXML(ClassDoc interfaceDoc) throws SAXException {
          AttributesImpl atts = new AttributesImpl();
          atts.addAttribute(xmlns, localName, "name", "String", interfaceDoc.name());
          String access = "package";
          if (interfaceDoc.isPublic()) {
              access = "public";
          }
          atts.addAttribute(xmlns, localName, "access", "String", access);
          cm.startElement(xmlns, localName, "interface", atts);
  
          // generate "doc" sub-element
          docXML(interfaceDoc);
  
          // generate "extends_interface"
          extends_interfaceXML(interfaceDoc);
  
          // generate "field" sub-elements
          FieldDoc[] fieldArray = interfaceDoc.fields();
          for (int i = 0; i < fieldArray.length; ++i) {
              fieldXML(fieldArray[i]);
          }
  
          // generate "method" sub-elements
          MethodDoc[] methodArray = interfaceDoc.methods();
          for (int i = 0; i < methodArray.length; ++i) {
              methodXML(methodArray[i]);
          }
          cm.endElement(xmlns, localName, "interface");
      }
  
      /**
       * Generates doc for element "extends_interface"
       * <xmp><!ELEMENT extends_interface (interfaceref+)></xmp>
       */
      private void extends_interfaceXML(ClassDoc interfaceDoc) throws SAXException {
          ClassDoc[] interfaceArray = interfaceDoc.interfaces();
          if (interfaceArray.length > 0) {
              cm.startElement(xmlns, localName, "extends_interface", emptyAtts);
              for (int i = 0; i < interfaceArray.length; ++i) {
                  createRefXML("interfaceref", interfaceArray[i].qualifiedName());
              }
              cm.endElement(xmlns, localName, "extends_interface");
          }
      }
  
      /**
       * Generates doc for element "implements"
       * <xmp><!ELEMENT implements (interfaceref+)></xmp>
       */
      private void implementsXML(ClassDoc classDoc) throws SAXException {
          ClassDoc[] interfaceArray = classDoc.interfaces();
          if (interfaceArray.length > 0) {
              cm.startElement(xmlns, localName, "implements", emptyAtts);
              for (int i = 0; i < interfaceArray.length; ++i) {
                  createRefXML("interfaceref", interfaceArray[i].qualifiedName());
              }
              cm.endElement(xmlns, localName, "implements");
          }
          if (classDoc.superclass() != null) {
              implementsXML(classDoc.superclass());
          }        
      }
  
      /**
       * Generates doc for element "throws"
       * <xmp><!ELEMENT throws (classref)+></xmp>
       */
      private void throwsXML(ExecutableMemberDoc member) throws SAXException {
          ThrowsTag[] tagArray = member.throwsTags();
          if(tagArray.length > 0) {
              cm.startElement(xmlns, localName, "throws", emptyAtts);
              for (int i = 0; i < tagArray.length; ++i) {
                  ClassDoc exceptionClass = tagArray[i].exception();
                  String name = null;
                  if (exceptionClass == null) {
                      name = tagArray[i].exceptionName();
                  } else {
                      name = tagArray[i].exception().qualifiedName();
                  }
                  createRefXML("classref", name);
              }
              cm.endElement(xmlns, localName, "throws");
          }
      }
  
      /**
       * Generates doc for following elements
       * <xmp> <!ELEMENT classref EMPTY>
       * <!ATTLIST classref %name;>
       * <!ELEMENT interfaceref EMPTY>
       * <!ATTLIST interfaceref %name;>
       * <!ELEMENT methodref EMPTY>
       * <!ATTLIST methodref %name;>
       * <!ELEMENT packageref EMPTY>
       * <!ATTLIST packageref %name;></xmp>
       */
      private void createRefXML(String elementName, String nameValue) throws SAXException {
          AttributesImpl atts = new AttributesImpl();
          atts.addAttribute(xmlns, localName, "name", "String", nameValue);
          cm.startElement(xmlns, localName, elementName, atts);
          cm.endElement(xmlns, localName, elementName);
      }
  
      /**
       * Generates doc for "(classref|interfaceref|primitive)" sub-element
       */
      private void createTypeRef(Type type) throws SAXException {
          String qualifiedName = type.qualifiedTypeName();
          ClassDoc fieldType = type.asClassDoc();
          if (fieldType == null) {
              // primitive data type
              AttributesImpl subElmAtts = new AttributesImpl();
              subElmAtts.addAttribute(xmlns, localName, "type", "String", qualifiedName);
              cm.startElement(xmlns, localName, "primitive", subElmAtts);
              cm.endElement(xmlns, localName, "primitive");
          } else if (fieldType.isInterface()) {
              // interface
              createRefXML("interfaceref", qualifiedName);
          } else {
              // class
              createRefXML("classref", qualifiedName);
          }
      }
  
      /**
       * Generates doc for element "field"
       * <xmp> <!ELEMENT field (doc?, (classref | interfaceref | primitive))>
       * <!ATTLIST field
       *    %name;
       *    %access;
       *    %dimension;
       *    %synthetic;
       *    %static;
       *    %final;
       *    %transient;
       *    %volatile;></xmp>
       */
      private void fieldXML(FieldDoc field) throws SAXException {
          AttributesImpl atts = new AttributesImpl();
  
          atts.addAttribute(xmlns, localName, "name", "String", field.name());
  
          String access = "package";
          if (field.isPrivate()) {
              access = "private";
          } else if (field.isProtected()) {
              access = "protected";
          } else if (field.isPublic()) {
              access = "public";
          }
          atts.addAttribute(xmlns, localName, "access", "String", access);
  
          atts.addAttribute(xmlns, localName, "dimension", "String", field.type().dimension());
          atts.addAttribute(xmlns, localName, "synthetic", "String", "" + field.isSynthetic());
          atts.addAttribute(xmlns, localName, "static", "String", "" + field.isStatic());
          atts.addAttribute(xmlns, localName, "final", "String", "" + field.isFinal());
          atts.addAttribute(xmlns, localName, "transient", "String", "" + field.isTransient());
          atts.addAttribute(xmlns, localName, "volatile", "String", "" + field.isVolatile());
          cm.startElement(xmlns, localName, "field", atts);
  
          // generate "doc" sub-element
          docXML(field);
  
          // generate "(classref|interfaceref|primitive)" sub-element
          createTypeRef(field.type()); // foo , field.qualifiedName());
  
          cm.endElement(xmlns, localName, "field");
      }
  
      /**
       * Generates doc for element "constructor"
       * <xmp><!ELEMENT constructor (doc?, parameter*, throws*)>
       * <!ATTLIST constructor
       *     %name;
       *     %access;
       *     %synthetic;></xmp>
       */
      private void constructorXML(ConstructorDoc constrDoc) throws SAXException {
          AttributesImpl atts = new AttributesImpl();
          atts.addAttribute(xmlns, localName, "name", "String", constrDoc.qualifiedName());
          String access = "package";
          if (constrDoc.isPrivate()) {
              access = "private";
          } else if (constrDoc.isProtected()) {
              access = "protected";
          } else if (constrDoc.isPublic()) {
              access = "public";
          }
          atts.addAttribute(xmlns, localName, "access", "String", access);
          atts.addAttribute(xmlns, localName, "synthetic", "String", "" + constrDoc.isSynthetic());
          cm.startElement(xmlns, localName, "constructor", atts);
  
          // generate "doc" sub-element
          docXML(constrDoc);
  
          // generate "parameter" sub-elements
          Parameter[] parameterArray = constrDoc.parameters();
          for (int i = 0; i < parameterArray.length; ++i) {
              parameterXML(parameterArray[i]);
          }
  
          // generate "throws" sub-element
          throwsXML(constrDoc);
  
          cm.endElement(xmlns, localName, "constructor");
      }
  
      /**
       * Generates doc for element "method"
       * <xmp> <!ELEMENT method (doc?, returns, parameter*, throws*)>
       * <!ATTLIST method
       *         %name;
       *         %access;
       *         %extensibility;
       *         %native;
       *         %synthetic;
       *         %static;
       *         %synchronized;></xmp>
       */
      private void methodXML(MethodDoc methodDoc) throws SAXException {
          AttributesImpl atts = new AttributesImpl();
          //atts.addAttribute(xmlns, localName, "", String, );
          atts.addAttribute(xmlns, localName, "name", "String", methodDoc.name());
  
          String access = "package";
          if (methodDoc.isPrivate()) {
              access = "private";
          } else if (methodDoc.isProtected()) {
              access = "protected";
          } else if (methodDoc.isPublic()) {
              access = "public";
          }
          atts.addAttribute(xmlns, localName, "access", "String", access);
  
          String extensibility = "default";
          if (methodDoc.isAbstract()) {
              extensibility = "abstract";
          } else if (methodDoc.isFinal()) {
              extensibility = "final";
          }
          atts.addAttribute(xmlns, localName, "extensiblity", "String", extensibility);
  
          atts.addAttribute(xmlns, localName, "native", "String", ""+ methodDoc.isNative());
          atts.addAttribute(xmlns, localName, "synthetic", "String", "" + methodDoc.isSynthetic());
          atts.addAttribute(xmlns, localName, "static", "String", "" + methodDoc.isStatic());
          atts.addAttribute(xmlns, localName, "synchronized", "String", ""+ methodDoc.isSynchronized());
          cm.startElement(xmlns, localName, "method", atts);
  
          // generate "doc" sub-element
          docXML(methodDoc);
  
          // generate "returns" sub-element
          returnsXML(methodDoc.returnType());
  
          // generate "parameter" sub-elements
          Parameter[] parameterArray = methodDoc.parameters();
          for (int i = 0; i < parameterArray.length; ++i) {
              parameterXML(parameterArray[i]);
          }
  
          // generate "throws" sub-element
          throwsXML(methodDoc);
  
          cm.endElement(xmlns, localName, "method");
      }
  
      /**
       * Generates doc for element "returns"
       * <xmp> <!ELEMENT returns (classref | interfaceref | primitive)>
       * <!ATTLIST returns %dimension;></xmp>
       */
      private void returnsXML(Type type) throws SAXException {
          AttributesImpl atts = new AttributesImpl();
          atts.addAttribute(xmlns, localName, "dimension", "String", type.dimension());
          cm.startElement(xmlns, localName, "returns", atts);
  
          // generate "(classref|interfaceref|primitive)" sub-element
          createTypeRef(type);
  
          cm.endElement(xmlns, localName, "returns");
      }
  
      /**
       * Generates doc for element "parameter"
       * <xmp> <!ELEMENT parameter (classref | interfaceref | primitive)>
       * <!ATTLIST parameter
       *         %name;
       *         %final;
       *         %dimension;></xmp>
       */
      private void parameterXML(Parameter parameter) throws SAXException {
          AttributesImpl atts = new AttributesImpl();
          atts.addAttribute(xmlns, localName, "name", "String", parameter.name());
          boolean isFinal = false;
          Type type = parameter.type();
          if (type.asClassDoc() == null) {
              isFinal = true;
          }
          atts.addAttribute(xmlns, localName, "final", "String", ""+ "" + isFinal);
          atts.addAttribute(xmlns, localName, "dimension", "String", parameter.type().dimension());
          cm.startElement(xmlns, localName, "parameter", atts);
  
          // generate "(classref|interfaceref|primitive)" sub-element
          createTypeRef(parameter.type());
  
          cm.endElement(xmlns, localName,"parameter");
      }
  
      /**
       * Generates doc for element "doc"
       * <xmp><!ELEMENT doc (#PCDATA |
       *              linktag |
       *              authortag |
       *              versiontag |
       *              paramtag |
       *              returntag |
       *              exceptiontag |
       *              throwstag |
       *              seetag |
       *              sincetag |
       *              deprecatedtag |
       *              serialtag |
       *              serialfieldtag |
       *              serialdatatag)*></xmp>
       */
      private void docXML(Doc doc) throws SAXException {
          String commentText = "";
          boolean createDoc = false;
          commentText = doc.commentText();
          if (! commentText.equals("")) {
              createDoc = true;
          }
          Tag[] tags = doc.tags();
          if (tags.length > 0) {
              createDoc = true;
          }
          if (createDoc) {
              cm.startElement(xmlns, localName, "doc", emptyAtts);
              if (! commentText.equals("")) {
                  cm.characters(commentText.toCharArray(), 0, commentText.length());
              }
              for (int i = 0; i < tags.length; ++i) {
                  tagXML(tags[i]);
              }
              cm.endElement(xmlns, localName, "doc");
          }
      }
  
      /**
       * Generates doc for all tag elements.
       */
      private void tagXML(Tag tag) throws SAXException {
          String name = tag.name().substring(1) + "tag";
          if (! tag.text().equals("")) {
              cm.startElement(xmlns, localName, name, emptyAtts);
              cm.characters(tag.text().toCharArray(), 0, tag.text().length());
              cm.endElement(xmlns, localName, name);
          }
      }
  
      public static boolean start(RootDoc root) {
          try {
              new XMLDoclet(root);
              return true;
          } catch (Exception e) {
              e.printStackTrace();
              System.exit(1);
              return false;
          }
      }
  }