001/* 002 * Licensed to DuraSpace under one or more contributor license agreements. 003 * See the NOTICE file distributed with this work for additional information 004 * regarding copyright ownership. 005 * 006 * DuraSpace licenses this file to you under the Apache License, 007 * Version 2.0 (the "License"); you may not use this file except in 008 * compliance with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.fcrepo.jena; 019 020import org.apache.jena.atlas.io.AWriter; 021import org.apache.jena.datatypes.RDFDatatype; 022import org.apache.jena.datatypes.xsd.XSDDatatype; 023import org.apache.jena.graph.Node; 024import org.apache.jena.riot.out.NodeFormatterTTL; 025import org.apache.jena.riot.out.NodeToLabel; 026import org.apache.jena.riot.system.PrefixMap; 027import org.apache.jena.riot.system.RiotChars; 028 029/** 030 * @author awoods 031 * @since 2017/01/03 032 */ 033public class FedoraNodeFormatterTTL extends NodeFormatterTTL { 034 035 /** 036 * @param baseIRI 037 * @param prefixMap 038 * @param nodeToLabel 039 */ 040 public FedoraNodeFormatterTTL(final String baseIRI, final PrefixMap prefixMap, final NodeToLabel nodeToLabel) { 041 super(baseIRI, prefixMap, nodeToLabel); 042 } 043 044 /** 045 * @param w 046 * @param n 047 */ 048 @Override 049 public void formatLiteral(final AWriter w, final Node n) { 050 final RDFDatatype dt = n.getLiteralDatatype(); 051 final String lang = n.getLiteralLanguage(); 052 final String lex = n.getLiteralLexicalForm(); 053 054 if (lang != null && !lang.equals("")) { 055 formatLitLang(w, lex, lang); 056 } else if (dt == null) { 057 // RDF 1.0, simple literal. 058 formatLitString(w, lex); 059 // NOTE, Fedora change: remove condition 060// } else if ( JenaRuntime.isRDF11 && dt.equals(XSDDatatype.XSDstring) ) { 061// // RDF 1.1, xsd:string - output as short string. 062// formatLitString(w, lex) ; 063 } else { 064 // Datatype, no language tag, not short string. 065 formatLitDT(w, lex, dt.getURI()); 066 } 067 } 068 069 // NOTE, Fedora change: private -> protected 070 protected static final String dtDecimal = XSDDatatype.XSDdecimal.getURI() ; 071 protected static final String dtInteger = XSDDatatype.XSDinteger.getURI() ; 072 protected static final String dtDouble = XSDDatatype.XSDdouble.getURI() ; 073 074 /** 075 * Write in a short form, e.g. integer. 076 * 077 * @return True if a short form was output else false. 078 */ 079 protected boolean writeLiteralAbbreviated(final AWriter w, final String lex, final String datatypeURI) { 080 if (dtDecimal.equals(datatypeURI)) { 081 if (validDecimal(lex)) { 082 w.print(lex); 083 return true; 084 } 085 } else if (dtInteger.equals(datatypeURI)) { 086 if (validInteger(lex)) { 087 w.print(lex); 088 return true; 089 } 090 } else if (dtDouble.equals(datatypeURI)) { 091 if (validDouble(lex)) { 092 w.print(lex); 093 return true; 094 } 095 // NOTE, Fedora change: Remove condition 096// } else if ( dtBoolean.equals(datatypeURI) ) { 097// // We leave "0" and "1" as-is assumign that if written like that, 098// // there was a reason. 099// if ( lex.equals("true") || lex.equals("false") ) { 100// w.print(lex) ; 101// return true ; 102// } 103 } 104 return false; 105 } 106 107 //******************************************************************** 108 // NOTE, Fedora: Below are added from NodeFormatterTTL without change. 109 //******************************************************************** 110 111 private static boolean validInteger(String lex) { 112 int N = lex.length() ; 113 if ( N == 0 ) 114 return false ; 115 int idx = 0 ; 116 117 idx = skipSign(lex, idx) ; 118 idx = skipDigits(lex, idx) ; 119 return (idx == N) ; 120 } 121 122 private static boolean validDecimal(String lex) { 123 // case : In N3, "." illegal, as is "+." and -." but legal in Turtle. 124 int N = lex.length() ; 125 if ( N <= 1 ) 126 return false ; 127 int idx = 0 ; 128 129 idx = skipSign(lex, idx) ; 130 idx = skipDigits(lex, idx) ; // Maybe none. 131 132 // DOT required. 133 if ( idx >= N ) 134 return false ; 135 136 char ch = lex.charAt(idx) ; 137 if ( ch != '.' ) 138 return false ; 139 idx++ ; 140 // Digit required. 141 if ( idx >= N ) 142 return false ; 143 idx = skipDigits(lex, idx) ; 144 return (idx == N) ; 145 } 146 147 private static boolean validDouble(String lex) { 148 int N = lex.length() ; 149 if ( N == 0 ) 150 return false ; 151 int idx = 0 ; 152 153 // Decimal part (except 12. is legal) 154 155 idx = skipSign(lex, idx) ; 156 157 int idx2 = skipDigits(lex, idx) ; 158 boolean initialDigits = (idx != idx2) ; 159 idx = idx2 ; 160 // Exponent required. 161 if ( idx >= N ) 162 return false ; 163 char ch = lex.charAt(idx) ; 164 if ( ch == '.' ) { 165 idx++ ; 166 if ( idx >= N ) 167 return false ; 168 idx2 = skipDigits(lex, idx) ; 169 boolean trailingDigits = (idx != idx2) ; 170 idx = idx2 ; 171 if ( idx >= N ) 172 return false ; 173 if ( !initialDigits && !trailingDigits ) 174 return false ; 175 } 176 // "e" or "E" 177 ch = lex.charAt(idx) ; 178 if ( ch != 'e' && ch != 'E' ) 179 return false ; 180 idx++ ; 181 if ( idx >= N ) 182 return false ; 183 idx = skipSign(lex, idx) ; 184 if ( idx >= N ) 185 return false ; // At least one digit. 186 idx = skipDigits(lex, idx) ; 187 return (idx == N) ; 188 } 189 190 /** 191 * Skip digits [0-9] and return the index just after the digits, which may 192 * be beyond the length of the string. May skip zero. 193 */ 194 private static int skipDigits(String str, int start) { 195 int N = str.length() ; 196 for (int i = start; i < N; i++) { 197 char ch = str.charAt(i) ; 198 if ( !RiotChars.isDigit(ch) ) 199 return i ; 200 } 201 return N ; 202 } 203 204 /** Skip any plus or minus */ 205 private static int skipSign(String str, int idx) { 206 int N = str.length() ; 207 char ch = str.charAt(idx) ; 208 if ( ch == '+' || ch == '-' ) 209 return idx + 1 ; 210 return idx ; 211 } 212 213}