Thu, 31 Aug 2017 15:18:52 +0800
merge
1 /*
2 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25 /*
26 * Copyright (C) 2004-2011
27 *
28 * Permission is hereby granted, free of charge, to any person obtaining a copy
29 * of this software and associated documentation files (the "Software"), to deal
30 * in the Software without restriction, including without limitation the rights
31 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
32 * copies of the Software, and to permit persons to whom the Software is
33 * furnished to do so, subject to the following conditions:
34 *
35 * The above copyright notice and this permission notice shall be included in
36 * all copies or substantial portions of the Software.
37 *
38 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
39 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
40 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
41 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
42 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
43 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
44 * THE SOFTWARE.
45 */
46 package com.sun.xml.internal.rngom.digested;
48 import java.io.File;
49 import java.io.FileOutputStream;
50 import java.io.OutputStream;
51 import java.util.List;
53 import javax.xml.namespace.QName;
54 import javax.xml.stream.XMLOutputFactory;
55 import javax.xml.stream.XMLStreamException;
56 import javax.xml.stream.XMLStreamWriter;
58 import com.sun.xml.internal.rngom.ast.builder.BuildException;
59 import com.sun.xml.internal.rngom.ast.builder.SchemaBuilder;
60 import com.sun.xml.internal.rngom.ast.util.CheckingSchemaBuilder;
61 import com.sun.xml.internal.rngom.nc.NameClass;
62 import com.sun.xml.internal.rngom.nc.NameClassVisitor;
63 import com.sun.xml.internal.rngom.nc.SimpleNameClass;
64 import com.sun.xml.internal.rngom.parse.Parseable;
65 import com.sun.xml.internal.rngom.parse.compact.CompactParseable;
66 import com.sun.xml.internal.rngom.parse.xml.SAXParseable;
67 import com.sun.xml.internal.rngom.xml.util.WellKnownNamespaces;
68 import org.w3c.dom.Element;
69 import org.w3c.dom.Node;
70 import org.xml.sax.ErrorHandler;
71 import org.xml.sax.InputSource;
72 import org.xml.sax.SAXException;
73 import org.xml.sax.SAXParseException;
74 import org.xml.sax.helpers.DefaultHandler;
76 /**
77 * Printer of RELAX NG digested model to XML using StAX {@link XMLStreamWriter}.
78 *
79 * @author <A href="mailto:demakov@ispras.ru">Alexey Demakov</A>
80 */
81 public class DXMLPrinter {
82 protected XMLStreamWriter out;
83 protected String indentStep = "\t";
84 protected String newLine = System.getProperty("line.separator");
85 protected int indent;
86 protected boolean afterEnd = false;
87 protected DXMLPrinterVisitor visitor;
88 protected NameClassXMLPrinterVisitor ncVisitor;
89 protected DOMPrinter domPrinter;
91 /**
92 * @param out Output stream.
93 */
94 public DXMLPrinter(XMLStreamWriter out) {
95 this.out = out;
96 this.visitor = new DXMLPrinterVisitor();
97 this.ncVisitor = new NameClassXMLPrinterVisitor();
98 this.domPrinter = new DOMPrinter(out);
99 }
101 /**
102 * Prints grammar enclosed by start/end document.
103 *
104 * @param grammar
105 * @throws XMLStreamException
106 */
107 public void printDocument(DGrammarPattern grammar) throws XMLStreamException {
108 try {
109 visitor.startDocument();
110 visitor.on(grammar);
111 visitor.endDocument();
112 } catch (XMLWriterException e) {
113 if (e.getCause() instanceof XMLStreamException) {
114 throw (XMLStreamException) e.getCause();
115 } else {
116 throw new XMLStreamException(e);
117 }
118 }
119 }
121 /**
122 * Prints XML fragment for the given pattern.
123 *
124 * @throws XMLStreamException
125 */
126 public void print(DPattern pattern) throws XMLStreamException {
127 try {
128 pattern.accept(visitor);
129 } catch (XMLWriterException e) {
130 if (e.getCause() instanceof XMLStreamException) {
131 throw (XMLStreamException) e.getCause();
132 } else {
133 throw new XMLStreamException(e);
134 }
135 }
136 }
138 /**
139 * Prints XML fragment for the given name class.
140 *
141 * @throws XMLStreamException
142 */
143 public void print(NameClass nc) throws XMLStreamException {
144 try {
145 nc.accept(ncVisitor);
146 } catch (XMLWriterException e) {
147 if (e.getCause() instanceof XMLStreamException) {
148 throw (XMLStreamException) e.getCause();
149 } else {
150 throw new XMLStreamException(e);
151 }
152 }
153 }
155 public void print(Node node) throws XMLStreamException {
156 domPrinter.print(node);
157 }
159 protected class XMLWriterException extends RuntimeException {
160 protected XMLWriterException(Throwable cause) {
161 super(cause);
162 }
163 }
165 protected class XMLWriter {
166 protected void newLine() {
167 try {
168 out.writeCharacters(newLine);
169 } catch (XMLStreamException e) {
170 throw new XMLWriterException(e);
171 }
172 }
174 protected void indent() {
175 try {
176 for (int i = 0; i < indent; i++) {
177 out.writeCharacters(indentStep);
178 }
179 } catch (XMLStreamException e) {
180 throw new XMLWriterException(e);
181 }
182 }
184 public void startDocument() {
185 try {
186 out.writeStartDocument();
187 } catch (XMLStreamException e) {
188 throw new XMLWriterException(e);
189 }
190 }
192 public void endDocument() {
193 try {
194 out.writeEndDocument();
195 } catch (XMLStreamException e) {
196 throw new XMLWriterException(e);
197 }
198 }
200 public final void start(String element) {
201 try {
202 newLine();
203 indent();
204 out.writeStartElement(element);
205 indent++;
206 afterEnd = false;
207 } catch (XMLStreamException e) {
208 throw new XMLWriterException(e);
209 }
210 }
212 public void end() {
213 try {
214 indent--;
215 if (afterEnd) {
216 newLine();
217 indent();
218 }
219 out.writeEndElement();
220 afterEnd = true;
221 } catch (XMLStreamException e) {
222 throw new XMLWriterException(e);
223 }
224 }
226 public void attr(String prefix, String ns, String name, String value) {
227 try {
228 out.writeAttribute(prefix, ns, name, value);
229 } catch (XMLStreamException e) {
230 throw new XMLWriterException(e);
231 }
232 }
234 public void attr(String name, String value) {
235 try {
236 out.writeAttribute(name, value);
237 } catch (XMLStreamException e) {
238 throw new XMLWriterException(e);
239 }
240 }
242 public void ns(String prefix, String uri) {
243 try {
244 out.writeNamespace(prefix, uri);
245 } catch (XMLStreamException e) {
246 throw new XMLWriterException(e);
247 }
248 }
250 public void body(String text) {
251 try {
252 out.writeCharacters(text);
253 afterEnd = false;
254 } catch (XMLStreamException e) {
255 throw new XMLWriterException(e);
256 }
257 }
258 }
260 protected class DXMLPrinterVisitor extends XMLWriter implements DPatternVisitor<Void> {
261 protected void on(DPattern p) {
262 p.accept(this);
263 }
265 protected void unwrapGroup(DPattern p) {
266 if (p instanceof DGroupPattern && p.getAnnotation() == DAnnotation.EMPTY) {
267 for (DPattern d : (DGroupPattern) p) {
268 on(d);
269 }
270 } else {
271 on(p);
272 }
273 }
275 protected void unwrapChoice(DPattern p) {
276 if (p instanceof DChoicePattern && p.getAnnotation() == DAnnotation.EMPTY) {
277 for (DPattern d : (DChoicePattern) p) {
278 on(d);
279 }
280 } else {
281 on(p);
282 }
283 }
285 protected void on(NameClass nc) {
286 if (nc instanceof SimpleNameClass) {
287 QName qname = ((SimpleNameClass) nc).name;
288 String name = qname.getLocalPart();
289 if (!qname.getPrefix().equals("")) name = qname.getPrefix() + ":";
290 attr("name", name);
291 } else {
292 nc.accept(ncVisitor);
293 }
294 }
296 protected void on(DAnnotation ann) {
297 if (ann == DAnnotation.EMPTY) return;
298 for (DAnnotation.Attribute attr : ann.getAttributes().values()) {
299 attr(attr.getPrefix(), attr.getNs(), attr.getLocalName(), attr.getValue());
300 }
301 for (Element elem : ann.getChildren()) {
302 try {
303 newLine();
304 indent();
305 print(elem);
306 }
307 catch (XMLStreamException e) {
308 throw new XMLWriterException(e);
309 }
310 }
311 }
313 public Void onAttribute(DAttributePattern p) {
314 start("attribute");
315 on(p.getName());
316 on(p.getAnnotation());
317 DPattern child = p.getChild();
318 // do not print default value
319 if (!(child instanceof DTextPattern)) {
320 on(p.getChild());
321 }
322 end();
323 return null;
324 }
326 public Void onChoice(DChoicePattern p) {
327 start("choice");
328 on(p.getAnnotation());
329 for (DPattern d : p) {
330 on(d);
331 }
332 end();
333 return null;
334 }
336 public Void onData(DDataPattern p) {
337 List<DDataPattern.Param> params = p.getParams();
338 DPattern except = p.getExcept();
339 start("data");
340 attr("datatypeLibrary", p.getDatatypeLibrary());
341 attr("type", p.getType());
342 on(p.getAnnotation());
343 for (DDataPattern.Param param : params) {
344 start("param");
345 attr("ns", param.getNs());
346 attr("name", param.getName());
347 body(param.getValue());
348 end();
349 }
350 if (except != null) {
351 start("except");
352 unwrapChoice(except);
353 end();
354 }
355 end();
356 return null;
357 }
359 public Void onElement(DElementPattern p) {
360 start("element");
361 on(p.getName());
362 on(p.getAnnotation());
363 unwrapGroup(p.getChild());
364 end();
365 return null;
366 }
368 public Void onEmpty(DEmptyPattern p) {
369 start("empty");
370 on(p.getAnnotation());
371 end();
372 return null;
373 }
375 public Void onGrammar(DGrammarPattern p) {
376 start("grammar");
377 ns(null, WellKnownNamespaces.RELAX_NG);
378 on(p.getAnnotation());
379 start("start");
380 on(p.getStart());
381 end();
382 for (DDefine d : p) {
383 start("define");
384 attr("name", d.getName());
385 on(d.getAnnotation());
386 unwrapGroup(d.getPattern());
387 end();
388 }
389 end();
390 return null;
391 }
393 public Void onGroup(DGroupPattern p) {
394 start("group");
395 on(p.getAnnotation());
396 for (DPattern d : p) {
397 on(d);
398 }
399 end();
400 return null;
401 }
403 public Void onInterleave(DInterleavePattern p) {
404 start("interleave");
405 on(p.getAnnotation());
406 for (DPattern d : p) {
407 on(d);
408 }
409 end();
410 return null;
411 }
413 public Void onList(DListPattern p) {
414 start("list");
415 on(p.getAnnotation());
416 unwrapGroup(p.getChild());
417 end();
418 return null;
419 }
421 public Void onMixed(DMixedPattern p) {
422 start("mixed");
423 on(p.getAnnotation());
424 unwrapGroup(p.getChild());
425 end();
426 return null;
427 }
429 public Void onNotAllowed(DNotAllowedPattern p) {
430 start("notAllowed");
431 on(p.getAnnotation());
432 end();
433 return null;
434 }
436 public Void onOneOrMore(DOneOrMorePattern p) {
437 start("oneOrMore");
438 on(p.getAnnotation());
439 unwrapGroup(p.getChild());
440 end();
441 return null;
442 }
444 public Void onOptional(DOptionalPattern p) {
445 start("optional");
446 on(p.getAnnotation());
447 unwrapGroup(p.getChild());
448 end();
449 return null;
450 }
452 public Void onRef(DRefPattern p) {
453 start("ref");
454 attr("name", p.getName());
455 on(p.getAnnotation());
456 end();
457 return null;
458 }
460 public Void onText(DTextPattern p) {
461 start("text");
462 on(p.getAnnotation());
463 end();
464 return null;
465 }
467 public Void onValue(DValuePattern p) {
468 start("value");
469 if (!p.getNs().equals("")) attr("ns", p.getNs());
470 attr("datatypeLibrary", p.getDatatypeLibrary());
471 attr("type", p.getType());
472 on(p.getAnnotation());
473 body(p.getValue());
474 end();
475 return null;
476 }
478 public Void onZeroOrMore(DZeroOrMorePattern p) {
479 start("zeroOrMore");
480 on(p.getAnnotation());
481 unwrapGroup(p.getChild());
482 end();
483 return null;
484 }
485 }
487 protected class NameClassXMLPrinterVisitor extends XMLWriter implements NameClassVisitor<Void> {
488 public Void visitChoice(NameClass nc1, NameClass nc2) {
489 // TODO: flatten nested choices
490 start("choice");
491 nc1.accept(this);
492 nc2.accept(this);
493 end();
494 return null;
495 }
497 public Void visitNsName(String ns) {
498 start("nsName");
499 attr("ns", ns);
500 end();
501 return null;
502 }
504 public Void visitNsNameExcept(String ns, NameClass nc) {
505 start("nsName");
506 attr("ns", ns);
507 start("except");
508 nc.accept(this);
509 end();
510 end();
511 return null;
512 }
514 public Void visitAnyName() {
515 start("anyName");
516 end();
517 return null;
518 }
520 public Void visitAnyNameExcept(NameClass nc) {
521 start("anyName");
522 start("except");
523 nc.accept(this);
524 end();
525 end();
526 return null;
527 }
529 public Void visitName(QName name) {
530 start("name");
531 if (!name.getPrefix().equals("")) {
532 body(name.getPrefix() + ":");
533 }
534 body(name.getLocalPart());
535 end();
536 return null;
537 }
539 public Void visitNull() {
540 throw new UnsupportedOperationException("visitNull");
541 }
542 }
544 public static void main(String[] args) throws Exception {
545 Parseable p;
547 ErrorHandler eh = new DefaultHandler() {
548 @Override
549 public void error(SAXParseException e) throws SAXException {
550 throw e;
551 }
552 };
554 // the error handler passed to Parseable will receive parsing errors.
555 String path = new File(args[0]).toURL().toString();
556 if (args[0].endsWith(".rng")) {
557 p = new SAXParseable(new InputSource(path), eh);
558 } else {
559 p = new CompactParseable(new InputSource(path), eh);
560 }
562 // the error handler passed to CheckingSchemaBuilder will receive additional
563 // errors found during the RELAX NG restrictions check.
564 // typically you'd want to pass in the same error handler,
565 // as there's really no distinction between those two kinds of errors.
566 SchemaBuilder sb = new CheckingSchemaBuilder(new DSchemaBuilderImpl(), eh);
567 try {
568 // run the parser
569 DGrammarPattern grammar = (DGrammarPattern) p.parse(sb);
570 OutputStream out = new FileOutputStream(args[1]);
571 XMLOutputFactory factory = XMLOutputFactory.newInstance();
572 factory.setProperty("javax.xml.stream.isRepairingNamespaces", Boolean.TRUE);
573 XMLStreamWriter output = factory.createXMLStreamWriter(out);
574 DXMLPrinter printer = new DXMLPrinter(output);
575 printer.printDocument(grammar);
576 output.close();
577 out.close();
578 } catch (BuildException e) {
579 if (e.getCause() instanceof SAXParseException) {
580 SAXParseException se = (SAXParseException) e.getCause();
581 System.out.println("("
582 + se.getLineNumber()
583 + ","
584 + se.getColumnNumber()
585 + "): "
586 + se.getMessage());
587 return;
588 } else
589 // I found that Crimson doesn't show the proper stack trace
590 // when a RuntimeException happens inside a SchemaBuilder.
591 // the following code shows the actual exception that happened.
592 if (e.getCause() instanceof SAXException) {
593 SAXException se = (SAXException) e.getCause();
594 if (se.getException() != null)
595 se.getException().printStackTrace();
596 }
597 throw e;
598 }
599 }
600 }