com.sun.msv.reader.xmlschema.AttributeWildcardComputer Maven / Gradle / Ivy
/*
* Copyright (c) 2001-2013 Oracle and/or its affiliates. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - 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.
*
* - Neither the name of Oracle nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
* IS" AND ANY EXPRESS 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 COPYRIGHT OWNER OR
* 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.
*/
package com.sun.msv.reader.xmlschema;
import java.util.HashSet;
import java.util.Set;
import java.util.Stack;
import com.sun.msv.grammar.AttributeExp;
import com.sun.msv.grammar.ChoiceExp;
import com.sun.msv.grammar.ElementExp;
import com.sun.msv.grammar.Expression;
import com.sun.msv.grammar.NameClass;
import com.sun.msv.grammar.ReferenceExp;
import com.sun.msv.grammar.SimpleNameClass;
import com.sun.msv.grammar.util.ExpressionWalker;
import com.sun.msv.grammar.xmlschema.AttWildcardExp;
import com.sun.msv.grammar.xmlschema.AttributeGroupExp;
import com.sun.msv.grammar.xmlschema.AttributeWildcard;
import com.sun.msv.grammar.xmlschema.ComplexTypeExp;
/**
* Processes the attribtue wildcard according to the spec.
*
*
* Since the definition of the attribute wildcard is very adhoc,
* it cannot be naturally caputred by our AGM.
*
*
* Therefore, when we parse a schema, we just parse <anyAttribute> directly.
* After all components are loaded, arcane computation is done to correctly
* compute the attribute wildcard.
*
*
* Attribute wildcard will be ultimately converted into an expression, and that
* will be attached to the {@link ComplexTypeExp#attWildcard}.
*
*
* This class also computes the attribute propagation that happens
* only when a complex type is derived by restriction.
*
* Consider the following fragment:
*
*
*
*
*
*
*
*
*
*
*
*
*
*
* According to the spec, the derived type will have the 'abc' attribute.
* By "propagation", we mean this behavior.
*
*
* @author Kohsuke KAWAGUCHI
*/
public class AttributeWildcardComputer extends ExpressionWalker {
public static void compute( XMLSchemaReader reader, Expression topLevel ) {
new AttributeWildcardComputer(reader).compute(topLevel);
}
private void compute( Expression topLevel ) {
topLevel.visit(this);
while(!unprocessedElementExps.isEmpty())
((ElementExp)unprocessedElementExps.pop()).contentModel.visit(this);
}
protected AttributeWildcardComputer( XMLSchemaReader _reader ) {
this.reader = _reader;
}
private final XMLSchemaReader reader;
/**
* Visited ElementExps and ReferenceExps to prevent infinite recursion.
*/
private final Set visitedExps = new HashSet();
private final Stack unprocessedElementExps = new Stack();
/**
* Used to collect AttributeWildcards of children.
*/
private Set wildcards = null;
public void onElement( ElementExp exp ) {
if( !visitedExps.add(exp) )
return; // this element has already been processed
unprocessedElementExps.add(exp);
}
public void onRef( ReferenceExp exp ) {
if( visitedExps.add(exp) ) {
if( exp instanceof AttributeGroupExp ) {
AttributeGroupExp aexp = (AttributeGroupExp)exp;
final Set o = wildcards;
{
// process children and collect their wildcards.
wildcards = new HashSet();
exp.exp.visit(this);
// compute the attribute wildcard
aexp.wildcard = calcCompleteWildcard( aexp.wildcard, wildcards );
}
wildcards = o;
}
else
if( exp instanceof ComplexTypeExp ) {
ComplexTypeExp cexp = (ComplexTypeExp)exp;
final Set o = wildcards;
{
// process children and collect their wildcards.
wildcards = new HashSet();
exp.exp.visit(this);
// compute the attribute wildcard
cexp.wildcard = calcCompleteWildcard( cexp.wildcard, wildcards );
// if(cexp.wildcard==null)
// System.out.println("complete wildcard is: none");
// else
// System.out.println("complete wildcard is: "+cexp.wildcard.getName());
// if the base type is a complex type and the extension is chosen,
// then we need one last step. Sigh.
if(cexp.complexBaseType!=null) {
// System.out.println("check the base type");
// process the base type first.
cexp.complexBaseType.visit(this);
if(cexp.derivationMethod==ComplexTypeExp.EXTENSION)
cexp.wildcard = calcComplexTypeWildcard(
cexp.wildcard,
cexp.complexBaseType.wildcard );
propagateAttributes(cexp);
}
// create the expression for this complex type.
if( cexp.wildcard!=null )
cexp.attWildcard.exp = cexp.wildcard.createExpression(reader.grammar);
}
wildcards = o;
} else
// otherwise process it normally.
super.onRef(exp);
}
if( wildcards!=null ) {
// add the complete att wildcard of this component.
if( exp instanceof AttWildcardExp ) {
AttributeWildcard w = ((AttWildcardExp)exp).getAttributeWildcard();
if(w!=null) wildcards.add(w);
}
}
}
/**
* Computes the "complete attribute wildcard"
*/
private AttributeWildcard calcCompleteWildcard( AttributeWildcard local, Set s ) {
final AttributeWildcard[] children =
(AttributeWildcard[])s.toArray(new AttributeWildcard[s.size()]);
// 1st step is to compute the complete wildcard.
if( children.length==0 )
return local;
// assert(children.length>0)
// compute the intersection of wildcard.
NameClass target = children[0].getName();
for( int i=1; i