/*
 * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */
/*
 * Copyright (C) 2004-2011
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package com.sun.xml.internal.rngom.digested;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.List;

import javax.xml.namespace.QName;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;

import com.sun.xml.internal.rngom.ast.builder.BuildException;
import com.sun.xml.internal.rngom.ast.builder.SchemaBuilder;
import com.sun.xml.internal.rngom.ast.util.CheckingSchemaBuilder;
import com.sun.xml.internal.rngom.nc.NameClass;
import com.sun.xml.internal.rngom.nc.NameClassVisitor;
import com.sun.xml.internal.rngom.nc.SimpleNameClass;
import com.sun.xml.internal.rngom.parse.Parseable;
import com.sun.xml.internal.rngom.parse.compact.CompactParseable;
import com.sun.xml.internal.rngom.parse.xml.SAXParseable;
import com.sun.xml.internal.rngom.xml.util.WellKnownNamespaces;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;

Printer of RELAX NG digested model to XML using StAX XMLStreamWriter.
Author:Alexey Demakov
/** * Printer of RELAX NG digested model to XML using StAX {@link XMLStreamWriter}. * * @author <A href="mailto:demakov@ispras.ru">Alexey Demakov</A> */
public class DXMLPrinter { protected XMLStreamWriter out; protected String indentStep = "\t"; protected String newLine = System.getProperty("line.separator"); protected int indent; protected boolean afterEnd = false; protected DXMLPrinterVisitor visitor; protected NameClassXMLPrinterVisitor ncVisitor; protected DOMPrinter domPrinter;
Params:
  • out – Output stream.
/** * @param out Output stream. */
public DXMLPrinter(XMLStreamWriter out) { this.out = out; this.visitor = new DXMLPrinterVisitor(); this.ncVisitor = new NameClassXMLPrinterVisitor(); this.domPrinter = new DOMPrinter(out); }
Prints grammar enclosed by start/end document.
Params:
  • grammar –
Throws:
/** * Prints grammar enclosed by start/end document. * * @param grammar * @throws XMLStreamException */
public void printDocument(DGrammarPattern grammar) throws XMLStreamException { try { visitor.startDocument(); visitor.on(grammar); visitor.endDocument(); } catch (XMLWriterException e) { if (e.getCause() instanceof XMLStreamException) { throw (XMLStreamException) e.getCause(); } else { throw new XMLStreamException(e); } } }
Prints XML fragment for the given pattern.
Throws:
  • XMLStreamException –
/** * Prints XML fragment for the given pattern. * * @throws XMLStreamException */
public void print(DPattern pattern) throws XMLStreamException { try { pattern.accept(visitor); } catch (XMLWriterException e) { if (e.getCause() instanceof XMLStreamException) { throw (XMLStreamException) e.getCause(); } else { throw new XMLStreamException(e); } } }
Prints XML fragment for the given name class.
Throws:
  • XMLStreamException –
/** * Prints XML fragment for the given name class. * * @throws XMLStreamException */
public void print(NameClass nc) throws XMLStreamException { try { nc.accept(ncVisitor); } catch (XMLWriterException e) { if (e.getCause() instanceof XMLStreamException) { throw (XMLStreamException) e.getCause(); } else { throw new XMLStreamException(e); } } } public void print(Node node) throws XMLStreamException { domPrinter.print(node); } protected class XMLWriterException extends RuntimeException { protected XMLWriterException(Throwable cause) { super(cause); } } protected class XMLWriter { protected void newLine() { try { out.writeCharacters(newLine); } catch (XMLStreamException e) { throw new XMLWriterException(e); } } protected void indent() { try { for (int i = 0; i < indent; i++) { out.writeCharacters(indentStep); } } catch (XMLStreamException e) { throw new XMLWriterException(e); } } public void startDocument() { try { out.writeStartDocument(); } catch (XMLStreamException e) { throw new XMLWriterException(e); } } public void endDocument() { try { out.writeEndDocument(); } catch (XMLStreamException e) { throw new XMLWriterException(e); } } public final void start(String element) { try { newLine(); indent(); out.writeStartElement(element); indent++; afterEnd = false; } catch (XMLStreamException e) { throw new XMLWriterException(e); } } public void end() { try { indent--; if (afterEnd) { newLine(); indent(); } out.writeEndElement(); afterEnd = true; } catch (XMLStreamException e) { throw new XMLWriterException(e); } } public void attr(String prefix, String ns, String name, String value) { try { out.writeAttribute(prefix, ns, name, value); } catch (XMLStreamException e) { throw new XMLWriterException(e); } } public void attr(String name, String value) { try { out.writeAttribute(name, value); } catch (XMLStreamException e) { throw new XMLWriterException(e); } } public void ns(String prefix, String uri) { try { out.writeNamespace(prefix, uri); } catch (XMLStreamException e) { throw new XMLWriterException(e); } } public void body(String text) { try { out.writeCharacters(text); afterEnd = false; } catch (XMLStreamException e) { throw new XMLWriterException(e); } } } protected class DXMLPrinterVisitor extends XMLWriter implements DPatternVisitor<Void> { protected void on(DPattern p) { p.accept(this); } protected void unwrapGroup(DPattern p) { if (p instanceof DGroupPattern && p.getAnnotation() == DAnnotation.EMPTY) { for (DPattern d : (DGroupPattern) p) { on(d); } } else { on(p); } } protected void unwrapChoice(DPattern p) { if (p instanceof DChoicePattern && p.getAnnotation() == DAnnotation.EMPTY) { for (DPattern d : (DChoicePattern) p) { on(d); } } else { on(p); } } protected void on(NameClass nc) { if (nc instanceof SimpleNameClass) { QName qname = ((SimpleNameClass) nc).name; String name = qname.getLocalPart(); if (!qname.getPrefix().equals("")) name = qname.getPrefix() + ":"; attr("name", name); } else { nc.accept(ncVisitor); } } protected void on(DAnnotation ann) { if (ann == DAnnotation.EMPTY) return; for (DAnnotation.Attribute attr : ann.getAttributes().values()) { attr(attr.getPrefix(), attr.getNs(), attr.getLocalName(), attr.getValue()); } for (Element elem : ann.getChildren()) { try { newLine(); indent(); print(elem); } catch (XMLStreamException e) { throw new XMLWriterException(e); } } } public Void onAttribute(DAttributePattern p) { start("attribute"); on(p.getName()); on(p.getAnnotation()); DPattern child = p.getChild(); // do not print default value if (!(child instanceof DTextPattern)) { on(p.getChild()); } end(); return null; } public Void onChoice(DChoicePattern p) { start("choice"); on(p.getAnnotation()); for (DPattern d : p) { on(d); } end(); return null; } public Void onData(DDataPattern p) { List<DDataPattern.Param> params = p.getParams(); DPattern except = p.getExcept(); start("data"); attr("datatypeLibrary", p.getDatatypeLibrary()); attr("type", p.getType()); on(p.getAnnotation()); for (DDataPattern.Param param : params) { start("param"); attr("ns", param.getNs()); attr("name", param.getName()); body(param.getValue()); end(); } if (except != null) { start("except"); unwrapChoice(except); end(); } end(); return null; } public Void onElement(DElementPattern p) { start("element"); on(p.getName()); on(p.getAnnotation()); unwrapGroup(p.getChild()); end(); return null; } public Void onEmpty(DEmptyPattern p) { start("empty"); on(p.getAnnotation()); end(); return null; } public Void onGrammar(DGrammarPattern p) { start("grammar"); ns(null, WellKnownNamespaces.RELAX_NG); on(p.getAnnotation()); start("start"); on(p.getStart()); end(); for (DDefine d : p) { start("define"); attr("name", d.getName()); on(d.getAnnotation()); unwrapGroup(d.getPattern()); end(); } end(); return null; } public Void onGroup(DGroupPattern p) { start("group"); on(p.getAnnotation()); for (DPattern d : p) { on(d); } end(); return null; } public Void onInterleave(DInterleavePattern p) { start("interleave"); on(p.getAnnotation()); for (DPattern d : p) { on(d); } end(); return null; } public Void onList(DListPattern p) { start("list"); on(p.getAnnotation()); unwrapGroup(p.getChild()); end(); return null; } public Void onMixed(DMixedPattern p) { start("mixed"); on(p.getAnnotation()); unwrapGroup(p.getChild()); end(); return null; } public Void onNotAllowed(DNotAllowedPattern p) { start("notAllowed"); on(p.getAnnotation()); end(); return null; } public Void onOneOrMore(DOneOrMorePattern p) { start("oneOrMore"); on(p.getAnnotation()); unwrapGroup(p.getChild()); end(); return null; } public Void onOptional(DOptionalPattern p) { start("optional"); on(p.getAnnotation()); unwrapGroup(p.getChild()); end(); return null; } public Void onRef(DRefPattern p) { start("ref"); attr("name", p.getName()); on(p.getAnnotation()); end(); return null; } public Void onText(DTextPattern p) { start("text"); on(p.getAnnotation()); end(); return null; } public Void onValue(DValuePattern p) { start("value"); if (!p.getNs().equals("")) attr("ns", p.getNs()); attr("datatypeLibrary", p.getDatatypeLibrary()); attr("type", p.getType()); on(p.getAnnotation()); body(p.getValue()); end(); return null; } public Void onZeroOrMore(DZeroOrMorePattern p) { start("zeroOrMore"); on(p.getAnnotation()); unwrapGroup(p.getChild()); end(); return null; } } protected class NameClassXMLPrinterVisitor extends XMLWriter implements NameClassVisitor<Void> { public Void visitChoice(NameClass nc1, NameClass nc2) { // TODO: flatten nested choices start("choice"); nc1.accept(this); nc2.accept(this); end(); return null; } public Void visitNsName(String ns) { start("nsName"); attr("ns", ns); end(); return null; } public Void visitNsNameExcept(String ns, NameClass nc) { start("nsName"); attr("ns", ns); start("except"); nc.accept(this); end(); end(); return null; } public Void visitAnyName() { start("anyName"); end(); return null; } public Void visitAnyNameExcept(NameClass nc) { start("anyName"); start("except"); nc.accept(this); end(); end(); return null; } public Void visitName(QName name) { start("name"); if (!name.getPrefix().equals("")) { body(name.getPrefix() + ":"); } body(name.getLocalPart()); end(); return null; } public Void visitNull() { throw new UnsupportedOperationException("visitNull"); } } public static void main(String[] args) throws Exception { Parseable p; ErrorHandler eh = new DefaultHandler() { @Override public void error(SAXParseException e) throws SAXException { throw e; } }; // the error handler passed to Parseable will receive parsing errors. String path = new File(args[0]).toURL().toString(); if (args[0].endsWith(".rng")) { p = new SAXParseable(new InputSource(path), eh); } else { p = new CompactParseable(new InputSource(path), eh); } // the error handler passed to CheckingSchemaBuilder will receive additional // errors found during the RELAX NG restrictions check. // typically you'd want to pass in the same error handler, // as there's really no distinction between those two kinds of errors. SchemaBuilder sb = new CheckingSchemaBuilder(new DSchemaBuilderImpl(), eh); try { // run the parser DGrammarPattern grammar = (DGrammarPattern) p.parse(sb); OutputStream out = new FileOutputStream(args[1]); XMLOutputFactory factory = XMLOutputFactory.newInstance(); factory.setProperty("javax.xml.stream.isRepairingNamespaces", Boolean.TRUE); XMLStreamWriter output = factory.createXMLStreamWriter(out); DXMLPrinter printer = new DXMLPrinter(output); printer.printDocument(grammar); output.close(); out.close(); } catch (BuildException e) { if (e.getCause() instanceof SAXParseException) { SAXParseException se = (SAXParseException) e.getCause(); System.out.println("(" + se.getLineNumber() + "," + se.getColumnNumber() + "): " + se.getMessage()); return; } else // I found that Crimson doesn't show the proper stack trace // when a RuntimeException happens inside a SchemaBuilder. // the following code shows the actual exception that happened. if (e.getCause() instanceof SAXException) { SAXException se = (SAXException) e.getCause(); if (se.getException() != null) se.getException().printStackTrace(); } throw e; } } }