KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xerces > impl > xs > SubstitutionGroupHandler


1 /*
2  * Copyright 2001-2005 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.apache.xerces.impl.xs;
18
19 import org.apache.xerces.xs.XSConstants;
20 import org.apache.xerces.xs.XSTypeDefinition;
21 import org.apache.xerces.xni.QName;
22 import java.util.Hashtable JavaDoc;
23 import java.util.Vector JavaDoc;
24
25 /**
26  * To store and validate information about substitutionGroup
27  *
28  * @xerces.internal
29  *
30  * @author Sandy Gao, IBM
31  *
32  * @version $Id: SubstitutionGroupHandler.java,v 1.18 2005/02/04 03:36:57 mrglavas Exp $
33  */

34 public class SubstitutionGroupHandler {
35
36     private static final XSElementDecl[] EMPTY_GROUP = new XSElementDecl[0];
37
38     // grammar resolver
39
XSGrammarBucket fGrammarBucket;
40
41     /**
42      * Default constructor
43      */

44     public SubstitutionGroupHandler(XSGrammarBucket grammarBucket) {
45         fGrammarBucket = grammarBucket;
46     }
47
48     // 3.9.4 Element Sequence Locally Valid (Particle) 2.3.3
49
// check whether one element decl matches an element with the given qname
50
public XSElementDecl getMatchingElemDecl(QName element, XSElementDecl exemplar) {
51         if (element.localpart == exemplar.fName &&
52             element.uri == exemplar.fTargetNamespace) {
53             return exemplar;
54         }
55
56         // if the exemplar is not a global element decl, then it's not possible
57
// to be substituted by another element.
58
if (exemplar.fScope != XSConstants.SCOPE_GLOBAL)
59             return null;
60
61         // if the decl blocks substitution, return false
62
if ((exemplar.fBlock & XSConstants.DERIVATION_SUBSTITUTION) != 0)
63             return null;
64
65         // get grammar of the element
66
SchemaGrammar sGrammar = fGrammarBucket.getGrammar(element.uri);
67         if (sGrammar == null)
68             return null;
69
70         // get the decl for the element
71
XSElementDecl eDecl = sGrammar.getGlobalElementDecl(element.localpart);
72         if (eDecl == null)
73             return null;
74
75         // and check by using substitutionGroup information
76
if (substitutionGroupOK(eDecl, exemplar, exemplar.fBlock))
77             return eDecl;
78
79         return null;
80     }
81
82     // 3.3.6 Substitution Group OK (Transitive)
83
// check whether element can substitute exemplar
84
protected boolean substitutionGroupOK(XSElementDecl element, XSElementDecl exemplar, short blockingConstraint) {
85         // For an element declaration (call it D) to be validly substitutable for another element declaration (call it C) subject to a blocking constraint (a subset of {substitution, extension, restriction}, the value of a {disallowed substitutions}) one of the following must be true:
86
// 1. D and C are the same element declaration.
87
if (element == exemplar)
88             return true;
89         
90         // 2 All of the following must be true:
91
// 2.1 The blocking constraint does not contain substitution.
92
if ((blockingConstraint & XSConstants.DERIVATION_SUBSTITUTION) != 0)
93             return false;
94
95         // 2.2 There is a chain of {substitution group affiliation}s from D to C, that is, either D's {substitution group affiliation} is C, or D's {substitution group affiliation}'s {substitution group affiliation} is C, or . . .
96
XSElementDecl subGroup = element.fSubGroup;
97         while (subGroup != null && subGroup != exemplar) {
98             subGroup = subGroup.fSubGroup;
99         }
100
101         if (subGroup == null)
102             return false;
103
104         // 2.3 The set of all {derivation method}s involved in the derivation of D's {type definition} from C's {type definition} does not intersect with the union of the blocking constraint, C's {prohibited substitutions} (if C is complex, otherwise the empty set) and the {prohibited substitutions} (respectively the empty set) of any intermediate {type definition}s in the derivation of D's {type definition} from C's {type definition}.
105
// prepare the combination of {derivation method} and
106
// {disallowed substitution}
107
short devMethod = 0, blockConstraint = blockingConstraint;
108
109         // element.fType should be derived from exemplar.fType
110
// add derivation methods of derived types to devMethod;
111
// add block of base types to blockConstraint.
112
XSTypeDefinition type = element.fType;
113         while (type != exemplar.fType && type != SchemaGrammar.fAnyType) {
114             if (type.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE)
115                 devMethod |= ((XSComplexTypeDecl)type).fDerivedBy;
116             else
117                 devMethod |= XSConstants.DERIVATION_RESTRICTION;
118             type = type.getBaseType();
119             // type == null means the current type is anySimpleType,
120
// whose base type should be anyType
121
if (type == null)
122                 type = SchemaGrammar.fAnyType;
123             if (type.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE)
124                 blockConstraint |= ((XSComplexTypeDecl)type).fBlock;
125         }
126         if (type != exemplar.fType)
127             return false;
128         
129         if ((devMethod & blockConstraint) != 0)
130             return false;
131
132         return true;
133     }
134
135     // check whether element is in exemplar's substitution group
136
public boolean inSubstitutionGroup(XSElementDecl element, XSElementDecl exemplar) {
137         // [Definition:] Every element declaration (call this HEAD) in the {element declarations} of a schema defines a substitution group, a subset of those {element declarations}, as follows:
138
// Define PSG, the potential substitution group for HEAD, as follows:
139
// 1 The element declaration itself is in PSG;
140
// 2 PSG is closed with respect to {substitution group affiliation}, that is, if any element declaration in the {element declarations} has a {substitution group affiliation} in PSG, then it is also in PSG itself.
141
// HEAD's actual substitution group is then the set consisting of each member of PSG such that all of the following must be true:
142
// 1 Its {abstract} is false.
143
// 2 It is validly substitutable for HEAD subject to an empty blocking constraint, as defined in Substitution Group OK (Transitive) (3.3.6).
144
return substitutionGroupOK(element, exemplar, exemplar.fBlock);
145     }
146
147     // to store substitution group information
148
// the key to the hashtable is an element decl, and the value is
149
// - a Vector, which contains all elements that has this element as their
150
// substitution group affilication
151
// - an array of OneSubGroup, which contains its substitution group before block.
152
Hashtable JavaDoc fSubGroupsB = new Hashtable JavaDoc();
153     private static final OneSubGroup[] EMPTY_VECTOR = new OneSubGroup[0];
154     // The real substitution groups (after "block")
155
Hashtable JavaDoc fSubGroups = new Hashtable JavaDoc();
156
157     /**
158      * clear the internal registry of substitutionGroup information
159      */

160     public void reset() {
161         fSubGroupsB.clear();
162         fSubGroups.clear();
163     }
164
165     /**
166      * add a list of substitution group information.
167      */

168     public void addSubstitutionGroup(XSElementDecl[] elements) {
169         XSElementDecl subHead, element;
170         Vector JavaDoc subGroup;
171         // for all elements with substitution group affiliation
172
for (int i = elements.length-1; i >= 0; i--) {
173             element = elements[i];
174             subHead = element.fSubGroup;
175             // check whether this an entry for this element
176
subGroup = (Vector JavaDoc)fSubGroupsB.get(subHead);
177             if (subGroup == null) {
178                 // if not, create a new one
179
subGroup = new Vector JavaDoc();
180                 fSubGroupsB.put(subHead, subGroup);
181             }
182             // add to the vactor
183
subGroup.addElement(element);
184         }
185     }
186
187     /**
188      * get all elements that can substitute the given element,
189      * according to the spec, we shouldn't consider the {block} constraints.
190      *
191      * from the spec, substitution group of a given element decl also contains
192      * the element itself. but the array returned from this method doesn't
193      * containt this element.
194      */

195     public XSElementDecl[] getSubstitutionGroup(XSElementDecl element) {
196         // If we already have sub group for this element, just return it.
197
Object JavaDoc subGroup = fSubGroups.get(element);
198         if (subGroup != null)
199             return (XSElementDecl[])subGroup;
200         
201         if ((element.fBlock & XSConstants.DERIVATION_SUBSTITUTION) != 0) {
202             fSubGroups.put(element, EMPTY_GROUP);
203             return EMPTY_GROUP;
204         }
205         
206         // Otherwise, get all potential sub group elements
207
// (without considering "block" on this element
208
OneSubGroup[] groupB = getSubGroupB(element, new OneSubGroup());
209         int len = groupB.length, rlen = 0;
210         XSElementDecl[] ret = new XSElementDecl[len];
211         // For each of such elements, check whether the derivation methods
212
// overlap with "block". If not, add it to the sub group
213
for (int i = 0 ; i < len; i++) {
214             if ((element.fBlock & groupB[i].dMethod) == 0)
215                 ret[rlen++] = groupB[i].sub;
216         }
217         // Resize the array if necessary
218
if (rlen < len) {
219             XSElementDecl[] ret1 = new XSElementDecl[rlen];
220             System.arraycopy(ret, 0, ret1, 0, rlen);
221             ret = ret1;
222         }
223         // Store the subgroup
224
fSubGroups.put(element, ret);
225
226         return ret;
227     }
228
229     // Get potential sub group element (without considering "block")
230
private OneSubGroup[] getSubGroupB(XSElementDecl element, OneSubGroup methods) {
231         Object JavaDoc subGroup = fSubGroupsB.get(element);
232
233         // substitution group for this one is empty
234
if (subGroup == null) {
235             fSubGroupsB.put(element, EMPTY_VECTOR);
236             return EMPTY_VECTOR;
237         }
238         
239         // we've already calculated the element, just return.
240
if (subGroup instanceof OneSubGroup[])
241             return (OneSubGroup[])subGroup;
242         
243         // we only have the *direct* substitutions
244
Vector JavaDoc group = (Vector JavaDoc)subGroup, newGroup = new Vector JavaDoc();
245         OneSubGroup[] group1;
246         // then for each of the direct substitutions, get its substitution
247
// group, and combine the groups together.
248
short dMethod, bMethod, dSubMethod, bSubMethod;
249         for (int i = group.size()-1, j; i >= 0; i--) {
250             // Check whether this element is blocked. If so, ignore it.
251
XSElementDecl sub = (XSElementDecl)group.elementAt(i);
252             if (!getDBMethods(sub.fType, element.fType, methods))
253                 continue;
254             // Remember derivation methods and blocks from the types
255
dMethod = methods.dMethod;
256             bMethod = methods.bMethod;
257             // Add this one to potential group
258
newGroup.addElement(new OneSubGroup(sub, methods.dMethod, methods.bMethod));
259             // Get potential group for this element
260
group1 = getSubGroupB(sub, methods);
261             for (j = group1.length-1; j >= 0; j--) {
262                 // For each of them, check whether it's blocked (by type)
263
dSubMethod = (short)(dMethod | group1[j].dMethod);
264                 bSubMethod = (short)(bMethod | group1[j].bMethod);
265                 // Ignore it if it's blocked
266
if ((dSubMethod & bSubMethod) != 0)
267                     continue;
268                 newGroup.addElement(new OneSubGroup(group1[j].sub, dSubMethod, bSubMethod));
269             }
270         }
271         // Convert to an array
272
OneSubGroup[] ret = new OneSubGroup[newGroup.size()];
273         for (int i = newGroup.size()-1; i >= 0; i--) {
274             ret[i] = (OneSubGroup)newGroup.elementAt(i);
275         }
276         // Store the potential sub group
277
fSubGroupsB.put(element, ret);
278         
279         return ret;
280     }
281
282     private boolean getDBMethods(XSTypeDefinition typed, XSTypeDefinition typeb,
283                                  OneSubGroup methods) {
284         short dMethod = 0, bMethod = 0;
285         while (typed != typeb && typed != SchemaGrammar.fAnyType) {
286             if (typed.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE)
287                 dMethod |= ((XSComplexTypeDecl)typed).fDerivedBy;
288             else
289                 dMethod |= XSConstants.DERIVATION_RESTRICTION;
290             typed = typed.getBaseType();
291             // type == null means the current type is anySimpleType,
292
// whose base type should be anyType
293
if (typed == null)
294                 typed = SchemaGrammar.fAnyType;
295             if (typed.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE)
296                 bMethod |= ((XSComplexTypeDecl)typed).fBlock;
297         }
298         // No derivation relation, or blocked, return false
299
if (typed != typeb || (dMethod & bMethod) != 0)
300             return false;
301         
302         // Remember the derivation methods and blocks, return true.
303
methods.dMethod = dMethod;
304         methods.bMethod = bMethod;
305         return true;
306     }
307
308     // Record the information about how one element substitute another one
309
private static final class OneSubGroup {
310         OneSubGroup() {}
311         OneSubGroup(XSElementDecl sub, short dMethod, short bMethod) {
312             this.sub = sub;
313             this.dMethod = dMethod;
314             this.bMethod = bMethod;
315         }
316         // The element that substitutes another one
317
XSElementDecl sub;
318         // The combination of all derivation methods from sub's type to
319
// the head's type
320
short dMethod;
321         // The combination of {block} of the types in the derivation chain
322
// excluding sub's type
323
short bMethod;
324     }
325 } // class SubstitutionGroupHandler
326
Popular Tags