alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*
 *                 Sun Public License Notice
 * 
 * The contents of this file are subject to the Sun Public License
 * Version 1.0 (the "License"). You may not use this file except in
 * compliance with the License. A copy of the License is available at
 * http://www.sun.com/
 * 
 * The Original Code is NetBeans. The Initial Developer of the Original
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2001 Sun
 * Microsystems, Inc. All Rights Reserved.
 */
package org.netbeans.lib.jmi.xmi;

import java.io.*;
import java.util.*;

import org.xml.sax.*;
import org.xml.sax.helpers.AttributesImpl;
import org.xml.sax.helpers.DefaultHandler;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;

import javax.jmi.reflect.*;
import javax.jmi.model.*;

import org.netbeans.lib.jmi.util.DebugException;
import org.netbeans.lib.jmi.util.Logger;
import org.netbeans.lib.jmi.util.TagProvider;

public class SchemaProducer {
        
    // Fixed schema content file name.
    private static String FIXED_SCHEMA_FILE = "resources/fixed_schema.xml";

    // output stream to which the produced DTD is written
    private OutputStreamWriter streamWriter;
    // default writer
    private DefaultWriter writer;
    // tag provider
    private TagProvider tagProvider;
    // main package extent
    private RefPackage extent;
    // elements cache used to obtain classes' attributes, references, etc.
    private ElementsCache elementsCache;
    // stored already processed packages
    private Set trackedPackages;
    // stores mapping class -> set of all direct subtypes
    private Map classHierarchy;
    // cache for mapping class -> all subtypes (direct and non-direct)
    private Map allSubtypes_cache;
    // mapping MofPackage -> namespace name
    private Map namespaces;
    // mapping namespace prefix -> URI
    private HashMap nsPrefixToURI;    
    // stores all enumeration types belonging to the tracked classes and packages
    private Set enumerations;
    
    // content handler related variables
    private boolean elementStarted;
    private String elementName;
    private AttributesImpl attributes = new AttributesImpl ();

    // **************************************************************************
    // Methods related to writing to content handler.
    // **************************************************************************

    private void startElement (String name) {
        if (elementStarted) {
            writeStartElement ();
        }
        elementName = name;
        elementStarted = true;
    }

    private void endElement (String name) {
        if (elementStarted) {
            writeStartElement ();
        }
        try {
            writer.endElement (null, null, name);
        } catch (SAXException e) {            
            throw new DebugException (e.getMessage ());
        }
    }

    private void addAttribute (String name, String value) {
        attributes.addAttribute(null, null, name, null, value); // uri, localName, qName, type, value
    }
    
    private void characters (String text) {
        if (elementStarted) {
            writeStartElement ();
        }
        try {
            writer.characters (text.toCharArray(), 0, text.length ());
        } catch (SAXException e) {
            throw new DebugException (e.getMessage ());
        }
    }

    private void writeStartElement () {
        try {
            writer.startElement (null, null, elementName, attributes);
        } catch (SAXException e) {
            throw new DebugException (e.getMessage ());
        }
        elementStarted = false;
        attributes.clear ();
    }

    // **************************************************************************
    
    // init .....................................................................

    
    public void init () {
        writer = new DefaultWriter (streamWriter, null);
        elementStarted = false;
        elementName = null;
        attributes.clear ();
    
        enumerations = new HashSet ();
        tagProvider = new TagProvider ();
        elementsCache = new ElementsCache (extent);
        trackedPackages = new HashSet ();
        classHierarchy = new HashMap ();
        allSubtypes_cache = new HashMap ();
        namespaces = new HashMap ();
        nsPrefixToURI = new HashMap ();
        
        findNamespaces (extent);        
        trackedPackages.clear ();
    }
    
    // ..........................................................................
    
    /** 
     * Generates XML Schema for metamodel residing in the passed package extent.
     * @param outermost package
     */
    public void generate (OutputStream stream, RefPackage extent) throws IOException {
        streamWriter = new OutputStreamWriter (stream);
        this.extent = extent;
        init ();
        
        try {
            writer.startDocument ();        
        
            startElement ("xsd:schema");
            addAttribute ("xmlns:xsd", "http://www.w3.org/2001/XMLSchema");
            addAttribute ("xmlns:xmi", "http://www.omg.org/XMI");
            
            // writeStartElement ();
            // writeFixedContent ();
            startElement ("xsd:import");
            addAttribute ("namespace", "http://www.omg.org/XMI");
            endElement ("xsd:import");
            
            // writeNamespaces ();
            
            writePackageSchema (extent);
            for (Iterator iter = enumerations.iterator (); iter.hasNext ();) {
                writeEnumerationSchema ((EnumerationType) iter.next ());
            }

            endElement ("xsd:schema");

            try {
                writer.endDocument ();
            } catch (SAXException e) {
                throw new IOException (e.getMessage ());
            }

            stream.flush ();
            stream.close ();
        } catch (SAXException e) {
            e.printStackTrace ();
            throw new IOException (e.getMessage ());
        }
    }

    public void writePackageSchema (RefPackage pkg) {
        if (trackedPackages.contains (pkg)) {
            return;
        } else {
            trackedPackages.add (pkg);
        }
        Iterator iter = pkg.refAllPackages ().iterator ();
        while (iter.hasNext ()) {
            writePackageSchema ((RefPackage) iter.next ());
        }
        iter = pkg.refAllClasses ().iterator ();
        while (iter.hasNext ()) {
            writeClassSchema ((RefClass) iter.next ());
        }
        writePackageElementDef (pkg);
    }
    
    public void writeClassSchema (RefClass proxy) {
        Iterator iter;
        String text;
        StringBuffer buffer = new StringBuffer ();
        MofClass meta = (MofClass) proxy.refMetaObject ();
        String className = objectName (meta);
        List instAttrs, references;
        
        String contentType = getContentType (meta);
        boolean useExtensions = isUseSchemaExtensions (meta);
        boolean isChoice = isMaxMultiplicityEnforced (meta) || isMinMultiplicityEnforced (meta);
        
        findEnumerations (meta);
        
        // ClassTypeDef        
        startElement ("xsd:complexType");
        addAttribute ("name", meta.getName ());
        if ((contentType != null) && contentType.equals ("mixed")) {
            addAttribute ("mixed", "true");
        }
        
        if (useExtensions) {
            startElement ("xsd:complexContent");
            startElement ("xsd:extension");
            Collection supers = meta.getSupertypes ();
            if (supers.size () != 1) {
                // [PENDING] throw some exception ... ?
            }
            String base = objectName ((MofClass) supers.iterator ().next ());
            addAttribute ("base", base);
        }
        
        if (isChoice) {
            startElement ("xsd:choice");
            addAttribute ("minOccurs", "0");
            addAttribute ("maxOccurs", "unbounded");
        } else {
            startElement ("xsd:sequence");
        }
        
        if (contentType == null) {
            // attributes            
            instAttrs = useExtensions ? elementsCache.localInstanceAttributes (meta) : 
                elementsCache.instanceAttributes (meta);
            for (iter = instAttrs.iterator (); iter.hasNext ();) {
                Attribute attr = (Attribute) iter.next ();
                startElement ("xsd:element");
                addAttribute ("name", attr.getName ());
                if (isNillable (attr)) {
                    addAttribute ("nillable", "true");
                }
                if (isMinMultiplicityEnforced (attr)) {
                    addAttribute ("minOccurs", multToString (attr.getMultiplicity ().getLower ()));
                }            
                if (isMaxMultiplicityEnforced (attr)) {
                    addAttribute ("maxOccurs", multToString (attr.getMultiplicity ().getUpper ()));
                }
                Classifier type = getType (attr);
                if (type instanceof MofClass) {
                    String schemaType = getSchemaType (attr);
                    if (schemaType != null) {
                        addAttribute ("type", schemaType);
                    } else {
                        writeAnyElement ();
                    }
                } else if (type instanceof EnumerationType) {
                    addAttribute ("type", type.getName ());
                } else {
                    addAttribute ("type", "xsd:string");
                }
                endElement ("xsd:element");
            } // for
            // references
            references = useExtensions ? elementsCache.localReferences (meta) : 
                elementsCache.references (meta);
            for (iter = references.iterator (); iter.hasNext ();) {
                Reference reference = (Reference) iter.next ();
                startElement ("xsd:element");
                addAttribute ("name", reference.getName ());                
                if (isMinMultiplicityEnforced (reference)) {
                    addAttribute ("minOccurs", multToString (reference.getMultiplicity ().getLower ()));
                }            
                if (isMaxMultiplicityEnforced (reference)) {
                    addAttribute ("maxOccurs", multToString (reference.getMultiplicity ().getUpper ()));
                }
                String contType = getContentType (reference);
                if (((contType != null) && (contType.equals ("complex"))) || isUseSchemaExtensions (reference)) {
                    addAttribute ("type", getType (reference).getName ());
                } else {                
                    writeAnyElement ();                    
                }
                endElement ("xsd:element");
            } // for
            // extension
            startElement ("xsd:element");
            addAttribute ("ref", "xmi:extension");
            endElement ("xsd:element");
            
        } else if (contentType.equals ("any")) {
            startElement ("xsd:any");
            addAttribute ("minOccurs", "0");
            addAttribute ("maxOccurs", "unbounded");
            addAttribute ("processContents", getProcessContents (meta));
            endElement ("xsd:any");
        } // else no content

        endElement (isChoice ? "xsd:choice" : "xsd:sequence");
        
        // ClassAttListItems
            // fixed attributes
        writeFixedAttribs (meta);
            // references
        references = useExtensions ? elementsCache.localReferences (meta) : 
            elementsCache.references (meta);
        for (iter = references.iterator (); iter.hasNext ();) {
            Reference reference = (Reference) iter.next ();            
            if (AggregationKindEnum.COMPOSITE.equals (reference.getReferencedEnd ().getAggregation ()))
                continue;
            startElement ("xsd:attribute");
            addAttribute ("name", reference.getName ());
            MultiplicityType mult = reference.getMultiplicity ();
            if ((mult.getLower () == 1) && (mult.getUpper () == 1) && isMinMultiplicityEnforced (reference)) {
                addAttribute ("type", "xsd:IDREFS");
                addAttribute ("use", "optional");
            } else {
                addAttribute ("type", "xsd:IDREF");
                addAttribute ("use", "required");
            }
            endElement ("xsd:attribute");
        } // for
            // attributes            
        instAttrs = useExtensions ? elementsCache.localInstanceAttributes (meta) : 
            elementsCache.instanceAttributes (meta);
        for (iter = instAttrs.iterator (); iter.hasNext ();) {
            Attribute attr = (Attribute) iter.next ();
            String val;
            Classifier type = getType (attr);
            if (type instanceof MofClass) {
                continue;
            }
            MultiplicityType mult = attr.getMultiplicity ();
            boolean required = (mult.getLower () == 1) && (mult.getUpper () == 1) && isMinMultiplicityEnforced (attr);
            startElement ("xsd:attribute");
            addAttribute ("name", attr.getName ());
            if (type instanceof EnumerationType) {
                addAttribute ("type", objectName (type));
                val = getDefaultValue (attr);
                if (val != null) {
                    addAttribute ("use", "default");
                    addAttribute ("value", val);
                } else {
                    addAttribute ("use", required ? "required" : "optional");
                }
            } else {
                addAttribute ("type", "xsd:string");
                addAttribute ("use", required ? "required" : "optional");
                val = getDefaultValue (attr);
                if (val != null)
                    addAttribute ("default", val);
                val = getFixedValue (attr);
                if (val != null)
                    addAttribute ("fixed", val);
                val = getForm (attr);
                if (val != null)
                    addAttribute ("form", val);                   
            }
            endElement ("xsd:attribute");            
        } // for
                
        if (useExtensions) {
            endElement ("xsd:extension");
            endElement ("xsd:complexContent");
        }
        endElement ("xsd:complexType");
        startElement ("xsd:attributeGroup");
        addAttribute ("ref", "xmi:ObjectAttribs");
        endElement ("xsd:attributeGroup");

        // ClassElementDef
        startElement ("xsd:element");
        addAttribute ("name", meta.getName ());
        addAttribute ("type", objectName (meta));
        endElement ("xsd:element");
    }

    public void writeAnyElement () {
        startElement ("xsd:complexType");
        startElement ("xsd:choice");
        addAttribute ("minOccurs", "0");
        addAttribute ("maxOccurs", "unbounded");
        startElement ("xsd:any");
        addAttribute ("processContents", "skip");
        endElement ("xsd:any");
        endElement ("xsd:choice");
        endElement ("xsd:complexType");
    }
        
    public void writeFixedAttribs (ModelElement elem) {
        startElement ("xsd:attribute");
        String idName = getIdName (elem);
        if (idName == null) {
            addAttribute ("ref", "xmi:id");                        
        } else {
            addAttribute ("name", idName);
            addAttribute ("type", "xsd:ID");
        }
        addAttribute ("use", "optional");
        endElement ("xsd:attribute");
    }
    
    public void writeAssociationSchema (Association assoc) {
        startElement ("xsd:element");
        addAttribute ("name", assoc.getName ());
        startElement ("xsd:complexType");
        startElement ("xsd:choice");
        addAttribute ("minOccurs", "0");
        addAttribute ("maxOccurs", "unbounded");
        for (Iterator iter = assoc.getContents ().iterator (); iter.hasNext ();) {
            Object elem = iter.next ();
            if (elem instanceof AssociationEnd) {
                writeAssociationEndDef ((AssociationEnd) elem);
            } // if
        } // for
        // extension
        startElement ("xsd:extension");
        addAttribute ("ref", "xmi:extension");
        endElement ("xsd:extension");
        // end of extension
        endElement ("xsd:choice");
        writeFixedAttribs (assoc);
        endElement ("xsd:complexType");
        endElement ("xsd:element");
    }
        
    public void writeAssociationEndDef (AssociationEnd end) {
        startElement ("xsd:element");
        addAttribute ("name", end.getName ());
        startElement ("xsd:complexType");
        writeFixedAttribs (end);
        endElement ("xsd:complexType");
        endElement ("xsd:element");
    }
    
    public void writeEnumerationSchema (EnumerationType enum) {
        startElement ("xsd:simpleType");
        addAttribute ("name", enum.getName ());
        startElement ("xsd:restriction");
        addAttribute ("base", "xsd:string");
        // int prefixLength = labelPrefix (enum).length ();
        for (Iterator iter = enum.getLabels ().iterator (); iter.hasNext ();) {
            String label = (String) iter.next ();
            startElement ("xsd:enumeration");
            addAttribute ("value", label);
            endElement ("xsd:enumeration");
        }
        endElement ("xsd:restriction");
        endElement ("xsd:simpleType");
    }
    
    public void writeFixedContent () throws SAXException {
        java.net.URL fixedSchema = getClass().getResource(FIXED_SCHEMA_FILE);
        if (fixedSchema == null) {
            throw new DebugException("Resource not found: " + FIXED_SCHEMA_FILE);
        }
        try {
            SAXParserFactory factory = SAXParserFactory.newInstance ();
            factory.setValidating (false);
            SAXParser saxParser = factory.newSAXParser ();
            saxParser.parse (fixedSchema.openStream (), new FixedContentHandler ());            
        } catch (IOException e) {
            Logger.getDefault().log("Unable to open " + FIXED_SCHEMA_FILE + ": " + e.getMessage());
            throw new DebugException (e.getMessage ());
        } catch (ParserConfigurationException e) {
            throw new SAXException (e.getMessage ());
        }
    }

    public void writeNamespaces () {
        /*
        Set names = new HashSet ();
        if (namespaces.size () > 0) {
            startAttlist ("XMI");
            for (Iterator iter = namespaces.entrySet ().iterator (); iter.hasNext ();) {
                Object name = ((Map.Entry) iter.next ()).getValue ();
                if (!names.contains (name)) {
                    addAttlistItem ("xmlns:" + name + " " + TAG_CDATA + " " + TAG_IMPLIED);
                    names.add (name);
                }
            } // for
            endAttlist ();
        } // if
         */
    }

    public void writePackageElementDef (RefPackage pkg) {
        Iterator iter;
        MofPackage meta = (MofPackage) pkg.refMetaObject ();
        String packageName = packageName (meta);
        
        findEnumerations (meta);
        
        startElement ("xsd:element");
        addAttribute ("name", meta.getName ());
        startElement ("xsd:complexType");
        startElement ("xsd:choice");
        addAttribute ("minOccurs", "0");
        addAttribute ("maxOccurs", "unbounded");
        // package contents
            // contained classes
        for (iter = pkg.refAllClasses ().iterator (); iter.hasNext ();) {
            Object metaObject = ((RefClass) iter.next ()).refMetaObject ();
            MofClass mofClass = (MofClass) (metaObject instanceof AliasType ? 
                getType ((AliasType) metaObject) : metaObject);
            
            startElement ("xsd:element");
            addAttribute ("name", objectName (mofClass));
            addAttribute ("type", mofClass.getName ());
            endElement ("xsd:element");
        } // for
            // associations without references
        for (iter = getFreeAssociations (pkg).iterator (); iter.hasNext ();) {
            writeAssociationSchema ((Association) iter.next ());
        } // for
        for (iter = pkg.refAllPackages ().iterator (); iter.hasNext ();) {
            startElement ("xsd:element");
            addAttribute ("ref", packageName ((MofPackage) ((RefPackage) iter.next ()).refMetaObject ()));
            endElement ("xsd:element");
        } // for
        startElement ("xsd:extension");
        addAttribute ("ref", "xmi:extension");
        endElement ("xsd:extension");
        // end of package contents
        endElement ("xsd:choice");
        endElement ("xsd:complexType");
        endElement ("xsd:element");
    }

    // helper methods ...........................................................

    protected void findNamespaces(RefPackage pkg) {
        String name, uri;
        Iterator iter;

        if (trackedPackages.contains (pkg))
            return;

        MofPackage metaPackage = (MofPackage) pkg.refMetaObject ();
        
        name = getNsPrefixTag (metaPackage);
        if (name == null) {
            name = tagProvider.getTagValue (metaPackage, XmiConstants.TAGID_XMI_NAMESPACE);
        }
         
        if (name != null) {
            iter = metaPackage.getQualifiedName ().iterator ();
            String fqName = (String) iter.next ();
            while (iter.hasNext ())
                fqName = fqName.concat (XmiConstants.DOT_SEPARATOR).concat ((String) iter.next ());
            namespaces.put (fqName, name);
            uri = getNsURITag (metaPackage);
            if (uri == null)
                throw new DebugException ("A tag defining namespace uri not found, package " + metaPackage.getName ());
            nsPrefixToURI.put (name, uri);
        }

        trackedPackages.add (pkg);
        iter =  pkg.refAllPackages ().iterator ();
        while (iter.hasNext ()) {
            findNamespaces ((RefPackage) iter.next ());
        }
    }
    
    public String elementName (ModelElement element) {
        ModelElement container = element.getContainer ();
        return objectName (container) + '.' + getXmiName (element);
    }

    public String objectName (ModelElement element) {
        String namespace = (String) namespaces.get (element.getContainer ());
        if (namespace != null) {
            return namespace + ":" + getXmiName (element);
        } else {
            return qualifiedName (element);
        }
    }

    public String packageName (MofPackage pkg) {
        String namespace = (String) namespaces.get (pkg);
        if (namespace != null) {
            return namespace + ":" + getXmiName (pkg);
        } else {
            return qualifiedName (pkg);
        }
    }

    public String qualifiedName (ModelElement element) {
        Iterator iter = element.getQualifiedName ().iterator ();
        String name = (String) iter.next ();
        while (iter.hasNext ()) {
            name = name.concat (XmiConstants.DOT_SEPARATOR).concat ((String) iter.next ());
        }
        return name;
    }        

    public Classifier getType (TypedElement elem) {
        Classifier type = elem.getType ();
        while (type instanceof AliasType)
            type = ((AliasType) type).getType ();
        return type;
    }        
    
    public Set getFreeAssociations (RefPackage pkg) {
        ModelPackage model = (ModelPackage) pkg.refMetaObject ().refImmediatePackage ();
        RefersTo refersTo = model.getRefersTo ();
        Set set = new HashSet ();
        for (Iterator iter = pkg.refAllAssociations ().iterator (); iter.hasNext ();) {
            Association assoc = (Association) ((RefAssociation) iter.next ()).refMetaObject ();
            boolean found = false;
            for (Iterator it = assoc.getContents ().iterator (); it.hasNext ();) {
                Object elem = it.next ();
                if (elem instanceof AssociationEnd) {
                    Collection col = refersTo.getReferent ((AssociationEnd) elem);
                    if ((col != null) && (col.size () > 0)) {
                        found = true;
                        break;
                    }
                }
            } // for
            if (!found) {
                set.add (assoc);
            }
        } // for
        return set;
    }

    public String multToString (int multiplicity) {
        return (multiplicity == -1) ? "unbounded" : "" + multiplicity;
    }
    
    public void findEnumerations (Namespace elem) {
        for (Iterator iter = elem.getContents ().iterator (); iter.hasNext ();) {
            Object obj = iter.next ();
            if (obj instanceof EnumerationType) {
                enumerations.add (obj);
            }
        } // for
    }
    
    // tags getters .............................................................

    public String getContentScopedTagValue (ModelElement elem, String tagId) {
        String value = null;
        while ((value == null) && (elem != null)) {
            value = tagProvider.getTagValue (elem, tagId);
            elem = elem.getContainer ();
        }
        if (value != null)
            value = value.trim ();
        return value;
    }
    
    public boolean isMaxMultiplicityEnforced (ModelElement elem) {
        String s = getContentScopedTagValue (elem, XmiConstants.TAG_ENFORCE_MAX_MULTIPLICITY);
        return (s != null) && s.equals ("true");
    }

    public boolean isMinMultiplicityEnforced (ModelElement elem) {
        String s = getContentScopedTagValue (elem, XmiConstants.TAG_ENFORCE_MIN_MULTIPLICITY);
        return (s != null) && s.equals ("true");
    }

    public boolean isUseSchemaExtensions (ModelElement elem) {
        String s = getContentScopedTagValue (elem, XmiConstants.TAG_USE_SCHEMA_EXTENSIONS);
        return (s != null) && s.equals ("true");
    }

    public boolean isNillable (ModelElement elem) {
        String s = getContentScopedTagValue (elem, XmiConstants.TAG_INCLUDE_NILS);
        return (s == null) || s.equals ("true");
    }
    
    public String getProcessContents (ModelElement elem) {
        String s = getContentScopedTagValue (elem, XmiConstants.TAG_PROCESS_CONTENTS);
        if (s == null) {
            return "strict"; // default value
        }
        return s;
    }
    
    public String getIdName (ModelElement elem) {
        return getContentScopedTagValue (elem, XmiConstants.TAG_ID_NAME);
    }
    
    public String getForm (ModelElement elem) {
        return getContentScopedTagValue (elem, XmiConstants.TAG_FORM);
    }
    
    public String getFixedValue (ModelElement elem) {
        return getContentScopedTagValue (elem, XmiConstants.TAG_FIXED_VALUE);
    }
    
    public String getNsPrefixTag (ModelElement elem) {
        return getContentScopedTagValue (elem, XmiConstants.TAG_NS_PREFIX);
    }
    
    public String getNsURITag (ModelElement elem) {
        return getContentScopedTagValue (elem, XmiConstants.TAG_NS_URI);
    }
    
    
    public String getDefaultValue (ModelElement elem) {
        return tagProvider.getTagValue (elem, XmiConstants.TAG_DEFAULT_VALUE);
    }    
    
    public String getXmiName (ModelElement elem) {
        String name = tagProvider.getTagValue (elem, XmiConstants.TAG_XMI_NAME);
        if (name == null)
            return elem.getName ();
        else
            return name;
    }
    
    public String getContentType (ModelElement elem) {
        return tagProvider.getTagValue (elem, XmiConstants.TAG_CONTENT_TYPE);
    }    
    
    public String getSchemaType (ModelElement elem) {
        return tagProvider.getTagValue (elem, XmiConstants.TAG_SCHEMA_TYPE);
    }                
    
    // ..........................................................................
    
    private class FixedContentHandler extends DefaultHandler {
    
        private int depth = 0;
        
        public void startElement (String namespaceURI, String sName, String qName, Attributes attrs) 
        throws SAXException {            
            if (depth > 0)
                writer.startElement (namespaceURI, sName, qName, attrs);
            depth++;
            // System.out.println("start element: " + qName + ", depth: " + depth);
        }
       
        public void endElement (String namespaceURI, String sName, String qName) throws SAXException {   
            depth--;
            if (depth > 0)
                writer.endElement (namespaceURI, sName, qName);
            // System.out.println("start element: " + qName + ", depth: " + depth);
        }
        
        public void characters (char buf[], int offset, int len) throws SAXException {
            for (int x = offset; x < offset + len; x++) {
                if (!Character.isWhitespace(buf[x])) {
                    writer.characters (buf, offset, len);
                    break;
                } // if
            } // for            
        }
        
    }

}

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.