1
package com.thaiopensource.relaxng.output.rnc;
3
import com.thaiopensource.relaxng.edit.Annotated;
4
import com.thaiopensource.relaxng.edit.AnnotationChild;
5
import com.thaiopensource.relaxng.edit.AnnotationChildVisitor;
6
import com.thaiopensource.relaxng.edit.AnyNameNameClass;
7
import com.thaiopensource.relaxng.edit.AttributeAnnotation;
8
import com.thaiopensource.relaxng.edit.AttributePattern;
9
import com.thaiopensource.relaxng.edit.ChoiceNameClass;
10
import com.thaiopensource.relaxng.edit.ChoicePattern;
11
import com.thaiopensource.relaxng.edit.Combine;
12
import com.thaiopensource.relaxng.edit.Comment;
13
import com.thaiopensource.relaxng.edit.Component;
14
import com.thaiopensource.relaxng.edit.ComponentVisitor;
15
import com.thaiopensource.relaxng.edit.CompositePattern;
16
import com.thaiopensource.relaxng.edit.Container;
17
import com.thaiopensource.relaxng.edit.DataPattern;
18
import com.thaiopensource.relaxng.edit.DefineComponent;
19
import com.thaiopensource.relaxng.edit.DivComponent;
20
import com.thaiopensource.relaxng.edit.ElementAnnotation;
21
import com.thaiopensource.relaxng.edit.ElementPattern;
22
import com.thaiopensource.relaxng.edit.EmptyPattern;
23
import com.thaiopensource.relaxng.edit.ExternalRefPattern;
24
import com.thaiopensource.relaxng.edit.GrammarPattern;
25
import com.thaiopensource.relaxng.edit.GroupPattern;
26
import com.thaiopensource.relaxng.edit.IncludeComponent;
27
import com.thaiopensource.relaxng.edit.InterleavePattern;
28
import com.thaiopensource.relaxng.edit.ListPattern;
29
import com.thaiopensource.relaxng.edit.MixedPattern;
30
import com.thaiopensource.relaxng.edit.NameClass;
31
import com.thaiopensource.relaxng.edit.NameClassVisitor;
32
import com.thaiopensource.relaxng.edit.NameClassedPattern;
33
import com.thaiopensource.relaxng.edit.NameNameClass;
34
import com.thaiopensource.relaxng.edit.NotAllowedPattern;
35
import com.thaiopensource.relaxng.edit.NsNameNameClass;
36
import com.thaiopensource.relaxng.edit.OneOrMorePattern;
37
import com.thaiopensource.relaxng.edit.OptionalPattern;
38
import com.thaiopensource.relaxng.edit.Param;
39
import com.thaiopensource.relaxng.edit.ParentRefPattern;
40
import com.thaiopensource.relaxng.edit.Pattern;
41
import com.thaiopensource.relaxng.edit.PatternVisitor;
42
import com.thaiopensource.relaxng.edit.RefPattern;
43
import com.thaiopensource.relaxng.edit.SourceLocation;
44
import com.thaiopensource.relaxng.edit.TextAnnotation;
45
import com.thaiopensource.relaxng.edit.TextPattern;
46
import com.thaiopensource.relaxng.edit.UnaryPattern;
47
import com.thaiopensource.relaxng.edit.ValuePattern;
48
import com.thaiopensource.relaxng.edit.VoidVisitor;
49
import com.thaiopensource.relaxng.edit.ZeroOrMorePattern;
50
import com.thaiopensource.relaxng.edit.NamespaceContext;
51
import com.thaiopensource.relaxng.output.OutputDirectory;
52
import com.thaiopensource.relaxng.output.common.ErrorReporter;
53
import com.thaiopensource.relaxng.parse.SchemaBuilder;
54
import com.thaiopensource.util.Utf16;
55
import com.thaiopensource.util.VoidValue;
56
import com.thaiopensource.xml.out.CharRepertoire;
57
import com.thaiopensource.xml.util.WellKnownNamespaces;
59
import java.io.IOException;
60
import java.util.Collections;
61
import java.util.HashMap;
62
import java.util.HashSet;
63
import java.util.Iterator;
64
import java.util.List;
67
import java.util.Vector;
70
private final Prettyprinter pp;
71
private final CharRepertoire cr;
72
private final String indent;
73
private final String sourceUri;
74
private final OutputDirectory od;
75
private final ErrorReporter er;
76
private final NamespaceManager.NamespaceBindings nsb;
77
private final Map<String, String> datatypeLibraryMap = new HashMap<String, String>();
78
private final ComplexityCache complexityCache = new ComplexityCache();
79
private final NameClassVisitor<VoidValue> nameClassOutput = new NameClassOutput(true);
80
private final NameClassVisitor<VoidValue> noParenNameClassOutput = new NameClassOutput(false);
81
private final PatternVisitor<VoidValue> noParenPatternOutput = new PatternOutput(false);
82
private final PatternVisitor<VoidValue> patternOutput = new PatternOutput(true);
83
private final ComponentVisitor<VoidValue> componentOutput = new ComponentOutput();
84
private final AnnotationChildVisitor<VoidValue> annotationChildOutput = new AnnotationChildOutput();
85
private final AnnotationChildVisitor<VoidValue> followingAnnotationChildOutput = new FollowingAnnotationChildOutput();
86
private boolean isAttributeNameClass;
87
private final StringBuffer encodeBuf = new StringBuffer();
90
static private final String[] keywords = {
91
"attribute", "default", "datatypes", "div", "element", "empty", "external",
92
"grammar", "include", "inherit", "list", "mixed", "namespace", "notAllowed",
93
"parent", "start", "string", "text", "token"
96
static private final Set<String> keywordSet = new HashSet<String>();
99
for (int i = 0; i < keywords.length; i++)
100
keywordSet.add(keywords[i]);
103
static void output(Pattern p, String encoding, String sourceUri, OutputDirectory od, ErrorReporter er) throws IOException {
105
new Output(sourceUri, encoding, od, er, NamespaceVisitor.createBindings(p)).topLevel(p);
107
catch (Prettyprinter.WrappedException e) {
108
throw e.getIOException();
112
private Output(String sourceUri, String encoding, OutputDirectory od, ErrorReporter er,
113
NamespaceManager.NamespaceBindings nsb) throws IOException {
114
this.sourceUri = sourceUri;
117
// Only preserve the input encoding if it's one that can be auto-detected.
119
&& !encoding.equalsIgnoreCase("UTF-8")
120
&& !encoding.equalsIgnoreCase("UTF-16")
121
&& !encoding.equalsIgnoreCase("US-ASCII"))
123
OutputDirectory.Stream stream = od.open(sourceUri, encoding);
124
this.cr = stream.getCharRepertoire();
125
this.pp = new StreamingPrettyprinter(od.getLineLength(), od.getLineSeparator(), stream.getWriter());
127
char[] tem = new char[od.getIndent()];
128
for (int i = 0; i < tem.length; i++)
130
this.indent = new String(tem);
133
private void topLevel(Pattern p) {
134
p.accept(new TextAnnotationMerger());
135
boolean implicitGrammar = p instanceof GrammarPattern && p.getAttributeAnnotations().isEmpty();
136
if (implicitGrammar && !p.getLeadingComments().isEmpty()) {
140
outputNamespaceDeclarations();
141
outputDatatypeLibraryDeclarations(p);
142
if (implicitGrammar) {
143
for (AnnotationChild annotationChild : p.getChildElementAnnotations()) {
144
annotationChild.accept(annotationChildOutput);
147
innerBody(((GrammarPattern)p).getComponents());
148
// This deals with trailing comments
149
for (AnnotationChild annotationChild : p.getFollowingElementAnnotations()) {
151
annotationChild.accept(annotationChildOutput);
155
p.accept(patternOutput);
156
// The pretty printer ensures that we have a terminating newline.
160
private void outputNamespaceDeclarations() {
161
List<String> prefixes = new Vector<String>();
162
prefixes.addAll(nsb.getPrefixes());
163
Collections.sort(prefixes);
165
boolean needNewline = false;
167
String defaultPrefix = null;
168
String defaultNamespace = nsb.getNamespaceUri("");
169
if (defaultNamespace != null && !defaultNamespace.equals(SchemaBuilder.INHERIT_NS))
170
defaultPrefix = nsb.getNonEmptyPrefix(defaultNamespace);
171
for (String prefix : prefixes) {
172
String ns = nsb.getNamespaceUri(prefix);
173
if (prefix.length() == 0) {
174
if (defaultPrefix == null && !ns.equals(SchemaBuilder.INHERIT_NS)) {
176
pp.text("default namespace =");
177
pp.startNest(indent);
186
else if (!prefix.equals("xml")) {
188
if (prefix.equals(defaultPrefix))
189
pp.text("default namespace ");
191
pp.text("namespace ");
194
pp.startNest(indent);
196
if (ns.equals(SchemaBuilder.INHERIT_NS))
212
private void outputDatatypeLibraryDeclarations(Pattern p) {
213
datatypeLibraryMap.put(WellKnownNamespaces.XML_SCHEMA_DATATYPES, "xsd");
214
List<String> datatypeLibraries = new Vector<String>();
215
datatypeLibraries.addAll(DatatypeLibraryVisitor.findDatatypeLibraries(p));
216
if (datatypeLibraries.isEmpty())
218
Collections.sort(datatypeLibraries);
219
for (int i = 0, len = datatypeLibraries.size(); i < len; i++) {
222
prefix += Integer.toString(i + 1);
223
String uri = datatypeLibraries.get(i);
224
datatypeLibraryMap.put(uri, prefix);
226
pp.text("datatypes ");
229
pp.startNest(indent);
239
private static class TextAnnotationMerger extends VoidVisitor {
240
public void voidVisitElement(ElementAnnotation ea) {
241
TextAnnotation prevText = null;
242
for (Iterator<AnnotationChild> iter = ea.getChildren().iterator(); iter.hasNext();) {
243
AnnotationChild child = iter.next();
244
if (child instanceof TextAnnotation) {
245
if (prevText == null)
246
prevText = (TextAnnotation)child;
248
prevText.setValue(prevText.getValue() + ((TextAnnotation)child).getValue());
260
static class DatatypeLibraryVisitor extends VoidVisitor {
261
private final Set<String> datatypeLibraries = new HashSet<String>();
263
public void voidVisitValue(ValuePattern p) {
264
noteDatatypeLibrary(p.getDatatypeLibrary());
265
super.voidVisitValue(p);
268
public void voidVisitData(DataPattern p) {
269
noteDatatypeLibrary(p.getDatatypeLibrary());
270
super.voidVisitData(p);
273
private void noteDatatypeLibrary(String uri) {
274
if (!uri.equals("") && !uri.equals(WellKnownNamespaces.XML_SCHEMA_DATATYPES))
275
datatypeLibraries.add(uri);
278
static Set<String> findDatatypeLibraries(Pattern p) {
279
DatatypeLibraryVisitor dlv = new DatatypeLibraryVisitor();
281
return dlv.datatypeLibraries;
285
static class NamespaceVisitor extends VoidVisitor {
286
private final NamespaceManager nsm = new NamespaceManager();
287
private boolean isAttribute;
289
public void voidVisitInclude(IncludeComponent c) {
290
super.voidVisitInclude(c);
291
nsm.requireNamespace(c.getNs(), true);
294
public void voidVisitExternalRef(ExternalRefPattern p) {
295
super.voidVisitExternalRef(p);
296
nsm.requireNamespace(p.getNs(), true);
299
public void voidVisitElement(ElementPattern p) {
301
super.voidVisitElement(p);
304
public void voidVisitAttribute(AttributePattern p) {
306
super.voidVisitAttribute(p);
309
public void voidVisitName(NameNameClass nc) {
310
super.voidVisitName(nc);
311
if (!isAttribute || nc.getNamespaceUri().length() != 0)
312
nsm.requireNamespace(nc.getNamespaceUri(), !isAttribute);
313
if (nc.getPrefix() == null) {
315
nsm.preferBinding("", nc.getNamespaceUri());
318
nsm.preferBinding(nc.getPrefix(), nc.getNamespaceUri());
321
public void voidVisitNsName(NsNameNameClass nc) {
322
super.voidVisitNsName(nc);
323
nsm.requireNamespace(nc.getNs(), false);
326
public void voidVisitValue(ValuePattern p) {
327
super.voidVisitValue(p);
328
for (Map.Entry<String, String> entry : p.getPrefixMap().entrySet()) {
329
nsm.requireBinding(entry.getKey(), entry.getValue());
333
public void voidVisitElement(ElementAnnotation ea) {
334
super.voidVisitElement(ea);
335
noteAnnotationBinding(ea.getPrefix(), ea.getNamespaceUri());
336
noteContext(ea.getContext(), true);
339
private void noteContext(NamespaceContext context, boolean required) {
342
for (String prefix : context.getPrefixes()) {
343
// Default namespace is not relevant to annotations
344
if (!prefix.equals("")) {
345
String ns = context.getNamespace(prefix);
346
if (ns != null && !ns.equals(SchemaBuilder.INHERIT_NS)) {
348
nsm.requireBinding(prefix, ns);
350
nsm.preferBinding(prefix, ns);
356
public void voidVisitAttribute(AttributeAnnotation a) {
357
super.voidVisitAttribute(a);
358
noteAnnotationBinding(a.getPrefix(), a.getNamespaceUri());
361
private void noteAnnotationBinding(String prefix, String ns) {
362
if (ns.length() != 0)
363
nsm.requireNamespace(ns, false);
365
nsm.preferBinding(prefix, ns);
368
public void voidVisitAnnotated(Annotated p) {
369
p.leadingCommentsAccept(this);
370
noteContext(p.getContext(), !p.getAttributeAnnotations().isEmpty());
371
p.attributeAnnotationsAccept(this);
372
List<AnnotationChild> before = (p.mayContainText()
373
? p.getFollowingElementAnnotations()
374
: p.getChildElementAnnotations());
375
// Avoid unnecessary prefix for documentation
377
for (AnnotationChild child : before) {
378
if (state < 2 && documentationString(child) != null)
380
else if (state != 1 || !(child instanceof Comment))
385
if (!p.mayContainText())
386
p.followingElementAnnotationsAccept(this);
389
static NamespaceManager.NamespaceBindings createBindings(Pattern p) {
390
NamespaceVisitor nsv = new NamespaceVisitor();
392
return nsv.nsm.createBindings();
396
private class ComponentOutput implements ComponentVisitor<VoidValue> {
397
public VoidValue visitDefine(DefineComponent c) {
400
String name = c.getName();
401
if (name == DefineComponent.START)
405
Combine combine = c.getCombine();
409
else if (combine == Combine.CHOICE)
414
pp.startNest(indent);
416
c.getBody().accept(noParenPatternOutput);
420
return VoidValue.VOID;
423
public VoidValue visitDiv(DivComponent c) {
428
return VoidValue.VOID;
431
public VoidValue visitInclude(IncludeComponent c) {
435
pp.startNest("include ");
436
literal(od.reference(sourceUri, c.getUri()));
440
List<Component> components = c.getComponents();
441
if (!components.isEmpty())
444
return VoidValue.VOID;
448
class PatternOutput implements PatternVisitor<VoidValue> {
449
private final boolean alwaysUseParens;
451
PatternOutput(boolean alwaysUseParens) {
452
this.alwaysUseParens = alwaysUseParens;
455
public VoidValue visitGrammar(GrammarPattern p) {
460
return VoidValue.VOID;
463
public VoidValue visitElement(ElementPattern p) {
464
isAttributeNameClass = false;
465
nameClassed(p, "element ");
466
return VoidValue.VOID;
469
public VoidValue visitAttribute(AttributePattern p) {
470
isAttributeNameClass = true;
471
nameClassed(p, "attribute ");
472
return VoidValue.VOID;
475
private void nameClassed(NameClassedPattern p, String key) {
479
p.getNameClass().accept(noParenNameClassOutput);
485
private void braceChild(UnaryPattern p) {
486
Pattern child = p.getChild();
487
boolean isSimple = !complexityCache.isComplex(child);
491
pp.startNest(indent);
496
child.accept(noParenPatternOutput);
507
public VoidValue visitOneOrMore(OneOrMorePattern p) {
509
return VoidValue.VOID;
512
public VoidValue visitZeroOrMore(ZeroOrMorePattern p) {
514
return VoidValue.VOID;
517
public VoidValue visitOptional(OptionalPattern p) {
519
return VoidValue.VOID;
522
private void postfix(UnaryPattern p, String op) {
523
if (!startAnnotations(p)) {
524
p.getChild().accept(patternOutput);
530
p.getChild().accept(patternOutput);
538
public VoidValue visitRef(RefPattern p) {
540
identifier(p.getName());
542
return VoidValue.VOID;
545
public VoidValue visitParentRef(ParentRefPattern p) {
548
identifier(p.getName());
550
return VoidValue.VOID;
553
public VoidValue visitExternalRef(ExternalRefPattern p) {
556
pp.text("external ");
557
pp.startNest("external ");
558
literal(od.reference(sourceUri, p.getUri()));
563
return VoidValue.VOID;
566
public VoidValue visitText(TextPattern p) {
570
return VoidValue.VOID;
573
public VoidValue visitEmpty(EmptyPattern p) {
577
return VoidValue.VOID;
580
public VoidValue visitNotAllowed(NotAllowedPattern p) {
582
pp.text("notAllowed");
584
return VoidValue.VOID;
587
public VoidValue visitList(ListPattern p) {
589
return VoidValue.VOID;
592
public VoidValue visitMixed(MixedPattern p) {
594
return VoidValue.VOID;
597
private void prefix(UnaryPattern p, String key) {
604
public VoidValue visitChoice(ChoicePattern p) {
605
composite(p, "| ", false);
606
return VoidValue.VOID;
609
public VoidValue visitInterleave(InterleavePattern p) {
610
composite(p, "& ", false);
611
return VoidValue.VOID;
614
public VoidValue visitGroup(GroupPattern p) {
615
composite(p, ",", true);
616
return VoidValue.VOID;
619
void composite(CompositePattern p, String sep, boolean sepBeforeNewline) {
620
boolean useParens = alwaysUseParens;
621
if (startAnnotations(p))
623
boolean isSimple = !complexityCache.isComplex(p);
631
boolean first = true;
632
for (Pattern child : p.getChildren()) {
634
if (sepBeforeNewline)
640
if (!sepBeforeNewline) {
645
child.accept(patternOutput);
648
else if (!sepBeforeNewline)
660
public VoidValue visitData(DataPattern p) {
662
String lib = p.getDatatypeLibrary();
665
qn = datatypeLibraryMap.get(lib) + ":" + p.getType();
670
List<Param> params = p.getParams();
671
if (params.size() > 0) {
674
pp.startNest(indent);
675
for (Param param : params) {
677
startAnnotations(param);
679
encodedText(param.getName());
681
pp.startNest(indent);
683
literal(param.getValue());
686
endAnnotations(param);
693
Pattern e = p.getExcept();
695
boolean useParen = (!e.mayContainText()
696
&& !e.getFollowingElementAnnotations().isEmpty());
698
if (params.isEmpty())
708
pp.startNest(params.isEmpty() ? qn + s : s);
709
e.accept(useParen ? noParenPatternOutput : patternOutput);
713
if (!params.isEmpty())
717
return VoidValue.VOID;
720
public VoidValue visitValue(ValuePattern p) {
721
for (Map.Entry<String, String> entry : p.getPrefixMap().entrySet()) {
722
String prefix = entry.getKey();
723
String uri = entry.getValue();
724
if (!uri.equals(nsb.getNamespaceUri(prefix))) {
725
if (prefix.equals(""))
726
er.error("value_inconsistent_default_binding", uri, p.getSourceLocation());
728
er.error("value_inconsistent_binding", prefix, uri, p.getSourceLocation());
732
String lib = p.getDatatypeLibrary();
735
if (lib.equals("")) {
736
if (!p.getType().equals("token"))
737
str = p.getType() + " ";
740
str = datatypeLibraryMap.get(lib) + ":" + p.getType() + " ";
742
String encoded = encode(str);
744
pp.startNest(encoded);
746
literal(p.getValue());
751
return VoidValue.VOID;
756
class NameClassOutput implements NameClassVisitor<VoidValue> {
757
private final boolean alwaysUseParens;
759
NameClassOutput(boolean alwaysUseParens) {
760
this.alwaysUseParens = alwaysUseParens;
763
public VoidValue visitAnyName(AnyNameNameClass nc) {
764
NameClass e = nc.getExcept();
766
startAnnotations(nc);
770
boolean useParens = startAnnotations(nc) || alwaysUseParens;
771
String s = useParens ? "(* - " : "* - ";
774
e.accept(nameClassOutput);
780
return VoidValue.VOID;
783
public VoidValue visitNsName(NsNameNameClass nc) {
784
NameClass e = nc.getExcept();
785
String prefix = nsb.getNonEmptyPrefix(nc.getNs());
787
startAnnotations(nc);
792
boolean useParens = startAnnotations(nc) || alwaysUseParens;
793
String s = useParens ? "(" : "";
798
e.accept(nameClassOutput);
804
return VoidValue.VOID;
807
public VoidValue visitName(NameNameClass nc) {
808
startAnnotations(nc);
809
qualifiedName(nc.getNamespaceUri(), nc.getPrefix(), nc.getLocalName(), isAttributeNameClass);
811
return VoidValue.VOID;
814
public VoidValue visitChoice(ChoiceNameClass nc) {
815
boolean useParens = alwaysUseParens;
816
if (startAnnotations(nc))
818
else if (nc.getChildren().size() == 1)
825
boolean first = true;
826
for (NameClass child : nc.getChildren()) {
833
child.accept(nameClassOutput);
841
return VoidValue.VOID;
845
class AnnotationChildOutput implements AnnotationChildVisitor<VoidValue> {
846
public VoidValue visitText(TextAnnotation ta) {
847
literal(ta.getValue());
848
return VoidValue.VOID;
851
public VoidValue visitComment(Comment c) {
852
comment("#", c.getValue());
853
return VoidValue.VOID;
856
public VoidValue visitElement(ElementAnnotation elem) {
857
checkContext(elem.getContext(), elem.getSourceLocation());
858
qualifiedName(elem.getNamespaceUri(), elem.getPrefix(), elem.getLocalName(),
859
// unqualified annotation element names have "" namespace
862
annotationBody(elem.getAttributes(), elem.getChildren());
863
return VoidValue.VOID;
867
class FollowingAnnotationChildOutput extends AnnotationChildOutput {
868
public VoidValue visitElement(ElementAnnotation elem) {
871
super.visitElement(elem);
873
return VoidValue.VOID;
877
private static boolean hasAnnotations(Annotated annotated) {
878
return (!annotated.getChildElementAnnotations().isEmpty()
879
|| !annotated.getAttributeAnnotations().isEmpty()
880
|| !annotated.getFollowingElementAnnotations().isEmpty());
883
private boolean startAnnotations(Annotated annotated) {
884
if (!annotated.getLeadingComments().isEmpty()) {
885
leadingComments(annotated);
886
if (!hasAnnotations(annotated))
889
else if (!hasAnnotations(annotated))
891
List<AnnotationChild> before = (annotated.mayContainText()
892
? annotated.getFollowingElementAnnotations()
893
: annotated.getChildElementAnnotations());
895
int len = before.size();
896
for (; i < len; i++) {
900
if (!(before.get(j) instanceof Comment))
906
String doc = documentationString(before.get(j));
913
before.get(i).accept(annotationChildOutput);
922
before = before.subList(i, len);
924
if (!annotated.getAttributeAnnotations().isEmpty()
925
|| !before.isEmpty()) {
926
if (!annotated.getAttributeAnnotations().isEmpty())
927
checkContext(annotated.getContext(), annotated.getSourceLocation());
928
annotationBody(annotated.getAttributeAnnotations(), before);
934
private static String documentationString(AnnotationChild child) {
935
if (!(child instanceof ElementAnnotation))
937
ElementAnnotation elem = (ElementAnnotation)child;
938
if (!elem.getLocalName().equals("documentation"))
940
if (!elem.getNamespaceUri().equals(WellKnownNamespaces.RELAX_NG_COMPATIBILITY_ANNOTATIONS))
942
if (!elem.getAttributes().isEmpty())
944
StringBuffer buf = new StringBuffer();
945
for (AnnotationChild a : elem.getChildren()) {
946
if (!(a instanceof TextAnnotation))
948
buf.append(((TextAnnotation)a).getValue());
950
return buf.toString();
953
private void endAnnotations(Annotated annotated) {
954
if (!annotated.mayContainText()) {
955
for (AnnotationChild child : annotated.getFollowingElementAnnotations()) {
956
if (annotated instanceof Component)
960
AnnotationChildVisitor<VoidValue> output = (annotated instanceof Component
961
? annotationChildOutput
962
: followingAnnotationChildOutput);
963
child.accept(output);
966
if (hasAnnotations(annotated))
970
private void leadingComments(Annotated annotated) {
971
boolean first = true;
972
for (Comment comment : annotated.getLeadingComments()) {
977
comment.accept(annotationChildOutput);
981
private void annotationBody(List<AttributeAnnotation> attributes, List<AnnotationChild> children) {
984
pp.startNest(indent);
985
for (AttributeAnnotation att : attributes) {
988
qualifiedName(att.getNamespaceUri(), att.getPrefix(), att.getLocalName(), true);
990
pp.startNest(indent);
992
literal(att.getValue());
996
for (AnnotationChild child : children) {
998
child.accept(annotationChildOutput);
1001
pp.softNewline(" ");
1006
private void body(Container container) {
1007
body(container.getComponents());
1010
private void body(List<Component> components) {
1011
if (components.size() == 0)
1015
pp.startNest(indent);
1017
innerBody(components);
1024
private void innerBody(List<Component> components) {
1025
boolean first = true;
1026
for (Component c : components) {
1031
c.accept(componentOutput);
1035
private void inherit(String ns) {
1036
if (ns.equals(nsb.getNamespaceUri("")))
1038
pp.softNewline(" ");
1039
pp.text("inherit = ");
1040
encodedText(nsb.getNonEmptyPrefix(ns));
1043
private void identifier(String name) {
1044
if (keywordSet.contains(name))
1049
private static final String[] delims = { "\"", "'", "\"\"\"", "'''" };
1051
private void literal(String str) {
1052
for (int i = 0, len = str.length();;) {
1053
// Find the delimiter that gives the longest segment
1054
String bestDelim = null;
1056
int lim = str.indexOf('\n', i);
1061
for (int j = 0; j < delims.length; j++) {
1062
int end = (str + delims[j]).indexOf(delims[j], i);
1063
if (end > bestEnd) {
1064
bestDelim = delims[j];
1074
pp.softNewline(" ");
1077
encodedText(str.substring(i, bestEnd));
1085
private void encodedText(String str) {
1086
pp.text(encode(str));
1089
private String encode(String str) {
1091
int len = str.length();
1092
for (int i = 0; i < len; i++) {
1093
char c = str.charAt(i);
1096
if (!startsWithEscapeOpen(str, i))
1102
encodeBuf.append(str.substring(start, i));
1107
if (Utf16.isSurrogate(c)) {
1108
if (!cr.contains(c, str.charAt(i + 1))) {
1110
encodeBuf.append(str.substring(start, i));
1111
escape(Utf16.scalarValue(c, str.charAt(i + 1)));
1116
else if (!cr.contains(c)) {
1118
encodeBuf.append(str.substring(start, i));
1128
encodeBuf.append(str.substring(start, len));
1129
str = encodeBuf.toString();
1130
encodeBuf.setLength(0);
1134
private void escape(int n) {
1135
encodeBuf.append("\\x{");
1136
encodeBuf.append(Integer.toHexString(n));
1137
encodeBuf.append("}");
1140
static private boolean startsWithEscapeOpen(String str, int off) {
1141
if (!str.startsWith("\\x", off))
1143
for (off += 2; str.startsWith("x", off); off++)
1145
return str.startsWith("{", off);
1149
* null means no prefix
1151
private void qualifiedName(String ns, String prefix, String localName, boolean isAttribute) {
1152
prefix = choosePrefix(ns, prefix, isAttribute);
1154
encodedText(localName);
1156
encodedText(prefix);
1158
encodedText(localName);
1163
* null means no prefix
1165
private String choosePrefix(String ns, String prefix, boolean isAttribute) {
1166
if (prefix != null && ns.equals(nsb.getNamespaceUri(prefix)))
1169
if (ns.length() == 0)
1173
if (ns.equals(nsb.getNamespaceUri("")))
1176
return nsb.getNonEmptyPrefix(ns);
1179
private void comment(String delim, String value) {
1183
if (i < value.length() && value.charAt(i) != '\t')
1185
int j = value.indexOf('\n', i);
1186
String tem = j < 0 ? value.substring(i) : value.substring(i, j);
1195
private void checkContext(NamespaceContext context, SourceLocation loc) {
1196
if (context == null)
1198
for (String prefix : context.getPrefixes()) {
1199
// Default namespace is not relevant to annotations
1200
if (!prefix.equals("")) {
1201
String ns = context.getNamespace(prefix);
1202
if (ns != null && !ns.equals(SchemaBuilder.INHERIT_NS)
1203
&& !nsb.getNamespaceUri(prefix).equals(ns))
1204
er.warning("annotation_inconsistent_binding", prefix, ns, loc);