1 |
| |
2 |
| |
3 |
| |
4 |
| |
5 |
| |
6 |
| |
7 |
| |
8 |
| |
9 |
| |
10 |
| package org.dom4j.datatype; |
11 |
| |
12 |
| import com.sun.msv.datatype.xsd.DatatypeFactory; |
13 |
| import com.sun.msv.datatype.xsd.TypeIncubator; |
14 |
| import com.sun.msv.datatype.xsd.XSDatatype; |
15 |
| |
16 |
| import java.util.HashMap; |
17 |
| import java.util.Iterator; |
18 |
| import java.util.Map; |
19 |
| |
20 |
| import org.dom4j.Attribute; |
21 |
| import org.dom4j.Document; |
22 |
| import org.dom4j.DocumentFactory; |
23 |
| import org.dom4j.Element; |
24 |
| import org.dom4j.Namespace; |
25 |
| import org.dom4j.QName; |
26 |
| import org.dom4j.io.SAXReader; |
27 |
| import org.dom4j.util.AttributeHelper; |
28 |
| import org.relaxng.datatype.DatatypeException; |
29 |
| import org.relaxng.datatype.ValidationContext; |
30 |
| import org.xml.sax.EntityResolver; |
31 |
| import org.xml.sax.InputSource; |
32 |
| |
33 |
| |
34 |
| |
35 |
| |
36 |
| |
37 |
| |
38 |
| |
39 |
| public class SchemaParser { |
40 |
| |
41 |
| private static final Namespace XSD_NAMESPACE = Namespace.get( "xsd", "http://www.w3.org/2001/XMLSchema" ); |
42 |
| |
43 |
| |
44 |
| private static final QName XSD_ELEMENT = QName.get( "element", XSD_NAMESPACE ); |
45 |
| private static final QName XSD_ATTRIBUTE = QName.get( "attribute", XSD_NAMESPACE ); |
46 |
| private static final QName XSD_SIMPLETYPE = QName.get( "simpleType", XSD_NAMESPACE ); |
47 |
| private static final QName XSD_COMPLEXTYPE = QName.get( "complexType", XSD_NAMESPACE ); |
48 |
| private static final QName XSD_RESTRICTION = QName.get( "restriction", XSD_NAMESPACE ); |
49 |
| private static final QName XSD_SEQUENCE = QName.get( "sequence", XSD_NAMESPACE ); |
50 |
| private static final QName XSD_CHOICE = QName.get( "choice", XSD_NAMESPACE ); |
51 |
| private static final QName XSD_ALL = QName.get( "all", XSD_NAMESPACE ); |
52 |
| private static final QName XSD_INCLUDE = QName.get("include", XSD_NAMESPACE); |
53 |
| |
54 |
| |
55 |
| private DatatypeDocumentFactory documentFactory; |
56 |
| |
57 |
| |
58 |
| private Map dataTypeCache = new HashMap(); |
59 |
| |
60 |
| |
61 |
| private NamedTypeResolver namedTypeResolver; |
62 |
| |
63 |
| |
64 |
| private Namespace targetNamespace; |
65 |
| |
66 |
0
| public SchemaParser() {
|
67 |
0
| this(DatatypeDocumentFactory.singleton);
|
68 |
| } |
69 |
| |
70 |
54
| public SchemaParser(DatatypeDocumentFactory documentFactory) {
|
71 |
54
| this.documentFactory = documentFactory;
|
72 |
54
| this.namedTypeResolver = new NamedTypeResolver(documentFactory);
|
73 |
| } |
74 |
| |
75 |
| |
76 |
| |
77 |
| |
78 |
| |
79 |
44
| public void build( Document schemaDocument ) {
|
80 |
44
| this.targetNamespace = null;
|
81 |
44
| internalBuild( schemaDocument );
|
82 |
| } |
83 |
| |
84 |
6
| public void build( Document schemaDocument, Namespace targetNamespace) {
|
85 |
6
| this.targetNamespace = targetNamespace;
|
86 |
6
| internalBuild( schemaDocument );
|
87 |
| } |
88 |
| |
89 |
50
| private synchronized void internalBuild( Document schemaDocument ) {
|
90 |
50
| Element root = schemaDocument.getRootElement();
|
91 |
50
| if ( root != null ) {
|
92 |
| |
93 |
50
| Iterator includeIter = root.elementIterator( XSD_INCLUDE );
|
94 |
50
| while (includeIter.hasNext()) {
|
95 |
0
| Element includeElement = (Element) includeIter.next();
|
96 |
0
| String inclSchemaInstanceURI = includeElement.attributeValue("schemaLocation");
|
97 |
0
| EntityResolver resolver = schemaDocument.getEntityResolver();
|
98 |
0
| try {
|
99 |
0
| if ( resolver == null ) {
|
100 |
0
| throw new InvalidSchemaException( "No EntityResolver available so could not resolve the schema URI: " +
|
101 |
| inclSchemaInstanceURI ); |
102 |
| } |
103 |
0
| InputSource inputSource = resolver.resolveEntity( null, inclSchemaInstanceURI );
|
104 |
0
| if ( inputSource == null ) {
|
105 |
0
| throw new InvalidSchemaException( "Could not resolve the schema URI: " + inclSchemaInstanceURI );
|
106 |
| } |
107 |
0
| SAXReader reader = new SAXReader();
|
108 |
0
| Document inclSchemaDocument = reader.read( inputSource );
|
109 |
0
| build( inclSchemaDocument );
|
110 |
| } |
111 |
| catch (Exception e) { |
112 |
0
| System.out.println( "Failed to load schema: " + inclSchemaInstanceURI );
|
113 |
0
| System.out.println( "Caught: " + e );
|
114 |
0
| e.printStackTrace();
|
115 |
0
| throw new InvalidSchemaException( "Failed to load schema: " + inclSchemaInstanceURI );
|
116 |
| } |
117 |
| } |
118 |
| |
119 |
| |
120 |
50
| Iterator iter = root.elementIterator( XSD_ELEMENT );
|
121 |
50
| while ( iter.hasNext() ) {
|
122 |
360
| onDatatypeElement( (Element) iter.next() , documentFactory);
|
123 |
| } |
124 |
| |
125 |
| |
126 |
50
| iter = root.elementIterator( XSD_SIMPLETYPE );
|
127 |
50
| while ( iter.hasNext() ) {
|
128 |
2
| onNamedSchemaSimpleType((Element) iter.next());
|
129 |
| } |
130 |
| |
131 |
| |
132 |
50
| iter = root.elementIterator( XSD_COMPLEXTYPE );
|
133 |
50
| while ( iter.hasNext() ) {
|
134 |
4
| onNamedSchemaComplexType((Element) iter.next());
|
135 |
| } |
136 |
| |
137 |
50
| namedTypeResolver.resolveNamedTypes();
|
138 |
| |
139 |
| } |
140 |
| } |
141 |
| |
142 |
| |
143 |
| |
144 |
| |
145 |
| |
146 |
| |
147 |
| |
148 |
812
| private void onDatatypeElement( Element xsdElement , DocumentFactory parentFactory ) {
|
149 |
812
| String name = xsdElement.attributeValue( "name" );
|
150 |
812
| String type = xsdElement.attributeValue( "type" );
|
151 |
812
| QName qname = getQName( name );
|
152 |
| |
153 |
812
| DatatypeElementFactory elementFactory = getDatatypeElementFactory( qname );
|
154 |
| |
155 |
812
| if ( type != null ) {
|
156 |
| |
157 |
292
| XSDatatype dataType = getTypeByName(type);
|
158 |
292
| if (dataType!=null) {
|
159 |
286
| elementFactory.setChildElementXSDatatype( qname, dataType );
|
160 |
| } |
161 |
| else { |
162 |
6
| QName typeQName=getQName(type);
|
163 |
6
| namedTypeResolver.registerTypedElement(xsdElement,typeQName,parentFactory);
|
164 |
| } |
165 |
292
| return;
|
166 |
| } |
167 |
| |
168 |
| |
169 |
520
| Element xsdSimpleType = xsdElement.element( XSD_SIMPLETYPE );
|
170 |
520
| if ( xsdSimpleType != null ) {
|
171 |
0
| System.out.println("Agfa-sg: handle element types derrived from simpleTypes for element: " + name);
|
172 |
0
| XSDatatype dataType = loadXSDatatypeFromSimpleType( xsdSimpleType );
|
173 |
0
| if (dataType != null) {
|
174 |
0
| System.out.println("dataType (from loadXSDatatypeFromSimpleType) = " + dataType);
|
175 |
0
| elementFactory.setChildElementXSDatatype( qname, dataType );
|
176 |
| } |
177 |
| } |
178 |
| |
179 |
520
| Element schemaComplexType = xsdElement.element( XSD_COMPLEXTYPE );
|
180 |
520
| if ( schemaComplexType != null ) {
|
181 |
214
| onSchemaComplexType( schemaComplexType, elementFactory );
|
182 |
| } |
183 |
| |
184 |
520
| Iterator iter = xsdElement.elementIterator( XSD_ATTRIBUTE );
|
185 |
520
| if ( iter.hasNext() ) {
|
186 |
0
| do {
|
187 |
0
| onDatatypeAttribute(
|
188 |
| xsdElement, |
189 |
| elementFactory, |
190 |
| (Element) iter.next() |
191 |
| ); |
192 |
| } |
193 |
0
| while ( iter.hasNext() );
|
194 |
| } |
195 |
| } |
196 |
| |
197 |
| |
198 |
| |
199 |
4
| private void onNamedSchemaComplexType(Element schemaComplexType) {
|
200 |
4
| Attribute nameAttr=schemaComplexType.attribute("name");
|
201 |
0
| if (nameAttr==null) return;
|
202 |
4
| String name=nameAttr.getText();
|
203 |
4
| QName qname=getQName(name);
|
204 |
| |
205 |
4
| DatatypeElementFactory elementFactory = getDatatypeElementFactory( qname );
|
206 |
| |
207 |
| |
208 |
4
| onSchemaComplexType(schemaComplexType,elementFactory);
|
209 |
4
| namedTypeResolver.registerComplexType(qname,elementFactory);
|
210 |
| } |
211 |
| |
212 |
| |
213 |
| |
214 |
218
| private void onSchemaComplexType( Element schemaComplexType, DatatypeElementFactory elementFactory ) {
|
215 |
218
| Iterator iter = schemaComplexType.elementIterator( XSD_ATTRIBUTE );
|
216 |
218
| while ( iter.hasNext() ) {
|
217 |
530
| Element xsdAttribute = (Element) iter.next();
|
218 |
530
| String name = xsdAttribute.attributeValue( "name" );
|
219 |
530
| QName qname = getQName( name );
|
220 |
| |
221 |
530
| XSDatatype dataType = dataTypeForXsdAttribute( xsdAttribute );
|
222 |
530
| if ( dataType != null ) {
|
223 |
| |
224 |
| |
225 |
| |
226 |
530
| elementFactory.setAttributeXSDatatype( qname, dataType );
|
227 |
| } |
228 |
| else { |
229 |
0
| String type = xsdAttribute.attributeValue( "type" );
|
230 |
0
| System.out.println( "Warning: Couldn't find XSDatatype for type: " + type + " attribute: " + name );
|
231 |
| } |
232 |
| } |
233 |
| |
234 |
| |
235 |
218
| Element schemaSequence = schemaComplexType.element( XSD_SEQUENCE );
|
236 |
218
| if (schemaSequence!=null) {
|
237 |
98
| onChildElements(schemaSequence,elementFactory);
|
238 |
| } |
239 |
| |
240 |
| |
241 |
218
| Element schemaChoice = schemaComplexType.element( XSD_CHOICE );
|
242 |
218
| if (schemaChoice!=null) {
|
243 |
0
| onChildElements(schemaChoice,elementFactory);
|
244 |
| } |
245 |
| |
246 |
| |
247 |
218
| Element schemaAll = schemaComplexType.element( XSD_ALL );
|
248 |
218
| if (schemaAll!=null) {
|
249 |
38
| onChildElements(schemaAll,elementFactory);
|
250 |
| } |
251 |
| } |
252 |
| |
253 |
136
| private void onChildElements(Element element,DatatypeElementFactory factory) {
|
254 |
136
| Iterator iter = element.elementIterator( XSD_ELEMENT );
|
255 |
136
| while ( iter.hasNext() ) {
|
256 |
452
| Element xsdElement = (Element) iter.next();
|
257 |
452
| onDatatypeElement(xsdElement,factory);
|
258 |
| } |
259 |
| } |
260 |
| |
261 |
| |
262 |
| |
263 |
0
| private void onDatatypeAttribute(
|
264 |
| Element xsdElement, |
265 |
| DatatypeElementFactory elementFactory, |
266 |
| Element xsdAttribute |
267 |
| ) { |
268 |
0
| String name = xsdAttribute.attributeValue( "name" );
|
269 |
0
| QName qname = getQName( name );
|
270 |
0
| XSDatatype dataType = dataTypeForXsdAttribute( xsdAttribute );
|
271 |
0
| if ( dataType != null ) {
|
272 |
| |
273 |
0
| elementFactory.setAttributeXSDatatype( qname, dataType );
|
274 |
| } |
275 |
| else { |
276 |
0
| String type = xsdAttribute.attributeValue( "type" );
|
277 |
0
| System.out.println( "Warning: Couldn't find XSDatatype for type: " + type + " attribute: " + name );
|
278 |
| } |
279 |
| } |
280 |
| |
281 |
| |
282 |
| |
283 |
530
| private XSDatatype dataTypeForXsdAttribute( Element xsdAttribute ) {
|
284 |
530
| String type = xsdAttribute.attributeValue( "type" );
|
285 |
530
| XSDatatype dataType = null;
|
286 |
530
| if ( type != null ) {
|
287 |
418
| dataType = getTypeByName( type );
|
288 |
| } |
289 |
| else { |
290 |
| |
291 |
112
| Element xsdSimpleType = xsdAttribute.element( XSD_SIMPLETYPE );
|
292 |
112
| if ( xsdSimpleType == null ) {
|
293 |
0
| String name = xsdAttribute.attributeValue( "name" );
|
294 |
0
| throw new InvalidSchemaException(
|
295 |
| "The attribute: " + name + " has no type attribute and does not contain a <simpleType/> element" |
296 |
| ); |
297 |
| } |
298 |
112
| dataType = loadXSDatatypeFromSimpleType( xsdSimpleType );
|
299 |
| } |
300 |
530
| return dataType;
|
301 |
| } |
302 |
| |
303 |
| |
304 |
| |
305 |
2
| private void onNamedSchemaSimpleType(Element schemaSimpleType) {
|
306 |
2
| Attribute nameAttr=schemaSimpleType.attribute("name");
|
307 |
0
| if (nameAttr==null) return;
|
308 |
2
| String name=nameAttr.getText();
|
309 |
2
| QName qname=getQName(name);
|
310 |
2
| XSDatatype datatype=loadXSDatatypeFromSimpleType(schemaSimpleType);
|
311 |
2
| namedTypeResolver.registerSimpleType(qname,datatype);
|
312 |
| } |
313 |
| |
314 |
| |
315 |
114
| private XSDatatype loadXSDatatypeFromSimpleType( Element xsdSimpleType ) {
|
316 |
114
| Element xsdRestriction = xsdSimpleType.element( XSD_RESTRICTION );
|
317 |
114
| if ( xsdRestriction != null ) {
|
318 |
114
| String base = xsdRestriction.attributeValue( "base" );
|
319 |
114
| if ( base != null ) {
|
320 |
114
| XSDatatype baseType = getTypeByName( base );
|
321 |
114
| if ( baseType == null ) {
|
322 |
0
| onSchemaError(
|
323 |
| "Invalid base type: " + base |
324 |
| + " when trying to build restriction: " + xsdRestriction |
325 |
| ); |
326 |
| } |
327 |
| else { |
328 |
114
| return deriveSimpleType( baseType, xsdRestriction );
|
329 |
| } |
330 |
| } |
331 |
| else { |
332 |
| |
333 |
| |
334 |
0
| Element xsdSubType = xsdSimpleType.element( XSD_SIMPLETYPE );
|
335 |
0
| if ( xsdSubType == null ) {
|
336 |
0
| onSchemaError(
|
337 |
| "The simpleType element: "+ xsdSimpleType |
338 |
| + " must contain a base attribute or simpleType element" |
339 |
| ); |
340 |
| } |
341 |
| else { |
342 |
0
| return loadXSDatatypeFromSimpleType( xsdSubType );
|
343 |
| } |
344 |
| } |
345 |
| } |
346 |
| else { |
347 |
0
| onSchemaError(
|
348 |
| "No <restriction>. Could not create XSDatatype for simpleType: " |
349 |
| + xsdSimpleType |
350 |
| ); |
351 |
| } |
352 |
0
| return null;
|
353 |
| } |
354 |
| |
355 |
| |
356 |
114
| private XSDatatype deriveSimpleType( XSDatatype baseType, Element xsdRestriction ) {
|
357 |
114
| TypeIncubator incubator = new TypeIncubator(baseType);
|
358 |
114
| ValidationContext context = null;
|
359 |
| |
360 |
114
| try {
|
361 |
114
| for ( Iterator iter = xsdRestriction.elementIterator(); iter.hasNext(); ) {
|
362 |
206
| Element element = (Element) iter.next();
|
363 |
206
| String name = element.getName();
|
364 |
206
| String value = element.attributeValue( "value" );
|
365 |
206
| boolean fixed = AttributeHelper.booleanValue( element, "fixed" );
|
366 |
| |
367 |
| |
368 |
206
| incubator.addFacet( name, value, fixed, context );
|
369 |
| } |
370 |
| |
371 |
114
| String newTypeName = null;
|
372 |
114
| return incubator.derive( newTypeName );
|
373 |
| } |
374 |
| catch (DatatypeException e) { |
375 |
0
| onSchemaError(
|
376 |
| "Invalid restriction: " + e.getMessage() |
377 |
| + " when trying to build restriction: " + xsdRestriction |
378 |
| ); |
379 |
0
| return null;
|
380 |
| } |
381 |
| } |
382 |
| |
383 |
| |
384 |
| |
385 |
| |
386 |
816
| private DatatypeElementFactory getDatatypeElementFactory( QName elementQName ) {
|
387 |
816
| DatatypeElementFactory factory = documentFactory.getElementFactory( elementQName );
|
388 |
816
| if ( factory == null ) {
|
389 |
806
| factory = new DatatypeElementFactory( elementQName );
|
390 |
806
| elementQName.setDocumentFactory(factory);
|
391 |
| } |
392 |
816
| return factory;
|
393 |
| } |
394 |
| |
395 |
824
| private XSDatatype getTypeByName( String type ) {
|
396 |
824
| XSDatatype dataType = (XSDatatype) dataTypeCache.get( type );
|
397 |
824
| if ( dataType == null ) {
|
398 |
| |
399 |
| |
400 |
380
| int idx = type.indexOf(':');
|
401 |
380
| if (idx >= 0 ) {
|
402 |
100
| String localName = type.substring(idx + 1);
|
403 |
100
| try {
|
404 |
100
| dataType = DatatypeFactory.getTypeByName( localName );
|
405 |
| } catch (DatatypeException e) {} |
406 |
| } |
407 |
380
| if ( dataType == null ) {
|
408 |
280
| try {
|
409 |
280
| dataType = DatatypeFactory.getTypeByName( type );
|
410 |
| } catch (DatatypeException e) {} |
411 |
| } |
412 |
| |
413 |
380
| if ( dataType == null ) {
|
414 |
| |
415 |
6
| QName typeQName = getQName(type);
|
416 |
6
| dataType = (XSDatatype) namedTypeResolver.simpleTypeMap.get( typeQName );
|
417 |
| } |
418 |
| |
419 |
380
| if ( dataType != null ) {
|
420 |
| |
421 |
374
| dataTypeCache.put( type, dataType );
|
422 |
| } |
423 |
| } |
424 |
| |
425 |
824
| return dataType;
|
426 |
| } |
427 |
| |
428 |
1360
| private QName getQName( String name ) {
|
429 |
1360
| if (targetNamespace == null) {
|
430 |
1192
| return documentFactory.createQName(name);
|
431 |
| } else { |
432 |
168
| return documentFactory.createQName(name, targetNamespace);
|
433 |
| } |
434 |
| } |
435 |
| |
436 |
| |
437 |
| |
438 |
| |
439 |
0
| private void onSchemaError( String message ) {
|
440 |
| |
441 |
| |
442 |
| |
443 |
| |
444 |
0
| throw new InvalidSchemaException( message );
|
445 |
| } |
446 |
| } |
447 |
| |
448 |
| |
449 |
| |
450 |
| |
451 |
| |
452 |
| |
453 |
| |
454 |
| |
455 |
| |
456 |
| |
457 |
| |
458 |
| |
459 |
| |
460 |
| |
461 |
| |
462 |
| |
463 |
| |
464 |
| |
465 |
| |
466 |
| |
467 |
| |
468 |
| |
469 |
| |
470 |
| |
471 |
| |
472 |
| |
473 |
| |
474 |
| |
475 |
| |
476 |
| |
477 |
| |
478 |
| |
479 |
| |
480 |
| |
481 |
| |
482 |
| |
483 |
| |
484 |
| |
485 |
| |
486 |
| |
487 |
| |
488 |
| |
489 |
| |
490 |
| |
491 |
| |
492 |
| |
493 |
| |
494 |
| |