001: /*
002: * The contents of this file are subject to the terms
003: * of the Common Development and Distribution License
004: * (the "License"). You may not use this file except
005: * in compliance with the License.
006: *
007: * You can obtain a copy of the license at
008: * https://jwsdp.dev.java.net/CDDLv1.0.html
009: * See the License for the specific language governing
010: * permissions and limitations under the License.
011: *
012: * When distributing Covered Code, include this CDDL
013: * HEADER in each file and include the License file at
014: * https://jwsdp.dev.java.net/CDDLv1.0.html If applicable,
015: * add the following below this CDDL HEADER, with the
016: * fields enclosed by brackets "[]" replaced with your
017: * own identifying information: Portions Copyright [yyyy]
018: * [name of copyright owner]
019: */
020: package com.sun.xml.xsom.impl.util;
021:
022: import com.sun.xml.xsom.XSAnnotation;
023: import com.sun.xml.xsom.XSAttGroupDecl;
024: import com.sun.xml.xsom.XSAttributeDecl;
025: import com.sun.xml.xsom.XSAttributeUse;
026: import com.sun.xml.xsom.XSComplexType;
027: import com.sun.xml.xsom.XSContentType;
028: import com.sun.xml.xsom.XSElementDecl;
029: import com.sun.xml.xsom.XSFacet;
030: import com.sun.xml.xsom.XSIdentityConstraint;
031: import com.sun.xml.xsom.XSListSimpleType;
032: import com.sun.xml.xsom.XSModelGroup;
033: import com.sun.xml.xsom.XSModelGroupDecl;
034: import com.sun.xml.xsom.XSNotation;
035: import com.sun.xml.xsom.XSParticle;
036: import com.sun.xml.xsom.XSRestrictionSimpleType;
037: import com.sun.xml.xsom.XSSchema;
038: import com.sun.xml.xsom.XSSchemaSet;
039: import com.sun.xml.xsom.XSSimpleType;
040: import com.sun.xml.xsom.XSType;
041: import com.sun.xml.xsom.XSUnionSimpleType;
042: import com.sun.xml.xsom.XSWildcard;
043: import com.sun.xml.xsom.XSXPath;
044: import com.sun.xml.xsom.impl.Const;
045: import com.sun.xml.xsom.visitor.XSSimpleTypeVisitor;
046: import com.sun.xml.xsom.visitor.XSTermVisitor;
047: import com.sun.xml.xsom.visitor.XSVisitor;
048:
049: import java.io.IOException;
050: import java.io.Writer;
051: import java.text.MessageFormat;
052: import java.util.Iterator;
053:
054: /**
055: * Generates approximated XML Schema representation from
056: * a schema component. This is not intended to be a fully-fledged
057: * round-trippable schema writer.
058: *
059: * <h2>Usage of this class</h2>
060: * <ol>
061: * <li>Create a new instance with whatever Writer
062: * you'd like to send the output to.
063: * <li>Call one of the overloaded dump methods.
064: * You can repeat this process as many times as you want.
065: * </ol>
066: *
067: * @author Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
068: * @author Kirill Grouchnikov (kirillcool@yahoo.com)
069: */
070: public class SchemaWriter implements XSVisitor, XSSimpleTypeVisitor {
071: public SchemaWriter(Writer _out) {
072: this .out = _out;
073: }
074:
075: /** output is sent to this object. */
076: private final Writer out;
077:
078: /** indentation. */
079: private int indent;
080:
081: private void println(String s) {
082: try {
083: for (int i = 0; i < indent; i++)
084: out.write(" ");
085: out.write(s);
086: out.write('\n');
087: // flush stream to make the output appear immediately
088: out.flush();
089: } catch (IOException e) {
090: // ignore IOException.
091: hadError = true;
092: }
093: }
094:
095: private void println() {
096: println("");
097: }
098:
099: /** If IOException is encountered, this flag is set to true. */
100: private boolean hadError = false;
101:
102: /** Flush the stream and check its error state. */
103: public boolean checkError() {
104: try {
105: out.flush();
106: } catch (IOException e) {
107: hadError = true;
108: }
109: return hadError;
110: }
111:
112: public void visit(XSSchemaSet s) {
113: Iterator itr = s.iterateSchema();
114: while (itr.hasNext()) {
115: schema((XSSchema) itr.next());
116: println();
117: }
118: }
119:
120: public void schema(XSSchema s) {
121:
122: // QUICK HACK: don't print the built-in components
123: if (s.getTargetNamespace().equals(Const.schemaNamespace))
124: return;
125:
126: println(MessageFormat.format(
127: "<schema targetNamespace=\"{0}\">", new Object[] { s
128: .getTargetNamespace(), }));
129: indent++;
130:
131: Iterator itr;
132:
133: itr = s.iterateAttGroupDecls();
134: while (itr.hasNext())
135: attGroupDecl((XSAttGroupDecl) itr.next());
136:
137: itr = s.iterateAttributeDecls();
138: while (itr.hasNext())
139: attributeDecl((XSAttributeDecl) itr.next());
140:
141: itr = s.iterateComplexTypes();
142: while (itr.hasNext())
143: complexType((XSComplexType) itr.next());
144:
145: itr = s.iterateElementDecls();
146: while (itr.hasNext())
147: elementDecl((XSElementDecl) itr.next());
148:
149: itr = s.iterateModelGroupDecls();
150: while (itr.hasNext())
151: modelGroupDecl((XSModelGroupDecl) itr.next());
152:
153: itr = s.iterateSimpleTypes();
154: while (itr.hasNext())
155: simpleType((XSSimpleType) itr.next());
156:
157: indent--;
158: println("</schema>");
159: }
160:
161: public void attGroupDecl(XSAttGroupDecl decl) {
162: Iterator itr;
163:
164: println(MessageFormat.format("<attGroup name=\"{0}\">",
165: new Object[] { decl.getName() }));
166: indent++;
167:
168: // TODO: wildcard
169:
170: itr = decl.iterateAttGroups();
171: while (itr.hasNext())
172: dumpRef((XSAttGroupDecl) itr.next());
173:
174: itr = decl.iterateDeclaredAttributeUses();
175: while (itr.hasNext())
176: attributeUse((XSAttributeUse) itr.next());
177:
178: indent--;
179: println("</attGroup>");
180: }
181:
182: public void dumpRef(XSAttGroupDecl decl) {
183: println(MessageFormat.format(
184: "<attGroup ref=\"'{'{0}'}'{1}\"/>", new Object[] {
185: decl.getTargetNamespace(), decl.getName() }));
186: }
187:
188: public void attributeUse(XSAttributeUse use) {
189: XSAttributeDecl decl = use.getDecl();
190:
191: String additionalAtts = "";
192:
193: if (use.isRequired())
194: additionalAtts += " use=\"required\"";
195: if (use.getFixedValue() != null
196: && use.getDecl().getFixedValue() == null)
197: additionalAtts += " fixed=\"" + use.getFixedValue() + '\"';
198: if (use.getDefaultValue() != null
199: && use.getDecl().getDefaultValue() == null)
200: additionalAtts += " default=\"" + use.getDefaultValue()
201: + '\"';
202:
203: if (decl.isLocal()) {
204: // this is anonymous attribute use
205: dump(decl, additionalAtts);
206: } else {
207: // reference to a global one
208: println(MessageFormat.format(
209: "<attribute ref=\"'{'{0}'}'{1}{2}\"/>",
210: new Object[] { decl.getTargetNamespace(),
211: decl.getName(), additionalAtts }));
212: }
213: }
214:
215: public void attributeDecl(XSAttributeDecl decl) {
216: dump(decl, "");
217: }
218:
219: private void dump(XSAttributeDecl decl, String additionalAtts) {
220: XSSimpleType type = decl.getType();
221:
222: println(MessageFormat
223: .format(
224: "<attribute name=\"{0}\"{1}{2}{3}{4}{5}>",
225: new Object[] {
226: decl.getName(),
227: additionalAtts,
228: type.isLocal() ? ""
229: : MessageFormat
230: .format(
231: " type=\"'{'{0}'}'{1}\"",
232: new Object[] {
233: type
234: .getTargetNamespace(),
235: type
236: .getName() }),
237: decl.getFixedValue() == null ? ""
238: : " fixed=\""
239: + decl.getFixedValue()
240: + '\"',
241: decl.getDefaultValue() == null ? ""
242: : " default=\""
243: + decl
244: .getDefaultValue()
245: + '\"',
246: type.isLocal() ? "" : " /" }));
247:
248: if (type.isLocal()) {
249: indent++;
250: simpleType(type);
251: indent--;
252: println("</attribute>");
253: }
254: }
255:
256: public void simpleType(XSSimpleType type) {
257: println(MessageFormat.format("<simpleType{0}>",
258: new Object[] { type.isLocal() ? "" : " name=\""
259: + type.getName() + '\"' }));
260: indent++;
261:
262: type.visit((XSSimpleTypeVisitor) this );
263:
264: indent--;
265: println("</simpleType>");
266: }
267:
268: public void listSimpleType(XSListSimpleType type) {
269: XSSimpleType itemType = type.getItemType();
270:
271: if (itemType.isLocal()) {
272: println("<list>");
273: indent++;
274: simpleType(itemType);
275: indent--;
276: println("</list>");
277: } else {
278: // global type
279: println(MessageFormat.format(
280: "<list itemType=\"'{'{0}'}'{1}\" />", new Object[] {
281: itemType.getTargetNamespace(),
282: itemType.getName() }));
283: }
284: }
285:
286: public void unionSimpleType(XSUnionSimpleType type) {
287: final int len = type.getMemberSize();
288: StringBuffer ref = new StringBuffer();
289:
290: for (int i = 0; i < len; i++) {
291: XSSimpleType member = type.getMember(i);
292: if (member.isGlobal())
293: ref.append(MessageFormat.format(" '{'{0}'}'{1}",
294: new Object[] { member.getTargetNamespace(),
295: member.getName() }));
296: }
297:
298: if (ref.length() == 0)
299: println("<union>");
300: else
301: println("<union memberTypes=\"" + ref + "\">");
302: indent++;
303:
304: for (int i = 0; i < len; i++) {
305: XSSimpleType member = type.getMember(i);
306: if (member.isLocal())
307: simpleType(member);
308: }
309: indent--;
310: println("</union>");
311: }
312:
313: public void restrictionSimpleType(XSRestrictionSimpleType type) {
314:
315: if (type.getBaseType() == null) {
316: // don't print anySimpleType
317: if (!type.getName().equals("anySimpleType"))
318: throw new InternalError();
319: if (!Const.schemaNamespace
320: .equals(type.getTargetNamespace()))
321: throw new InternalError();
322: return;
323: }
324:
325: XSSimpleType baseType = type.getSimpleBaseType();
326:
327: println(MessageFormat.format("<restriction{0}>",
328: new Object[] { baseType.isLocal() ? "" : " base=\"{"
329: + baseType.getTargetNamespace() + '}'
330: + baseType.getName() + '\"' }));
331: indent++;
332:
333: if (baseType.isLocal())
334: simpleType(baseType);
335:
336: Iterator itr = type.iterateDeclaredFacets();
337: while (itr.hasNext())
338: facet((XSFacet) itr.next());
339:
340: indent--;
341: println("</restriction>");
342: }
343:
344: public void facet(XSFacet facet) {
345: println(MessageFormat.format("<{0} value=\"{1}\"/>",
346: new Object[] { facet.getName(), facet.getValue(), }));
347: }
348:
349: public void notation(XSNotation notation) {
350: println(MessageFormat
351: .format(
352: "<notation name='\"0}\" public =\"{1}\" system=\"{2}\" />",
353: new Object[] { notation.getName(),
354: notation.getPublicId(),
355: notation.getSystemId() }));
356: }
357:
358: public void complexType(XSComplexType type) {
359: println(MessageFormat.format("<complexType{0}>",
360: new Object[] { type.isLocal() ? "" : " name=\""
361: + type.getName() + '\"' }));
362: indent++;
363:
364: // TODO: wildcard
365:
366: if (type.getContentType().asSimpleType() != null) {
367: // simple content
368: println("<simpleContent>");
369: indent++;
370:
371: XSType baseType = type.getBaseType();
372:
373: if (type.getDerivationMethod() == XSType.RESTRICTION) {
374: // restriction
375: println(MessageFormat.format(
376: "<restriction base=\"<{0}>{1}\">",
377: new Object[] { baseType.getTargetNamespace(),
378: baseType.getName() }));
379: indent++;
380:
381: dumpComplexTypeAttribute(type);
382:
383: indent--;
384: println("</restriction>");
385: } else {
386: // extension
387: println(MessageFormat.format(
388: "<extension base=\"<{0}>{1}\">", new Object[] {
389: baseType.getTargetNamespace(),
390: baseType.getName() }));
391:
392: // check if have redefine tag - Kirill
393: if (type.isGlobal()
394: && type.getTargetNamespace().equals(
395: baseType.getTargetNamespace())
396: && type.getName().equals(baseType.getName())) {
397: indent++;
398: println("<redefine>");
399: indent++;
400: baseType.visit(this );
401: indent--;
402: println("</redefine>");
403: indent--;
404: }
405:
406: indent++;
407:
408: dumpComplexTypeAttribute(type);
409:
410: indent--;
411: println("</extension>");
412: }
413:
414: indent--;
415: println("</simpleContent>");
416: } else {
417: // complex content
418: println("<complexContent>");
419: indent++;
420:
421: XSComplexType baseType = type.getBaseType().asComplexType();
422:
423: if (type.getDerivationMethod() == XSType.RESTRICTION) {
424: // restriction
425: println(MessageFormat.format(
426: "<restriction base=\"'{'{0}'}'{1}\">",
427: new Object[] { baseType.getTargetNamespace(),
428: baseType.getName() }));
429: indent++;
430:
431: type.getContentType().visit(this );
432: dumpComplexTypeAttribute(type);
433:
434: indent--;
435: println("</restriction>");
436: } else {
437: // extension
438: println(MessageFormat.format(
439: "<extension base=\"'{'{0}'}'{1}\">",
440: new Object[] { baseType.getTargetNamespace(),
441: baseType.getName() }));
442:
443: // check if have redefine - Kirill
444: if (type.isGlobal()
445: && type.getTargetNamespace().equals(
446: baseType.getTargetNamespace())
447: && type.getName().equals(baseType.getName())) {
448: indent++;
449: println("<redefine>");
450: indent++;
451: baseType.visit(this );
452: indent--;
453: println("</redefine>");
454: indent--;
455: }
456:
457: indent++;
458:
459: type.getExplicitContent().visit(this );
460: dumpComplexTypeAttribute(type);
461:
462: indent--;
463: println("</extension>");
464: }
465:
466: indent--;
467: println("</complexContent>");
468: }
469:
470: indent--;
471: println("</complexType>");
472: }
473:
474: private void dumpComplexTypeAttribute(XSComplexType type) {
475: Iterator itr;
476:
477: itr = type.iterateAttGroups();
478: while (itr.hasNext())
479: dumpRef((XSAttGroupDecl) itr.next());
480:
481: itr = type.iterateDeclaredAttributeUses();
482: while (itr.hasNext())
483: attributeUse((XSAttributeUse) itr.next());
484: }
485:
486: public void elementDecl(XSElementDecl decl) {
487: elementDecl(decl, "");
488: }
489:
490: private void elementDecl(XSElementDecl decl, String extraAtts) {
491: XSType type = decl.getType();
492:
493: // TODO: various other attributes
494:
495: println(MessageFormat.format("<element name=\"{0}\"{1}{2}{3}>",
496: new Object[] {
497: decl.getName(),
498: type.isLocal() ? "" : " type=\"{"
499: + type.getTargetNamespace() + '}'
500: + type.getName() + '\"', extraAtts,
501: type.isLocal() ? "" : "/" }));
502:
503: if (type.isLocal()) {
504: indent++;
505:
506: if (type.isLocal())
507: type.visit(this );
508:
509: indent--;
510: println("</element>");
511: }
512: }
513:
514: public void modelGroupDecl(XSModelGroupDecl decl) {
515: println(MessageFormat.format("<group name=\"{0}\">",
516: new Object[] { decl.getName() }));
517: indent++;
518:
519: modelGroup(decl.getModelGroup());
520:
521: indent--;
522: println("</group>");
523: }
524:
525: public void modelGroup(XSModelGroup group) {
526: modelGroup(group, "");
527: }
528:
529: private void modelGroup(XSModelGroup group, String extraAtts) {
530: println(MessageFormat.format("<{0}{1}>", new Object[] {
531: group.getCompositor(), extraAtts }));
532: indent++;
533:
534: final int len = group.getSize();
535: for (int i = 0; i < len; i++)
536: particle(group.getChild(i));
537:
538: indent--;
539: println(MessageFormat.format("</{0}>", new Object[] { group
540: .getCompositor() }));
541: }
542:
543: public void particle(XSParticle part) {
544: int i;
545:
546: StringBuffer buf = new StringBuffer();
547:
548: i = part.getMaxOccurs();
549: if (i == XSParticle.UNBOUNDED)
550: buf.append(" maxOccurs=\"unbounded\"");
551: else if (i != 1)
552: buf.append(" maxOccurs=\"" + i + '\"');
553:
554: i = part.getMinOccurs();
555: if (i != 1)
556: buf.append(" minOccurs=\"" + i + '\"');
557:
558: final String extraAtts = buf.toString();
559:
560: part.getTerm().visit(new XSTermVisitor() {
561: public void elementDecl(XSElementDecl decl) {
562: if (decl.isLocal())
563: SchemaWriter.this .elementDecl(decl, extraAtts);
564: else {
565: // reference
566: println(MessageFormat.format(
567: "<element ref=\"'{'{0}'}'{1}\"{2}/>",
568: new Object[] { decl.getTargetNamespace(),
569: decl.getName(), extraAtts }));
570: }
571: }
572:
573: public void modelGroupDecl(XSModelGroupDecl decl) {
574: // reference
575: println(MessageFormat.format(
576: "<group ref=\"'{'{0}'}'{1}\"{2}/>",
577: new Object[] { decl.getTargetNamespace(),
578: decl.getName(), extraAtts }));
579: }
580:
581: public void modelGroup(XSModelGroup group) {
582: SchemaWriter.this .modelGroup(group, extraAtts);
583: }
584:
585: public void wildcard(XSWildcard wc) {
586: SchemaWriter.this .wildcard(wc, extraAtts);
587: }
588: });
589: }
590:
591: public void wildcard(XSWildcard wc) {
592: wildcard(wc, "");
593: }
594:
595: private void wildcard(XSWildcard wc, String extraAtts) {
596: // TODO
597: println(MessageFormat.format("<any/>",
598: new Object[] { extraAtts }));
599: }
600:
601: public void annotation(XSAnnotation ann) {
602: // TODO: it would be nice even if we just put <xs:documentation>
603: }
604:
605: public void identityConstraint(XSIdentityConstraint decl) {
606: // TODO
607: }
608:
609: public void xpath(XSXPath xp) {
610: // TODO
611: }
612:
613: public void empty(XSContentType t) {
614: }
615: }
|