import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.stream.StreamResult;

import org.apache.xerces.xs.XSAnnotation;
import org.apache.xerces.xs.XSConstants;
import org.apache.xerces.xs.XSElementDeclaration;
import org.apache.xerces.xs.XSImplementation;
import org.apache.xerces.xs.XSLoader;
import org.apache.xerces.xs.XSModel;
import org.apache.xerces.xs.XSNamedMap;
import org.apache.xerces.xs.XSObjectList;
import org.w3c.dom.DOMError;
import org.w3c.dom.DOMErrorHandler;
import org.w3c.dom.bootstrap.DOMImplementationRegistry;
import org.xml.sax.ContentHandler;

public class AnnotationTest {

    private static SAXTransformerFactory saxtf;
    static {
        TransformerFactory tf = TransformerFactory.newInstance();
        if (!tf.getFeature(SAXTransformerFactory.FEATURE))
            throw new AssertionError("Not a SAXTransformerFactory");
        
        saxtf = (SAXTransformerFactory) tf;
    }

    public static void main(String[] args) {
        XSModel xsd = loadSampleSchema();
        if (xsd == null)
            System.exit(1);
        
        XSNamedMap elements =
                xsd.getComponents(XSConstants.ELEMENT_DECLARATION);
        for (int i = 0, len = elements.getLength(); i < len; i++) {
            XSElementDeclaration elemDecl =
                    (XSElementDeclaration) elements.item(i);
            
            System.out.println();
            System.out.println('[' + elemDecl.getName() + ']');
            dumpAnnotations(elemDecl.getAnnotations());
        }
    }

    static XSModel loadSampleSchema() {
        DOMImplementationRegistry registry;
        try {
            registry = DOMImplementationRegistry.newInstance();
        } catch (Exception ex) {
            throw new AssertionError(ex);
        }
        XSImplementation impl = 
                (XSImplementation) registry.getDOMImplementation("XS-Loader");
        
        XSLoader schemaLoader = impl.createXSLoader(null);
        schemaLoader.getConfig().setParameter("error-handler",
                new DOMErrorHandler() {
            public boolean handleError(DOMError error) {
                System.err.println(error.getMessage());
                return false;
            }
        });
        return schemaLoader.loadURI(AnnotationTest.class
                .getResource("sample_schema.xsd").toExternalForm());
    }

    static void dumpAnnotations(XSObjectList annotations) {
        for (int i = 0, len = annotations.getLength(); i < len; i++) {
            dumpAnnotation((XSAnnotation) annotations.item(i));
        }
    }

    static void dumpAnnotation(XSAnnotation ann) {
        System.out.println("---");
        ann.writeAnnotation(newContentHandler(),
                            XSAnnotation.SAX_CONTENTHANDLER);
    }

    private static ContentHandler newContentHandler() {
        TransformerHandler handler;
        try {
            handler = saxtf.newTransformerHandler();
        } catch (TransformerConfigurationException ex) {
            throw new AssertionError(ex);
        }
        Transformer transformer = handler.getTransformer();
        transformer.setOutputProperty(OutputKeys.METHOD, "xml");
        transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
        transformer.setOutputProperty(OutputKeys.ENCODING, "US-ASCII");
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
        transformer.setOutputProperty("{http://xml.apache.org/xalan}indent-amount", "2");
        handler.setResult(new StreamResult(System.out));
        return handler;
    }

}
