GH-2387: Update prefix namespace rule to Turtle
diff --git a/jena-arq/src/main/java/org/apache/jena/riot/system/Prefixes.java b/jena-arq/src/main/java/org/apache/jena/riot/system/Prefixes.java
index 162d64c..57a9b16 100644
--- a/jena-arq/src/main/java/org/apache/jena/riot/system/Prefixes.java
+++ b/jena-arq/src/main/java/org/apache/jena/riot/system/Prefixes.java
@@ -31,7 +31,7 @@
 import org.apache.jena.shared.PrefixMapping;
 import org.apache.jena.sparql.core.Quad;
 import org.apache.jena.sparql.graph.PrefixMappingAdapter;
-
+import org.apache.jena.util.XML11Char;
 
 /**
  * Functions related to {@link PrefixMap}.
@@ -92,23 +92,6 @@
     private static final String dftUri1           = Quad.defaultGraphIRI.getURI();
     private static final String dftUri2           = Quad.defaultGraphNodeGenerated.getURI();
 
-    // Unused : datasets have prefix sets and all graphs for the dataset use that prefix set.
-//    /** Is this a name for the default graph prefix set? */
-//    public static boolean isDftGraph(String graphName) {
-//        return graphName == null
-//               //|| graphName.equals(dftGraphPrefixSet)
-//               || graphName.equals(dftUri1) || graphName.equals(dftUri2);
-//    }
-//
-//    /** Is this a name node for the default graph prefix set? */
-//    public static boolean isDftGraph(Node graphName) {
-//        if ( !graphName.isURI() )
-//            return false;
-//        return graphName == null
-//            //|| graphName.equals(nodeDefaultGraph)
-//            || Quad.isDefaultGraph(graphName);
-//    }
-
     /**
      * Canonical prefix - remove a trailing ":". The return is not null.
      */
@@ -122,9 +105,27 @@
     }
 
     /**
+     * Test whether a prefix string is legal for Turtle.
+     * Turtle grammar rule
+     * <a href="https://www.w3.org/TR/rdf-turtle/#grammar-production-PN_PREFIX">PN_PREFIX</a>.
+     * This rule is the same as the XML 1.1 QName namespace production
+     * with the addition of allowing the empty string.
+     * A "prefix" does not include any trailing ":" character.
+     */
+    public static boolean isLegalPrefix(String prefix) {
+        Objects.requireNonNull(prefix, "Prefix argument is null");
+        if ( prefix.isEmpty() )
+            return true;
+        String prefixStr = prefix;
+        if ( prefix.endsWith(":") )
+            prefixStr = prefix.substring(prefix.length() - 1);
+        return XML11Char.isXML11ValidNCName(prefixStr);
+    }
+
+    /**
      * Reverse lookup of URI to a prefix. General implementation by scanning the
-     * {@link PrefixMap}. Returns a prefix if found or null. If several prefixes for
-     * the same URI, returns one at random.
+     * {@link PrefixMap}. Returns a prefix if found or null. If there are
+     * several prefixes for the same URI, returns one at random.
      */
     public static String findByURI(PrefixMap pmap, String uriStr) {
         return pmap.getMapping().entrySet().stream()
diff --git a/jena-arq/src/main/java/org/apache/jena/sparql/graph/PrefixMappingBase.java b/jena-arq/src/main/java/org/apache/jena/sparql/graph/PrefixMappingBase.java
index d52b18f..541df78 100644
--- a/jena-arq/src/main/java/org/apache/jena/sparql/graph/PrefixMappingBase.java
+++ b/jena-arq/src/main/java/org/apache/jena/sparql/graph/PrefixMappingBase.java
@@ -24,9 +24,9 @@
 import java.util.StringJoiner;
 import java.util.function.BiConsumer;
 
+import org.apache.jena.riot.system.Prefixes;
 import org.apache.jena.shared.PrefixMapping;
 import org.apache.jena.util.SplitIRI;
-import org.apache.jena.util.XMLChar;
 
 /**
  * Framework for implementing {@link PrefixMapping}. It is stateless (unlike
@@ -65,9 +65,6 @@
      * Database backed ones typically don't.
      */
 
-    /** Whether to apply XML 1.0 prefix restrictions. */
-    private static final boolean XML_PREFIX_RULES = true;
-
     protected PrefixMappingBase() {}
 
     // The storage operations of an implementation.
@@ -143,18 +140,14 @@
     }
 
     /**
-     *
-     * <p>
-     * See also {@link #qnameFor}.
+     * Check for legal prefix. If not, throw
+     * {@link org.apache.jena.shared.PrefixMapping.IllegalPrefixException}
      */
-    public static void checkLegalPrefix(String prefix) {
+    private static void checkLegalPrefix(String prefix) {
         if ( prefix == null )
             throw new PrefixMapping.IllegalPrefixException("null for prefix");
-        if ( XML_PREFIX_RULES ) {
-            // For Full compatibility with PrefixMappingImpl.
-            if ( prefix.length() > 0 && !XMLChar.isValidNCName(prefix) )
-                throw new PrefixMapping.IllegalPrefixException(prefix);
-        }
+        if ( ! Prefixes.isLegalPrefix(prefix) )
+            throw new PrefixMapping.IllegalPrefixException(prefix);
     }
 
     @Override
@@ -231,9 +224,7 @@
         // This operation applies a fixed splitting rule and
         // does not search for other possibilities.
         // See findMapping.
-        int split = XML_PREFIX_RULES
-                ? SplitIRI.splitXML(uri)     // The longest XML NCName at the end of the URI
-                : SplitIRI.splitpoint(uri);  // Split at last "#", "/" (or ":" for urn's).
+        int split = SplitIRI.splitXML(uri); // Split by XML rules (no digit starting the local part.)
         String ns = uri.substring(0, split);
         String local = uri.substring(split);
         if ( local.equals("") )
diff --git a/jena-arq/src/test/java/org/apache/jena/sparql/graph/TestGraphUnionRead.java b/jena-arq/src/test/java/org/apache/jena/sparql/graph/TestGraphUnionRead.java
index a447c46..8777606 100644
--- a/jena-arq/src/test/java/org/apache/jena/sparql/graph/TestGraphUnionRead.java
+++ b/jena-arq/src/test/java/org/apache/jena/sparql/graph/TestGraphUnionRead.java
@@ -142,8 +142,8 @@
 
     @Test
     public void gr_union_prefixes_bad_PrefixMapping() {
-        // Turtle-valid, RDF/XML invalid prefix.
-        Graph graph = setupPrefixGraph("😀", "http://example/");
+        // Not valid.
+        Graph graph = setupPrefixGraph("-", "http://example/");
 
         // Test : Must be createGeneral
         DatasetGraph dsg = DatasetGraphFactory.createGeneral();
diff --git a/jena-arq/src/test/java/org/apache/jena/system/TS_System.java b/jena-arq/src/test/java/org/apache/jena/system/TS_System.java
index 146b1c9..b40a228 100644
--- a/jena-arq/src/test/java/org/apache/jena/system/TS_System.java
+++ b/jena-arq/src/test/java/org/apache/jena/system/TS_System.java
@@ -31,6 +31,8 @@
     , TestTxnThread.class
     , TestJenaTitanium.class
     , TestReadXML.class
+    , TestPrefixes.class
+    , TestPrefixLib.class
     , TestRDFStarTranslation.class
 })
 
diff --git a/jena-db/jena-dboe-storage/src/test/java/org/apache/jena/dboe/storage/prefixes/TestPrefixLib.java b/jena-arq/src/test/java/org/apache/jena/system/TestPrefixLib.java
similarity index 97%
rename from jena-db/jena-dboe-storage/src/test/java/org/apache/jena/dboe/storage/prefixes/TestPrefixLib.java
rename to jena-arq/src/test/java/org/apache/jena/system/TestPrefixLib.java
index 495fa33..e5afbb0 100644
--- a/jena-db/jena-dboe-storage/src/test/java/org/apache/jena/dboe/storage/prefixes/TestPrefixLib.java
+++ b/jena-arq/src/test/java/org/apache/jena/system/TestPrefixLib.java
@@ -16,7 +16,7 @@
  * limitations under the License.
  */
 
-package org.apache.jena.dboe.storage.prefixes;
+package org.apache.jena.system;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
diff --git a/jena-arq/src/test/java/org/apache/jena/system/TestPrefixes.java b/jena-arq/src/test/java/org/apache/jena/system/TestPrefixes.java
new file mode 100644
index 0000000..5cd2d06
--- /dev/null
+++ b/jena-arq/src/test/java/org/apache/jena/system/TestPrefixes.java
@@ -0,0 +1,72 @@
+/*
+ * 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.system;
+
+import static org.junit.Assert.*;
+
+import org.apache.jena.riot.system.Prefixes;
+import org.junit.Test;
+
+public class TestPrefixes {
+
+    // U+1F600 is 😀 "grinning face"
+    // U+1F631 is 😱 "face screaming in fear"
+    // Create carefully to make sure the exact Java characters are used.
+    private static String emoji1 = new String(Character.toChars(0x1F600));
+    private static String emoji2 = new String(Character.toChars(0x1F631));
+
+    @Test public void prefixes_good_01() { good(""); }
+
+    @Test public void prefixes_good_02() { good("abc"); }
+
+    @Test public void prefixes_good_03() { good("a-bc"); }
+
+    @Test public void prefixes_good_04() { good("a.b.c"); }
+
+    @Test public void prefixes_good_05() { good("a0117"); }
+
+    @Test public void prefixes_good_06() { good(emoji1); }
+
+    @Test public void prefixes_good_07() { good(emoji1+"."+emoji2); }
+
+    @Test public void prefixes_bad_01() { bad("-"); }
+
+    @Test public void prefixes_bad_02() { bad("."); }
+
+    @Test public void prefixes_bad_03() { bad("9ab"); }
+
+    @Test public void prefixes_bad_04() { bad("<>"); }
+
+    @Test public void prefixes_bad_05() { bad(":"); }
+
+    @Test public void prefixes_bad_06() { bad("ex:"); }
+
+    @Test(expected=NullPointerException.class)
+    public void prefixes_bad_NPE() { bad(null); }
+
+    // ----
+
+    private static void good(String string) {
+        assertTrue(Prefixes.isLegalPrefix(string));
+    }
+
+    private static void bad(String string) {
+        assertFalse(Prefixes.isLegalPrefix(string));
+    }
+}
diff --git a/jena-core/src/main/java/org/apache/jena/rdf/model/impl/ModelCom.java b/jena-core/src/main/java/org/apache/jena/rdf/model/impl/ModelCom.java
index 7d5602d..3920fb7 100644
--- a/jena-core/src/main/java/org/apache/jena/rdf/model/impl/ModelCom.java
+++ b/jena-core/src/main/java/org/apache/jena/rdf/model/impl/ModelCom.java
@@ -18,8 +18,6 @@
 
 package org.apache.jena.rdf.model.impl;
 
-import static org.apache.jena.shared.impl.PrefixMappingImpl.isNiceURI;
-
 import java.io.*;
 import java.net.URL;
 import java.util.*;
@@ -955,10 +953,7 @@
             Set<String> values = e.getValue();
             Set<String> niceValues = CollectionFactory.createHashedSet();
             for ( String uri : values ) {
-                @SuppressWarnings("deprecation")
-                boolean b = isNiceURI(uri);
-                if ( b )
-                    niceValues.add(uri);
+                niceValues.add(uri);
             }
             if ( niceValues.size() == 1 ) {
                 pm.setNsPrefix(key, niceValues.iterator().next());
diff --git a/jena-core/src/main/java/org/apache/jena/rdfxml/xmlinput0/JenaHandler.java b/jena-core/src/main/java/org/apache/jena/rdfxml/xmlinput0/JenaHandler.java
index feafcec..fdfea1b 100644
--- a/jena-core/src/main/java/org/apache/jena/rdfxml/xmlinput0/JenaHandler.java
+++ b/jena-core/src/main/java/org/apache/jena/rdfxml/xmlinput0/JenaHandler.java
@@ -25,7 +25,7 @@
 import org.apache.jena.rdfxml.xmlinput0.impl.ARPSaxErrorHandler;
 import org.apache.jena.shared.JenaException ;
 import org.apache.jena.shared.PrefixMapping ;
-import org.apache.jena.shared.impl.PrefixMappingImpl ;
+import org.apache.jena.util.XMLChar;
 
 final class JenaHandler extends ARPSaxErrorHandler implements StatementHandler, NamespaceHandler
     {
@@ -92,14 +92,22 @@
         }
     }
 
-    @Override
-    @SuppressWarnings("deprecation")
-    public void startPrefixMapping( String prefix, String uri )
-        {
-        if (PrefixMappingImpl.isNiceURI( uri )) prefixMapping.setNsPrefix( prefix, uri );
-        }
+    /**
+     * Test whether a URI is "nice" for RDF/XML (ends in a non-NCName character).
+     */
+    static boolean isNiceURI(String uri) {
+        if ( uri.equals("") )
+            return false;
+        char last = uri.charAt(uri.length() - 1);
+        return !XMLChar.isNCName(last);
+    }
 
     @Override
-    public void endPrefixMapping( String prefix )
-        {}
+    public void startPrefixMapping(String prefix, String uri) {
+        if ( isNiceURI(uri) )
+            prefixMapping.setNsPrefix(prefix, uri);
+    }
+
+    @Override
+    public void endPrefixMapping(String prefix) {}
     }
diff --git a/jena-core/src/main/java/org/apache/jena/rdfxml/xmlinput1/JenaHandler.java b/jena-core/src/main/java/org/apache/jena/rdfxml/xmlinput1/JenaHandler.java
index dd16ff8..97d7ff0 100644
--- a/jena-core/src/main/java/org/apache/jena/rdfxml/xmlinput1/JenaHandler.java
+++ b/jena-core/src/main/java/org/apache/jena/rdfxml/xmlinput1/JenaHandler.java
@@ -25,7 +25,7 @@
 import org.apache.jena.rdfxml.xmlinput1.impl.ARPSaxErrorHandler;
 import org.apache.jena.shared.JenaException ;
 import org.apache.jena.shared.PrefixMapping ;
-import org.apache.jena.shared.impl.PrefixMappingImpl ;
+import org.apache.jena.util.XMLChar;
 
 /**
  * Interface between Jena and ARP.
@@ -89,10 +89,19 @@
         }
     }
 
+    /**
+     * Test whether a URI is "nice" for RDF/XML (ends in a non-NCName character).
+     */
+    static boolean isNiceURI(String uri) {
+        if ( uri.equals("") )
+            return false;
+        char last = uri.charAt(uri.length() - 1);
+        return !XMLChar.isNCName(last);
+    }
+
     @Override
-    @SuppressWarnings("deprecation")
     public void startPrefixMapping(String prefix, String uri) {
-        if ( PrefixMappingImpl.isNiceURI(uri) )
+        if ( isNiceURI(uri) )
             prefixMapping.setNsPrefix(prefix, uri);
     }
 
diff --git a/jena-core/src/main/java/org/apache/jena/rdfxml/xmloutput/impl/BaseXMLWriter.java b/jena-core/src/main/java/org/apache/jena/rdfxml/xmloutput/impl/BaseXMLWriter.java
index f3c90e3..9294e2d 100644
--- a/jena-core/src/main/java/org/apache/jena/rdfxml/xmloutput/impl/BaseXMLWriter.java
+++ b/jena-core/src/main/java/org/apache/jena/rdfxml/xmloutput/impl/BaseXMLWriter.java
@@ -39,7 +39,6 @@
 import org.apache.jena.shared.* ;
 import org.apache.jena.util.CharEncoding ;
 import org.apache.jena.util.FileUtils ;
-import org.apache.jena.util.SplitIRI;
 import org.apache.jena.util.XMLChar;
 import org.apache.jena.vocabulary.* ;
 import org.slf4j.Logger ;
@@ -373,7 +372,7 @@
 	}
 
 	String splitTag(String uriref, int type) {
-		int split = SplitIRI.splitXML( uriref );
+		int split = SplitRDFXML.splitXML10( uriref );
 		if (split == uriref.length()) throw new InvalidPropertyURIException( uriref );
 		return tag( uriref.substring( 0, split ), uriref.substring( split ), type, true );
     }
@@ -491,7 +490,7 @@
         if (!showDoctypeDeclaration.booleanValue())
             return attributeQuoted( substituted );
         else {
-            int split = SplitIRI.splitXML( substituted );
+            int split = SplitRDFXML.splitXML10( substituted );
             String namespace = substituted.substring(  0, split );
             String prefix = modelPrefixMapping.getNsURIPrefix( namespace );
             return prefix == null || isPredefinedEntityName( prefix )
@@ -865,7 +864,6 @@
         return false;
     }
 
-
     static private String flags2str(int f) {
 	StringBuffer oldValue = new StringBuffer(64);
 	if ( (f&IRIRelativize.SAMEDOCUMENT)!=0 )
diff --git a/jena-core/src/main/java/org/apache/jena/rdfxml/xmloutput/impl/RDFXML_Basic.java b/jena-core/src/main/java/org/apache/jena/rdfxml/xmloutput/impl/RDFXML_Basic.java
index a6b85da..4a186bc 100644
--- a/jena-core/src/main/java/org/apache/jena/rdfxml/xmloutput/impl/RDFXML_Basic.java
+++ b/jena-core/src/main/java/org/apache/jena/rdfxml/xmloutput/impl/RDFXML_Basic.java
@@ -95,8 +95,8 @@
 		writer.print(space+space+
 			"<"
 				+ startElementTag(
-					predicate.getNameSpace(),
-					predicate.getLocalName()));
+					SplitRDFXML.namespace(predicate),
+					SplitRDFXML.localname(predicate)));
 
 		if (object instanceof Resource) {
 			writer.print(" ");
@@ -106,7 +106,7 @@
 			writeLiteral((Literal) object, writer);
 			writer.println(
 				"</"
-					+ endElementTag(predicate.getNameSpace(), predicate.getLocalName())
+					+ endElementTag(SplitRDFXML.namespace(predicate), SplitRDFXML.localname(predicate))
 					+ ">");
 		}
 	}
diff --git a/jena-core/src/main/java/org/apache/jena/rdfxml/xmloutput/impl/SplitRDFXML.java b/jena-core/src/main/java/org/apache/jena/rdfxml/xmloutput/impl/SplitRDFXML.java
new file mode 100644
index 0000000..687c198
--- /dev/null
+++ b/jena-core/src/main/java/org/apache/jena/rdfxml/xmloutput/impl/SplitRDFXML.java
@@ -0,0 +1,70 @@
+/*
+ * 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.rdfxml.xmloutput.impl;
+
+import org.apache.jena.rdf.model.Resource;
+import org.apache.jena.util.SplitIRI;
+
+/*
+ * Utilities for RDF/XML writing.
+ * Use these functions and don't call SplitIRI,
+ * Resource.getNameSpace or Resource.getLocalName
+ * directly. The Resource methods call SplitIRI.
+ *
+ * The functions here will continue to provide XML 1.0.
+ */
+class SplitRDFXML {
+
+    @SuppressWarnings("deprecation")
+    static int splitXML10(String uri) {
+        return SplitIRI.splitXML10(uri);
+    }
+
+    static String namespace(Resource resource) {
+        return namespace(resource.getURI());
+    }
+
+    static String namespace(String uriStr) {
+        return namespaceXML10(uriStr);
+    }
+
+    static String localname(Resource resource) {
+        return localname(resource.getURI());
+    }
+
+    static String localname(String uriStr) {
+        return localnameXML10(uriStr);
+    }
+
+    /**
+     * Namespace, according to XML 1.0 qname rules.
+     * Use with {@link #localnameXML}.
+     */
+    private static String namespaceXML10(String string) {
+        int i = splitXML10(string);
+        return string.substring(0, i);
+    }
+
+    /** Localname, according to XML 1.0 qname rules. */
+    private  static String localnameXML10(String string) {
+        int i = splitXML10(string);
+        return string.substring(i);
+    }
+
+}
diff --git a/jena-core/src/main/java/org/apache/jena/rdfxml/xmloutput/impl/Unparser.java b/jena-core/src/main/java/org/apache/jena/rdfxml/xmloutput/impl/Unparser.java
index 50722fc..f36cbfe 100644
--- a/jena-core/src/main/java/org/apache/jena/rdfxml/xmloutput/impl/Unparser.java
+++ b/jena-core/src/main/java/org/apache/jena/rdfxml/xmloutput/impl/Unparser.java
@@ -127,7 +127,6 @@
 import org.apache.jena.shared.BrokenException ;
 import org.apache.jena.shared.JenaException ;
 import org.apache.jena.shared.PropertyNotFoundException ;
-import org.apache.jena.util.SplitIRI;
 import org.apache.jena.util.XMLChar;
 import org.apache.jena.util.iterator.* ;
 import org.apache.jena.vocabulary.RDF ;
@@ -1179,7 +1178,7 @@
             throw new BrokenException("Internal error: getNameSpace(bNode)");
         }
         String uri = r.getURI();
-        int split = SplitIRI.splitXML(uri);
+        int split = SplitRDFXML.splitXML10(uri);
         return uri.substring(0, split);
     }
 
@@ -1211,13 +1210,12 @@
 
     private String getXMLLocalName(Resource r) {
         if (r.isAnon()) {
-            logger.error("Internal error - giving up - Unparser.getLocalName");
-            throw new BrokenException("Internal error: getLocalName(bNode)");
+            logger.error("Internal error - giving up - Unparser.getXMLLocalName");
+            throw new BrokenException("Internal error: getXMLLocalName(bNode)");
         }
         String uri = r.getURI();
-        int split = SplitIRI.splitXML(uri);
+        int split = SplitRDFXML.splitXML10(uri);
         return uri.substring(split);
-
     }
 
     /**
@@ -1497,7 +1495,7 @@
         // Only allow resources with namespace and fragment ID
         String uri = ((Resource) n).getURI();
 
-        int split = SplitIRI.splitXML(uri);
+        int split = SplitRDFXML.splitXML10(uri);
         if (split == 0 || split == uri.length())
             return -1;
         return split;
diff --git a/jena-core/src/main/java/org/apache/jena/shared/impl/PrefixMappingImpl.java b/jena-core/src/main/java/org/apache/jena/shared/impl/PrefixMappingImpl.java
index 7ec8555..6a3e31e 100644
--- a/jena-core/src/main/java/org/apache/jena/shared/impl/PrefixMappingImpl.java
+++ b/jena-core/src/main/java/org/apache/jena/shared/impl/PrefixMappingImpl.java
@@ -27,7 +27,7 @@
 import org.apache.jena.shared.PrefixMapping ;
 import org.apache.jena.util.CollectionFactory ;
 import org.apache.jena.util.SplitIRI;
-import org.apache.jena.util.XMLChar;
+import org.apache.jena.util.XML11Char;
 
 /**
     An implementation of PrefixMapping. The mappings are stored in a pair
@@ -111,30 +111,34 @@
             throw new JenaLockedException(this);
     }
 
+    // Is this suitable for use as a prefix.
+    // Turtle does not have the XML QName restrictions.
     private void checkProperURI(String uri) {
-        // suppressed by popular demand.
-        // if (!isNiceURI( uri )) throw new NamespaceEndsWithNameCharException( uri
-        // );
+//        if ( !isNiceURI(uri) )
+//            throw new NamespaceEndsWithNameCharException(uri);
     }
 
     /**
      * Checks that a prefix is "legal" - it must be a valid XML NCName.
+     * Jena 5.1.0 loosen the test from XML 1.0 to XML 1.1 NCName
+     * which aligns with Turtle.
      */
     private void checkLegalPrefix(String prefix) {
-        if ( prefix.length() > 0 && !XMLChar.isValidNCName(prefix) )
+        if ( prefix.length() > 0 && !XML11Char.isXML11ValidNCName(prefix) )
             throw new PrefixMapping.IllegalPrefixException(prefix);
     }
 
     /**
-     * Test whether a URI is "nice" for RDF/XML (ends in a non-NCName character).
+     * Test whether a URI is "nice" for RDF/XML (ends in a non-NCName character according to XML 1.0).
      * @deprecated To be removed.
      */
     @Deprecated
     public static boolean isNiceURI(String uri) {
+        // Not used in Jena anymore.
         if ( uri.equals("") )
             return false;
         char last = uri.charAt(uri.length() - 1);
-        return !XMLChar.isNCName(last);
+        return !org.apache.jena.util.XMLChar.isNCName(last);
     }
 
     /**
@@ -165,10 +169,10 @@
     }
 
     /**
-     * Add the bindings in the prefixToURI to our own. This will fail with a
-     * ClassCastException if any key or value is not a String; we make no guarantees
-     * about order or completeness if this happens. It will fail with an
-     * IllegalPrefixException if any prefix is illegal; similar provisos apply.
+     * Add the bindings in the prefixToURI to our own.
+     * <p>
+     * It will fail with an IllegalPrefixException if any prefix is illegal; we make
+     * no guarantees about order or completeness if this happens.
      *
      * @param other the Map whose bindings we are to add to this.
      */
diff --git a/jena-core/src/main/java/org/apache/jena/util/SplitIRI.java b/jena-core/src/main/java/org/apache/jena/util/SplitIRI.java
index fcc3e7d..aba18e6 100644
--- a/jena-core/src/main/java/org/apache/jena/util/SplitIRI.java
+++ b/jena-core/src/main/java/org/apache/jena/util/SplitIRI.java
@@ -20,7 +20,6 @@
 
 import java.util.Objects;
 
-import org.apache.jena.atlas.lib.StrUtils;
 import org.apache.jena.graph.Node;
 //Has copies of    import org.apache.jena.riot.system.RiotChars;
 
@@ -47,8 +46,6 @@
  * provide a strict Turtle split, if possible;
  * the local name is escaped if necessary.
  * {@link #namespaceTTL} can be used to build a set of prefix mappings.
- * {@link #localnameTTLNoEsc} is the same as {@link #localnameTTL}
- * without the escaping applied.
  * <p>
  * The functions {@link #namespaceXML} and {@link #localnameXML}
  * apply the rules for XML qnames.
@@ -111,23 +108,6 @@
         return escape_PN_LOCAL_ESC(x);
     }
 
-    /**
-     * Calculate a localname - enforce legal Turtle
-     * without applying the escape PN_LOCAL_ESC.
-     * Return "" for 'no split'
-     * Check for final '.' - if present, return "".
-     */
-    public static String localnameTTLNoEsc(String string) {
-        String x = localname(string);
-        if ( x.isEmpty())
-            return x;
-        char lastChar = StrUtils.lastChar(x);
-        if ( lastChar == '.' )
-            // No legal localname.
-            return "";
-        return x;
-    }
-
     private static String escape_PN_LOCAL_ESC(String x) {
         // Assume that escapes are rare so scan once to make sure there
         // is work to do then scan again doing the work.
@@ -290,31 +270,31 @@
         return /*RiotChars.*/isHexChar(uri.charAt(i));
     }
 
-    // Assuming legal URIs, there is no work to be done
-    // for %XX.  If illegal (e.g. %X), the best we can do
-    // is not mess them up.
-    /*
-        // %  - just need to check that it is followed by two hex.
-        if ( ch == '%' ) {
-            if ( i+2 >= uri.length() ) {
-                // Too short
-                return -1;
-            }
-            if ( ! checkhex(uri, i+1) || ! checkhex(uri, i+2) )
-                return -1;
-        }
-
-     */
     /**
-     * Split point, according to XML qname rules.
-     * This is the longest NCName at the end of the uri.
+     * Split point, according to XML 1.0 qname rules.
+     * This is the longest XML 1.0 NCName at the end of the uri.
      * Return a split at the end of the string if there is no match
      * (e.g. the URI string ends in '/' or '#').
      */
-    public static int splitXML(String string) { return splitNamespaceXML(string); }
+    public static int splitXML(String string) { return splitXML11(string); }
 
     /**
-     * Namespace, according to XML qname rules.
+     * splitXML with local stricter XML 1.0 rules (only single Java characters)
+     * @deprecated Retained as a record of previous split handling.
+     */
+    @Deprecated
+    public static int splitXML10(String string) { return splitNamespaceXML10(string); }
+
+    /**
+     * Split point, according to XML 1.1 qname rules.
+     * This is the longest XML 1.1 NCName at the end of the uri.
+     * Return a split at the end of the string if there is no match
+     * (e.g. the URI string ends in '/' or '#').
+     */
+    private static int splitXML11(String string) { return splitNamespaceXML11(string); }
+
+    /**
+     * Namespace, according to XML 1.0 qname rules.
      * Use with {@link #localnameXML}.
      */
     public static String namespaceXML(String string) {
@@ -322,7 +302,7 @@
         return string.substring(0, i);
     }
 
-    /** Localname, according to XML qname rules. */
+    /** Localname, according to XML 1.0 qname rules. */
     public static String localnameXML(String string) {
         int i = splitXML(string);
         return string.substring(i);
@@ -399,11 +379,36 @@
     }
 
     // -------- --------
+    // Splitting for XML.
+    //   An additional rule is that the local part can not start with a digit.
+    //   In Turtle, it can.
+
+    // XML Namespaces:
+    // A qname name is NCName ':' NCName
+    // NCName             ::=      NCNameStartChar NCNameChar*
+    // NCNameChar         ::=      NameChar - ':'
+    // NCNameStartChar    ::=      Letter | '_'
+    //
+    // XML 1.0
+    // NameStartChar      ::= ":" | [A-Z] | "_" | [a-z] | [#xC0-#xD6] |
+    //                        [#xD8-#xF6] | [#xF8-#x2FF] |
+    //                        [#x370-#x37D] | [#x37F-#x1FFF] |
+    //                        [#x200C-#x200D] | [#x2070-#x218F] |
+    //                        [#x2C00-#x2FEF] | [#x3001-#xD7FF] |
+    //                        [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF]
+    // NameChar           ::= NameStartChar | "-" | "." | [0-9] | #xB7 |
+    //                        [#x0300-#x036F] | [#x203F-#x2040]
+    // Name               ::= NameStartChar (NameChar)*
+
+    // XMLChar does not support [#x10000-#xEFFFF]
+    // XML11Char does support [#x10000-#xEFFFF]
+
+
     /**
      * Given an absolute URI, determine the split point between the namespace
      * part and the localname part. If there is no valid localname part then the
      * length of the string is returned. The algorithm tries to find the longest
-     * NCName at the end of the uri, not immediately preceeded by the first
+     * NCName at the end of the uri, not immediately preceded by the first
      * colon in the string.
      * <p>
      * This operation follows XML QName rules which are more complicated than
@@ -413,25 +418,61 @@
      * @return the index of the first character of the localname
      * @see SplitIRI
      */
-    private static int splitNamespaceXML(String uri) {
+    private static int splitNamespaceXML11(String uri) {
+        // Updated for XML 1.1
+        // The main difference is that XML11Char class works for character beyond 0xFFFF.
+        // This is not a restriction in XML 1.0 itself.
 
-        // XML Namespaces 1.0:
-        // A qname name is NCName ':' NCName
-        // NCName             ::=      NCNameStartChar NCNameChar*
-        // NCNameChar         ::=      NameChar - ':'
-        // NCNameStartChar    ::=      Letter | '_'
-        //
-        // XML 1.0
-        // NameStartChar      ::= ":" | [A-Z] | "_" | [a-z] | [#xC0-#xD6] |
-        //                        [#xD8-#xF6] | [#xF8-#x2FF] |
-        //                        [#x370-#x37D] | [#x37F-#x1FFF] |
-        //                        [#x200C-#x200D] | [#x2070-#x218F] |
-        //                        [#x2C00-#x2FEF] | [#x3001-#xD7FF] |
-        //                        [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF]
-        // NameChar           ::= NameStartChar | "-" | "." | [0-9] | #xB7 |
-        //                        [#x0300-#x036F] | [#x203F-#x2040]
-        // Name               ::= NameStartChar (NameChar)*
+        char ch;
+        int lg = uri.length();
+        if (lg == 0)
+            return 0;
+        int i = lg-1;
+        for (; i >= 1; i--) {
+            ch = uri.charAt(i);
+            if ( !XML11Char.isXML11NCName(ch) ) // ****
+                break;
+        }
 
+        int j = i + 1;
+
+        if ( j >= lg )
+            return lg;
+
+        // Check we haven't split up a %-encoding.
+        if ( j >= 2 && uri.charAt(j-2) == '%' )
+            j = j+1;
+        if ( j >= 1 && uri.charAt(j-1) == '%' ) {
+            j = j+2;
+            if ( j > lg )
+                // JENA-1941: Protect against overshoot in the case of "%x"
+                // at end of a (bad) URI.
+                return lg;
+        }
+
+        // Have found the leftmost NCNameChar from the
+        // end of the URI string.
+        // Now scan forward for an NCNameStartChar
+        // The split must start with NCNameStart.
+        for (; j < lg; j++) {
+            ch = uri.charAt(j);
+            if (XML11Char.isXML11NCNameStart(ch)) // ****
+            {
+                // "mailto:" is special.
+                // split "mailto:me" as "mailto:m" and "e" !
+                // Keep part after mailto: with at least one character.
+                if ( j == 7 && uri.startsWith("mailto:"))
+                    // Don't split at "mailto:"
+                    continue;
+                else
+                    break;
+            }
+        }
+        return j;
+    }
+
+    private static int splitNamespaceXML10(String uri) {
+        // The original code.
         char ch;
         int lg = uri.length();
         if (lg == 0)
@@ -465,8 +506,6 @@
         // The split must start with NCNameStart.
         for (; j < lg; j++) {
             ch = uri.charAt(j);
-//            if (XMLChar.isNCNameStart(ch))
-//                break;
             if (XMLChar.isNCNameStart(ch))
             {
                 // "mailto:" is special.
@@ -481,5 +520,6 @@
         }
         return j;
     }
+
 }
 
diff --git a/jena-core/src/test/java/org/apache/jena/shared/AbstractTestPrefixMapping.java b/jena-core/src/test/java/org/apache/jena/shared/AbstractTestPrefixMapping.java
index e4ceef6..0b5352b 100644
--- a/jena-core/src/test/java/org/apache/jena/shared/AbstractTestPrefixMapping.java
+++ b/jena-core/src/test/java/org/apache/jena/shared/AbstractTestPrefixMapping.java
@@ -22,22 +22,22 @@
 import java.util.List;
 import java.util.Map;
 
-import org.apache.jena.graph.test.GraphTestBase ;
+import org.apache.jena.graph.test.GraphTestBase;
 
 /**
-    Test prefix mappings - subclass this test and override getMapping() to
-    deliver the prefixMapping to be tested.
-*/
+ * Test prefix mappings - subclass this test and override getMapping() to deliver the
+ * prefixMapping to be tested.
+ */
 
-public abstract class AbstractTestPrefixMapping extends GraphTestBase
-    {
-    public AbstractTestPrefixMapping( String name )
-         { super( name ); }
+public abstract class AbstractTestPrefixMapping extends GraphTestBase {
+    public AbstractTestPrefixMapping(String name) {
+        super(name);
+    }
 
     /**
-        Subclasses implement to return a new, empty prefixMapping of their
-        preferred kind.
-    */
+     * Subclasses implement to return a new, empty prefixMapping of their preferred
+     * kind.
+     */
     abstract protected PrefixMapping getMapping();
 
     static final String crispURI = "http://crisp.nosuch.net/";
@@ -45,459 +45,430 @@
     static final String butterURI = "ftp://ftp.nowhere.at.all/cream#";
 
     /**
-        The empty prefix is specifically allowed [for the default namespace].
-    */
-    public void testEmptyPrefix()
-        {
-        PrefixMapping pm = getMapping();
-        pm.setNsPrefix( "", crispURI );
-        assertEquals( crispURI, pm.getNsPrefixURI( "" ) );
-        }
+     * The empty prefix is specifically allowed [for the default namespace].
+     */
+    public void testEmptyPrefix() {
+        addGetTest("", crispURI);
+    }
 
-    static final String [] badNames =
-        {
-        "<hello>",
-        "foo:bar",
-        "with a space",
-        "-argument"
-        };
+    public void testStrPrefix1() {
+        addGetTest("abc", "http://example/");
+    }
+
+    public void testStrPrefix2() {
+        // U+1F607 - smiling face with halo
+        String prefix = new String(Character.toChars(0x1F607));
+        addGetTest(prefix, "http://example/");
+    }
+
+    private void addGetTest(String prefix, String uri) {
+        PrefixMapping pmap = getMapping();
+        pmap.setNsPrefix(prefix, uri);
+        assertEquals(uri, pmap.getNsPrefixURI(prefix));
+    }
+
+    static final String[] badNames = {"<hello>", "foo:bar", "with a space", "-argument"};
 
     /**
-        Test that various illegal names are trapped.
-    */
-    public void testCheckNames()
-        {
+     * Test that various illegal names are trapped.
+     */
+    public void testCheckNames() {
         PrefixMapping ns = getMapping();
-            for ( String bad : badNames )
-            {
-                try
-                {
-                    ns.setNsPrefix( bad, crispURI );
-                    fail( "'" + bad + "' is an illegal prefix and should be trapped" );
-                }
-                catch ( PrefixMapping.IllegalPrefixException e )
-                {
-                    pass();
-                }
+        for ( String bad : badNames ) {
+            try {
+                ns.setNsPrefix(bad, crispURI);
+                fail("'" + bad + "' is an illegal prefix and should be trapped");
+            } catch (PrefixMapping.IllegalPrefixException e) {
+                pass();
             }
         }
+    }
 
-    public void testNullURITrapped()
-        {
-        try
-            {
-            getMapping().setNsPrefix( "xy", null );
-            fail( "should trap null URI in setNsPrefix" );
-            }
-        catch (NullPointerException e)
-            { pass(); }
+    public void testNullURITrapped() {
+        try {
+            getMapping().setNsPrefix("xy", null);
+            fail("should trap null URI in setNsPrefix");
+        } catch (NullPointerException e) {
+            pass();
         }
+    }
 
     /**
-        test that a PrefixMapping maps names to URIs. The names and URIs are
-        all fully distinct - overlapping names/uris are dealt with in other tests.
-    */
-    public void testPrefixMappingMapping()
-        {
+     * test that a PrefixMapping maps names to URIs. The names and URIs are all fully
+     * distinct - overlapping names/uris are dealt with in other tests.
+     */
+    public void testPrefixMappingMapping() {
         String toast = "ftp://ftp.nowhere.not/";
-        assertDiffer( "crisp and toast must differ", crispURI, toast );
-    /* */
+        assertDiffer("crisp and toast must differ", crispURI, toast);
+        /* */
         PrefixMapping ns = getMapping();
-        assertEquals( "crisp should be unset", null, ns.getNsPrefixURI( "crisp" ) );
-        assertEquals( "toast should be unset", null, ns.getNsPrefixURI( "toast" ) );
-        assertEquals( "butter should be unset", null, ns.getNsPrefixURI( "butter" ) );
-    /* */
-        ns.setNsPrefix( "crisp", crispURI );
-        assertEquals( "crisp should be set", crispURI, ns.getNsPrefixURI( "crisp" ) );
-        assertEquals( "toast should still be unset", null, ns.getNsPrefixURI( "toast" ) );
-        assertEquals( "butter should still be unset", null, ns.getNsPrefixURI( "butter" ) );
-    /* */
-        ns.setNsPrefix( "toast", toast );
-        assertEquals( "crisp should be set", crispURI, ns.getNsPrefixURI( "crisp" ) );
-        assertEquals( "toast should be set", toast, ns.getNsPrefixURI( "toast" ) );
-        assertEquals( "butter should still be unset", null, ns.getNsPrefixURI( "butter" ) );
-        }
+        assertEquals("crisp should be unset", null, ns.getNsPrefixURI("crisp"));
+        assertEquals("toast should be unset", null, ns.getNsPrefixURI("toast"));
+        assertEquals("butter should be unset", null, ns.getNsPrefixURI("butter"));
+        /* */
+        ns.setNsPrefix("crisp", crispURI);
+        assertEquals("crisp should be set", crispURI, ns.getNsPrefixURI("crisp"));
+        assertEquals("toast should still be unset", null, ns.getNsPrefixURI("toast"));
+        assertEquals("butter should still be unset", null, ns.getNsPrefixURI("butter"));
+        /* */
+        ns.setNsPrefix("toast", toast);
+        assertEquals("crisp should be set", crispURI, ns.getNsPrefixURI("crisp"));
+        assertEquals("toast should be set", toast, ns.getNsPrefixURI("toast"));
+        assertEquals("butter should still be unset", null, ns.getNsPrefixURI("butter"));
+    }
 
     /**
-        Test that we can run the prefix mapping in reverse - from URIs to prefixes.
-        uriB is a prefix of uriA to try and ensure that the ordering of the map doesn't matter.
-    */
-    public void testReversePrefixMapping()
-        {
+     * Test that we can run the prefix mapping in reverse - from URIs to prefixes.
+     * uriB is a prefix of uriA to try and ensure that the ordering of the map
+     * doesn't matter.
+     */
+    public void testReversePrefixMapping() {
         PrefixMapping ns = getMapping();
         String uriA = "http://jena.hpl.hp.com/A#", uriB = "http://jena.hpl.hp.com/";
         String uriC = "http://jena.hpl.hp.com/Csharp/";
         String prefixA = "aa", prefixB = "bb";
-        ns.setNsPrefix( prefixA, uriA ).setNsPrefix( prefixB, uriB );
-        assertEquals( null, ns.getNsURIPrefix( uriC) );
-        assertEquals( prefixA, ns.getNsURIPrefix( uriA ) );
-        assertEquals( prefixB, ns.getNsURIPrefix( uriB ) );
-        }
+        ns.setNsPrefix(prefixA, uriA).setNsPrefix(prefixB, uriB);
+        assertEquals(null, ns.getNsURIPrefix(uriC));
+        assertEquals(prefixA, ns.getNsURIPrefix(uriA));
+        assertEquals(prefixB, ns.getNsURIPrefix(uriB));
+    }
 
     /**
-       test that we can extract a proper Map from a PrefixMapping
-    */
-    public void testPrefixMappingMap()
-        {
+     * test that we can extract a proper Map from a PrefixMapping
+     */
+    public void testPrefixMappingMap() {
         PrefixMapping ns = getCrispyRope();
         Map<String, String> map = ns.getNsPrefixMap();
-        assertEquals( "map should have two elements", 2, map.size() );
-        assertEquals( crispURI, map.get( "crisp" ) );
-        assertEquals( "scheme:rope/string#", map.get( "rope" ) );
-        }
+        assertEquals("map should have two elements", 2, map.size());
+        assertEquals(crispURI, map.get("crisp"));
+        assertEquals("scheme:rope/string#", map.get("rope"));
+    }
 
     /**
-       test that the Map returned by getNsPrefixMap does not alias (parts of)
-       the secret internal map of the PrefixMapping
-    */
-    public void testPrefixMappingSecret()
-        {
+     * test that the Map returned by getNsPrefixMap does not alias (parts of) the
+     * secret internal map of the PrefixMapping
+     */
+    public void testPrefixMappingSecret() {
         PrefixMapping ns = getCrispyRope();
         Map<String, String> map = ns.getNsPrefixMap();
-        // The map may be unmodifiable in which case put throws UnsupportedOperationException
+        // The map may be unmodifiable in which case put throws
+        // UnsupportedOperationException
         try {
-            map.put( "crisp", "with/onions" );
-            map.put( "sandwich", "with/cheese" );
+            map.put("crisp", "with/onions");
+            map.put("sandwich", "with/cheese");
         } catch (UnsupportedOperationException ex) {}
 
-        assertEquals( crispURI, ns.getNsPrefixURI( "crisp" ) );
-        assertEquals( ropeURI, ns.getNsPrefixURI( "rope" ) );
-        assertEquals( null, ns.getNsPrefixURI( "sandwich" ) );
-        }
+        assertEquals(crispURI, ns.getNsPrefixURI("crisp"));
+        assertEquals(ropeURI, ns.getNsPrefixURI("rope"));
+        assertEquals(null, ns.getNsPrefixURI("sandwich"));
+    }
 
-    private PrefixMapping getCrispyRope()
-        {
+    private PrefixMapping getCrispyRope() {
         PrefixMapping ns = getMapping();
-        ns.setNsPrefix( "crisp", crispURI);
-        ns.setNsPrefix( "rope", ropeURI );
+        ns.setNsPrefix("crisp", crispURI);
+        ns.setNsPrefix("rope", ropeURI);
         return ns;
-        }
+    }
 
     /**
-       these are strings that should not change when they are prefix-expanded
-       with crisp and rope as legal prefixes.
-   */
-   static final String [] dontChange =
-       {
-       "",
-       "http://www.somedomain.something/whatever#",
-       "crispy:cabbage",
-       "cris:isOnInfiniteEarths",
-       "rop:tangled/web",
-       "roped:abseiling"
-       };
+     * these are strings that should not change when they are prefix-expanded with
+     * crisp and rope as legal prefixes.
+     */
+    static final String[] dontChange = {"", "http://www.somedomain.something/whatever#", "crispy:cabbage", "cris:isOnInfiniteEarths",
+        "rop:tangled/web", "roped:abseiling"};
 
     /**
-       these are the required mappings which the test cases below should
-       satisfy: an array of 2-arrays, where element 0 is the string to expand
-       and element 1 is the string it should expand to.
-   */
-   static final String [][] expansions =
-       {
-           { "crisp:pathPart", crispURI + "pathPart" },
-           { "rope:partPath", ropeURI + "partPath" },
-           { "crisp:path:part", crispURI + "path:part" },
-       };
+     * these are the required mappings which the test cases below should satisfy: an
+     * array of 2-arrays, where element 0 is the string to expand and element 1 is
+     * the string it should expand to.
+     */
+    static final String[][] expansions = {{"crisp:pathPart", crispURI + "pathPart"}, {"rope:partPath", ropeURI + "partPath"},
+        {"crisp:path:part", crispURI + "path:part"},};
 
-   public void testExpandPrefix()
-       {
-       PrefixMapping ns = getMapping();
-       ns.setNsPrefix( "crisp", crispURI );
-       ns.setNsPrefix( "rope", ropeURI );
-   /* */
-           for ( String aDontChange : dontChange )
-           {
-               assertEquals( "should be unchanged", aDontChange, ns.expandPrefix( aDontChange ) );
-           }
-   /* */
-           for ( String[] expansion : expansions )
-           {
-               assertEquals( "should expand correctly", expansion[1], ns.expandPrefix( expansion[0] ) );
-           }
-       }
-
-    public void testUseEasyPrefix()
-       {
-       testUseEasyPrefix( "prefix mapping impl", getMapping() );
-       testShortForm( "prefix mapping impl", getMapping() );
-       }
-
-    public static void testUseEasyPrefix( String title, PrefixMapping ns )
-        {
-        testShortForm( title, ns );
+    public void testExpandPrefix() {
+        PrefixMapping ns = getMapping();
+        ns.setNsPrefix("crisp", crispURI);
+        ns.setNsPrefix("rope", ropeURI);
+        /* */
+        for ( String aDontChange : dontChange ) {
+            assertEquals("should be unchanged", aDontChange, ns.expandPrefix(aDontChange));
         }
-
-    public static void testShortForm( String title, PrefixMapping ns )
-        {
-        ns.setNsPrefix( "crisp", crispURI );
-        ns.setNsPrefix( "butter", butterURI );
-        assertEquals( title, "", ns.shortForm( "" ) );
-        assertEquals( title, ropeURI, ns.shortForm( ropeURI ) );
-        assertEquals( title, "crisp:tail", ns.shortForm( crispURI + "tail" ) );
-        assertEquals( title, "butter:here:we:are", ns.shortForm( butterURI + "here:we:are" ) );
+        /* */
+        for ( String[] expansion : expansions ) {
+            assertEquals("should expand correctly", expansion[1], ns.expandPrefix(expansion[0]));
         }
+    }
 
-    public void testEasyQName()
-        {
+    public void testUseEasyPrefix() {
+        testUseEasyPrefix("prefix mapping impl", getMapping());
+        testShortForm("prefix mapping impl", getMapping());
+    }
+
+    public static void testUseEasyPrefix(String title, PrefixMapping ns) {
+        testShortForm(title, ns);
+    }
+
+    public static void testShortForm(String title, PrefixMapping ns) {
+        ns.setNsPrefix("crisp", crispURI);
+        ns.setNsPrefix("butter", butterURI);
+        assertEquals(title, "", ns.shortForm(""));
+        assertEquals(title, ropeURI, ns.shortForm(ropeURI));
+        assertEquals(title, "crisp:tail", ns.shortForm(crispURI + "tail"));
+        assertEquals(title, "butter:here:we:are", ns.shortForm(butterURI + "here:we:are"));
+    }
+
+    public void testEasyQName() {
         PrefixMapping ns = getMapping();
         String alphaURI = "http://seasonal.song/preamble/";
-        ns.setNsPrefix( "alpha", alphaURI );
-        assertEquals( "alpha:rowboat", ns.qnameFor( alphaURI + "rowboat" ) );
-        }
+        ns.setNsPrefix("alpha", alphaURI);
+        assertEquals("alpha:rowboat", ns.qnameFor(alphaURI + "rowboat"));
+    }
 
-    public void testNoQNameNoPrefix()
-        {
+    public void testNoQNameNoPrefix() {
         PrefixMapping ns = getMapping();
         String alphaURI = "http://seasonal.song/preamble/";
-        ns.setNsPrefix( "alpha", alphaURI );
-        assertEquals( null, ns.qnameFor( "eg:rowboat" ) );
-        }
+        ns.setNsPrefix("alpha", alphaURI);
+        assertEquals(null, ns.qnameFor("eg:rowboat"));
+    }
 
-    public void testNoQNameBadLocal()
-        {
+    public void testNoQNameBadLocal() {
         PrefixMapping ns = getMapping();
         String alphaURI = "http://seasonal.song/preamble/";
-        ns.setNsPrefix( "alpha", alphaURI );
-        assertEquals( null, ns.qnameFor( alphaURI + "12345" ) );
-        }
+        ns.setNsPrefix("alpha", alphaURI);
+        assertEquals(null, ns.qnameFor(alphaURI + "12345"));
+    }
 
     /**
-        The tests implied by the email where Chris suggested adding qnameFor;
-        shortForm generates illegal qnames but qnameFor does not.
-    */
-    public void testQnameFromEmail()
-        {
-    	String uri = "http://some.long.uri/for/a/namespace#";
+     * The tests implied by the email where Chris suggested adding qnameFor;
+     * shortForm generates illegal qnames but qnameFor does not.
+     */
+    public void testQnameFromEmail() {
+        String uri = "http://some.long.uri/for/a/namespace#";
         PrefixMapping ns = getMapping();
-    	ns.setNsPrefix( "x", uri );
-    	assertEquals( null, ns.qnameFor( uri ) );
-        assertEquals( null, ns.qnameFor( uri + "non/fiction" ) );
-        }
-
+        ns.setNsPrefix("x", uri);
+        assertEquals(null, ns.qnameFor(uri));
+        assertEquals(null, ns.qnameFor(uri + "non/fiction"));
+    }
 
     /**
-        test that we can add the maplets from another PrefixMapping without
-        losing our own.
-    */
-    public void testAddOtherPrefixMapping()
-        {
+     * test that we can add the maplets from another PrefixMapping without losing our
+     * own.
+     */
+    public void testAddOtherPrefixMapping() {
         PrefixMapping a = getMapping();
         PrefixMapping b = getMapping();
-        assertFalse( "must have two diffferent maps", a == b );
-        a.setNsPrefix( "crisp", crispURI );
-        a.setNsPrefix( "rope", ropeURI );
-        b.setNsPrefix( "butter", butterURI );
-        assertEquals( null, b.getNsPrefixURI( "crisp") );
-        assertEquals( null, b.getNsPrefixURI( "rope") );
-        b.setNsPrefixes( a );
-        checkContainsMapping( b );
-        }
+        assertFalse("must have two diffferent maps", a == b);
+        a.setNsPrefix("crisp", crispURI);
+        a.setNsPrefix("rope", ropeURI);
+        b.setNsPrefix("butter", butterURI);
+        assertEquals(null, b.getNsPrefixURI("crisp"));
+        assertEquals(null, b.getNsPrefixURI("rope"));
+        b.setNsPrefixes(a);
+        checkContainsMapping(b);
+    }
 
-    private void checkContainsMapping( PrefixMapping b )
-        {
-        assertEquals( crispURI, b.getNsPrefixURI( "crisp") );
-        assertEquals( ropeURI, b.getNsPrefixURI( "rope") );
-        assertEquals( butterURI, b.getNsPrefixURI( "butter") );
-        }
+    private void checkContainsMapping(PrefixMapping b) {
+        assertEquals(crispURI, b.getNsPrefixURI("crisp"));
+        assertEquals(ropeURI, b.getNsPrefixURI("rope"));
+        assertEquals(butterURI, b.getNsPrefixURI("butter"));
+    }
 
     /**
-        as for testAddOtherPrefixMapping, except that it's a plain Map
-        we're adding.
-    */
-    public void testAddMap()
-        {
+     * as for testAddOtherPrefixMapping, except that it's a plain Map we're adding.
+     */
+    public void testAddMap() {
         PrefixMapping b = getMapping();
         Map<String, String> map = new HashMap<>();
-        map.put( "crisp", crispURI );
-        map.put( "rope", ropeURI );
-        b.setNsPrefix( "butter", butterURI );
-        b.setNsPrefixes( map );
-        checkContainsMapping( b );
-        }
+        map.put("crisp", crispURI);
+        map.put("rope", ropeURI);
+        b.setNsPrefix("butter", butterURI);
+        b.setNsPrefixes(map);
+        checkContainsMapping(b);
+    }
 
-    public void testAddDefaultMap()
-        {
+    public void testAddDefaultMap() {
         PrefixMapping pm = getMapping();
         PrefixMapping root = PrefixMapping.Factory.create();
-        pm.setNsPrefix( "a", "aPrefix:" );
-        pm.setNsPrefix( "b", "bPrefix:" );
-        root.setNsPrefix( "a", "pootle:" );
-        root.setNsPrefix( "z", "bPrefix:" );
-        root.setNsPrefix( "c", "cootle:" );
-        assertSame( pm, pm.withDefaultMappings( root ) );
-        assertEquals( "aPrefix:", pm.getNsPrefixURI( "a" ) );
-        assertEquals( null, pm.getNsPrefixURI( "z" ) );
-        assertEquals( "bPrefix:", pm.getNsPrefixURI( "b" ) );
-        assertEquals( "cootle:", pm.getNsPrefixURI( "c" ) );
-        }
+        pm.setNsPrefix("a", "aPrefix:");
+        pm.setNsPrefix("b", "bPrefix:");
+        root.setNsPrefix("a", "pootle:");
+        root.setNsPrefix("z", "bPrefix:");
+        root.setNsPrefix("c", "cootle:");
+        assertSame(pm, pm.withDefaultMappings(root));
+        assertEquals("aPrefix:", pm.getNsPrefixURI("a"));
+        assertEquals(null, pm.getNsPrefixURI("z"));
+        assertEquals("bPrefix:", pm.getNsPrefixURI("b"));
+        assertEquals("cootle:", pm.getNsPrefixURI("c"));
+    }
 
-
-    public void testSecondPrefixRetainsExistingMap()
-        {
+    public void testSecondPrefixRetainsExistingMap() {
         PrefixMapping A = getMapping();
-        A.setNsPrefix( "a", crispURI );
-        A.setNsPrefix( "b", crispURI );
-        assertEquals( crispURI, A.getNsPrefixURI( "a" ) );
-        assertEquals( crispURI, A.getNsPrefixURI( "b" ) );
-        }
+        A.setNsPrefix("a", crispURI);
+        A.setNsPrefix("b", crispURI);
+        assertEquals(crispURI, A.getNsPrefixURI("a"));
+        assertEquals(crispURI, A.getNsPrefixURI("b"));
+    }
 
-    public void testSecondPrefixReplacesReverseMap()
-        {
+    public void testSecondPrefixReplacesReverseMap() {
         PrefixMapping A = getMapping();
-        A.setNsPrefix( "a", crispURI );
-        A.setNsPrefix( "b", crispURI );
-        assertEquals( "b", A.getNsURIPrefix( crispURI ) );
-        }
+        A.setNsPrefix("a", crispURI);
+        A.setNsPrefix("b", crispURI);
+        assertEquals("b", A.getNsURIPrefix(crispURI));
+    }
 
-    public void testSecondPrefixDeletedUncoversPreviousMap()
-        {
+    public void testSecondPrefixDeletedUncoversPreviousMap() {
         PrefixMapping A = getMapping();
-        A.setNsPrefix( "x", crispURI );
-        A.setNsPrefix( "y", crispURI );
-        A.removeNsPrefix( "y" );
-        assertEquals( "x", A.getNsURIPrefix( crispURI ) );
-        }
+        A.setNsPrefix("x", crispURI);
+        A.setNsPrefix("y", crispURI);
+        A.removeNsPrefix("y");
+        assertEquals("x", A.getNsURIPrefix(crispURI));
+    }
 
     /**
-        Test that the empty prefix does not wipe an existing prefix for the same URI.
-    */
-    public void testEmptyDoesNotWipeURI()
-        {
+     * Test that the empty prefix does not wipe an existing prefix for the same URI.
+     */
+    public void testEmptyDoesNotWipeURI() {
         PrefixMapping pm = getMapping();
-        pm.setNsPrefix( "frodo", ropeURI );
-        pm.setNsPrefix( "", ropeURI );
-        assertEquals( ropeURI, pm.getNsPrefixURI( "frodo" ) );
-        }
+        pm.setNsPrefix("frodo", ropeURI);
+        pm.setNsPrefix("", ropeURI);
+        assertEquals(ropeURI, pm.getNsPrefixURI("frodo"));
+    }
 
     /**
-        Test that adding a new prefix mapping for U does not throw away a default
-        mapping for U.
-    */
-    public void testSameURIKeepsDefault()
-        {
+     * Test that adding a new prefix mapping for U does not throw away a default
+     * mapping for U.
+     */
+    public void testSameURIKeepsDefault() {
         PrefixMapping A = getMapping();
-        A.setNsPrefix( "", crispURI );
-        A.setNsPrefix( "crisp", crispURI );
-        assertEquals( crispURI, A.getNsPrefixURI( "" ) );
-        }
+        A.setNsPrefix("", crispURI);
+        A.setNsPrefix("crisp", crispURI);
+        assertEquals(crispURI, A.getNsPrefixURI(""));
+    }
 
-    public void testReturnsSelf()
-        {
+    public void testReturnsSelf() {
         PrefixMapping A = getMapping();
-        assertSame( A, A.setNsPrefix( "crisp", crispURI ) );
-        assertSame( A, A.setNsPrefixes( A ) );
-        assertSame( A, A.setNsPrefixes( new HashMap<String, String>() ) );
-        assertSame( A, A.removeNsPrefix( "rhubarb" ) );
-        }
+        assertSame(A, A.setNsPrefix("crisp", crispURI));
+        assertSame(A, A.setNsPrefixes(A));
+        assertSame(A, A.setNsPrefixes(new HashMap<String, String>()));
+        assertSame(A, A.removeNsPrefix("rhubarb"));
+    }
 
-    public void testRemovePrefix()
-        {
+    public void testRemovePrefix() {
         String hURI = "http://test.remove.prefixes/prefix#";
         String bURI = "http://other.test.remove.prefixes/prefix#";
         PrefixMapping A = getMapping();
-        A.setNsPrefix( "hr", hURI );
-        A.setNsPrefix( "br", bURI );
-        A.removeNsPrefix( "hr" );
-        assertEquals( null, A.getNsPrefixURI( "hr" ) );
-        assertEquals( bURI, A.getNsPrefixURI( "br" ) );
-        }
+        A.setNsPrefix("hr", hURI);
+        A.setNsPrefix("br", bURI);
+        A.removeNsPrefix("hr");
+        assertEquals(null, A.getNsPrefixURI("hr"));
+        assertEquals(bURI, A.getNsPrefixURI("br"));
+    }
 
-    public void testClear()
-    {
+    public void testClear() {
         String hURI = "http://test.remove.prefixes/prefix#";
         String bURI = "http://other.test.remove.prefixes/prefix#";
         PrefixMapping A = getMapping();
-        A.setNsPrefix( "hr", hURI );
-        A.setNsPrefix( "br", bURI );
-        A.clearNsPrefixMap() ;
+        A.setNsPrefix("hr", hURI);
+        A.setNsPrefix("br", bURI);
+        A.clearNsPrefixMap();
 
-        assertEquals( null, A.getNsPrefixURI( "hr" ) );
-        assertEquals( null, A.getNsPrefixURI( "br" ) );
+        assertEquals(null, A.getNsPrefixURI("hr"));
+        assertEquals(null, A.getNsPrefixURI("br"));
 
-        assertEquals( null, A.getNsURIPrefix(hURI) ) ;
-        assertEquals( null, A.getNsURIPrefix(bURI) ) ;
+        assertEquals(null, A.getNsURIPrefix(hURI));
+        assertEquals(null, A.getNsURIPrefix(bURI));
     }
 
     public void testNoMapping() {
         String hURI = "http://test.prefixes/prefix#";
         PrefixMapping A = getMapping();
-        assertTrue(A.hasNoMappings()) ;
-        A.setNsPrefix( "hr", hURI );
-        assertFalse(A.hasNoMappings()) ;
+        assertTrue(A.hasNoMappings());
+        A.setNsPrefix("hr", hURI);
+        assertFalse(A.hasNoMappings());
     }
 
     public void testNumPrefixes() {
         String hURI = "http://test.prefixes/prefix#";
         PrefixMapping A = getMapping();
-        assertEquals(0, A.numPrefixes()) ;
-        A.setNsPrefix( "hr", hURI );
-        assertEquals(1, A.numPrefixes()) ;
+        assertEquals(0, A.numPrefixes());
+        A.setNsPrefix("hr", hURI);
+        assertEquals(1, A.numPrefixes());
     }
 
-    public void testEquality()
-        {
-        testEquals( "" );
-        testEquals( "", "x=a", false );
-        testEquals( "x=a", "", false );
-        testEquals( "x=a" );
-        testEquals( "x=a y=b", "y=b x=a", true );
-        testEquals( "x=a x=b", "x=b x=a", false );
-        }
+    public void testEquality() {
+        testEquals("");
+        testEquals("", "x=a", false);
+        testEquals("x=a", "", false);
+        testEquals("x=a");
+        testEquals("x=a y=b", "y=b x=a", true);
+        testEquals("x=a x=b", "x=b x=a", false);
+    }
 
-    protected void testEquals( String S )
-        { testEquals( S, S, true ); }
+    protected void testEquals(String S) {
+        testEquals(S, S, true);
+    }
 
-    protected void testEquals( String S, String T, boolean expected )
-        {
-        testEqualsBase( S, T, expected );
-        testEqualsBase( T, S, expected );
-        }
+    protected void testEquals(String S, String T, boolean expected) {
+        testEqualsBase(S, T, expected);
+        testEqualsBase(T, S, expected);
+    }
 
-    public void testEqualsBase( String S, String T, boolean expected )
-        {
-        testEquals( S, T, expected, getMapping(), getMapping() );
-        testEquals( S, T, expected, PrefixMapping.Factory.create(), getMapping() );
-        }
+    public void testEqualsBase(String S, String T, boolean expected) {
+        testEquals(S, T, expected, getMapping(), getMapping());
+        testEquals(S, T, expected, PrefixMapping.Factory.create(), getMapping());
+    }
 
-    protected void testEquals( String S, String T, boolean expected, PrefixMapping A, PrefixMapping B )
-        {
-        fill( A, S );
-        fill( B, T );
+    protected void testEquals(String S, String T, boolean expected, PrefixMapping A, PrefixMapping B) {
+        fill(A, S);
+        fill(B, T);
         String title = "usual: '" + S + "', testing: '" + T + "', should be " + (expected ? "equal" : "different");
-        assertEquals( title, expected, A.samePrefixMappingAs( B ) );
-        assertEquals( title, expected, B.samePrefixMappingAs( A ) );
-        }
+        assertEquals(title, expected, A.samePrefixMappingAs(B));
+        assertEquals(title, expected, B.samePrefixMappingAs(A));
+    }
 
-    protected void fill( PrefixMapping pm, String settings )
-        {
-        List<String> L = listOfStrings( settings );
-            for ( String setting : L )
-            {
-                int eq = setting.indexOf( '=' );
-                pm.setNsPrefix( setting.substring( 0, eq ), setting.substring( eq + 1 ) );
-            }
-        }
-
-    public void testAllowNastyNamespace()
-        { // we now allow namespaces to end with non-punctuational characters
-        getMapping().setNsPrefix( "abc", "def" );
-        }
-
-    public void testLock()
-        {
-        PrefixMapping A = getMapping();
-        assertSame( A, A.lock() );
-    /* */
-        try { A.setNsPrefix( "crisp", crispURI ); fail( "mapping should be frozen" ); }
-        catch (PrefixMapping.JenaLockedException e) { pass(); }
-    /* */
-        try { A.setNsPrefixes( A ); fail( "mapping should be frozen" ); }
-        catch (PrefixMapping.JenaLockedException e) { pass(); }
-    /* */
-        try { A.setNsPrefixes( new HashMap<String, String>() ); fail( "mapping should be frozen" ); }
-        catch (PrefixMapping.JenaLockedException e) { pass(); }
-    /* */
-        try { A.removeNsPrefix( "toast" ); fail( "mapping should be frozen" ); }
-        catch (PrefixMapping.JenaLockedException e) { pass(); }
+    protected void fill(PrefixMapping pm, String settings) {
+        List<String> L = listOfStrings(settings);
+        for ( String setting : L ) {
+            int eq = setting.indexOf('=');
+            pm.setNsPrefix(setting.substring(0, eq), setting.substring(eq + 1));
         }
     }
+
+    // we now allow namespaces to end with non-punctuational characters
+    public void testAllowNastyNamespace() {
+        getMapping().setNsPrefix("abc", "def");
+    }
+
+    public void testLock() {
+        PrefixMapping A = getMapping();
+        assertSame(A, A.lock());
+        /* */
+        try {
+            A.setNsPrefix("crisp", crispURI);
+            fail("mapping should be frozen");
+        } catch (PrefixMapping.JenaLockedException e) {
+            pass();
+        }
+        /* */
+        try {
+            A.setNsPrefixes(A);
+            fail("mapping should be frozen");
+        } catch (PrefixMapping.JenaLockedException e) {
+            pass();
+        }
+        /* */
+        try {
+            A.setNsPrefixes(new HashMap<String, String>());
+            fail("mapping should be frozen");
+        } catch (PrefixMapping.JenaLockedException e) {
+            pass();
+        }
+        /* */
+        try {
+            A.removeNsPrefix("toast");
+            fail("mapping should be frozen");
+        } catch (PrefixMapping.JenaLockedException e) {
+            pass();
+        }
+    }
+}
diff --git a/jena-core/src/test/java/org/apache/jena/util/TestSplitIRI_TTL.java b/jena-core/src/test/java/org/apache/jena/util/TestSplitIRI_TTL.java
index 45eb95f..8b0fb3f 100644
--- a/jena-core/src/test/java/org/apache/jena/util/TestSplitIRI_TTL.java
+++ b/jena-core/src/test/java/org/apache/jena/util/TestSplitIRI_TTL.java
@@ -103,12 +103,6 @@
                              expectedLocalname, localnameTTL(string)) ;
     }
 
-    private void testPrefixLocalnameTTLnoESC(String string, String expectedNamespace, String expectedLocalname) {
-        checkPrefixLocalname(string,
-                             expectedNamespace, namespaceTTL(string),
-                             expectedLocalname, localnameTTLNoEsc(string)) ;
-    }
-
     private void checkPrefixLocalname(String string,
                                       String expectedNamespace, String actualNamespace,
                                       String expectedLocalname, String actualLocalName) {
diff --git a/jena-db/jena-dboe-storage/src/test/java/org/apache/jena/dboe/storage/prefixes/TS_Prefixes.java b/jena-db/jena-dboe-storage/src/test/java/org/apache/jena/dboe/storage/prefixes/TS_Prefixes.java
index 8378718..ff0f7f2 100644
--- a/jena-db/jena-dboe-storage/src/test/java/org/apache/jena/dboe/storage/prefixes/TS_Prefixes.java
+++ b/jena-db/jena-dboe-storage/src/test/java/org/apache/jena/dboe/storage/prefixes/TS_Prefixes.java
@@ -26,11 +26,7 @@
     TestDatasetPrefixesMem.class
     , TestPrefixMappingOverDatasetPrefixes.class
     , TestPrefixMappingOverDatasetPrefixes2.class
-    , TestPrefixLib.class
 })
 
 public class TS_Prefixes
-{
-
-}
-
+{}