001: /*
002: * Copyright Aduna (http://www.aduna-software.com/) (c) 1997-2007
003: *
004: * Licensed under the Aduna BSD-style license.
005: */
006: package org.openrdf.rio.trix;
007:
008: import static org.openrdf.rio.trix.TriXConstants.BNODE_TAG;
009: import static org.openrdf.rio.trix.TriXConstants.CONTEXT_TAG;
010: import static org.openrdf.rio.trix.TriXConstants.DATATYPE_ATT;
011: import static org.openrdf.rio.trix.TriXConstants.LANGUAGE_ATT;
012: import static org.openrdf.rio.trix.TriXConstants.NAMESPACE;
013: import static org.openrdf.rio.trix.TriXConstants.PLAIN_LITERAL_TAG;
014: import static org.openrdf.rio.trix.TriXConstants.ROOT_TAG;
015: import static org.openrdf.rio.trix.TriXConstants.TRIPLE_TAG;
016: import static org.openrdf.rio.trix.TriXConstants.TYPED_LITERAL_TAG;
017: import static org.openrdf.rio.trix.TriXConstants.URI_TAG;
018:
019: import java.io.IOException;
020: import java.io.OutputStream;
021: import java.io.Writer;
022:
023: import info.aduna.xml.XMLWriter;
024:
025: import org.openrdf.model.BNode;
026: import org.openrdf.model.Literal;
027: import org.openrdf.model.Resource;
028: import org.openrdf.model.Statement;
029: import org.openrdf.model.URI;
030: import org.openrdf.model.Value;
031: import org.openrdf.rio.RDFFormat;
032: import org.openrdf.rio.RDFHandlerException;
033: import org.openrdf.rio.RDFWriter;
034:
035: /**
036: * An implementation of the RDFWriter interface that writes RDF documents in <a
037: * href="http://www.w3.org/2004/03/trix/">TriX format</a>.
038: *
039: * @author Arjohn Kampman
040: */
041: public class TriXWriter implements RDFWriter {
042:
043: /*-----------*
044: * Variables *
045: *-----------*/
046:
047: private XMLWriter xmlWriter;
048:
049: private boolean writingStarted;
050:
051: private boolean inActiveContext;
052:
053: private Resource currentContext;
054:
055: /*--------------*
056: * Constructors *
057: *--------------*/
058:
059: /**
060: * Creates a new TriXWriter that will write to the supplied OutputStream.
061: *
062: * @param out
063: * The OutputStream to write the RDF/XML document to.
064: */
065: public TriXWriter(OutputStream out) {
066: this (new XMLWriter(out));
067: }
068:
069: /**
070: * Creates a new TriXWriter that will write to the supplied Writer.
071: *
072: * @param writer
073: * The Writer to write the RDF/XML document to.
074: */
075: public TriXWriter(Writer writer) {
076: this (new XMLWriter(writer));
077: }
078:
079: protected TriXWriter(XMLWriter xmlWriter) {
080: this .xmlWriter = xmlWriter;
081: this .xmlWriter.setPrettyPrint(true);
082:
083: writingStarted = false;
084: inActiveContext = false;
085: currentContext = null;
086: }
087:
088: /*---------*
089: * Methods *
090: *---------*/
091:
092: public RDFFormat getRDFFormat() {
093: return RDFFormat.TRIX;
094: }
095:
096: public void startRDF() throws RDFHandlerException {
097: if (writingStarted) {
098: throw new RDFHandlerException(
099: "Document writing has already started");
100: }
101:
102: try {
103: xmlWriter.startDocument();
104:
105: xmlWriter.setAttribute("xmlns", NAMESPACE);
106: xmlWriter.startTag(ROOT_TAG);
107: } catch (IOException e) {
108: throw new RDFHandlerException(e);
109: } finally {
110: writingStarted = true;
111: }
112: }
113:
114: public void endRDF() throws RDFHandlerException {
115: if (!writingStarted) {
116: throw new RDFHandlerException(
117: "Document writing has not yet started");
118: }
119:
120: try {
121: if (inActiveContext) {
122: xmlWriter.endTag(CONTEXT_TAG);
123: inActiveContext = false;
124: currentContext = null;
125: }
126: xmlWriter.endTag(ROOT_TAG);
127: xmlWriter.endDocument();
128: } catch (IOException e) {
129: throw new RDFHandlerException(e);
130: } finally {
131: writingStarted = false;
132: }
133: }
134:
135: public void handleNamespace(String prefix, String name) {
136: // ignore
137: }
138:
139: public void handleStatement(Statement st)
140: throws RDFHandlerException {
141: if (!writingStarted) {
142: throw new RDFHandlerException(
143: "Document writing has not yet been started");
144: }
145:
146: try {
147: Resource context = st.getContext();
148:
149: if (inActiveContext
150: && !contextsEquals(context, currentContext)) {
151: // Close currently active context
152: xmlWriter.endTag(CONTEXT_TAG);
153: inActiveContext = false;
154: }
155:
156: if (!inActiveContext) {
157: // Open new context
158: xmlWriter.startTag(CONTEXT_TAG);
159:
160: if (context != null) {
161: writeValue(context);
162: }
163:
164: currentContext = context;
165: inActiveContext = true;
166: }
167:
168: xmlWriter.startTag(TRIPLE_TAG);
169:
170: writeValue(st.getSubject());
171: writeValue(st.getPredicate());
172: writeValue(st.getObject());
173:
174: xmlWriter.endTag(TRIPLE_TAG);
175: } catch (IOException e) {
176: throw new RDFHandlerException(e);
177: }
178: }
179:
180: public void handleComment(String comment)
181: throws RDFHandlerException {
182: try {
183: xmlWriter.comment(comment);
184: } catch (IOException e) {
185: throw new RDFHandlerException(e);
186: }
187: }
188:
189: /**
190: * Writes out the XML-representation for the supplied value.
191: */
192: private void writeValue(Value value) throws IOException,
193: RDFHandlerException {
194: if (value instanceof URI) {
195: URI uri = (URI) value;
196: xmlWriter.textElement(URI_TAG, uri.toString());
197: } else if (value instanceof BNode) {
198: BNode bNode = (BNode) value;
199: xmlWriter.textElement(BNODE_TAG, bNode.getID());
200: } else if (value instanceof Literal) {
201: Literal literal = (Literal) value;
202: URI datatype = literal.getDatatype();
203:
204: if (datatype != null) {
205: xmlWriter.setAttribute(DATATYPE_ATT, datatype
206: .toString());
207: xmlWriter.textElement(TYPED_LITERAL_TAG, literal
208: .getLabel());
209: } else {
210: String language = literal.getLanguage();
211: if (language != null) {
212: xmlWriter.setAttribute(LANGUAGE_ATT, language);
213: }
214: xmlWriter.textElement(PLAIN_LITERAL_TAG, literal
215: .getLabel());
216: }
217: } else {
218: throw new RDFHandlerException("Unknown value type: "
219: + value.getClass());
220: }
221: }
222:
223: private static final boolean contextsEquals(Resource context1,
224: Resource context2) {
225: if (context1 == null) {
226: return context2 == null;
227: } else {
228: return context1.equals(context2);
229: }
230: }
231: }
|