/* * 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.out; import java.net.MalformedURLException ; import java.util.Map ; import org.apache.jena.atlas.io.IndentedLineBuffer ; import org.apache.jena.atlas.io.IndentedWriter ; import org.apache.jena.atlas.lib.Bytes ; import org.apache.jena.atlas.lib.Chars ; import org.apache.jena.graph.Node ; import org.apache.jena.graph.Triple ; import org.apache.jena.iri.IRI ; import org.apache.jena.iri.IRIRelativize ; import org.apache.jena.rdf.model.RDFNode ; import org.apache.jena.riot.system.* ; import org.apache.jena.shared.PrefixMapping ; import org.apache.jena.sparql.ARQConstants ; import org.apache.jena.sparql.core.Quad ; /** Presentation utilitiles for Nodes, Triples, Quads and more. * <p> * Methods <tt>str</tt> generate a reparsable string. * <p> * Methods <tt>displayStr</tt> do not guarantee a reparsable string * e.g. may use abbreviations or common prefixes. */ public class NodeFmtLib { // Replaces FmtUtils // See OutputLangUtils. // See and use EscapeStr private static final NodeFormatter plainFormatter = new NodeFormatterNT() ; private static PrefixMap dftPrefixMap = PrefixMapFactory.create() ; static { PrefixMapping pm = ARQConstants.getGlobalPrefixMap() ; Map<String, String> map = pm.getNsPrefixMap() ; for ( Map.Entry<String, String> e : map.entrySet() ) dftPrefixMap.add(e.getKey(), e.getValue() ) ; } public static String str(Triple t) { return strNodes(t.getSubject(), t.getPredicate(),t.getObject()) ; } public static String str(Quad q) { return strNodes(q.getGraph(), q.getSubject(), q.getPredicate(), q.getObject()) ; } public static String str(Node n) { IndentedLineBuffer sw = new IndentedLineBuffer() ; str(sw, n) ; return sw.toString() ; } /** A displayable string for an RDFNode. Includes common abbreviations */ public static String displayStr(RDFNode obj) { return displayStr(obj.asNode()) ; } public static String displayStr(Node n) { return str(n, null, dftPrefixMap) ; } // Worker public static String strNodes(Node ... nodes) { IndentedLineBuffer sw = new IndentedLineBuffer() ; boolean first = true ; for ( Node n : nodes ) { if ( ! first ) sw.append(" ") ; first = false ; str(sw, n) ; } return sw.toString() ; } //public static String displayStr(Node n) { return serialize(n) ; } public static void str(IndentedWriter w, Node n) { serialize(w, n, null, null) ; } public static String str(Node n, Prologue prologue) { return str(n, prologue.getBaseURI(), prologue.getPrefixMap()) ; } public static String str(Node n, String base, PrefixMap prefixMap) { IndentedLineBuffer sw = new IndentedLineBuffer() ; serialize(sw, n, base, prefixMap) ; return sw.toString() ; } public static void serialize(IndentedWriter w, Node n, Prologue prologue) { serialize(w, n, prologue.getBaseURI(), prologue.getPrefixMap()) ; } public static void serialize(IndentedWriter w, Node n, String base, PrefixMap prefixMap) { NodeFormatter formatter ; if ( base == null && prefixMap == null ) formatter = plainFormatter ; else formatter = new NodeFormatterTTL(base, prefixMap) ; formatter.format(w, n) ; } // ---- Blank node labels. // Strict N-triples only allows [A-Za-z][A-Za-z0-9] static char encodeMarkerChar = 'X' ; // These two form a pair to convert bNode labels to a safe (i.e. legal N-triples form) and back agains. // Encoding is: // 1 - Add a Letter // 2 - Hexify, as Xnn, anything outside ASCII A-Za-z0-9 // 3 - X is encoded as XX private static char LabelLeadingLetter = 'B' ; public static String encodeBNodeLabel(String label) { StringBuilder buff = new StringBuilder() ; // Must be at least one char and not a digit. buff.append(LabelLeadingLetter) ; for ( int i = 0 ; i < label.length() ; i++ ) { char ch = label.charAt(i) ; if ( ch == encodeMarkerChar ) { buff.append(ch) ; buff.append(ch) ; } else if ( RiotChars.isA2ZN(ch) ) buff.append(ch) ; else Chars.encodeAsHex(buff, encodeMarkerChar, ch) ; } return buff.toString() ; } // Assumes that blank nodes only have characters in the range of 0-255 public static String decodeBNodeLabel(String label) { StringBuilder buffer = new StringBuilder() ; if ( label.charAt(0) != LabelLeadingLetter ) return label ; // Skip first. for ( int i = 1; i < label.length(); i++ ) { char ch = label.charAt(i) ; if ( ch != encodeMarkerChar ) { buffer.append(ch) ; } else { // Maybe XX or Xnn. char ch2 = label.charAt(i+1) ; if ( ch2 == encodeMarkerChar ) { i++ ; buffer.append(ch) ; continue ; } // Xnn i++ ; char hiC = label.charAt(i) ; int hi = Bytes.hexCharToInt(hiC) ; i++ ; char loC = label.charAt(i) ; int lo = Bytes.hexCharToInt(loC) ; int combined = ((hi << 4) | lo) ; buffer.append((char) combined) ; } } return buffer.toString() ; } // ---- Relative URIs. static private int relFlags = IRIRelativize.SAMEDOCUMENT | IRIRelativize.CHILD ; static public String abbrevByBase(String uri, String base) { if ( base == null ) return null ; IRI baseIRI = IRIResolver.iriFactory.construct(base) ; IRI rel = baseIRI.relativize(uri, relFlags) ; String r = null ; try { r = rel.toASCIIString() ; } catch (MalformedURLException ex) { r = rel.toString() ; } return r ; } }