blob: cb0fca62e4b052f7f37fdac6b0b8e2e74732d9c7 [file] [log] [blame]
/*
* 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 java.util.StringJoiner;
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 utilities 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();
}
// Worker
public static String strNodes(Node...nodes) {
IndentedLineBuffer sw = new IndentedLineBuffer();
boolean first = true;
for ( Node n : nodes ) {
if ( !first )
sw.append(" ");
first = false;
if ( n == null ) {
sw.append("null");
continue;
}
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(Triple t) {
return displayStrNodes(t.getSubject(), t.getPredicate(), t.getObject());
}
public static String displayStr(Node n) {
return str(n, null, dftPrefixMap);
}
private static String displayStrNodes(Node...nodes) {
StringJoiner sj = new StringJoiner(" ");
for ( Node n : nodes )
sj.add(displayStr(n));
return sj.toString();
}
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, PrefixMap prefixMap) {
return str(n, null, prefixMap);
}
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;
}
}