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 javax.xml.stream.XMLOutputFactory;
011 import javax.xml.stream.XMLStreamException;
012 import javax.xml.stream.XMLStreamWriter;
013 import net.rootdev.javardfa.StatementSink;
014 import org.slf4j.Logger;
015 import org.slf4j.LoggerFactory;
016
017 /**
018 * A pretty ropey RDF/XML serialiser.
019 * Advantages: streams, no dependencies.
020 *
021 * @author pldms
022 */
023 public class RDFXMLSink implements StatementSink {
024 final static Logger log = LoggerFactory.getLogger(RDFXMLSink.class);
025 final static String RDFNS = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
026
027 private final XMLStreamWriter out;
028 private final String[] comments;
029
030 public RDFXMLSink(OutputStream os, String... comments) {
031 this.comments = comments;
032 XMLOutputFactory factory = XMLOutputFactory.newInstance();
033 factory.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, true);
034 try {
035 out = factory.createXMLStreamWriter(os, "utf-8");
036 } catch (XMLStreamException ex) {
037 throw new RuntimeException("Couldn't create writer", ex);
038 }
039 }
040
041 public void start() {
042 try {
043 out.writeStartDocument("utf-8", "1.0");
044 if (comments.length != 0) {
045 out.writeCharacters("\n");
046 StringBuilder sb = new StringBuilder("\n");
047 for (String line: comments) { sb.append(line); sb.append("\n"); }
048 out.writeComment(sb.toString());
049 }
050 out.writeCharacters("\n");
051 out.writeStartElement(RDFNS, "RDF");
052 out.writeNamespace("rdf", RDFNS);
053 out.writeCharacters("\n");
054 } catch (XMLStreamException ex) {
055 throw new RuntimeException("Problem starting document", ex);
056 }
057 }
058
059 public void end() {
060 try {
061 out.writeEndDocument();
062 out.flush();
063 out.close();
064 } catch (XMLStreamException ex) {
065 throw new RuntimeException("Problem ending document", ex);
066 }
067 }
068
069 public void addObject(String subject, String predicate, String object) {
070 try {
071 out.writeStartElement(RDFNS, "Description");
072 writeSubject(subject);
073 out.writeCharacters("\n\t");
074 writePredicate(predicate, true); // closed
075 writeObject(object);
076 out.writeCharacters("\n");
077 out.writeEndElement();
078 out.writeCharacters("\n");
079 } catch (XMLStreamException ex) {
080 throw new RuntimeException("Problem writing statement", ex);
081 }
082 }
083
084 public void addLiteral(String subject, String predicate, String lex, String lang, String datatype) {
085 try {
086 out.writeStartElement(RDFNS, "Description");
087 writeSubject(subject);
088 out.writeCharacters("\n\t");
089 writePredicate(predicate, false); // not closed
090 writeLiteral(lex, lang, datatype);
091 out.writeEndElement();
092 out.writeCharacters("\n");
093 out.writeEndElement();
094 out.writeCharacters("\n");
095 } catch (XMLStreamException ex) {
096 throw new RuntimeException("Problem writing statement", ex);
097 }
098 }
099
100 public void addPrefix(String prefix, String uri) {
101 }
102
103 private void writeSubject(String subject) throws XMLStreamException {
104 if (blank(subject))
105 out.writeAttribute(RDFNS, "nodeID", id(subject));
106 else
107 out.writeAttribute(RDFNS, "about", subject);
108 }
109
110 private void writePredicate(String predicate, boolean closed) throws XMLStreamException {
111 String[] nsln = split(predicate);
112 if (closed)
113 out.writeEmptyElement("ns", nsln[1], nsln[0]);
114 else
115 out.writeStartElement("ns", nsln[1], nsln[0]);
116 out.writeNamespace("ns", nsln[0]);
117 }
118
119 private void writeObject(String object) throws XMLStreamException {
120 if (blank(object))
121 out.writeAttribute(RDFNS, "nodeID", id(object));
122 else
123 out.writeAttribute(RDFNS, "resource", object);
124 }
125
126 private void writeLiteral(String lex, String lang, String datatype) throws XMLStreamException {
127 if (lang != null)
128 out.writeAttribute("xml:lang", lang);
129 else if (datatype != null)
130 out.writeAttribute(RDFNS, "datatype", datatype);
131 out.writeCharacters(lex);
132 }
133
134 private boolean blank(String subject) {
135 return subject.startsWith("_:");
136 }
137
138 private String id(String subject) {
139 return subject.substring(2);
140 }
141
142 protected String[] split(String predicate) {
143 String[] toReturn = new String[2];
144 int i = predicate.length() - 1;
145 int lastStartChar = -1;
146 while (i > 0 && isNameChar(predicate.codePointAt(i))) {
147 if (isNameStartChar(predicate.codePointAt(i)))
148 lastStartChar = i;
149 i--;
150 }
151 if (lastStartChar == -1)
152 throw new RuntimeException("Unsplitable predicate " + predicate);
153 toReturn[0] = predicate.substring(0, lastStartChar);
154 toReturn[1] = predicate.substring(lastStartChar);
155 return toReturn;
156 }
157
158 private boolean isNameChar(int cp) {
159 return isNameStartChar(cp) ||
160 (cp == '.') ||
161 (cp == '-') ||
162 (cp >= '0' && cp <= '9');
163 }
164
165 private boolean isNameStartChar(int cp) {
166 return (cp >= 'a' && cp <= 'z') ||
167 (cp >= 'A' && cp <= 'Z') ||
168 cp == ':' ||
169 cp == '_';
170 }
171
172 public void setBase(String base) {}
173 }
174
175 /*
176 * (c) Copyright 2009 University of Bristol
177 * All rights reserved.
178 *
179 * Redistribution and use in source and binary forms, with or without
180 * modification, are permitted provided that the following conditions
181 * are met:
182 * 1. Redistributions of source code must retain the above copyright
183 * notice, this list of conditions and the following disclaimer.
184 * 2. Redistributions in binary form must reproduce the above copyright
185 * notice, this list of conditions and the following disclaimer in the
186 * documentation and/or other materials provided with the distribution.
187 * 3. The name of the author may not be used to endorse or promote products
188 * derived from this software without specific prior written permission.
189 *
190 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
191 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
192 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
193 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
194 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
195 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
196 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
197 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
198 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
199 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
200 */