private static CmsXmlContentDefinition unmarshalInternal(
        Document document,
        String schemaLocation,
        EntityResolver resolver)
    throws CmsXmlException {

        // analyze the document and generate the XML content type definition
        Element root = document.getRootElement();
        if (!XSD_NODE_SCHEMA.equals(root.getQName())) {
            // schema node is required
            throw new CmsXmlException(Messages.get().container(Messages.ERR_CD_NO_SCHEMA_NODE_0));
        }

        List<Element> includes = CmsXmlGenericWrapper.elements(root, XSD_NODE_INCLUDE);
        if (includes.size() < 1) {
            // one include is required
            throw new CmsXmlException(Messages.get().container(Messages.ERR_CD_ONE_INCLUDE_REQUIRED_0));
        }

        Element include = includes.get(0);
        String target = validateAttribute(include, XSD_ATTRIBUTE_SCHEMA_LOCATION, null);
        if (!XSD_INCLUDE_OPENCMS.equals(target)) {
            // the first include must point to the default OpenCms standard schema include
            throw new CmsXmlException(
                Messages.get().container(Messages.ERR_CD_FIRST_INCLUDE_2, XSD_INCLUDE_OPENCMS, target));
        }

        boolean recursive = false;
        Set<CmsXmlContentDefinition> nestedDefinitions = new HashSet<CmsXmlContentDefinition>();
        if (includes.size() > 1) {
            // resolve additional, nested include calls
            for (int i = 1; i < includes.size(); i++) {

                Element inc = includes.get(i);
                String schemaLoc = validateAttribute(inc, XSD_ATTRIBUTE_SCHEMA_LOCATION, null);
                if (!(schemaLoc.equals(schemaLocation))) {
                    InputSource source = null;
                    try {
                        source = resolver.resolveEntity(null, schemaLoc);
                    } catch (Exception e) {
                        throw new CmsXmlException(
                            Messages.get().container(
                                Messages.ERR_CD_BAD_INCLUDE_3,
                                schemaLoc,
                                schemaLocation,
                                document.asXML()),
                            e);
                    }
                    // Couldn't resolve the entity?
                    if (null == source) {
                        throw new CmsXmlException(
                            Messages.get().container(
                                Messages.ERR_CD_BAD_INCLUDE_3,
                                schemaLoc,
                                schemaLocation,
                                document.asXML()));
                    }
                    CmsXmlContentDefinition xmlContentDefinition = unmarshal(source, schemaLoc, resolver);
                    nestedDefinitions.add(xmlContentDefinition);
                } else {
                    // recursion
                    recursive = true;
                }
            }
        }

        List<Element> elements = CmsXmlGenericWrapper.elements(root, XSD_NODE_ELEMENT);
        if (elements.size() != 1) {
            // only one root element is allowed
            throw new CmsXmlException(
                Messages.get().container(
                    Messages.ERR_CD_ROOT_ELEMENT_COUNT_1,
                    XSD_INCLUDE_OPENCMS,
                    new Integer(elements.size())));
        }

        // collect the data from the root element node
        Element main = elements.get(0);
        String name = validateAttribute(main, XSD_ATTRIBUTE_NAME, null);

        // now process the complex types
        List<Element> complexTypes = CmsXmlGenericWrapper.elements(root, XSD_NODE_COMPLEXTYPE);
        if (complexTypes.size() != 2) {
            // exactly two complex types are required
            throw new CmsXmlException(
                Messages.get().container(Messages.ERR_CD_COMPLEX_TYPE_COUNT_1, new Integer(complexTypes.size())));
        }

        // get the outer element sequence, this must be the first element
        CmsXmlComplexTypeSequence outerSequence = validateComplexTypeSequence(complexTypes.get(0), nestedDefinitions);
        CmsXmlNestedContentDefinition outer = (CmsXmlNestedContentDefinition)outerSequence.getSequence().get(0);

        // make sure the inner and outer element names are as required
        String outerTypeName = createTypeName(name);
        String innerTypeName = createTypeName(outer.getName());
        validateAttribute(complexTypes.get(0), XSD_ATTRIBUTE_NAME, outerTypeName);
        validateAttribute(complexTypes.get(1), XSD_ATTRIBUTE_NAME, innerTypeName);
        validateAttribute(main, XSD_ATTRIBUTE_TYPE, outerTypeName);

        // generate the result XML content definition
        CmsXmlContentDefinition result = new CmsXmlContentDefinition(name, null, schemaLocation);

        // set the nested definitions
        result.m_includes = nestedDefinitions;
        // set the schema document
        result.m_schemaDocument = document;

        // the inner name is the element name set in the outer sequence
        result.setInnerName(outer.getName());
        if (recursive) {
            nestedDefinitions.add(result);
        }

        // get the inner element sequence, this must be the second element
        CmsXmlComplexTypeSequence innerSequence = validateComplexTypeSequence(complexTypes.get(1), nestedDefinitions);

        // add the types from the main sequence node
        Iterator<I_CmsXmlSchemaType> it = innerSequence.getSequence().iterator();
        while (it.hasNext()) {
            result.addType(it.next());
        }

        // store if this content definition contains a xsd:choice sequence
        result.m_sequenceType = innerSequence.getSequenceType();
        result.m_choiceMaxOccurs = innerSequence.getChoiceMaxOccurs();

        // resolve the XML content handler information
        List<Element> annotations = CmsXmlGenericWrapper.elements(root, XSD_NODE_ANNOTATION);
        I_CmsXmlContentHandler contentHandler = null;
        Element appInfoElement = null;

        if (annotations.size() > 0) {
            List<Element> appinfos = CmsXmlGenericWrapper.elements(annotations.get(0), XSD_NODE_APPINFO);

            if (appinfos.size() > 0) {
                // the first appinfo node contains the specific XML content data
                appInfoElement = appinfos.get(0);

                // check for a special content handler in the appinfo node
                Element handlerElement = appInfoElement.element("handler");
                if (handlerElement != null) {
                    String className = handlerElement.attributeValue("class");
                    if (className != null) {
                        contentHandler = OpenCms.getXmlContentTypeManager().getFreshContentHandler(className);
                    }
                }
            }
        }

        if (contentHandler == null) {
            // if no content handler is defined, the default handler is used
            contentHandler = OpenCms.getXmlContentTypeManager().getFreshContentHandler(
                CmsDefaultXmlContentHandler.class.getName());
        }

        // analyze the app info node with the selected XML content handler
        contentHandler.initialize(appInfoElement, result);
        result.m_contentHandler = contentHandler;

        result.freeze();

        if (resolver instanceof CmsXmlEntityResolver) {
            // put the generated content definition in the cache
            ((CmsXmlEntityResolver)resolver).cacheContentDefinition(schemaLocation, result);
        }

        return result;
    }
private static CmsXmlContentDefinition unmarshalInternal ( Document document , String schemaLocation , EntityResolver resolver ) throws CmsXmlException { Element root = document . getRootElement ( ) ; if ( ! XSD_NODE_SCHEMA . equals ( root . getQName ( ) ) ) { throw new CmsXmlException ( Messages . get ( ) . container ( Messages . ERR_CD_NO_SCHEMA_NODE_0 ) ) ; } List < Element > includes = CmsXmlGenericWrapper . elements ( root , XSD_NODE_INCLUDE ) ; if ( includes . size ( ) < 1 ) { throw new CmsXmlException ( Messages . get ( ) . container ( Messages . ERR_CD_ONE_INCLUDE_REQUIRED_0 ) ) ; } Element include = includes . get ( 0 ) ; String target = validateAttribute ( include , XSD_ATTRIBUTE_SCHEMA_LOCATION , null ) ; if ( ! XSD_INCLUDE_OPENCMS . equals ( target ) ) { throw new CmsXmlException ( Messages . get ( ) . container ( Messages . ERR_CD_FIRST_INCLUDE_2 , XSD_INCLUDE_OPENCMS , target ) ) ; } boolean recursive = false ; Set < CmsXmlContentDefinition > nestedDefinitions = new HashSet < CmsXmlContentDefinition > ( ) ; if ( includes . size ( ) > 1 ) { for ( int i = 1 ; i < includes . size ( ) ; i ++ ) { Element inc = includes . get ( i ) ; String schemaLoc = validateAttribute ( inc , XSD_ATTRIBUTE_SCHEMA_LOCATION , null ) ; if ( ! ( schemaLoc . equals ( schemaLocation ) ) ) { InputSource source = null ; try { source = resolver . resolveEntity ( null , schemaLoc ) ; } catch ( Exception e ) { throw new CmsXmlException ( Messages . get ( ) . container ( Messages . ERR_CD_BAD_INCLUDE_3 , schemaLoc , schemaLocation , document . asXML ( ) ) , e ) ; } if ( null == source ) { throw new CmsXmlException ( Messages . get ( ) . container ( Messages . ERR_CD_BAD_INCLUDE_3 , schemaLoc , schemaLocation , document . asXML ( ) ) ) ; } CmsXmlContentDefinition xmlContentDefinition = unmarshal ( source , schemaLoc , resolver ) ; nestedDefinitions . add ( xmlContentDefinition ) ; } else { recursive = true ; } } } List < Element > elements = CmsXmlGenericWrapper . elements ( root , XSD_NODE_ELEMENT ) ; if ( elements . size ( ) != 1 ) { throw new CmsXmlException ( Messages . get ( ) . container ( Messages . ERR_CD_ROOT_ELEMENT_COUNT_1 , XSD_INCLUDE_OPENCMS , new Integer ( elements . size ( ) ) ) ) ; } Element main = elements . get ( 0 ) ; String name = validateAttribute ( main , XSD_ATTRIBUTE_NAME , null ) ; List < Element > complexTypes = CmsXmlGenericWrapper . elements ( root , XSD_NODE_COMPLEXTYPE ) ; if ( complexTypes . size ( ) != 2 ) { throw new CmsXmlException ( Messages . get ( ) . container ( Messages . ERR_CD_COMPLEX_TYPE_COUNT_1 , new Integer ( complexTypes . size ( ) ) ) ) ; } CmsXmlComplexTypeSequence outerSequence = validateComplexTypeSequence ( complexTypes . get ( 0 ) , nestedDefinitions ) ; CmsXmlNestedContentDefinition outer = ( CmsXmlNestedContentDefinition ) outerSequence . getSequence ( ) . get ( 0 ) ; String outerTypeName = createTypeName ( name ) ; String innerTypeName = createTypeName ( outer . getName ( ) ) ; validateAttribute ( complexTypes . get ( 0 ) , XSD_ATTRIBUTE_NAME , outerTypeName ) ; validateAttribute ( complexTypes . get ( 1 ) , XSD_ATTRIBUTE_NAME , innerTypeName ) ; validateAttribute ( main , XSD_ATTRIBUTE_TYPE , outerTypeName ) ; CmsXmlContentDefinition result = new CmsXmlContentDefinition ( name , null , schemaLocation ) ; result . m_includes = nestedDefinitions ; result . m_schemaDocument = document ; result . setInnerName ( outer . getName ( ) ) ; if ( recursive ) { nestedDefinitions . add ( result ) ; } CmsXmlComplexTypeSequence innerSequence = validateComplexTypeSequence ( complexTypes . get ( 1 ) , nestedDefinitions ) ; Iterator < I_CmsXmlSchemaType > it = innerSequence . getSequence ( ) . iterator ( ) ; while ( it . hasNext ( ) ) { result . addType ( it . next ( ) ) ; } result . m_sequenceType = innerSequence . getSequenceType ( ) ; result . m_choiceMaxOccurs = innerSequence . getChoiceMaxOccurs ( ) ; List < Element > annotations = CmsXmlGenericWrapper . elements ( root , XSD_NODE_ANNOTATION ) ; I_CmsXmlContentHandler contentHandler = null ; Element appInfoElement = null ; if ( annotations . size ( ) > 0 ) { List < Element > appinfos = CmsXmlGenericWrapper . elements ( annotations . get ( 0 ) , XSD_NODE_APPINFO ) ; if ( appinfos . size ( ) > 0 ) { appInfoElement = appinfos . get ( 0 ) ; Element handlerElement = appInfoElement . element ( "handler" ) ; if ( handlerElement != null ) { String className = handlerElement . attributeValue ( "class" ) ; if ( className != null ) { contentHandler = OpenCms . getXmlContentTypeManager ( ) . getFreshContentHandler ( className ) ; } } } } if ( contentHandler == null ) { contentHandler = OpenCms . getXmlContentTypeManager ( ) . getFreshContentHandler ( CmsDefaultXmlContentHandler . class . getName ( ) ) ; } contentHandler . initialize ( appInfoElement , result ) ; result . m_contentHandler = contentHandler ; result . freeze ( ) ; if ( resolver instanceof CmsXmlEntityResolver ) { ( ( CmsXmlEntityResolver ) resolver ) . cacheContentDefinition ( schemaLocation , result ) ; } return result ; }
Internal method to unmarshal (read) a XML content definition instance from a XML document.<p>

It is assumed that the XML content definition cache has already been tested and the document
has not been found in the cache. After the XML content definition has been successfully created,
it is placed in the cache.<p>

@param document the XML document to generate a XML content definition from
@param schemaLocation the location from which the XML schema was read (system id)
@param resolver the XML entity resolver used by the given XML document

@return a XML content definition instance unmarshalled from the XML document

@throws CmsXmlException if something goes wrong