/** * Copyright 2005-2014 Restlet * * The contents of this file are subject to the terms of one of the following * open source licenses: Apache 2.0 or or EPL 1.0 (the "Licenses"). You can * select the license that you prefer but you may not use this file except in * compliance with one of these Licenses. * * You can obtain a copy of the Apache 2.0 license at * http://www.opensource.org/licenses/apache-2.0 * * You can obtain a copy of the EPL 1.0 license at * http://www.opensource.org/licenses/eclipse-1.0 * * See the Licenses for the specific language governing permissions and * limitations under the Licenses. * * Alternatively, you can obtain a royalty free commercial license with less * limitations, transferable or non-transferable, directly at * http://restlet.com/products/restlet-framework * * Restlet is a registered trademark of Restlet S.A.S. */ package org.restlet.ext.rdf.internal.xml; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.io.Writer; import org.restlet.Context; import org.restlet.data.Reference; import org.restlet.ext.rdf.Graph; import org.restlet.ext.rdf.GraphHandler; import org.restlet.ext.rdf.Link; import org.restlet.ext.rdf.Literal; import org.restlet.ext.rdf.internal.RdfConstants; import org.restlet.ext.xml.XmlWriter; import org.xml.sax.SAXException; import org.xml.sax.helpers.AttributesImpl; /** * Handler of RDF content according to the RDF XML syntax. * * @author Thierry Boileau */ public class RdfXmlWriter extends GraphHandler { /** The last source reference written, to try to factor statements. */ private Reference lastSource; /** URI of the RDF SYNTAX namespace. */ private final String RDF_SYNTAX = RdfConstants.RDF_SYNTAX.toString(true, true); /** XML writer. */ private XmlWriter writer; /** * Constructor. * * @param writer * The character writer. * @throws UnsupportedEncodingException */ public RdfXmlWriter(Writer writer) throws UnsupportedEncodingException { super(); this.writer = new XmlWriter(writer); this.lastSource = null; } @Override public void endGraph() throws IOException { try { if (this.lastSource != null) { // We need to end the previous source this.writer.endElement(RDF_SYNTAX, "Description"); } this.writer.endElement(RDF_SYNTAX, "RDF"); this.writer.endDocument(); } catch (SAXException e) { Context.getCurrentLogger().warning( "Cannot write the end of the graph: " + e.getMessage()); } this.writer.flush(); } /** * Returns the namespace of the given reference. * * @param reference * the given reference. * @return The namespace of the given reference. */ private String getNamespace(Reference reference) { String prefix = getPrefix(reference); String ref = reference.toString(true, true); if (prefix != null) { return ref.substring(0, ref.length() - prefix.length()); } return ref; } /** * Returns the prefix of the qualified name representing the given * reference. * * @param ref * the given reference. * @return The prefix of the qualified name representing the given * reference. Context .getCurrentLogger() .warning( * "Cannot write the end of the graph" + e.getMessage()); */ private String getPrefix(Reference ref) { String result = null; if (ref.hasFragment()) { result = ref.getFragment(); } else { result = ref.getLastSegment(); } return result; } @Override public void link(Graph source, Reference typeRef, Literal target) { Context.getCurrentLogger() .warning( "Cannot write the representation of a statement due to the fact that the subject is not a Reference."); } @Override public void link(Graph source, Reference typeRef, Reference target) { Context.getCurrentLogger() .warning( "Cannot write the representation of a statement due to the fact that the subject is not a Reference."); } @Override public void link(Reference source, Reference typeRef, Literal target) { try { if (this.lastSource == null) { writeNode(source, true); } else if (!source.equals(this.lastSource)) { // We need to first end the previous source this.writer.endElement(RDF_SYNTAX, "Description"); writeNode(source, true); } this.lastSource = source; String typeRefNs = getNamespace(typeRef.getTargetRef()); String typeRefPrefix = getPrefix(typeRef.getTargetRef()); if (target.getLanguage() != null || target.getDatatypeRef() != null) { AttributesImpl attr = new AttributesImpl(); if (target.getLanguage() != null) { attr.addAttribute(null, "lang", "xml:lang", "text", target .getLanguage().getName()); } if (target.getDatatypeRef() != null) { attr.addAttribute(RDF_SYNTAX, "datatype", "rdf:datatype", "text", target.getDatatypeRef() .toString(true, true)); } this.writer.startElement(typeRefNs, typeRefPrefix, null, attr); } else { this.writer.startElement(typeRefNs, typeRefPrefix); } this.writer.characters(target.getValue()); this.writer.endElement(typeRefNs, typeRefPrefix); } catch (SAXException e) { org.restlet.Context.getCurrentLogger().warning( "Cannot write the representation of a statement due to: " + e.getMessage()); } } @Override public void link(Reference source, Reference typeRef, Reference target) { try { if (this.lastSource == null) { writeNode(source, true); } else if (!source.equals(this.lastSource)) { // We need to first end the previous source this.writer.endElement(RDF_SYNTAX, "Description"); writeNode(source, true); } this.lastSource = source; String typeRefNs = getNamespace(typeRef.getTargetRef()); String typeRefPrefix = getPrefix(typeRef.getTargetRef()); this.writer.startElement(typeRefNs, typeRefPrefix); writeNode(target, false); this.writer.endElement(typeRefNs, typeRefPrefix); } catch (SAXException e) { Context.getCurrentLogger().warning( "Cannot write the representation of a statement due to: " + e.getMessage()); } } @Override public void startGraph() throws IOException { this.writer.setPrefix(RDF_SYNTAX, "rdf"); this.writer.setPrefix(RdfConstants.XML_SCHEMA.toString(true, true), "type"); writer.setDataFormat(true); writer.setIndentStep(3); try { this.writer.startDocument(); this.writer.startElement(RDF_SYNTAX, "RDF"); } catch (SAXException e) { Context.getCurrentLogger().warning( "Cannot write the start of the graph: " + e.getMessage()); } } @Override public void startPrefixMapping(String prefix, Reference reference) { if (prefix == null) { writer.forceNSDecl(getNamespace(reference.getTargetRef())); } else { writer.forceNSDecl(getNamespace(reference.getTargetRef()), prefix); } } /** * Writes a subject or object node. * * @param ref * The reference of the subject or object node. * @param subject * True if the node is the subject of a predicate * @throws SAXException */ private void writeNode(Reference reference, boolean subject) throws SAXException { AttributesImpl atts = new AttributesImpl(); if (Link.isBlankRef(reference)) { atts.addAttribute(RDF_SYNTAX, "NodeId", "rdf:NodeId", "text", reference.getTargetRef().toString(true, true)); } else { atts.addAttribute(RDF_SYNTAX, "about", "rdf:about", "text", reference.getTargetRef().toString(true, true)); } try { if (!subject) { this.writer.emptyElement(RDF_SYNTAX, "Description", "rdf:Description", atts); } else { this.writer.startElement(RDF_SYNTAX, "Description", "rdf:Description", atts); } } catch (SAXException e) { org.restlet.Context.getCurrentLogger().warning( "Cannot write the representation of a statement due to: " + e.getMessage()); } } }