/* * Copyright 2008 Fedora Commons, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.mulgara.protocol; import java.io.IOException; import java.io.OutputStream; import java.net.URI; import java.util.Map; import org.jrdf.graph.BlankNode; import org.jrdf.graph.Literal; import org.jrdf.graph.URIReference; import org.mulgara.query.Answer; import org.mulgara.query.BooleanAnswer; import org.mulgara.query.TuplesException; import org.mulgara.query.Variable; import org.mulgara.util.StringUtil; /** * Represents an Answer as XML. * The format is specified at: {@link http://www.w3.org/TR/rdf-sparql-XMLres/} * * @created Jul 8, 2008 * @author Paula Gearon * @copyright © 2008 <a href="http://www.fedora-commons.org/">Fedora Commons</a> */ public class StreamedSparqlXMLAnswer extends AbstractStreamedXMLAnswer { /** Indent to use for namespaces in the document header. */ private static final String HEADER_INDENT = "\n "; /** Indicates that the W3C Schema should be used. */ boolean useW3CSchema = false; /** Additional metadata about the results. */ URI additionalMetadata = null; /** Boolean answer. */ boolean booleanResult = false; /** * Creates an XML Answer conforming to SPARQL XML results. * @param answer The Answer to wrap. */ public StreamedSparqlXMLAnswer(Answer answer, OutputStream output) { super((answer instanceof BooleanAnswer) ? null : answer, output); if (answer instanceof BooleanAnswer) booleanResult = ((BooleanAnswer)answer).getResult(); } /** * Creates an XML Answer with additional metadata. * @param answer The Answer to wrap. * @param metadata Additional metadata for the answer. */ public StreamedSparqlXMLAnswer(Answer answer, URI metadata, OutputStream output) { this(answer, output); additionalMetadata = metadata; } /** * Creates an XML Answer conforming to SPARQL XML results. * @param result The boolean result to encode. */ public StreamedSparqlXMLAnswer(boolean result, OutputStream output) { super((Answer)null, output); booleanResult = result; } /** * Creates an XML Answer with additional metadata. * @param result The boolean result to encode. * @param metadata Additional metadata for the answer. */ public StreamedSparqlXMLAnswer(boolean result, URI metadata, OutputStream output) { super((Answer)null, output); booleanResult = result; additionalMetadata = metadata; } /** * Set this XMLAnswer to use the W3C Schema for SPARQL results. * @param use Set to <code>true</code> if the W3C schema should be used. */ public void useW3CSchema(boolean use) { useW3CSchema = use; s = null; } /** {@inheritDoc} */ public void addDocHeader() throws IOException { s.append("<?xml version=\"1.0\" encoding=\""); s.append(charset.name()); s.append("\"?>\n"); s.append("<sparql xmlns=\"http://www.w3.org/2005/sparql-results#\""); for (Map.Entry<String,URI> ns: namespaces.entrySet()) { s.append(prettyPrint ? HEADER_INDENT : " "); s.append(ns.getKey()).append("=\"").append(ns.getValue().toString()).append("\""); } if (useW3CSchema) s.append(prettyPrint ? HEADER_INDENT : " ").append("xsi:schemaLocation=\"http://www.w3.org/2007/SPARQL/result.xsd\""); s.append(">"); } /** {@inheritDoc} */ public void addDocFooter() throws IOException { s.append(i(0)).append("</sparql>"); } /** {@inheritDoc} */ protected void addHeader(Answer a) throws IOException { s.append(i(1)).append("<head>"); if (a != null && a.getVariables() != null) { for (Variable v: a.getVariables()) addHeaderVariable(v); } if (additionalMetadata != null) { s.append(i(2)).append("<link href=\"").append(additionalMetadata.toString()).append("\"/>"); } s.append(i(1)).append("</head>"); } /** * No Answer footer needed for this type of document */ protected void addFooter(Answer answer) throws IOException { } /** {@inheritDoc} */ protected void addHeaderVariable(Variable var) throws IOException { s.append(i(2)).append("<variable name=\""); s.append(var.getName()).append("\"/>"); } /** {@inheritDoc} */ protected void addResults(Answer a) throws TuplesException, IOException { if (a != null) { s.append(i(1)).append("<results>"); a.beforeFirst(); while (a.next()) addResult(a); s.append(i(1)).append("</results>"); } else { s.append(i(1)).append("<boolean>").append(Boolean.toString(booleanResult)).append("</boolean>"); } } /** {@inheritDoc} */ protected void addResult(Answer a) throws TuplesException, IOException { s.append(i(2)).append("<result>"); for (int c = 0; c < width; c++) addBinding(vars[c], a.getObject(c)); s.append(i(2)).append("</result>"); } /** * {@inheritDoc} * No binding will be emitted if the value is null (unbound). */ protected void addBinding(Variable var, Object value) throws IOException { if (value != null) { s.append(i(3)).append("<binding name=\"").append(var.getName()).append("\">"); // no dynamic dispatch, so use if/then if (value instanceof URIReference) addURI((URIReference)value); else if (value instanceof Literal) addLiteral((Literal)value); else if (value instanceof BlankNode) addBNode((BlankNode)value); else throw new IllegalArgumentException("Unable to create a SPARQL response with an answer containing: " + value.getClass().getSimpleName()); s.append(i(3)).append("</binding>"); } } /** {@inheritDoc} */ protected void addURI(URIReference uri) throws IOException { s.append(i(4)).append("<uri>").append(uri.getURI().toString()).append("</uri>"); } /** {@inheritDoc} */ protected void addBNode(BlankNode bnode) throws IOException { s.append(i(4)).append("<bnode>").append(bnode.toString()).append("</bnode>"); } /** {@inheritDoc} */ protected void addLiteral(Literal literal) throws IOException { s.append(i(4)).append("<literal"); if (literal.getLanguage() != null) s.append(" xml:lang=\"").append(literal.getLanguage()).append("\""); else if (literal.getDatatype() != null) s.append(" datatype=\"").append(literal.getDatatype().toString()).append("\""); s.append(">").append(StringUtil.quoteAV(literal.getLexicalForm())).append("</literal>"); } /** * @see org.mulgara.protocol.StreamedAnswer#addAnswer(org.mulgara.query.Answer) */ public void addAnswer(Answer data) throws TuplesException, IOException { addResults(data); } }