1 /* XMLSchemaBuilder.java --
2    Copyright (C) 2006  Free Software Foundation, Inc.
3 
4 This file is part of GNU Classpath.
5 
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10 
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20 
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25 
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37 
38 package gnu.xml.validation.xmlschema;
39 
40 import java.util.LinkedHashSet;
41 import java.util.Set;
42 import java.util.StringTokenizer;
43 import javax.xml.XMLConstants;
44 import javax.xml.namespace.QName;
45 import org.relaxng.datatype.DatatypeException;
46 import org.relaxng.datatype.DatatypeLibrary;
47 import org.relaxng.datatype.helpers.DatatypeLibraryLoader;
48 import org.w3c.dom.NamedNodeMap;
49 import org.w3c.dom.Node;
50 import gnu.xml.validation.datatype.Annotation;
51 import gnu.xml.validation.datatype.SimpleType;
52 import gnu.xml.validation.datatype.Type;
53 
54 /**
55  * Parses an XML Schema DOM tree, constructing a compiled internal
56  * representation.
57  *
58  * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
59  */
60 class XMLSchemaBuilder
61 {
62 
63   XMLSchema schema;
64   final DatatypeLibrary typeLibrary;
65 
XMLSchemaBuilder()66   XMLSchemaBuilder()
67   {
68     final String ns = XMLConstants.W3C_XML_SCHEMA_NS_URI;
69     typeLibrary = new DatatypeLibraryLoader().createDatatypeLibrary(ns);
70   }
71 
parseSchema(Node node)72   void parseSchema(Node node)
73     throws DatatypeException
74   {
75     String uri = node.getNamespaceURI();
76     String name = node.getLocalName();
77     if (XMLConstants.W3C_XML_SCHEMA_NS_URI.equals(uri) &&
78         node.getNodeType() == Node.ELEMENT_NODE)
79       {
80         if ("schema".equals(name))
81           {
82             NamedNodeMap attrs = node.getAttributes();
83             String targetNamespace = getAttribute(attrs, "targetNamespace");
84             String version = getAttribute(attrs, "version");
85             String fd = getAttribute(attrs, "finalDefault");
86             int finalDefault = parseFullDerivationSet(fd);
87             String bd = getAttribute(attrs, "blockDefault");
88             int blockDefault = parseBlockSet(bd);
89             String afd = getAttribute(attrs, "attributeFormDefault");
90             boolean attributeFormQualified = "qualified".equals(afd);
91             String efd = getAttribute(attrs, "elementFormDefault");
92             boolean elementFormQualified = "qualified".equals(efd);
93             schema = new XMLSchema(targetNamespace, version,
94                                    finalDefault, blockDefault,
95                                    attributeFormQualified,
96                                    elementFormQualified);
97             for (Node child = node.getFirstChild(); child != null;
98                  child = child.getNextSibling())
99               {
100                 parseTopLevelElement(child);
101               }
102             return;
103           }
104       }
105     // TODO throw schema exception
106   }
107 
parseTopLevelElement(Node node)108   void parseTopLevelElement(Node node)
109     throws DatatypeException
110   {
111     String uri = node.getNamespaceURI();
112     String name = node.getLocalName();
113     if (XMLConstants.W3C_XML_SCHEMA_NS_URI.equals(uri) &&
114         node.getNodeType() == Node.ELEMENT_NODE)
115       {
116         if ("element".equals(name))
117           {
118             ElementDeclaration ed =
119               (ElementDeclaration) parseElement(node, null);
120             schema.elementDeclarations.put(ed.name, ed);
121             // TODO
122           }
123         else if ("attribute".equals(name))
124           {
125             AttributeDeclaration ad =
126               (AttributeDeclaration) parseAttribute(node, true);
127             schema.attributeDeclarations.put(ad.name, ad);
128             // TODO
129           }
130         else if ("type".equals(name))
131           {
132             // TODO
133           }
134         else if ("group".equals(name))
135           {
136             // TODO
137           }
138         else if ("attributeGroup".equals(name))
139           {
140             // TODO
141           }
142         else if ("notation".equals(name))
143           {
144             // TODO
145           }
146         else if ("identityConstraint".equals(name))
147           {
148             // TODO
149           }
150       }
151     // TODO throw schema exception
152   }
153 
parseAttribute(Node node, boolean scope)154   Object parseAttribute(Node node, boolean scope)
155     throws DatatypeException
156   {
157     NamedNodeMap attrs = node.getAttributes();
158     String def = getAttribute(attrs, "default");
159     String fixed = getAttribute(attrs, "fixed");
160     int constraintType = AttributeDeclaration.NONE;
161     String constraintValue = null;
162     if (def != null)
163       {
164         constraintType = AttributeDeclaration.DEFAULT;
165         constraintValue = def;
166       }
167     else if (fixed != null)
168       {
169         constraintType = AttributeDeclaration.FIXED;
170         constraintValue = fixed;
171       }
172     // TODO form = (qualified | unqualified)
173     String attrName = getAttribute(attrs, "name");
174     String attrNamespace = getAttribute(attrs, "targetNamespace");
175     String ref = getAttribute(attrs, "ref");
176     String use = getAttribute(attrs, "use");
177     String type = getAttribute(attrs, "type");
178     SimpleType datatype = (type == null) ? null :
179       parseSimpleType(asQName(type, node));
180     Annotation annotation = null;
181     for (Node child = node.getFirstChild(); child != null;
182          child = child.getNextSibling())
183       {
184         String uri = child.getNamespaceURI();
185         String name = child.getLocalName();
186         if (XMLConstants.W3C_XML_SCHEMA_NS_URI.equals(uri) &&
187             child.getNodeType() == Node.ELEMENT_NODE)
188           {
189             if ("annotation".equals(name))
190               {
191                 annotation = parseAnnotation(child);
192               }
193             else if ("simpleType".equals(name))
194               {
195                 datatype = parseSimpleType(child);
196               }
197             else
198               {
199                 // TODO throw schema exception
200               }
201           }
202       }
203     if (scope)
204       {
205         return new AttributeDeclaration(scope,
206                                         constraintType,
207                                         constraintValue,
208                                         new QName(attrNamespace, attrName),
209                                         datatype,
210                                         annotation);
211       }
212     else
213       {
214         boolean required = "required".equals(use);
215         // TODO ref
216         AttributeDeclaration decl = (ref == null) ?
217               new AttributeDeclaration(scope,
218                                        AttributeDeclaration.NONE,
219                                        null,
220                                        new QName(attrNamespace, attrName),
221                                        datatype,
222                                        annotation) :
223               /*schema.getAttributeDeclaration(ref)*/ null;
224         return new AttributeUse(required,
225                                 constraintType,
226                                 constraintValue,
227                                 decl);
228       }
229   }
230 
parseFullDerivationSet(String value)231   int parseFullDerivationSet(String value)
232   {
233     int ret = XMLSchema.FINAL_NONE;
234     if ("#all".equals(value))
235       {
236         ret = XMLSchema.FINAL_ALL;
237       }
238     else
239       {
240         StringTokenizer st = new StringTokenizer(value, " ");
241         while (st.hasMoreTokens())
242           {
243             String token = st.nextToken();
244             if ("extension".equals(token))
245               {
246                 ret |= XMLSchema.FINAL_EXTENSION;
247               }
248             else if ("restriction".equals(token))
249               {
250                 ret |= XMLSchema.FINAL_RESTRICTION;
251               }
252             else if ("list".equals(token))
253               {
254                 ret |= XMLSchema.FINAL_LIST;
255               }
256             else if ("union".equals(token))
257               {
258                 ret |= XMLSchema.FINAL_UNION;
259               }
260           }
261       }
262     return ret;
263   }
264 
parseSimpleTypeDerivationSet(String value)265   int parseSimpleTypeDerivationSet(String value)
266   {
267     int ret = XMLSchema.FINAL_NONE;
268     if ("#all".equals(value))
269       {
270         ret = XMLSchema.FINAL_LIST |
271           XMLSchema.FINAL_UNION |
272           XMLSchema.FINAL_RESTRICTION;
273       }
274     else
275       {
276         StringTokenizer st = new StringTokenizer(value, " ");
277         while (st.hasMoreTokens())
278           {
279             String token = st.nextToken();
280             if ("list".equals(token))
281               {
282                 ret |= XMLSchema.FINAL_LIST;
283               }
284             else if ("union".equals(token))
285               {
286                 ret |= XMLSchema.FINAL_UNION;
287               }
288             else if ("restriction".equals(token))
289               {
290                 ret |= XMLSchema.FINAL_RESTRICTION;
291               }
292           }
293       }
294     return ret;
295   }
296 
parseComplexTypeDerivationSet(String value)297   int parseComplexTypeDerivationSet(String value)
298   {
299     int ret = XMLSchema.FINAL_NONE;
300     if ("#all".equals(value))
301       {
302         ret = XMLSchema.FINAL_EXTENSION | XMLSchema.FINAL_RESTRICTION;
303       }
304     else
305       {
306         StringTokenizer st = new StringTokenizer(value, " ");
307         while (st.hasMoreTokens())
308           {
309             String token = st.nextToken();
310             if ("extension".equals(token))
311               {
312                 ret |= XMLSchema.FINAL_EXTENSION;
313               }
314             else if ("restriction".equals(token))
315               {
316                 ret |= XMLSchema.FINAL_RESTRICTION;
317               }
318           }
319       }
320     return ret;
321   }
322 
parseBlockSet(String value)323   int parseBlockSet(String value)
324   {
325     int ret = XMLSchema.BLOCK_NONE;
326     if ("#all".equals(value))
327       {
328         ret = XMLSchema.BLOCK_ALL;
329       }
330     else
331       {
332         StringTokenizer st = new StringTokenizer(value, " ");
333         while (st.hasMoreTokens())
334           {
335             String token = st.nextToken();
336             if ("extension".equals(token))
337               {
338                 ret |= XMLSchema.BLOCK_EXTENSION;
339               }
340             else if ("restriction".equals(token))
341               {
342                 ret |= XMLSchema.BLOCK_RESTRICTION;
343               }
344             else if ("substitution".equals(token))
345               {
346                 ret |= XMLSchema.BLOCK_SUBSTITUTION;
347               }
348           }
349       }
350     return ret;
351   }
352 
parseComplexTypeBlockSet(String value)353   int parseComplexTypeBlockSet(String value)
354   {
355     int ret = XMLSchema.BLOCK_NONE;
356     if ("#all".equals(value))
357       {
358         ret = XMLSchema.BLOCK_EXTENSION | XMLSchema.BLOCK_RESTRICTION;
359       }
360     else
361       {
362         StringTokenizer st = new StringTokenizer(value, " ");
363         while (st.hasMoreTokens())
364           {
365             String token = st.nextToken();
366             if ("extension".equals(token))
367               {
368                 ret |= XMLSchema.BLOCK_EXTENSION;
369               }
370             else if ("restriction".equals(token))
371               {
372                 ret |= XMLSchema.BLOCK_RESTRICTION;
373               }
374           }
375       }
376     return ret;
377   }
378 
parseElement(Node node, ElementDeclaration parent)379   Object parseElement(Node node, ElementDeclaration parent)
380     throws DatatypeException
381   {
382     NamedNodeMap attrs = node.getAttributes();
383     Integer minOccurs = null;
384     Integer maxOccurs = null;
385     Node parentNode = node.getParentNode();
386     boolean notTopLevel = !"schema".equals(parentNode.getLocalName());
387     if (notTopLevel)
388       {
389         String ref = getAttribute(attrs, "ref");
390         if (ref != null)
391           {
392             minOccurs = getOccurrence(getAttribute(attrs, "minOccurs"));
393             maxOccurs = getOccurrence(getAttribute(attrs, "maxOccurs"));
394             // TODO resolve top-level element declaration
395             ElementDeclaration ad = null;
396             return new Particle(minOccurs, maxOccurs, ad);
397           }
398       }
399     String elementName = getAttribute(attrs, "name");
400     String elementNamespace = getAttribute(attrs, "targetNamespace");
401     String type = getAttribute(attrs, "type");
402     Type datatype = (type != null) ?
403       parseSimpleType(asQName(type, node)) : null;
404     int scope = (parent == null) ?
405       XMLSchema.GLOBAL :
406       XMLSchema.LOCAL;
407     String def = getAttribute(attrs, "default");
408     String fixed = getAttribute(attrs, "fixed");
409     int constraintType = AttributeDeclaration.NONE;
410     String constraintValue = null;
411     if (def != null)
412       {
413         constraintType = AttributeDeclaration.DEFAULT;
414         constraintValue = def;
415       }
416     else if (fixed != null)
417       {
418         constraintType = AttributeDeclaration.FIXED;
419         constraintValue = fixed;
420       }
421     String sg = getAttribute(attrs, "substitutionGroup");
422     QName substitutionGroup = QName.valueOf(sg);
423     String sgPrefix = substitutionGroup.getPrefix();
424     if (sgPrefix != null && !"".equals(sgPrefix))
425       {
426         String sgName = substitutionGroup.getLocalPart();
427         String sgNamespace = node.lookupNamespaceURI(sgPrefix);
428         substitutionGroup = new QName(sgNamespace, sgName);
429       }
430 
431     String block = getAttribute(attrs, "block");
432     int substitutionGroupExclusions = (block == null) ?
433       schema.blockDefault :
434       parseBlockSet(block);
435     String final_ = getAttribute(attrs, "final");
436     int disallowedSubstitutions = (final_ == null) ?
437       schema.finalDefault :
438       parseFullDerivationSet(final_);
439 
440     boolean nillable = "true".equals(getAttribute(attrs, "nillable"));
441     boolean isAbstract = "true".equals(getAttribute(attrs, "abstract"));
442 
443     if (notTopLevel)
444       {
445         minOccurs = getOccurrence(getAttribute(attrs, "minOccurs"));
446         maxOccurs = getOccurrence(getAttribute(attrs, "maxOccurs"));
447         String form = getAttribute(attrs, "form");
448         if (form != null)
449           {
450             if ("qualified".equals(form))
451               {
452                 elementNamespace = schema.targetNamespace;
453               }
454           }
455         else if (schema.elementFormQualified)
456           {
457             elementNamespace = schema.targetNamespace;
458           }
459       }
460     ElementDeclaration ed =
461       new ElementDeclaration(new QName(elementNamespace, elementName),
462                              datatype,
463                              scope, parent,
464                              constraintType, constraintValue,
465                              nillable,
466                              substitutionGroup,
467                              substitutionGroupExclusions,
468                              disallowedSubstitutions,
469                              isAbstract);
470 
471     for (Node child = node.getFirstChild(); child != null;
472          child = child.getNextSibling())
473       {
474         String uri = child.getNamespaceURI();
475         String name = child.getLocalName();
476         if (XMLConstants.W3C_XML_SCHEMA_NS_URI.equals(uri) &&
477             child.getNodeType() == Node.ELEMENT_NODE)
478           {
479             if ("annotation".equals(name))
480               {
481                 ed.annotation = parseAnnotation(child);
482               }
483             else if ("simpleType".equals(name) && datatype == null)
484               {
485                 ed.datatype = parseSimpleType(child);
486               }
487             else if ("complexType".equals(name) && datatype == null)
488               {
489                 ed.datatype = parseComplexType(child, ed);
490               }
491             else
492               {
493                 // throw schema exception
494               }
495           }
496       }
497 
498     if (notTopLevel)
499       {
500         return new Particle(minOccurs, maxOccurs, ed);
501       }
502     else
503       {
504         return ed;
505       }
506   }
507 
getOccurrence(String value)508   Integer getOccurrence(String value)
509   {
510     if (value == null)
511       {
512         return new Integer(1);
513       }
514     else if ("unbounded".equals(value))
515       {
516         return null;
517       }
518     else
519       {
520         return new Integer(value);
521       }
522   }
523 
parseSimpleType(QName typeName)524   SimpleType parseSimpleType(QName typeName)
525     throws DatatypeException
526   {
527     SimpleType type = (SimpleType) schema.types.get(typeName);
528     if (!XMLConstants.W3C_XML_SCHEMA_NS_URI.equals(typeName.getNamespaceURI()))
529       return null;
530     String localName = typeName.getLocalPart();
531     return (SimpleType) typeLibrary.createDatatype(localName);
532   }
533 
parseSimpleType(Node simpleType)534   SimpleType parseSimpleType(Node simpleType)
535     throws DatatypeException
536   {
537     NamedNodeMap attrs = simpleType.getAttributes();
538     String typeFinal = getAttribute(attrs, "final");
539     if (typeFinal == null)
540       {
541         Node schema = simpleType.getParentNode();
542         while (schema != null && !"schema".equals(schema.getLocalName()))
543           {
544             schema = schema.getParentNode();
545           }
546         if (schema != null)
547           {
548             NamedNodeMap schemaAttrs = schema.getAttributes();
549             typeFinal = getAttribute(schemaAttrs, "finalDefault");
550           }
551       }
552     int typeFinality = parseSimpleTypeDerivationSet(typeFinal);
553     QName typeName = asQName(getAttribute(attrs, "name"), simpleType);
554     int variety = 0;
555     Set facets = new LinkedHashSet();
556     int fundamentalFacets = 0; // TODO
557     SimpleType baseType = null; // TODO
558     Annotation annotation = null;
559     // TODO use DatatypeBuilder
560     for (Node child = simpleType.getFirstChild(); child != null;
561          child = child.getNextSibling())
562       {
563         String uri = child.getNamespaceURI();
564         String name = child.getLocalName();
565         if (XMLConstants.W3C_XML_SCHEMA_NS_URI.equals(uri) &&
566             child.getNodeType() == Node.ELEMENT_NODE)
567           {
568             if ("annotation".equals(name))
569               {
570                 annotation = parseAnnotation(child);
571               }
572             else if ("restriction".equals(name))
573               {
574                 // TODO
575               }
576             else if ("list".equals(name))
577               {
578                 variety = SimpleType.LIST;
579                 // TODO
580               }
581             else if ("union".equals(name))
582               {
583                 variety = SimpleType.UNION;
584                 // TODO
585               }
586           }
587       }
588     return new SimpleType(typeName, variety, facets, fundamentalFacets,
589                           baseType, annotation);
590   }
591 
parseComplexType(Node complexType, ElementDeclaration parent)592   Type parseComplexType(Node complexType, ElementDeclaration parent)
593     throws DatatypeException
594   {
595     NamedNodeMap attrs = complexType.getAttributes();
596     QName typeName = asQName(getAttribute(attrs, "name"), complexType);
597     boolean isAbstract = "true".equals(getAttribute(attrs, "abstract"));
598     String block = getAttribute(attrs, "block");
599     int prohibitedSubstitutions = (block == null) ?
600       schema.blockDefault :
601       parseComplexTypeBlockSet(block);
602     String final_ = getAttribute(attrs, "final");
603     int finality = (final_ == null) ?
604       schema.finalDefault :
605       parseComplexTypeDerivationSet(final_);
606     ComplexType type = new ComplexType(typeName, isAbstract,
607                                        prohibitedSubstitutions, finality);
608     boolean mixed = "true".equals(getAttribute(attrs, "mixed"));
609     for (Node child = complexType.getFirstChild(); child != null;
610          child = child.getNextSibling())
611       {
612         String uri = child.getNamespaceURI();
613         String name = child.getLocalName();
614         if (XMLConstants.W3C_XML_SCHEMA_NS_URI.equals(uri) &&
615             child.getNodeType() == Node.ELEMENT_NODE)
616           {
617             if ("simpleContent".equals(name))
618               {
619                 parseSimpleContent(child, type);
620               }
621           }
622       }
623     if (mixed)
624       {
625         type.contentType = XMLSchema.CONTENT_MIXED;
626       }
627     return type;
628   }
629 
parseSimpleContent(Node simpleContent, ComplexType type)630   void parseSimpleContent(Node simpleContent, ComplexType type)
631     throws DatatypeException
632   {
633     for (Node child = simpleContent.getFirstChild(); child != null;
634          child = child.getNextSibling())
635       {
636         String uri = child.getNamespaceURI();
637         String name = child.getLocalName();
638         if (XMLConstants.W3C_XML_SCHEMA_NS_URI.equals(uri) &&
639             child.getNodeType() == Node.ELEMENT_NODE)
640           {
641             if ("annotation".equals(name))
642               {
643                 type.annotations.add(parseAnnotation(child));
644               }
645             else if ("restriction".equals(name))
646               {
647                 type.derivationMethod = XMLSchema.FINAL_RESTRICTION;
648                 parseRestriction(child, type);
649               }
650             else if ("extension".equals(name))
651               {
652                 type.derivationMethod = XMLSchema.FINAL_EXTENSION;
653                 parseExtension(child, type);
654               }
655           }
656       }
657   }
658 
parseRestriction(Node restriction, ComplexType type)659   void parseRestriction(Node restriction, ComplexType type)
660     throws DatatypeException
661   {
662     NamedNodeMap attrs = restriction.getAttributes();
663     String base = getAttribute(attrs, "base");
664     QName baseType = asQName(base, restriction);
665     SimpleType simpleType = null;
666     for (Node child = restriction.getFirstChild(); child != null;
667          child = child.getNextSibling())
668       {
669         String uri = child.getNamespaceURI();
670         String name = child.getLocalName();
671         if (XMLConstants.W3C_XML_SCHEMA_NS_URI.equals(uri) &&
672             child.getNodeType() == Node.ELEMENT_NODE)
673           {
674             if ("annotation".equals(name))
675               {
676                 type.annotations.add(parseAnnotation(child));
677               }
678             else if ("simpleType".equals(name))
679               {
680                 type.contentType = XMLSchema.CONTENT_SIMPLE;
681                 simpleType = parseSimpleType(child);
682               }
683             else if ("minExclusive".equals(name))
684               {
685               }
686             else if ("minInclusive".equals(name))
687               {
688               }
689             else if ("maxExclusive".equals(name))
690               {
691               }
692             else if ("maxInclusive".equals(name))
693               {
694               }
695             else if ("totalDigits".equals(name))
696               {
697               }
698             else if ("fractionDigits".equals(name))
699               {
700               }
701             else if ("length".equals(name))
702               {
703               }
704             else if ("minLength".equals(name))
705               {
706               }
707             else if ("maxLength".equals(name))
708               {
709               }
710             else if ("enumeration".equals(name))
711               {
712               }
713             else if ("whiteSpace".equals(name))
714               {
715               }
716             else if ("pattern".equals(name))
717               {
718               }
719             else if ("attribute".equals(name))
720               {
721                 AttributeUse use =
722                   (AttributeUse) parseAttribute(child, false);
723                 schema.attributeDeclarations.put(use.declaration.name,
724                                                  use.declaration);
725                 type.attributeUses.add(use);
726               }
727             else if ("attributeGroup".equals(name))
728               {
729                 NamedNodeMap agAttrs = child.getAttributes();
730                 String ref = getAttribute(agAttrs, "ref");
731                 QName ag = asQName(ref, child);
732                 type.attributeUses.add(ag);
733               }
734             else if ("anyAttribute".equals(name))
735               {
736                 type.attributeWildcard = parseAnyAttribute(child);
737               }
738           }
739       }
740   }
741 
parseExtension(Node extension, ComplexType type)742   void parseExtension(Node extension, ComplexType type)
743     throws DatatypeException
744   {
745     NamedNodeMap attrs = extension.getAttributes();
746     String base = getAttribute(attrs, "base");
747     QName baseType = asQName(base, extension);
748     for (Node child = extension.getFirstChild(); child != null;
749          child = child.getNextSibling())
750       {
751         String uri = child.getNamespaceURI();
752         String name = child.getLocalName();
753         if (XMLConstants.W3C_XML_SCHEMA_NS_URI.equals(uri) &&
754             child.getNodeType() == Node.ELEMENT_NODE)
755           {
756             if ("annotation".equals(name))
757               {
758                 type.annotations.add(parseAnnotation(child));
759               }
760             else if ("attribute".equals(name))
761               {
762                 AttributeUse use =
763                   (AttributeUse) parseAttribute(child, false);
764                 schema.attributeDeclarations.put(use.declaration.name,
765                                                  use.declaration);
766                 type.attributeUses.add(use);
767               }
768             else if ("attributeGroup".equals(name))
769               {
770                 NamedNodeMap agAttrs = child.getAttributes();
771                 String ref = getAttribute(agAttrs, "ref");
772                 QName ag = asQName(ref, child);
773                 type.attributeUses.add(ag);
774               }
775             else if ("anyAttribute".equals(name))
776               {
777                 type.attributeWildcard = parseAnyAttribute(child);
778               }
779           }
780       }
781   }
782 
parseAnyAttribute(Node node)783   AnyAttribute parseAnyAttribute(Node node)
784   {
785     NamedNodeMap attrs = node.getAttributes();
786     String namespace = getAttribute(attrs, "namespace");
787     String pc = getAttribute(attrs, "processContents");
788     int processContents = AnyAttribute.STRICT;
789     if ("lax".equals(pc))
790       {
791         processContents = AnyAttribute.LAX;
792       }
793     else if ("skip".equals(pc))
794       {
795         processContents = AnyAttribute.SKIP;
796       }
797     AnyAttribute ret = new AnyAttribute(namespace, processContents);
798     for (Node child = node.getFirstChild(); child != null;
799          child = child.getNextSibling())
800       {
801         String uri = child.getNamespaceURI();
802         String name = child.getLocalName();
803         if (XMLConstants.W3C_XML_SCHEMA_NS_URI.equals(uri) &&
804             child.getNodeType() == Node.ELEMENT_NODE)
805           {
806             if ("annotation".equals(name))
807               {
808                 ret.annotation = parseAnnotation(child);
809               }
810           }
811       }
812     return ret;
813   }
814 
parseAnnotation(Node node)815   Annotation parseAnnotation(Node node)
816   {
817     // TODO
818     return null;
819   }
820 
getAttribute(NamedNodeMap attrs, String name)821   private static String getAttribute(NamedNodeMap attrs, String name)
822   {
823     Node attr = attrs.getNamedItem(name);
824     return (attr == null) ? null : attr.getNodeValue();
825   }
826 
asQName(String text, Node resolver)827   private static QName asQName(String text, Node resolver)
828   {
829     QName name = QName.valueOf(text);
830     String prefix = name.getPrefix();
831     if (prefix != null && prefix.length() > 0)
832       {
833         String uri = resolver.lookupNamespaceURI(prefix);
834         name = new QName(uri, name.getLocalPart());
835       }
836     return name;
837   }
838 
839 }
840