Package org.apache.xerces.impl.xs.models

Source Code of org.apache.xerces.impl.xs.models.CMBuilder

/*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 2001 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 acknowledgment:
*       "This product includes software developed by the
*        Apache Software Foundation (http://www.apache.org/)."
*    Alternately, this acknowledgment may appear in the software itself,
*    if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Xerces" 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 name, without prior written
*    permission of the Apache Software Foundation.
*
* 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 and was
* originally based on software copyright (c) 2001, International
* Business Machines, Inc., http://www.apache.org.  For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/

package org.apache.xerces.impl.xs.models;

import org.apache.xerces.xni.QName;
import org.apache.xerces.impl.dtd.models.CMNode;
import org.apache.xerces.impl.xs.SchemaSymbols;
import org.apache.xerces.impl.xs.XSDeclarationPool;
import org.apache.xerces.impl.xs.XSComplexTypeDecl;
import org.apache.xerces.impl.xs.XSParticleDecl;
import org.apache.xerces.impl.xs.XSElementDecl;
import org.apache.xerces.impl.xs.models.*;

/**
* This class constructs content models for a given grammar.
*
* @author Elena Litani, IBM
* @version $Id: CMBuilder.java,v 1.3 2001/11/13 20:32:32 sandygao Exp $
*/
public class CMBuilder {

    private final QName fQName1 = new QName();
    private final QName fQName2 = new QName();

    private XSDeclarationPool fDeclPool = null;

    // needed for DFA construction
    private int fLeafCount;

    public CMBuilder (XSDeclarationPool pool){
        fDeclPool = pool;
    }

    /**
     * Get content model for the a given type
     *
     * @param elementDeclIndex
     * @param comparator
     * @return
     * @exception Exception
     */
    public XSCMValidator getContentModel(XSComplexTypeDecl typeDecl) {

        // REVISIT: can we assume that this method never called for elements of simpleType
        // content?
        short contentType = typeDecl.fContentType;
        if (contentType == XSComplexTypeDecl.CONTENTTYPE_SIMPLE ||
            contentType == XSComplexTypeDecl.CONTENTTYPE_EMPTY) {
            return null;
        }

        XSCMValidator cmValidator = null;

        XSParticleDecl particle = typeDecl.fParticle;

        // This check is performed in XSComplexTypeDecl.
        //if (cmValidator != null)
        //    return cmValidator;


        if (particle != null)
            particle = expandParticleTree( (XSParticleDecl)particle);

        // REVISIT: should we expand?? or throw away the expanded tree??
        //typeDecl.fParticle

        // And create the content model according to the spec type

        if (particle == null) {
            // create special content model for no element content
            cmValidator = new XSEmptyCM();
        }
        else if (contentType == XSComplexTypeDecl.CONTENTTYPE_MIXED) {
               //
              // Create a child model as
              // per the element-only case
            cmValidator = createChildModel(particle, true);
        }
        else if (contentType == XSComplexTypeDecl.CONTENTTYPE_ELEMENT) {
            //  This method will create an optimal model for the complexity
            //  of the element's defined model. If its simple, it will create
            //  a SimpleContentModel object. If its a simple list, it will
            //  create a SimpleListContentModel object. If its complex, it
            //  will create a DFAContentModel object.
            //
            cmValidator = createChildModel(particle, false);
        }
        else {
            throw new RuntimeException("Unknown content type for a element decl "
                                       + "in getElementContentModelValidator() in Grammar class");
        }

        return cmValidator;
    }


    private XSParticleDecl expandParticleTree( XSParticleDecl particle) {

        // We may want to consider trying to combine this with buildSyntaxTree at some
        // point (if possible)

        //REVISIT: need access to grammar object
        //if (!grammar.fDeferParticleExpantion) {
        //    return particle;
        //}
        int maxOccurs = particle.fMaxOccurs;
        int minOccurs = particle.fMinOccurs;
        short type = particle.fType;
        if ((type == XSParticleDecl.PARTICLE_WILDCARD) ||
            (type == XSParticleDecl.PARTICLE_ELEMENT)) {
            return expandContentModel(particle, minOccurs, maxOccurs);
        }
        else if (type == XSParticleDecl.PARTICLE_CHOICE ||
                 type == XSParticleDecl.PARTICLE_ALL ||
                 type == XSParticleDecl.PARTICLE_SEQUENCE) {

            Object left = particle.fValue;
            Object right = particle.fOtherValue;

            left =  expandParticleTree( (XSParticleDecl)left);
            if (right != null)
                right =  expandParticleTree( (XSParticleDecl)right);

            // At this point, by expanding the particle tree, we may have a null left or right
            if (left==null && right==null)
                return null;

            if (left == null)
                return expandContentModel((XSParticleDecl)right, minOccurs, maxOccurs);

            if (right == null)
                return expandContentModel((XSParticleDecl)left, minOccurs, maxOccurs);

            XSParticleDecl newParticle = new XSParticleDecl();
            newParticle.fType = particle.fType;
            newParticle.fValue = left;
            newParticle.fOtherValue = right;
            return expandContentModel((XSParticleDecl)newParticle, minOccurs, maxOccurs);
        }
        else if (type == XSParticleDecl.PARTICLE_EMPTY) {
            return null;
        }

        return particle;
    }



    /**
     * When the element has a 'CONTENTTYPE_ELEMENT' model, this method is called to
     * create the content model object. It looks for some special case simple
     * models and creates SimpleContentModel objects for those. For the rest
     * it creates the standard DFA style model.
     *
     * @param grammar
     * @param fParticleIndex
     * @return
     */
    private XSCMValidator createChildModel(XSParticleDecl particle, boolean isMixed) {

        //
        //  Get the content spec node for the element we are working on.
        //  This will tell us what kind of node it is, which tells us what
        //  kind of model we will try to create.
        //
        //XMLContentSpec fParticle = new XMLContentSpec();
        short type = particle.fType;
        if (type == XSParticleDecl.PARTICLE_WILDCARD) {
            // let fall through to build a DFAContentModel
        }
        else if (isMixed) {
            if (type ==XSParticleDecl.PARTICLE_ALL) {
                // All the nodes under an ALL must be additional ALL nodes and
                // ELEMENTs (or ELEMENTs under ZERO_OR_ONE nodes.)
                // We collapse the ELEMENTs into a single vector.
                XSAllCM allContent = new XSAllCM(false);
                gatherAllLeaves ((XSParticleDecl)(particle.fValue), allContent);
                gatherAllLeaves ((XSParticleDecl)(particle.fOtherValue), allContent);
                return allContent;

            }
            else if (type == XSParticleDecl.PARTICLE_ZERO_OR_ONE) {
                 XSParticleDecl left = (XSParticleDecl)particle.fValue;


                // An ALL node can appear under a ZERO_OR_ONE node.
                if (type ==XSParticleDecl.PARTICLE_ALL) {
                    XSAllCM allContent = new XSAllCM(true);
                    gatherAllLeaves (left, allContent);
                    return allContent;

                }
            }
            // otherwise, let fall through to build a DFAContentModel
        }
        else if (type == XSParticleDecl.PARTICLE_ELEMENT) {
            //
            //  Check that the left value is not null, since any content model
            //  with PCDATA should be MIXED, so we should not have gotten here.
            //
            if (particle.fValue == null &&
                particle.fOtherValue == null)
                throw new RuntimeException("ImplementationMessages.VAL_NPCD");

            //
            //  Its a single leaf, so its an 'a' type of content model, i.e.
            //  just one instance of one element. That one is definitely a
            //  simple content model.
            //
            // pass element declaration

            return new XSSimpleCM(type, (XSElementDecl)particle.fValue);
        }
        else if ((type == XSParticleDecl.PARTICLE_CHOICE)
                 ||  (type == XSParticleDecl.PARTICLE_SEQUENCE)) {
            //
            //  Lets see if both of the children are leafs. If so, then it
            //  it has to be a simple content model
            //
            XSParticleDecl left = (XSParticleDecl)particle.fValue;
            XSParticleDecl right = (XSParticleDecl)particle.fOtherValue;

            if ((right.fType == XSParticleDecl.PARTICLE_ELEMENT)
                &&  (left.fType == XSParticleDecl.PARTICLE_ELEMENT)) {
                //
                //  Its a simple choice or sequence, so we can do a simple
                //  content model for it.
                //
                // pass both element decls
                return new XSSimpleCM(type, (XSElementDecl)left.fValue, (XSElementDecl)right.fValue);
            }

        }
    else if (type == XSParticleDecl.PARTICLE_ALL) {

            XSParticleDecl left = (XSParticleDecl)particle.fValue;
            XSParticleDecl right = (XSParticleDecl)particle.fOtherValue;

            XSAllCM allContent = new XSAllCM(false);

            gatherAllLeaves (left, allContent);
            gatherAllLeaves (right, allContent);
            return allContent;
        }
        else if ((type == XSParticleDecl.PARTICLE_ZERO_OR_ONE)
                 ||  (type == XSParticleDecl.PARTICLE_ZERO_OR_MORE)
                 ||  (type == XSParticleDecl.PARTICLE_ONE_OR_MORE)) {
            //
            //  Its a repetition, so see if its one child is a leaf. If so
            //  its a repetition of a single element, so we can do a simple
            //  content model for that.
            XSParticleDecl left = (XSParticleDecl) particle.fValue;

            if (left.fType == XSParticleDecl.PARTICLE_ELEMENT) {
                //
                //  It is, so we can create a simple content model here that
                //  will check for this repetition. We pass -1 for the unused
                //  right node.
                //
                return new XSSimpleCM(type, (XSElementDecl)left.fValue);
            }
            else if (left.fType==XSParticleDecl.PARTICLE_ALL) {
                 XSAllCM allContent = new XSAllCM(true);
                gatherAllLeaves (left, allContent);
                return allContent;
            }


        }
        else {
            throw new RuntimeException("ImplementationMessages.VAL_CST");
        }

        //
        //  Its not a simple content model, so here we have to create a DFA
        //  for this element. So we create a DFAContentModel object. He
        //  encapsulates all of the work to create the DFA.
        //

        fLeafCount = 0;
        CMNode node = buildSyntaxTree(particle);
        return new XSDFACM(node, fLeafCount, isMixed);
    }



    private XSParticleDecl expandContentModel(XSParticleDecl particle,
                                              int minOccurs, int maxOccurs) {

        XSParticleDecl leafParticle = particle;
        XSParticleDecl optional = null;
        if (minOccurs==1 && maxOccurs==1) {
            return particle;
        }
        else if (minOccurs==0 && maxOccurs==1) {
            //zero or one
            return createParticle ( XSParticleDecl.PARTICLE_ZERO_OR_ONE,particle,null);
        }
        else if (minOccurs == 0 && maxOccurs==SchemaSymbols.OCCURRENCE_UNBOUNDED) {
            //zero or more
            return createParticle (XSParticleDecl.PARTICLE_ZERO_OR_MORE, particle, null);
        }
        else if (minOccurs == 1 && maxOccurs==SchemaSymbols.OCCURRENCE_UNBOUNDED) {
            //one or more
            return createParticle (XSParticleDecl.PARTICLE_ONE_OR_MORE, particle, null);
        }
        else if (maxOccurs == SchemaSymbols.OCCURRENCE_UNBOUNDED) {
            // REVISIT: should we handle (maxOccurs - minOccurs) = {1,2} as
            //          separate case?
            if (minOccurs<2) {
            }

            // => a,a,..,a+
            particle = createParticle (XSParticleDecl.PARTICLE_ONE_OR_MORE,
                                       particle, null);

            for (int i=0; i < (minOccurs-1); i++) {
                particle = createParticle (XSParticleDecl.PARTICLE_SEQUENCE, leafParticle, particle);
            }
            return particle;

        }
        else {
            // {n,m} => a,a,a,...(a),(a),...


            if (minOccurs==0) {
                optional = createParticle (XSParticleDecl.PARTICLE_ZERO_OR_ONE,
                                           leafParticle,
                                           null);
                particle = optional;
                for (int i=0; i < (maxOccurs-minOccurs-1); i++) {
                    particle = createParticle (XSParticleDecl.PARTICLE_SEQUENCE,
                                               particle,
                                               optional);
                }
            }
            else {
                for (int i=0; i<(minOccurs-1); i++) {
                    particle = createParticle (XSParticleDecl.PARTICLE_SEQUENCE,
                                               particle,
                                               leafParticle);
                }

                optional = createParticle(XSParticleDecl.PARTICLE_ZERO_OR_ONE,
                                          leafParticle,
                                          null);

                for (int i=0; i < (maxOccurs-minOccurs); i++) {
                    particle = createParticle(XSParticleDecl.PARTICLE_SEQUENCE,
                                              particle,
                                              optional);
                }
            }
        }

        return particle;
    }

    /**
     *  Recursively builds an AllContentModel based on a particle tree
     *  rooted at an ALL node.
     */
     private void gatherAllLeaves(XSParticleDecl particle,
                                        XSAllCM allContent) {
        Object left = particle.fValue;
        Object right = particle.fOtherValue;
        int type = particle.fType;

        if (type == XSParticleDecl.PARTICLE_ALL) {

            // At an all node, visit left and right subtrees
            gatherAllLeaves ((XSParticleDecl)left, allContent);
            gatherAllLeaves ((XSParticleDecl) particle.fOtherValue, allContent);
        }
        else if (type == XSParticleDecl.PARTICLE_ELEMENT) {

            // At leaf, add the element to list of elements permitted in the all
            allContent.addElement ((XSElementDecl)left, false);
        }
        else if (type == XSParticleDecl.PARTICLE_ZERO_OR_ONE) {

            // At ZERO_OR_ONE node, subtree must be an element
            // that was specified with minOccurs=0, maxOccurs=1
            // Add the optional element to list of elements permitted in the all

            if (((XSParticleDecl)left).fType == XSParticleDecl.PARTICLE_ELEMENT) {
                allContent.addElement ((XSElementDecl)(((XSParticleDecl)left).fValue), true);
            }
            else {
            // report error
        throw new RuntimeException("ImplementationMessages.VAL_CST");
            }
        }
        else {
            // report error
            throw new RuntimeException("ImplementationMessages.VAL_CSTA");
        }
    }

    private XSParticleDecl createParticle (short type,
                                           XSParticleDecl left,
                                           XSParticleDecl right) {

        XSParticleDecl newParticle = new XSParticleDecl();
        newParticle.fType = type;
        newParticle.fValue = (Object) left;
        newParticle.fOtherValue = (Object)right;
        return newParticle;
    }

    // this method is needed to convert a tree of ParticleDecl
    // nodes into a tree of content models that XSDFACM methods can then use as input.
    private final CMNode buildSyntaxTree(XSParticleDecl startNode) {

        // We will build a node at this level for the new tree
        CMNode nodeRet = null;
        if (startNode.fType == XSParticleDecl.PARTICLE_WILDCARD) {
            nodeRet = new XSCMLeaf(startNode, fLeafCount++);
        }
        //
        //  If this node is a leaf, then its an easy one. We just add it
        //  to the tree.
        //
        else if (startNode.fType == XSParticleDecl.PARTICLE_ELEMENT) {
            //
            //  Create a new leaf node, and pass it the current leaf count,
            //  which is its DFA state position. Bump the leaf count after
            //  storing it. This makes the positions zero based since we
            //  store first and then increment.
            //
            nodeRet = new XSCMLeaf(startNode, fLeafCount++);
        }
        else {
            //
            //  Its not a leaf, so we have to recurse its left and maybe right
            //  nodes. Save both values before we recurse and trash the node.
            final XSParticleDecl leftNode = ((XSParticleDecl)startNode.fValue);
            final XSParticleDecl rightNode = ((XSParticleDecl)startNode.fOtherValue);

            if ((startNode.fType == XSParticleDecl.PARTICLE_CHOICE)
                ||  (startNode.fType == XSParticleDecl.PARTICLE_SEQUENCE)) {
                //
                //  Recurse on both children, and return a binary op node
                //  with the two created sub nodes as its children. The node
                //  type is the same type as the source.
                //

                nodeRet = new XSCMBinOp( startNode.fType, buildSyntaxTree(leftNode)
                                       , buildSyntaxTree(rightNode));
            }
            else if (startNode.fType == XSParticleDecl.PARTICLE_ZERO_OR_MORE
               || startNode.fType == XSParticleDecl.PARTICLE_ZERO_OR_ONE
               || startNode.fType == XSParticleDecl.PARTICLE_ONE_OR_MORE) {
                nodeRet = new XSCMUniOp(startNode.fType, buildSyntaxTree(leftNode));
            }
            else {
                throw new RuntimeException("ImplementationMessages.VAL_CST");
            }
        }
        // And return our new node for this level
        return nodeRet;
    }

}
TOP

Related Classes of org.apache.xerces.impl.xs.models.CMBuilder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.