/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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.apache.jena.riot.writer; import java.io.OutputStream ; import java.util.Objects ; import org.apache.jena.atlas.io.IndentedWriter ; import org.apache.jena.datatypes.xsd.impl.XMLLiteralType ; import org.apache.jena.graph.Node ; import org.apache.jena.graph.Triple ; import org.apache.jena.rdf.model.impl.Util ; import org.apache.jena.riot.RiotException ; import org.apache.jena.riot.lang.ReaderTriX ; import org.apache.jena.riot.lang.TriX ; import org.apache.jena.riot.system.PrefixMap ; import org.apache.jena.riot.system.PrefixMapFactory ; import org.apache.jena.riot.system.StreamRDF ; import org.apache.jena.sparql.core.Quad ; /** Write TriX by streaming. * See {@link TriX} for details. * * @see TriX * @see ReaderTriX * @see WriterTriX */ public class StreamWriterTriX implements StreamRDF { /* * Notes on writing qname: * 1/ Currently disabled in favour of the most regular XML output. * 2/ There is code in write(...,Node,...) to handle it currently commented out. * 3/ Need to write prefixes which in turn needs delaying writing the <TriX> start. */ private static String rdfXMLLiteral = XMLLiteralType.theXMLLiteralType.getURI() ; private IndentedWriter out ; private Node gn = null ; private boolean inGraph = false ; private PrefixMap pmap = PrefixMapFactory.create() ; private int depth = 0 ; // Start/finish count public StreamWriterTriX(OutputStream out) { this.out = new IndentedWriter(out) ; } public StreamWriterTriX(IndentedWriter out) { this.out = out ; } @Override public void start() { if ( depth == 0 ) { StreamWriterTriX.startXML(out) ; // Wirte using the element name from the W3C DTD. StreamWriterTriX.startTag(out, TriX.tagTriX, "xmlns", TriX.NS) ; out.println() ; } depth ++ ; } @Override public void finish() { depth-- ; if ( depth != 0 ) return ; if ( inGraph ) { StreamWriterTriX.endTag(out, TriX.tagGraph) ; out.println() ; } StreamWriterTriX.endTag(out, TriX.tagTriX) ; out.println() ; out.flush() ; } @Override public void base(String base) {} // Ignore. @Override public void prefix(String prefix, String iri) { pmap.add(prefix, iri) ; } @Override public void triple(Triple triple) { if ( inGraph && gn != null ) { StreamWriterTriX.endTag(out, TriX.tagGraph) ; out.println() ; inGraph = false ; } if ( ! inGraph ) { StreamWriterTriX.startTag(out, TriX.tagGraph) ; out.println() ; } inGraph = true ; gn = null ; //end graph? StreamWriterTriX.write(out, triple, pmap) ; } @Override public void quad(Quad quad) { Node g = quad.getGraph() ; if ( g == null || Quad.isDefaultGraph(g) ) { triple(quad.asTriple()) ; return ; } if ( inGraph ) { if ( ! Objects.equals(g, gn) ) { StreamWriterTriX.endTag(out, TriX.tagGraph) ; out.println() ; inGraph = false ; } } if ( ! inGraph ) { StreamWriterTriX.startTag(out, TriX.tagGraph) ; out.println() ; if ( gn == null || ! Quad.isDefaultGraph(gn) ) { gn = quad.getGraph() ; StreamWriterTriX.write(out, gn, pmap) ; } } inGraph = true ; gn = g ; StreamWriterTriX.write(out, quad.asTriple(), pmap) ; } static void write(IndentedWriter out, Triple triple, PrefixMap prefixMap) { out.println("<triple>") ; out.incIndent(); write(out, triple.getSubject(), prefixMap) ; write(out, triple.getPredicate(), prefixMap) ; write(out, triple.getObject(), prefixMap) ; out.decIndent(); out.println("</triple>") ; } static void write(IndentedWriter out, Node node, PrefixMap prefixMap) { if ( node.isURI() ) { String uri = node.getURI() ; // The decent use of TriX is very regular output as we do not use <qname>. // See Notes above. // if ( false && prefixMap != null ) { // String abbrev = prefixMap.abbreviate(uri) ; // if ( abbrev != null ) { // startTag(out, TriX.tagQName) ; // writeText(out, abbrev) ; // endTag(out, TriX.tagQName) ; // out.println() ; // return ; // } // } startTag(out, TriX.tagURI) ; writeText(out, node.getURI()) ; endTag(out, TriX.tagURI) ; out.println() ; return ; } if ( node.isBlank() ) { startTag(out, TriX.tagId) ; writeText(out, node.getBlankNodeLabel()) ; endTag(out, TriX.tagId) ; out.println() ; return ; } if ( node.isLiteral() ) { // RDF 1.1 String lang = node.getLiteralLanguage() ; if ( lang != null && lang.isEmpty() ) lang = null ; String dt = node.getLiteralDatatypeURI() ; if ( lang != null ) { startTag(out, TriX.tagPlainLiteral, "xml:lang", lang) ; writeTextNoIndent(out, node.getLiteralLexicalForm()) ; endTag(out, TriX.tagPlainLiteral) ; out.println() ; return ; } if ( dt == null ) { startTag(out, TriX.tagPlainLiteral) ; writeTextNoIndent(out, node.getLiteralLexicalForm()) ; endTag(out, TriX.tagPlainLiteral) ; out.println() ; return ; } // The case of ( lang == null && dt != null ) startTag(out, TriX.tagTypedLiteral, TriX.attrDatatype, dt) ; String lex = node.getLiteralLexicalForm() ; if ( rdfXMLLiteral.equals(dt) ) { int x = out.getAbsoluteIndent() ; out.setAbsoluteIndent(0) ; out.print(lex) ; // Write raw out.setAbsoluteIndent(x) ; } else writeTextNoIndent(out, lex) ; endTag(out, TriX.tagTypedLiteral) ; out.println() ; return ; } throw new RiotException("Not a concrete node: "+node) ; } static void writeText(IndentedWriter out, String string) { string = Util.substituteEntitiesInElementContent(string) ; out.print(string) ; } static void writeTextNoIndent(IndentedWriter out, String string) { int x = out.getAbsoluteIndent() ; out.setAbsoluteIndent(0) ; writeText(out, string) ; out.setAbsoluteIndent(x) ; } static void startXML(IndentedWriter out) { //out.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>") ; } static void startTag(IndentedWriter out, String text) { out.print("<") ; out.print(text) ; out.print(">") ; out.incIndent(); } static void startTag(IndentedWriter out, String text, String attr, String attrValue) { out.print("<") ; out.print(text) ; out.print(" ") ; out.print(attr) ; out.print("=\"") ; attrValue = Util.substituteStandardEntities(attrValue) ; out.print(attrValue) ; out.print("\"") ; out.print(">") ; out.incIndent(); } static void endTag(IndentedWriter out, String text) { out.decIndent(); out.print("</") ; out.print(text) ; out.print(">") ; } }