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