1
|
|
/*
|
2
|
|
* JBind
|
3
|
|
*
|
4
|
|
* Copyright (c) by Stefan Wachter. All rights reserved.
|
5
|
|
*
|
6
|
|
* Usage, modification, and redistribution is subject to license terms that are
|
7
|
|
* available at 'http://www.jbind.org'. The JBind license is like the
|
8
|
|
* 'Apache Software License V 1.1'.
|
9
|
|
*/
|
10
|
|
package org.jbind.xml.schema.element;
|
11
|
|
|
12
|
|
import java.util.Iterator;
|
13
|
|
import java.util.Set;
|
14
|
|
|
15
|
|
import org.jbind.xml.base.FinalType;
|
16
|
|
import org.jbind.xml.base.IAttribute;
|
17
|
|
import org.jbind.xml.base.INamespaces;
|
18
|
|
import org.jbind.xml.base.IRange;
|
19
|
|
import org.jbind.xml.base.IRef;
|
20
|
|
import org.jbind.xml.base.ISymbolspace;
|
21
|
|
import org.jbind.xml.base.ISymbolspaces;
|
22
|
|
import org.jbind.xml.base.Range;
|
23
|
|
import org.jbind.xml.core.cmp.IComponent;
|
24
|
|
import org.jbind.xml.core.cmp.ISchema;
|
25
|
|
import org.jbind.xml.core.content.IElemDecl;
|
26
|
|
import org.jbind.xml.core.content.IElemRefOrDecl;
|
27
|
|
import org.jbind.xml.core.type.IAnyType;
|
28
|
|
import org.jbind.xml.msg.IConstraintViolations;
|
29
|
|
import org.jbind.xml.msg.XmlException;
|
30
|
|
import org.jbind.xml.msg.XmlMessages;
|
31
|
|
import org.jbind.xml.schema.cmp.ElemDecl;
|
32
|
|
import org.jbind.xml.schema.cmp.ElemRef;
|
33
|
|
import org.jbind.xml.schema.cmp.W3CTypes;
|
34
|
|
import org.jbind.xml.schema.constraint.ElementIdentityConstraint;
|
35
|
|
import org.jbind.xml.schema.instantiation.IComponentSetter;
|
36
|
|
import org.jbind.xml.schema.instantiation.IElemValHelper;
|
37
|
|
import org.jbind.xml.schema.instantiation.IElementHelper;
|
38
|
|
import org.jbind.xml.schema.instantiation.IJobRefs;
|
39
|
|
|
40
|
|
public class ElementDeclaration extends PartDeclaration implements IElementDeclaration {
|
41
|
|
|
42
|
|
private boolean myIsUnbounded = false;
|
43
|
|
private int myMin = 1;
|
44
|
|
private int myMax = 1;
|
45
|
|
|
46
|
|
private boolean myIsNillable = false;
|
47
|
|
private boolean myIsAbstract = false;
|
48
|
|
private Set myBlockTypes = null;
|
49
|
|
private Set myFinalTypes = null;
|
50
|
|
|
51
|
|
private IRef mySubstitutionGroup = null;
|
52
|
|
private ITypeDef myTypeDef = null;
|
53
|
|
|
54
|
951
|
public ElementDeclaration(CreationParams aCreationParams, boolean anIsLocal) {
|
55
|
951
|
super(aCreationParams, anIsLocal);
|
56
|
951
|
myBlockTypes = getSchemaElement().getDefaultBlockTypes();
|
57
|
951
|
myFinalTypes = getSchemaElement().getDefaultFinalTypes();
|
58
|
|
}
|
59
|
|
|
60
|
316
|
public IElement doCreateChild(CreationParams aCreationParams) throws XmlException {
|
61
|
316
|
IElement res = null;
|
62
|
316
|
String componentName = NameUtil.getSchemaComponentName(aCreationParams);
|
63
|
316
|
if ("unique".equals(componentName)) {
|
64
|
5
|
res = new ElementUniqueConstraintElement(aCreationParams);
|
65
|
311
|
} else if ("key".equals(componentName)) {
|
66
|
27
|
res = new ElementKeyConstraintElement(aCreationParams);
|
67
|
284
|
} else if ("keyref".equals(componentName)) {
|
68
|
15
|
res = new ElementKeyRefConstraintElement(aCreationParams);
|
69
|
269
|
} else if ("simpleType".equals(componentName)) {
|
70
|
3
|
res = new SimpleTypeDef(aCreationParams, getBoundName());
|
71
|
266
|
} else if ("complexType".equals(componentName)) {
|
72
|
190
|
res = new ComplexTypeDef(aCreationParams, getBoundName());
|
73
|
|
} else {
|
74
|
76
|
res = super.doCreateChild(aCreationParams);
|
75
|
|
}
|
76
|
316
|
return res;
|
77
|
|
}
|
78
|
|
|
79
|
1799
|
protected IAttribute doCreateAttribute(ACParams anACParams) throws XmlException {
|
80
|
1799
|
IAttribute res = null;
|
81
|
1799
|
String an = NameUtil.getSchemaAttributeName(anACParams);
|
82
|
1799
|
if ("abstract".equals(an)) {
|
83
|
8
|
res = new BooleanAttribute(anACParams);
|
84
|
7
|
myIsAbstract = res.getBoolean();
|
85
|
1791
|
} else if ("nillable".equals(an)) {
|
86
|
2
|
res = new BooleanAttribute(anACParams);
|
87
|
2
|
myIsNillable = res.getBoolean();
|
88
|
1789
|
} else if ("block".equals(an)) {
|
89
|
2
|
res = new Attribute(anACParams);
|
90
|
2
|
myBlockTypes = ConstantResolver.getBlockTypes(res.getStringValue(), this);
|
91
|
1787
|
} else if ("final".equals(an)) {
|
92
|
4
|
res = new Attribute(anACParams);
|
93
|
4
|
myFinalTypes = ConstantResolver.getFinalTypes(res.getStringValue(), this);
|
94
|
1783
|
} else if ("substitutionGroup".equals(an)) {
|
95
|
42
|
res = new RefAttribute(anACParams, ISymbolspaces.ELEMENT);
|
96
|
42
|
mySubstitutionGroup = res.getRef();
|
97
|
1741
|
} else if ("minOccurs".equals(an)) {
|
98
|
140
|
if (isTopLevelComponent()) {
|
99
|
0
|
throw new XmlException(XmlMessages.minOccursAttributeNotAllowedAtTopLevel(this));
|
100
|
|
}
|
101
|
140
|
res = new IntAttribute(anACParams);
|
102
|
140
|
myMin = res.getInt();
|
103
|
1601
|
} else if ("maxOccurs".equals(an)) {
|
104
|
84
|
if (isTopLevelComponent()) {
|
105
|
0
|
throw new XmlException(XmlMessages.maxOccursAttributeNotAllowedAtTopLevel(this));
|
106
|
|
}
|
107
|
84
|
if ("unbounded".equals(anACParams.value)) {
|
108
|
52
|
res = new Attribute(anACParams);
|
109
|
52
|
myIsUnbounded = true;
|
110
|
|
} else {
|
111
|
32
|
res = new IntAttribute(anACParams);
|
112
|
32
|
myMax = res.getInt();
|
113
|
|
}
|
114
|
|
} else {
|
115
|
1517
|
res = super.doCreateAttribute(anACParams);
|
116
|
|
}
|
117
|
1797
|
return res;
|
118
|
|
}
|
119
|
|
|
120
|
0
|
public int getMinOccurs() {
|
121
|
0
|
return myMin;
|
122
|
|
}
|
123
|
0
|
public int getMaxOccurs() {
|
124
|
0
|
return myMax;
|
125
|
|
}
|
126
|
0
|
public boolean isUnbounded() {
|
127
|
0
|
return myIsUnbounded;
|
128
|
|
}
|
129
|
|
|
130
|
0
|
public boolean getIsAbstract() {
|
131
|
0
|
return myIsAbstract;
|
132
|
|
}
|
133
|
|
|
134
|
0
|
public Set getFinalTypes() {
|
135
|
0
|
return myFinalTypes;
|
136
|
|
}
|
137
|
|
|
138
|
0
|
public Set getBlockTypes() {
|
139
|
0
|
return myBlockTypes;
|
140
|
|
}
|
141
|
|
|
142
|
2432
|
public IRef getSubstitutionGroup() {
|
143
|
2432
|
return mySubstitutionGroup;
|
144
|
|
}
|
145
|
|
|
146
|
0
|
public boolean getIsNillable() {
|
147
|
0
|
return myIsNillable;
|
148
|
|
}
|
149
|
|
|
150
|
0
|
public Iterator iterIdentityConstraintElements() {
|
151
|
0
|
return iterChildrenByClass(IIdentityConstraintElement.class);
|
152
|
|
}
|
153
|
|
|
154
|
541
|
public ISymbolspace getSymbolSpace() {
|
155
|
541
|
return ISymbolspaces.ELEMENT;
|
156
|
|
}
|
157
|
|
|
158
|
456
|
public ITypeDef getTypeDef() {
|
159
|
456
|
return myTypeDef;
|
160
|
|
}
|
161
|
|
|
162
|
951
|
public void validateElement(IElemValHelper aHelper, IConstraintViolations aViolations) {
|
163
|
951
|
super.validateElement(aHelper, aViolations);
|
164
|
951
|
myTypeDef = (ITypeDef)getSubElement(ITypeDef.class, "duplicate type definition", aViolations);
|
165
|
951
|
if ((null != getType()) && (null != myTypeDef)) {
|
166
|
0
|
aViolations.add(XmlMessages.declMustNotHaveTypeAttAndInlinedType(this));
|
167
|
|
}
|
168
|
951
|
if (((null != getType()) || (null != myTypeDef)) && (null != getRef())) {
|
169
|
0
|
aViolations.add(XmlMessages.declWithRefMustNotHaveType(this));
|
170
|
|
}
|
171
|
951
|
if (myMin < 0) {
|
172
|
0
|
aViolations.add(XmlMessages.minOccursLessThan0(this));
|
173
|
|
}
|
174
|
951
|
if (!myIsUnbounded && (myMin > myMax)) {
|
175
|
0
|
aViolations.add(XmlMessages.minOccursGreaterThanMax(this));
|
176
|
|
}
|
177
|
|
}
|
178
|
|
|
179
|
919
|
private IRange getRange() {
|
180
|
919
|
return Range.createRange(myMin, myMax, myIsUnbounded);
|
181
|
|
}
|
182
|
|
|
183
|
|
//
|
184
|
|
// Implementation of IComponentJobHelper
|
185
|
|
//
|
186
|
|
|
187
|
1648
|
public void collectRefsForCreation(IJobRefs aJobRefs) {
|
188
|
1648
|
if (null != getRef()) {
|
189
|
446
|
aJobRefs.add(getRef(), false, this);
|
190
|
|
}
|
191
|
|
// The type of an element must only be created and not yet be completed when the element declaration
|
192
|
|
// is created. This allows recursive data structures.
|
193
|
1648
|
if (null != getType()) {
|
194
|
749
|
aJobRefs.add(getType(), false, this);
|
195
|
|
}
|
196
|
1648
|
if (null != myTypeDef) {
|
197
|
235
|
myTypeDef.collectRefsForCreation(aJobRefs);
|
198
|
|
}
|
199
|
1648
|
if (null != getSubstitutionGroup()) {
|
200
|
42
|
aJobRefs.add(getSubstitutionGroup(), true, this);
|
201
|
|
}
|
202
|
|
}
|
203
|
|
|
204
|
3248
|
public void collectRefsForCompletion(IElementHelper anElementHelper, IJobRefs aJobRefs) {
|
205
|
|
// if (null != getRef()) {
|
206
|
|
// aJobRefs.add(getRef(), false, this);
|
207
|
|
// }
|
208
|
|
// The type of an element must have been validated before the element declaration can
|
209
|
|
// be validated if the type is a simple type. In this case the element declaration
|
210
|
|
// may contain value constrains that need a validated type to be applied.
|
211
|
3248
|
if (null != getType()) {
|
212
|
1490
|
IAnyType type = (IAnyType)anElementHelper.getComponent(getType(), false);
|
213
|
1490
|
if (type.isSimple()) {
|
214
|
512
|
aJobRefs.add(getType(), true, this);
|
215
|
|
}
|
216
|
|
}
|
217
|
3248
|
if (null != myTypeDef) {
|
218
|
434
|
myTypeDef.collectRefsForCompletion(anElementHelper, aJobRefs);
|
219
|
|
}
|
220
|
|
}
|
221
|
|
|
222
|
0
|
public void collectRefsForValidation(IElementHelper anElementHelper, IJobRefs aJobRefs) {
|
223
|
0
|
if (null != myTypeDef) {
|
224
|
0
|
myTypeDef.collectRefsForValidation(anElementHelper, aJobRefs);
|
225
|
|
}
|
226
|
|
}
|
227
|
|
|
228
|
919
|
public IComponent createComponent(IElementHelper anElementHelper, IConstraintViolations aViolations) {
|
229
|
919
|
IElemRefOrDecl res = null;
|
230
|
|
|
231
|
919
|
if (null != getRef()) {
|
232
|
214
|
IElemDecl c = (IElemDecl)anElementHelper.getComponent(getRef(), false);
|
233
|
214
|
res = new ElemRef(this, getRange(), c);
|
234
|
|
|
235
|
|
} else {
|
236
|
705
|
FormType ft = null;
|
237
|
705
|
if (isTopLevelComponent()) {
|
238
|
310
|
ft = FormType.QUALIFIED;
|
239
|
|
} else {
|
240
|
395
|
ft = getFormType();
|
241
|
395
|
if (null == ft) {
|
242
|
389
|
ft = getSchemaElement().getElementFormDefault();
|
243
|
|
}
|
244
|
|
}
|
245
|
705
|
String namespace = ft.equals(FormType.QUALIFIED) ? getSchemaElement().getTargetNamespace() : INamespaces.NO;
|
246
|
|
|
247
|
705
|
final ElemDecl finalRes = new ElemDecl(this, namespace, getName(), getRange(), myFinalTypes, myBlockTypes, myIsAbstract, myIsNillable);
|
248
|
705
|
res = finalRes;
|
249
|
|
|
250
|
705
|
IElemDecl substitutionGroup = null;
|
251
|
705
|
if (null != getSubstitutionGroup()) {
|
252
|
37
|
substitutionGroup = (IElemDecl)anElementHelper.getComponent(getSubstitutionGroup(), true);
|
253
|
37
|
finalRes.setSubstitutionGroup(substitutionGroup);
|
254
|
37
|
for (IElemDecl d = substitutionGroup; null != d;
|
255
|
|
d = d.getSubstitutionGroup()) {
|
256
|
46
|
d.addSubstitute(finalRes);
|
257
|
|
}
|
258
|
|
}
|
259
|
|
|
260
|
705
|
if (null != getType()) {
|
261
|
|
// The type is possibley not yet validated.
|
262
|
428
|
finalRes.setType((IAnyType)anElementHelper.getComponent(getType(), false));
|
263
|
|
} else {
|
264
|
277
|
if (null != getTypeDef()) {
|
265
|
179
|
anElementHelper.addSubJob(getTypeDef(), new IComponentSetter() {
|
266
|
170
|
public void set(IComponent aComponent, IConstraintViolations aVls) {
|
267
|
170
|
IAnyType t = (IAnyType)aComponent;
|
268
|
170
|
finalRes.setType(t);
|
269
|
|
}
|
270
|
|
});
|
271
|
98
|
} else if (null != substitutionGroup) {
|
272
|
2
|
finalRes.setType(substitutionGroup.getType());
|
273
|
|
} else {
|
274
|
96
|
finalRes.setType(W3CTypes.anyType);
|
275
|
|
}
|
276
|
|
}
|
277
|
|
|
278
|
705
|
final ISchema schema = getSchema();
|
279
|
|
|
280
|
705
|
for (Iterator i = iterChildrenByClass(IIdentityConstraintElement.class);
|
281
|
752
|
i.hasNext(); ) {
|
282
|
47
|
IIdentityConstraintElement ice = (IIdentityConstraintElement)i.next();
|
283
|
47
|
anElementHelper.addSubJob(ice, new IComponentSetter() {
|
284
|
43
|
public void set(IComponent aComponent, IConstraintViolations aVls) {
|
285
|
43
|
ElementIdentityConstraint c = (ElementIdentityConstraint)aComponent;
|
286
|
43
|
finalRes.add(c);
|
287
|
43
|
c.setElementDecl(finalRes);
|
288
|
43
|
schema.setComponent(c, aVls);
|
289
|
|
}
|
290
|
|
});
|
291
|
|
}
|
292
|
|
|
293
|
|
}
|
294
|
|
|
295
|
919
|
return res;
|
296
|
|
}
|
297
|
|
|
298
|
906
|
public void completeComponent(IElementHelper anElementHelper, IComponent aComponent, IConstraintViolations aViolations) {
|
299
|
906
|
super.completeComponent(anElementHelper, aComponent, aViolations);
|
300
|
|
// Substitution group constraints must only be checked if the element is not a reference.
|
301
|
|
// In case that the element is a reference then the referenced element will check the
|
302
|
|
// constraints.
|
303
|
906
|
if (getRef() == null) {
|
304
|
692
|
IElemRefOrDecl decl = (IElemRefOrDecl)aComponent;
|
305
|
692
|
if (null != decl.getSubstitutionGroup()) {
|
306
|
37
|
IAnyType type = decl.getType();
|
307
|
37
|
IElemDecl headDecl = decl.getSubstitutionGroup();
|
308
|
37
|
IAnyType headType = headDecl.getType();
|
309
|
37
|
if (!headType.isBaseType(type)) {
|
310
|
0
|
aViolations.add(XmlMessages.substitutionGroupTypeMustBeBaseType(this));
|
311
|
|
}
|
312
|
37
|
if (headDecl.isActive(FinalType.EXTENSION) && type.isExtension(headType)) {
|
313
|
0
|
aViolations.add(XmlMessages.substitutionFinalizedForExtension(headDecl.getGlobalRef(), this));
|
314
|
|
}
|
315
|
37
|
if (headDecl.isActive(FinalType.RESTRICTION) && type.isRestriction(headType)) {
|
316
|
0
|
aViolations.add(XmlMessages.substitutionFinalizedForRestriction(headDecl.getGlobalRef(), this));
|
317
|
|
}
|
318
|
|
}
|
319
|
|
}
|
320
|
|
}
|
321
|
|
|
322
|
|
}
|
323
|
|
|