~ubuntu-branches/ubuntu/utopic/jing-trang/utopic

« back to all changes in this revision

Viewing changes to mod/rng-schema/src/main/com/thaiopensource/relaxng/output/rnc/Output.java

  • Committer: Bazaar Package Importer
  • Author(s): Samuel Thibault
  • Date: 2009-09-01 15:53:03 UTC
  • Revision ID: james.westby@ubuntu.com-20090901155303-2kweef05h5v9j3ni
Tags: upstream-20090818
ImportĀ upstreamĀ versionĀ 20090818

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
package com.thaiopensource.relaxng.output.rnc;
 
2
 
 
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;
 
58
 
 
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;
 
65
import java.util.Map;
 
66
import java.util.Set;
 
67
import java.util.Vector;
 
68
 
 
69
class Output {
 
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();
 
88
 
 
89
 
 
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"
 
94
  };
 
95
 
 
96
  static private final Set<String> keywordSet = new HashSet<String>();
 
97
 
 
98
  static {
 
99
    for (int i = 0; i < keywords.length; i++)
 
100
      keywordSet.add(keywords[i]);
 
101
  }
 
102
 
 
103
  static void output(Pattern p, String encoding, String sourceUri, OutputDirectory od, ErrorReporter er) throws IOException {
 
104
    try {
 
105
      new Output(sourceUri, encoding, od, er, NamespaceVisitor.createBindings(p)).topLevel(p);
 
106
    }
 
107
    catch (Prettyprinter.WrappedException e) {
 
108
      throw e.getIOException();
 
109
    }
 
110
  }
 
111
 
 
112
  private Output(String sourceUri, String encoding, OutputDirectory od, ErrorReporter er,
 
113
                 NamespaceManager.NamespaceBindings nsb) throws IOException {
 
114
    this.sourceUri = sourceUri;
 
115
    this.od = od;
 
116
    this.er = er;
 
117
    // Only preserve the input encoding if it's one that can be auto-detected.
 
118
    if (encoding != null
 
119
        && !encoding.equalsIgnoreCase("UTF-8")
 
120
        && !encoding.equalsIgnoreCase("UTF-16")
 
121
        && !encoding.equalsIgnoreCase("US-ASCII"))
 
122
      encoding = null;
 
123
    OutputDirectory.Stream stream = od.open(sourceUri, encoding);
 
124
    this.cr = stream.getCharRepertoire();
 
125
    this.pp = new StreamingPrettyprinter(od.getLineLength(), od.getLineSeparator(), stream.getWriter());
 
126
    this.nsb = nsb;
 
127
    char[] tem = new char[od.getIndent()];
 
128
    for (int i = 0; i < tem.length; i++)
 
129
      tem[i] = ' ';
 
130
    this.indent = new String(tem);
 
131
  }
 
132
 
 
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()) {
 
137
      leadingComments(p);
 
138
      pp.hardNewline();
 
139
    }
 
140
    outputNamespaceDeclarations();
 
141
    outputDatatypeLibraryDeclarations(p);
 
142
    if (implicitGrammar) {
 
143
      for (AnnotationChild annotationChild : p.getChildElementAnnotations()) {
 
144
        annotationChild.accept(annotationChildOutput);
 
145
        pp.hardNewline();
 
146
      }
 
147
      innerBody(((GrammarPattern)p).getComponents());
 
148
      // This deals with trailing comments
 
149
      for (AnnotationChild annotationChild : p.getFollowingElementAnnotations()) {
 
150
        pp.hardNewline();
 
151
        annotationChild.accept(annotationChildOutput);
 
152
      }
 
153
    }
 
154
    else
 
155
      p.accept(patternOutput);
 
156
    // The pretty printer ensures that we have a terminating newline.
 
157
    pp.close();
 
158
  }
 
159
 
 
160
  private void outputNamespaceDeclarations() {
 
161
    List<String> prefixes = new Vector<String>();
 
162
    prefixes.addAll(nsb.getPrefixes());
 
163
    Collections.sort(prefixes);
 
164
 
 
165
    boolean needNewline = false;
 
166
 
 
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)) {
 
175
          pp.startGroup();
 
176
          pp.text("default namespace =");
 
177
          pp.startNest(indent);
 
178
          pp.softNewline(" ");
 
179
          literal(ns);
 
180
          pp.endNest();
 
181
          pp.endGroup();
 
182
          pp.hardNewline();
 
183
          needNewline = true;
 
184
        }
 
185
      }
 
186
      else if (!prefix.equals("xml")) {
 
187
        pp.startGroup();
 
188
        if (prefix.equals(defaultPrefix))
 
189
          pp.text("default namespace ");
 
190
        else
 
191
          pp.text("namespace ");
 
192
        encodedText(prefix);
 
193
        pp.text(" =");
 
194
        pp.startNest(indent);
 
195
        pp.softNewline(" ");
 
196
        if (ns.equals(SchemaBuilder.INHERIT_NS))
 
197
          pp.text("inherit");
 
198
        else
 
199
          literal(ns);
 
200
        pp.endNest();
 
201
        pp.endGroup();
 
202
        pp.hardNewline();
 
203
        needNewline = true;
 
204
      }
 
205
    }
 
206
 
 
207
    if (needNewline)
 
208
      pp.hardNewline();
 
209
  }
 
210
 
 
211
 
 
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())
 
217
      return;
 
218
    Collections.sort(datatypeLibraries);
 
219
    for (int i = 0, len = datatypeLibraries.size(); i < len; i++) {
 
220
      String prefix = "d";
 
221
      if (len > 1)
 
222
        prefix += Integer.toString(i + 1);
 
223
      String uri = datatypeLibraries.get(i);
 
224
      datatypeLibraryMap.put(uri, prefix);
 
225
      pp.startGroup();
 
226
      pp.text("datatypes ");
 
227
      encodedText(prefix);
 
228
      pp.text(" =");
 
229
      pp.startNest(indent);
 
230
      pp.softNewline(" ");
 
231
      literal(uri);
 
232
      pp.endNest();
 
233
      pp.endGroup();
 
234
      pp.hardNewline();
 
235
    }
 
236
    pp.hardNewline();
 
237
  }
 
238
 
 
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;
 
247
          else {
 
248
            prevText.setValue(prevText.getValue() + ((TextAnnotation)child).getValue());
 
249
            iter.remove();
 
250
          }
 
251
        }
 
252
        else {
 
253
          prevText = null;
 
254
          child.accept(this);
 
255
        }
 
256
      }
 
257
    }
 
258
  }
 
259
 
 
260
  static class DatatypeLibraryVisitor extends VoidVisitor {
 
261
    private final Set<String> datatypeLibraries = new HashSet<String>();
 
262
 
 
263
    public void voidVisitValue(ValuePattern p) {
 
264
      noteDatatypeLibrary(p.getDatatypeLibrary());
 
265
      super.voidVisitValue(p);
 
266
    }
 
267
 
 
268
    public void voidVisitData(DataPattern p) {
 
269
      noteDatatypeLibrary(p.getDatatypeLibrary());
 
270
      super.voidVisitData(p);
 
271
    }
 
272
 
 
273
    private void noteDatatypeLibrary(String uri) {
 
274
      if (!uri.equals("") && !uri.equals(WellKnownNamespaces.XML_SCHEMA_DATATYPES))
 
275
        datatypeLibraries.add(uri);
 
276
    }
 
277
 
 
278
    static Set<String> findDatatypeLibraries(Pattern p) {
 
279
      DatatypeLibraryVisitor dlv = new DatatypeLibraryVisitor();
 
280
      p.accept(dlv);
 
281
      return dlv.datatypeLibraries;
 
282
    }
 
283
  }
 
284
 
 
285
  static class NamespaceVisitor extends VoidVisitor {
 
286
    private final NamespaceManager nsm = new NamespaceManager();
 
287
    private boolean isAttribute;
 
288
 
 
289
    public void voidVisitInclude(IncludeComponent c) {
 
290
      super.voidVisitInclude(c);
 
291
      nsm.requireNamespace(c.getNs(), true);
 
292
    }
 
293
 
 
294
    public void voidVisitExternalRef(ExternalRefPattern p) {
 
295
      super.voidVisitExternalRef(p);
 
296
      nsm.requireNamespace(p.getNs(), true);
 
297
    }
 
298
 
 
299
    public void voidVisitElement(ElementPattern p) {
 
300
      isAttribute = false;
 
301
      super.voidVisitElement(p);
 
302
    }
 
303
 
 
304
    public void voidVisitAttribute(AttributePattern p) {
 
305
      isAttribute = true;
 
306
      super.voidVisitAttribute(p);
 
307
    }
 
308
 
 
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) {
 
314
        if (!isAttribute)
 
315
          nsm.preferBinding("", nc.getNamespaceUri());
 
316
      }
 
317
      else
 
318
        nsm.preferBinding(nc.getPrefix(), nc.getNamespaceUri());
 
319
    }
 
320
 
 
321
    public void voidVisitNsName(NsNameNameClass nc) {
 
322
      super.voidVisitNsName(nc);
 
323
      nsm.requireNamespace(nc.getNs(), false);
 
324
    }
 
325
 
 
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());
 
330
      }
 
331
    }
 
332
 
 
333
    public void voidVisitElement(ElementAnnotation ea) {
 
334
      super.voidVisitElement(ea);
 
335
      noteAnnotationBinding(ea.getPrefix(), ea.getNamespaceUri());
 
336
      noteContext(ea.getContext(), true);
 
337
    }
 
338
 
 
339
    private void noteContext(NamespaceContext context, boolean required) {
 
340
      if (context == null)
 
341
        return;
 
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)) {
 
347
            if (required)
 
348
              nsm.requireBinding(prefix, ns);
 
349
            else
 
350
              nsm.preferBinding(prefix, ns);
 
351
          }
 
352
        }
 
353
      }
 
354
    }
 
355
 
 
356
    public void voidVisitAttribute(AttributeAnnotation a) {
 
357
      super.voidVisitAttribute(a);
 
358
      noteAnnotationBinding(a.getPrefix(), a.getNamespaceUri());
 
359
    }
 
360
 
 
361
    private void noteAnnotationBinding(String prefix, String ns) {
 
362
      if (ns.length() != 0)
 
363
        nsm.requireNamespace(ns, false);
 
364
      if (prefix != null)
 
365
        nsm.preferBinding(prefix, ns);
 
366
    }
 
367
 
 
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
 
376
      int state = 0;
 
377
      for (AnnotationChild child : before) {
 
378
        if (state < 2 && documentationString(child) != null)
 
379
          state = 1;
 
380
        else if (state != 1 || !(child instanceof Comment))
 
381
          state = 2;
 
382
        if (state == 2)
 
383
          child.accept(this);
 
384
      }
 
385
      if (!p.mayContainText())
 
386
        p.followingElementAnnotationsAccept(this);
 
387
    }
 
388
 
 
389
    static NamespaceManager.NamespaceBindings createBindings(Pattern p) {
 
390
      NamespaceVisitor nsv = new NamespaceVisitor();
 
391
      p.accept(nsv);
 
392
      return nsv.nsm.createBindings();
 
393
    }
 
394
  }
 
395
 
 
396
  private class ComponentOutput implements ComponentVisitor<VoidValue> {
 
397
    public VoidValue visitDefine(DefineComponent c) {
 
398
      startAnnotations(c);
 
399
      pp.startGroup();
 
400
      String name = c.getName();
 
401
      if (name == DefineComponent.START)
 
402
        pp.text("start");
 
403
      else
 
404
        identifier(name);
 
405
      Combine combine = c.getCombine();
 
406
      String op;
 
407
      if (combine == null)
 
408
        op = " =";
 
409
      else if (combine == Combine.CHOICE)
 
410
        op = " |=";
 
411
      else
 
412
        op = " &=";
 
413
      pp.text(op);
 
414
      pp.startNest(indent);
 
415
      pp.softNewline(" ");
 
416
      c.getBody().accept(noParenPatternOutput);
 
417
      pp.endNest();
 
418
      pp.endGroup();
 
419
      endAnnotations(c);
 
420
      return VoidValue.VOID;
 
421
    }
 
422
 
 
423
    public VoidValue visitDiv(DivComponent c) {
 
424
      startAnnotations(c);
 
425
      pp.text("div");
 
426
      body(c);
 
427
      endAnnotations(c);
 
428
      return VoidValue.VOID;
 
429
    }
 
430
 
 
431
    public VoidValue visitInclude(IncludeComponent c) {
 
432
      startAnnotations(c);
 
433
      pp.startGroup();
 
434
      pp.text("include ");
 
435
      pp.startNest("include ");
 
436
      literal(od.reference(sourceUri, c.getUri()));
 
437
      inherit(c.getNs());
 
438
      pp.endNest();
 
439
      pp.endGroup();
 
440
      List<Component> components = c.getComponents();
 
441
      if (!components.isEmpty())
 
442
        body(components);
 
443
      endAnnotations(c);
 
444
      return VoidValue.VOID;
 
445
    }
 
446
  }
 
447
 
 
448
  class PatternOutput implements PatternVisitor<VoidValue> {
 
449
    private final boolean alwaysUseParens;
 
450
 
 
451
    PatternOutput(boolean alwaysUseParens) {
 
452
      this.alwaysUseParens = alwaysUseParens;
 
453
    }
 
454
 
 
455
    public VoidValue visitGrammar(GrammarPattern p) {
 
456
      startAnnotations(p);
 
457
      pp.text("grammar");
 
458
      body(p);
 
459
      endAnnotations(p);
 
460
      return VoidValue.VOID;
 
461
    }
 
462
 
 
463
    public VoidValue visitElement(ElementPattern p) {
 
464
      isAttributeNameClass = false;
 
465
      nameClassed(p, "element ");
 
466
      return VoidValue.VOID;
 
467
    }
 
468
 
 
469
    public VoidValue visitAttribute(AttributePattern p) {
 
470
      isAttributeNameClass = true;
 
471
      nameClassed(p, "attribute ");
 
472
      return VoidValue.VOID;
 
473
    }
 
474
 
 
475
    private void nameClassed(NameClassedPattern p, String key) {
 
476
      startAnnotations(p);
 
477
      pp.text(key);
 
478
      pp.startNest(key);
 
479
      p.getNameClass().accept(noParenNameClassOutput);
 
480
      pp.endNest();
 
481
      braceChild(p);
 
482
      endAnnotations(p);
 
483
    }
 
484
 
 
485
    private void braceChild(UnaryPattern p) {
 
486
      Pattern child = p.getChild();
 
487
      boolean isSimple = !complexityCache.isComplex(child);
 
488
      if (isSimple)
 
489
        pp.startGroup();
 
490
      pp.text(" {");
 
491
      pp.startNest(indent);
 
492
      if (isSimple)
 
493
        pp.softNewline(" ");
 
494
      else
 
495
        pp.hardNewline();
 
496
      child.accept(noParenPatternOutput);
 
497
      pp.endNest();
 
498
      if (isSimple)
 
499
        pp.softNewline(" ");
 
500
      else
 
501
        pp.hardNewline();
 
502
      pp.text("}");
 
503
      if (isSimple)
 
504
        pp.endGroup();
 
505
    }
 
506
 
 
507
    public VoidValue visitOneOrMore(OneOrMorePattern p) {
 
508
      postfix(p, "+");
 
509
      return VoidValue.VOID;
 
510
    }
 
511
 
 
512
    public VoidValue visitZeroOrMore(ZeroOrMorePattern p) {
 
513
      postfix(p, "*");
 
514
      return VoidValue.VOID;
 
515
    }
 
516
 
 
517
    public VoidValue visitOptional(OptionalPattern p) {
 
518
      postfix(p, "?");
 
519
      return VoidValue.VOID;
 
520
    }
 
521
 
 
522
    private void postfix(UnaryPattern p, String op) {
 
523
      if (!startAnnotations(p)) {
 
524
        p.getChild().accept(patternOutput);
 
525
        pp.text(op);
 
526
      }
 
527
      else {
 
528
        pp.text("(");
 
529
        pp.startNest("(");
 
530
        p.getChild().accept(patternOutput);
 
531
        pp.endNest();
 
532
        pp.text(op);
 
533
        pp.text(")");
 
534
      }
 
535
      endAnnotations(p);
 
536
    }
 
537
 
 
538
    public VoidValue visitRef(RefPattern p) {
 
539
      startAnnotations(p);
 
540
      identifier(p.getName());
 
541
      endAnnotations(p);
 
542
      return VoidValue.VOID;
 
543
    }
 
544
 
 
545
    public VoidValue visitParentRef(ParentRefPattern p) {
 
546
      startAnnotations(p);
 
547
      pp.text("parent ");
 
548
      identifier(p.getName());
 
549
      endAnnotations(p);
 
550
      return VoidValue.VOID;
 
551
    }
 
552
 
 
553
    public VoidValue visitExternalRef(ExternalRefPattern p) {
 
554
      startAnnotations(p);
 
555
      pp.startGroup();
 
556
      pp.text("external ");
 
557
      pp.startNest("external ");
 
558
      literal(od.reference(sourceUri, p.getUri()));
 
559
      inherit(p.getNs());
 
560
      pp.endNest();
 
561
      pp.endGroup();
 
562
      endAnnotations(p);
 
563
      return VoidValue.VOID;
 
564
    }
 
565
 
 
566
    public VoidValue visitText(TextPattern p) {
 
567
      startAnnotations(p);
 
568
      pp.text("text");
 
569
      endAnnotations(p);
 
570
      return VoidValue.VOID;
 
571
    }
 
572
 
 
573
    public VoidValue visitEmpty(EmptyPattern p) {
 
574
      startAnnotations(p);
 
575
      pp.text("empty");
 
576
      endAnnotations(p);
 
577
      return VoidValue.VOID;
 
578
    }
 
579
 
 
580
    public VoidValue visitNotAllowed(NotAllowedPattern p) {
 
581
      startAnnotations(p);
 
582
      pp.text("notAllowed");
 
583
      endAnnotations(p);
 
584
      return VoidValue.VOID;
 
585
    }
 
586
 
 
587
    public VoidValue visitList(ListPattern p) {
 
588
      prefix(p, "list");
 
589
      return VoidValue.VOID;
 
590
    }
 
591
 
 
592
    public VoidValue visitMixed(MixedPattern p) {
 
593
      prefix(p, "mixed");
 
594
      return VoidValue.VOID;
 
595
    }
 
596
 
 
597
    private void prefix(UnaryPattern p, String key) {
 
598
      startAnnotations(p);
 
599
      pp.text(key);
 
600
      braceChild(p);
 
601
      endAnnotations(p);
 
602
    }
 
603
 
 
604
    public VoidValue visitChoice(ChoicePattern p) {
 
605
      composite(p, "| ", false);
 
606
      return VoidValue.VOID;
 
607
    }
 
608
 
 
609
    public VoidValue visitInterleave(InterleavePattern p) {
 
610
      composite(p, "& ", false);
 
611
      return VoidValue.VOID;
 
612
    }
 
613
 
 
614
    public VoidValue visitGroup(GroupPattern p) {
 
615
      composite(p, ",", true);
 
616
      return VoidValue.VOID;
 
617
    }
 
618
 
 
619
    void composite(CompositePattern p, String sep, boolean sepBeforeNewline) {
 
620
      boolean useParens = alwaysUseParens;
 
621
      if (startAnnotations(p))
 
622
        useParens = true;
 
623
      boolean isSimple = !complexityCache.isComplex(p);
 
624
      if (isSimple)
 
625
        pp.startGroup();
 
626
      if (useParens) {
 
627
        pp.text("(");
 
628
        pp.startNest("(");
 
629
      }
 
630
 
 
631
      boolean first = true;
 
632
      for (Pattern child : p.getChildren()) {
 
633
        if (!first) {
 
634
          if (sepBeforeNewline)
 
635
            pp.text(sep);
 
636
          if (isSimple)
 
637
            pp.softNewline(" ");
 
638
          else
 
639
            pp.hardNewline();
 
640
          if (!sepBeforeNewline) {
 
641
            pp.text(sep);
 
642
            pp.startNest(sep);
 
643
          }
 
644
        }
 
645
        child.accept(patternOutput);
 
646
        if (first)
 
647
          first = false;
 
648
        else if (!sepBeforeNewline)
 
649
          pp.endNest();
 
650
      }
 
651
      if (useParens) {
 
652
        pp.endNest();
 
653
        pp.text(")");
 
654
      }
 
655
      if (isSimple)
 
656
        pp.endGroup();
 
657
      endAnnotations(p);
 
658
    }
 
659
 
 
660
    public VoidValue visitData(DataPattern p) {
 
661
      startAnnotations(p);
 
662
      String lib = p.getDatatypeLibrary();
 
663
      String qn;
 
664
      if (!lib.equals(""))
 
665
        qn = datatypeLibraryMap.get(lib) + ":" + p.getType();
 
666
      else
 
667
        qn = p.getType();
 
668
      qn = encode(qn);
 
669
      pp.text(qn);
 
670
      List<Param> params = p.getParams();
 
671
      if (params.size() > 0) {
 
672
        pp.startGroup();
 
673
        pp.text(" {");
 
674
        pp.startNest(indent);
 
675
        for (Param param : params) {
 
676
          pp.softNewline(" ");
 
677
          startAnnotations(param);
 
678
          pp.startGroup();
 
679
          encodedText(param.getName());
 
680
          pp.text(" =");
 
681
          pp.startNest(indent);
 
682
          pp.softNewline(" ");
 
683
          literal(param.getValue());
 
684
          pp.endNest();
 
685
          pp.endGroup();
 
686
          endAnnotations(param);
 
687
        }
 
688
        pp.endNest();
 
689
        pp.softNewline(" ");
 
690
        pp.text("}");
 
691
        pp.endGroup();
 
692
      }
 
693
      Pattern e = p.getExcept();
 
694
      if (e != null) {
 
695
        boolean useParen = (!e.mayContainText()
 
696
                            && !e.getFollowingElementAnnotations().isEmpty());
 
697
        String s;
 
698
        if (params.isEmpty())
 
699
          s = " - ";
 
700
        else {
 
701
          pp.startGroup();
 
702
          pp.softNewline(" ");
 
703
          s = "- ";
 
704
        }
 
705
        if (useParen)
 
706
          s += "(";
 
707
        pp.text(s);
 
708
        pp.startNest(params.isEmpty() ? qn + s : s);
 
709
        e.accept(useParen ? noParenPatternOutput : patternOutput);
 
710
        pp.endNest();
 
711
        if (useParen)
 
712
          pp.text(")");
 
713
        if (!params.isEmpty())
 
714
          pp.endGroup();
 
715
      }
 
716
      endAnnotations(p);
 
717
      return VoidValue.VOID;
 
718
    }
 
719
 
 
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());
 
727
          else
 
728
            er.error("value_inconsistent_binding", prefix, uri, p.getSourceLocation());
 
729
        }
 
730
      }
 
731
      startAnnotations(p);
 
732
      String lib = p.getDatatypeLibrary();
 
733
      pp.startGroup();
 
734
      String str = null;
 
735
      if (lib.equals("")) {
 
736
        if (!p.getType().equals("token"))
 
737
          str = p.getType() + " ";
 
738
      }
 
739
      else
 
740
        str = datatypeLibraryMap.get(lib) + ":" + p.getType() + " ";
 
741
      if (str != null) {
 
742
        String encoded = encode(str);
 
743
        pp.text(encoded);
 
744
        pp.startNest(encoded);
 
745
      }
 
746
      literal(p.getValue());
 
747
      if (str != null)
 
748
        pp.endNest();
 
749
      pp.endGroup();
 
750
      endAnnotations(p);
 
751
      return VoidValue.VOID;
 
752
    }
 
753
 
 
754
  }
 
755
 
 
756
  class NameClassOutput implements NameClassVisitor<VoidValue> {
 
757
    private final boolean alwaysUseParens;
 
758
 
 
759
    NameClassOutput(boolean alwaysUseParens) {
 
760
      this.alwaysUseParens = alwaysUseParens;
 
761
    }
 
762
 
 
763
    public VoidValue visitAnyName(AnyNameNameClass nc) {
 
764
      NameClass e = nc.getExcept();
 
765
      if (e == null) {
 
766
        startAnnotations(nc);
 
767
        pp.text("*");
 
768
      }
 
769
      else {
 
770
        boolean useParens = startAnnotations(nc) || alwaysUseParens;
 
771
        String s = useParens ?  "(* - " : "* - ";
 
772
        pp.text(s);
 
773
        pp.startNest(s);
 
774
        e.accept(nameClassOutput);
 
775
        if (useParens)
 
776
          pp.text(")");
 
777
        pp.endNest();
 
778
      }
 
779
      endAnnotations(nc);
 
780
      return VoidValue.VOID;
 
781
    }
 
782
 
 
783
    public VoidValue visitNsName(NsNameNameClass nc) {
 
784
      NameClass e = nc.getExcept();
 
785
      String prefix = nsb.getNonEmptyPrefix(nc.getNs());
 
786
      if (e == null) {
 
787
        startAnnotations(nc);
 
788
        encodedText(prefix);
 
789
        pp.text(":*");
 
790
      }
 
791
      else {
 
792
        boolean useParens = startAnnotations(nc) || alwaysUseParens;
 
793
        String s = useParens ? "(" : "";
 
794
        s += encode(prefix);
 
795
        s += ":* - ";
 
796
        pp.text(s);
 
797
        pp.startNest(s);
 
798
        e.accept(nameClassOutput);
 
799
        pp.endNest();
 
800
        if (useParens)
 
801
          pp.text(")");
 
802
      }
 
803
      endAnnotations(nc);
 
804
      return VoidValue.VOID;
 
805
    }
 
806
 
 
807
    public VoidValue visitName(NameNameClass nc) {
 
808
      startAnnotations(nc);
 
809
      qualifiedName(nc.getNamespaceUri(), nc.getPrefix(), nc.getLocalName(), isAttributeNameClass);
 
810
      endAnnotations(nc);
 
811
      return VoidValue.VOID;
 
812
    }
 
813
 
 
814
    public VoidValue visitChoice(ChoiceNameClass nc) {
 
815
      boolean useParens = alwaysUseParens;
 
816
      if (startAnnotations(nc))
 
817
        useParens = true;
 
818
      else if (nc.getChildren().size() == 1)
 
819
        useParens = false;
 
820
      if (useParens) {
 
821
        pp.text("(");
 
822
        pp.startNest("(");
 
823
      }
 
824
      pp.startGroup();
 
825
      boolean first = true;
 
826
      for (NameClass child : nc.getChildren()) {
 
827
        if (first)
 
828
          first = false;
 
829
        else {
 
830
          pp.softNewline(" ");
 
831
          pp.text("| ");
 
832
        }
 
833
        child.accept(nameClassOutput);
 
834
      }
 
835
      pp.endGroup();
 
836
      if (useParens) {
 
837
        pp.endNest();
 
838
        pp.text(")");
 
839
      }
 
840
      endAnnotations(nc);
 
841
      return VoidValue.VOID;
 
842
    }
 
843
  }
 
844
 
 
845
  class AnnotationChildOutput implements AnnotationChildVisitor<VoidValue> {
 
846
    public VoidValue visitText(TextAnnotation ta) {
 
847
      literal(ta.getValue());
 
848
      return VoidValue.VOID;
 
849
    }
 
850
 
 
851
    public VoidValue visitComment(Comment c) {
 
852
      comment("#", c.getValue());
 
853
      return VoidValue.VOID;
 
854
    }
 
855
 
 
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
 
860
                    true);
 
861
      pp.text(" ");
 
862
      annotationBody(elem.getAttributes(), elem.getChildren());
 
863
      return VoidValue.VOID;
 
864
    }
 
865
  }
 
866
 
 
867
  class FollowingAnnotationChildOutput extends AnnotationChildOutput {
 
868
    public VoidValue visitElement(ElementAnnotation elem) {
 
869
      pp.text(">> ");
 
870
      pp.startNest(">> ");
 
871
      super.visitElement(elem);
 
872
      pp.endNest();
 
873
      return VoidValue.VOID;
 
874
    }
 
875
  }
 
876
 
 
877
  private static boolean hasAnnotations(Annotated annotated) {
 
878
    return (!annotated.getChildElementAnnotations().isEmpty()
 
879
            || !annotated.getAttributeAnnotations().isEmpty()
 
880
            || !annotated.getFollowingElementAnnotations().isEmpty());
 
881
  }
 
882
 
 
883
  private boolean startAnnotations(Annotated annotated) {
 
884
    if (!annotated.getLeadingComments().isEmpty()) {
 
885
      leadingComments(annotated);
 
886
      if (!hasAnnotations(annotated))
 
887
        return false;
 
888
    }
 
889
    else if (!hasAnnotations(annotated))
 
890
      return false;
 
891
    List<AnnotationChild> before = (annotated.mayContainText()
 
892
                                    ? annotated.getFollowingElementAnnotations()
 
893
                                    : annotated.getChildElementAnnotations());
 
894
    int i = 0;
 
895
    int len = before.size();
 
896
    for (; i < len; i++) {
 
897
      int j = i;
 
898
      if (i != 0) {
 
899
        do {
 
900
          if (!(before.get(j) instanceof Comment))
 
901
            break;
 
902
        } while (++j < len);
 
903
        if (j >= len)
 
904
          break;
 
905
      }
 
906
      String doc = documentationString(before.get(j));
 
907
      if (doc == null)
 
908
        break;
 
909
      if (j == i)
 
910
        pp.hardNewline();
 
911
      else {
 
912
        for (;;) {
 
913
          before.get(i).accept(annotationChildOutput);
 
914
          if (++i == j)
 
915
            break;
 
916
          pp.hardNewline();
 
917
        }
 
918
      }
 
919
      comment("##", doc);
 
920
    }
 
921
    if (i > 0)
 
922
      before = before.subList(i, len);
 
923
    pp.startGroup();
 
924
    if (!annotated.getAttributeAnnotations().isEmpty()
 
925
        || !before.isEmpty()) {
 
926
      if (!annotated.getAttributeAnnotations().isEmpty())
 
927
        checkContext(annotated.getContext(), annotated.getSourceLocation());
 
928
      annotationBody(annotated.getAttributeAnnotations(), before);
 
929
      pp.softNewline(" ");
 
930
    }
 
931
    return true;
 
932
  }
 
933
 
 
934
  private static String documentationString(AnnotationChild child) {
 
935
    if (!(child instanceof ElementAnnotation))
 
936
     return null;
 
937
    ElementAnnotation elem = (ElementAnnotation)child;
 
938
    if (!elem.getLocalName().equals("documentation"))
 
939
      return null;
 
940
    if (!elem.getNamespaceUri().equals(WellKnownNamespaces.RELAX_NG_COMPATIBILITY_ANNOTATIONS))
 
941
      return null;
 
942
    if (!elem.getAttributes().isEmpty())
 
943
      return null;
 
944
    StringBuffer buf = new StringBuffer();
 
945
    for (AnnotationChild a : elem.getChildren()) {
 
946
      if (!(a instanceof TextAnnotation))
 
947
        return null;
 
948
      buf.append(((TextAnnotation)a).getValue());
 
949
    }
 
950
    return buf.toString();
 
951
  }
 
952
 
 
953
  private void endAnnotations(Annotated annotated) {
 
954
    if (!annotated.mayContainText()) {
 
955
      for (AnnotationChild child : annotated.getFollowingElementAnnotations()) {
 
956
        if (annotated instanceof Component)
 
957
          pp.hardNewline();
 
958
        else
 
959
          pp.softNewline(" ");
 
960
        AnnotationChildVisitor<VoidValue> output = (annotated instanceof Component
 
961
                                                    ? annotationChildOutput
 
962
                                                    : followingAnnotationChildOutput);
 
963
        child.accept(output);
 
964
      }
 
965
    }
 
966
    if (hasAnnotations(annotated))
 
967
      pp.endGroup();
 
968
  }
 
969
 
 
970
  private void leadingComments(Annotated annotated) {
 
971
    boolean first = true;
 
972
    for (Comment comment : annotated.getLeadingComments()) {
 
973
      if (!first)
 
974
        pp.hardNewline();
 
975
      else
 
976
        first = false;
 
977
      comment.accept(annotationChildOutput);
 
978
    }
 
979
  }
 
980
 
 
981
  private void annotationBody(List<AttributeAnnotation> attributes, List<AnnotationChild> children) {
 
982
    pp.startGroup();
 
983
    pp.text("[");
 
984
    pp.startNest(indent);
 
985
    for (AttributeAnnotation att : attributes) {
 
986
      pp.softNewline(" ");
 
987
      pp.startGroup();
 
988
      qualifiedName(att.getNamespaceUri(), att.getPrefix(), att.getLocalName(), true);
 
989
      pp.text(" =");
 
990
      pp.startNest(indent);
 
991
      pp.softNewline(" ");
 
992
      literal(att.getValue());
 
993
      pp.endNest();
 
994
      pp.endGroup();
 
995
    }
 
996
    for (AnnotationChild child : children) {
 
997
      pp.softNewline(" ");
 
998
      child.accept(annotationChildOutput);
 
999
    }
 
1000
    pp.endNest();
 
1001
    pp.softNewline(" ");
 
1002
    pp.text("]");
 
1003
    pp.endGroup();
 
1004
  }
 
1005
 
 
1006
  private void body(Container container) {
 
1007
    body(container.getComponents());
 
1008
  }
 
1009
 
 
1010
  private void body(List<Component> components) {
 
1011
    if (components.size() == 0)
 
1012
      pp.text(" { }");
 
1013
    else {
 
1014
      pp.text(" {");
 
1015
      pp.startNest(indent);
 
1016
      pp.hardNewline();
 
1017
      innerBody(components);
 
1018
      pp.endNest();
 
1019
      pp.hardNewline();
 
1020
      pp.text("}");
 
1021
    }
 
1022
  }
 
1023
 
 
1024
  private void innerBody(List<Component> components) {
 
1025
    boolean first = true;
 
1026
    for (Component c : components) {
 
1027
      if (first)
 
1028
        first = false;
 
1029
      else
 
1030
        pp.hardNewline();
 
1031
      c.accept(componentOutput);
 
1032
    }
 
1033
  }
 
1034
 
 
1035
  private void inherit(String ns) {
 
1036
    if (ns.equals(nsb.getNamespaceUri("")))
 
1037
      return;
 
1038
    pp.softNewline(" ");
 
1039
    pp.text("inherit = ");
 
1040
    encodedText(nsb.getNonEmptyPrefix(ns));
 
1041
  }
 
1042
 
 
1043
  private void identifier(String name) {
 
1044
    if (keywordSet.contains(name))
 
1045
      pp.text("\\");
 
1046
    encodedText(name);
 
1047
  }
 
1048
 
 
1049
  private static final String[] delims = { "\"", "'", "\"\"\"", "'''" };
 
1050
 
 
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;
 
1055
      int bestEnd = -1;
 
1056
      int lim = str.indexOf('\n', i);
 
1057
      if (lim < 0)
 
1058
        lim = len;
 
1059
      else
 
1060
        ++lim;
 
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];
 
1065
          bestEnd = end;
 
1066
          if (end >= lim) {
 
1067
            bestEnd = lim;
 
1068
            break;
 
1069
          }
 
1070
        }
 
1071
      }
 
1072
      if (i != 0) {
 
1073
        pp.text(" ~");
 
1074
        pp.softNewline(" ");
 
1075
      }
 
1076
      pp.text(bestDelim);
 
1077
      encodedText(str.substring(i, bestEnd));
 
1078
      pp.text(bestDelim);
 
1079
      i = bestEnd;
 
1080
      if (i == len)
 
1081
        break;
 
1082
    }
 
1083
  }
 
1084
 
 
1085
  private void encodedText(String str) {
 
1086
    pp.text(encode(str));
 
1087
  }
 
1088
 
 
1089
  private String encode(String str) {
 
1090
    int start = 0;
 
1091
    int len = str.length();
 
1092
    for (int i = 0; i < len; i++) {
 
1093
      char c = str.charAt(i);
 
1094
      switch (c) {
 
1095
      case '\\':
 
1096
        if (!startsWithEscapeOpen(str, i))
 
1097
          break;
 
1098
        // fall through
 
1099
      case '\r':
 
1100
      case '\n':
 
1101
        if (start < i)
 
1102
          encodeBuf.append(str.substring(start, i));
 
1103
        escape(c);
 
1104
        start = i + 1;
 
1105
        break;
 
1106
      default:
 
1107
        if (Utf16.isSurrogate(c)) {
 
1108
          if (!cr.contains(c, str.charAt(i + 1))) {
 
1109
            if (start < i)
 
1110
              encodeBuf.append(str.substring(start, i));
 
1111
            escape(Utf16.scalarValue(c, str.charAt(i + 1)));
 
1112
            start = i + 2;
 
1113
          }
 
1114
          ++i;
 
1115
        }
 
1116
        else if (!cr.contains(c)) {
 
1117
          if (start < i)
 
1118
            encodeBuf.append(str.substring(start, i));
 
1119
          escape(c);
 
1120
          start = i + 1;
 
1121
        }
 
1122
        break;
 
1123
      }
 
1124
    }
 
1125
    if (start == 0)
 
1126
      return str;
 
1127
    if (start != len)
 
1128
      encodeBuf.append(str.substring(start, len));
 
1129
    str = encodeBuf.toString();
 
1130
    encodeBuf.setLength(0);
 
1131
    return str;
 
1132
  }
 
1133
 
 
1134
  private void escape(int n) {
 
1135
    encodeBuf.append("\\x{");
 
1136
    encodeBuf.append(Integer.toHexString(n));
 
1137
    encodeBuf.append("}");
 
1138
  }
 
1139
 
 
1140
  static private boolean startsWithEscapeOpen(String str, int off) {
 
1141
    if (!str.startsWith("\\x", off))
 
1142
      return false;
 
1143
    for (off += 2; str.startsWith("x", off); off++)
 
1144
      ;
 
1145
    return str.startsWith("{", off);
 
1146
  }
 
1147
 
 
1148
  /**
 
1149
   * null means no prefix
 
1150
   */
 
1151
  private void qualifiedName(String ns, String prefix, String localName, boolean isAttribute) {
 
1152
    prefix = choosePrefix(ns, prefix, isAttribute);
 
1153
    if (prefix == null)
 
1154
      encodedText(localName);
 
1155
    else {
 
1156
      encodedText(prefix);
 
1157
      pp.text(":");
 
1158
      encodedText(localName);
 
1159
    }
 
1160
  }
 
1161
 
 
1162
  /**
 
1163
   * null means no prefix
 
1164
   */
 
1165
  private String choosePrefix(String ns, String prefix, boolean isAttribute) {
 
1166
    if (prefix != null && ns.equals(nsb.getNamespaceUri(prefix)))
 
1167
      return prefix;
 
1168
    if (isAttribute) {
 
1169
      if (ns.length() == 0)
 
1170
        return null;
 
1171
    }
 
1172
    else {
 
1173
      if (ns.equals(nsb.getNamespaceUri("")))
 
1174
        return null;
 
1175
    }
 
1176
    return nsb.getNonEmptyPrefix(ns);
 
1177
  }
 
1178
 
 
1179
  private void comment(String delim, String value) {
 
1180
    int i = 0;
 
1181
    for (;;) {
 
1182
      pp.text(delim);
 
1183
      if (i < value.length() && value.charAt(i) != '\t')
 
1184
        pp.text(" ");
 
1185
      int j = value.indexOf('\n', i);
 
1186
      String tem = j < 0 ? value.substring(i) : value.substring(i, j);
 
1187
      encodedText(tem);
 
1188
      pp.hardNewline();
 
1189
      if (j < 0)
 
1190
        break;
 
1191
      i = j + 1;
 
1192
    }
 
1193
  }
 
1194
 
 
1195
  private void checkContext(NamespaceContext context, SourceLocation loc) {
 
1196
    if (context == null)
 
1197
      return;
 
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);
 
1205
      }
 
1206
    }
 
1207
  }
 
1208
}