001    /*
002     * (c) Copyright 2009 University of Bristol
003     * All rights reserved.
004     * [See end of file]
005     */
006    
007    package net.rootdev.javardfa.output;
008    
009    import java.io.OutputStream;
010    import java.io.OutputStreamWriter;
011    import java.io.PrintWriter;
012    import java.io.UnsupportedEncodingException;
013    import java.io.Writer;
014    import java.util.regex.Pattern;
015    import net.rootdev.javardfa.StatementSink;
016    
017    
018    /**
019     * A pretty ropey NTriple serialiser.
020     * Advantages: streams, no dependencies.
021     *
022     * @author pldms
023     */
024    public class NTripleSink implements StatementSink {
025        protected final PrintWriter out;
026        protected final String[] comments;
027    
028        public NTripleSink(OutputStream os, String... comments) throws UnsupportedEncodingException {
029            this(new OutputStreamWriter(os, "US-ASCII"), comments); // N-Triples is 7-bit ascii
030        }
031    
032        public NTripleSink(Writer writer, String... comments) {
033            this.out = new PrintWriter(writer);
034            this.comments = comments;
035        }
036    
037        public void start() {
038            for (String line: comments) {
039                out.print("# ");
040                out.println(line);
041            }
042        }
043    
044        public void end() {
045            out.flush();
046        }
047    
048        public void addObject(String subject, String predicate, String object) {
049            out.print(toNode(subject));
050            out.print(toNode(predicate));
051            out.print(toNode(object));
052            out.println(".");
053        }
054    
055        public void addLiteral(String subject, String predicate, String lex, String lang, String datatype) {
056            out.print(toNode(subject));
057            out.print(toNode(predicate));
058            out.print(toLiteral(lex, lang, datatype));
059            out.println(".");
060        }
061    
062        public void addPrefix(String prefix, String uri) {}
063    
064        protected final String toNode(String node) {
065            if (node.startsWith("_:") || node.startsWith("?"))
066                return node + " ";
067            return "<" + node + "> ";
068        }
069    
070        protected final String toLiteral(String lex, String lang, String datatype) {
071            if (lang != null && lang.length() != 0)
072                return quote(lex) + "@" + lang + " ";
073            if (datatype != null)
074                return quote(lex) + "^^<" + datatype + "> ";
075            return quote(lex) + " ";
076        }
077    
078        private Pattern quotePattern = Pattern.compile("\"");
079        protected final String quote(String lex) {
080            return "\"" + encode(lex) + "\"";
081        }
082    
083        protected final String encode(String s) {
084            StringBuilder b = new StringBuilder();
085            for (int i = 0; i < s.length(); i++) {
086                int c = s.codePointAt(i);
087                if (c <= 8) b.append(enc(c));
088                else if (c == '\t') b.append("\\t");
089                else if (c == '\n') b.append("\\n");
090                else if (c == '\r') b.append("\\r");
091                else if (c == '"')  b.append("\\\"");
092                else if (c == '\\') b.append("\\\\");
093                else if (c <= 127)  b.appendCodePoint(c);
094                else if (c <= 0xFFFF) b.append(enc(c));
095                else b.append(longenc(c));
096            }
097            return b.toString();
098        }
099    
100        protected String enc(int codepoint) {
101            return String.format("\\u%04x", codepoint);
102        }
103    
104        protected String longenc(int codepoint) {
105            return String.format("\\U%08x", codepoint);
106        }
107    
108        public void setBase(String base) {}
109    }
110    
111    /*
112     * (c) Copyright 2009 University of Bristol
113     * All rights reserved.
114     *
115     * Redistribution and use in source and binary forms, with or without
116     * modification, are permitted provided that the following conditions
117     * are met:
118     * 1. Redistributions of source code must retain the above copyright
119     *    notice, this list of conditions and the following disclaimer.
120     * 2. Redistributions in binary form must reproduce the above copyright
121     *    notice, this list of conditions and the following disclaimer in the
122     *    documentation and/or other materials provided with the distribution.
123     * 3. The name of the author may not be used to endorse or promote products
124     *    derived from this software without specific prior written permission.
125     *
126     * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
127     * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
128     * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
129     * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
130     * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
131     * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
132     * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
133     * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
134     * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
135     * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
136     */