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 */