1818import java .util .Collection ;
1919import java .util .HashSet ;
2020import java .util .Stack ;
21+ import java .util .regex .Pattern ;
2122
2223import org .eclipse .rdf4j .common .net .ParsedIRI ;
24+ import org .eclipse .rdf4j .common .xml .XMLUtil ;
2325import org .eclipse .rdf4j .model .BNode ;
2426import org .eclipse .rdf4j .model .IRI ;
2527import org .eclipse .rdf4j .model .Literal ;
@@ -260,8 +262,9 @@ private void popStacks(Resource newSubject) throws IOException, RDFHandlerExcept
260262 writeIndents (i * 2 - 1 );
261263
262264 IRI predicate = predicateStack .get (i - 1 );
265+ var predicateQName = new QName (predicate );
263266
264- writeStartTag (predicate .getNamespace (), predicate .getLocalName ());
267+ writeStartTag (predicateQName .getNamespace (), predicateQName .getLocalName ());
265268 writeNewLine ();
266269 }
267270
@@ -281,6 +284,7 @@ private void popStacks(Resource newSubject) throws IOException, RDFHandlerExcept
281284 writeNewLine ();
282285 } else {
283286 IRI topPredicate = predicateStack .pop ();
287+ var topPredicateQName = new QName (topPredicate );
284288
285289 if (!topNode .hasType ()) {
286290 // we can use an abbreviated predicate
@@ -291,7 +295,7 @@ private void popStacks(Resource newSubject) throws IOException, RDFHandlerExcept
291295 // written out as well
292296
293297 writeIndents (nodeStack .size () * 2 - 1 );
294- writeStartTag (topPredicate .getNamespace (), topPredicate .getLocalName ());
298+ writeStartTag (topPredicateQName .getNamespace (), topPredicateQName .getLocalName ());
295299 writeNewLine ();
296300
297301 // write out an empty subject
@@ -300,7 +304,7 @@ private void popStacks(Resource newSubject) throws IOException, RDFHandlerExcept
300304 writeNewLine ();
301305
302306 writeIndents (nodeStack .size () * 2 - 1 );
303- writeEndTag (topPredicate .getNamespace (), topPredicate .getLocalName ());
307+ writeEndTag (topPredicateQName .getNamespace (), topPredicateQName .getLocalName ());
304308 writeNewLine ();
305309 }
306310 }
@@ -322,10 +326,11 @@ private void popStacks(Resource newSubject) throws IOException, RDFHandlerExcept
322326
323327 if (!predicateStack .isEmpty ()) {
324328 IRI nextPredicate = predicateStack .pop ();
329+ var nextPredicateQName = new QName (nextPredicate );
325330
326331 writeIndents (predicateStack .size () + nodeStack .size ());
327332
328- writeEndTag (nextPredicate .getNamespace (), nextPredicate .getLocalName ());
333+ writeEndTag (nextPredicateQName .getNamespace (), nextPredicateQName .getLocalName ());
329334
330335 writeNewLine ();
331336 }
@@ -392,7 +397,8 @@ private void writeNodeStartOfStartTag(Node node) throws IOException, RDFHandlerE
392397
393398 if (node .hasType ()) {
394399 // We can use abbreviated syntax
395- writeStartOfStartTag (node .getType ().getNamespace (), node .getType ().getLocalName ());
400+ var nodeTypeQName = new QName (node .getType ());
401+ writeStartOfStartTag (nodeTypeQName .getNamespace (), nodeTypeQName .getLocalName ());
396402 } else {
397403 // We cannot use abbreviated syntax
398404 writeStartOfStartTag (RDF .NAMESPACE , "Description" );
@@ -423,7 +429,8 @@ private void writeNodeStartTag(Node node) throws IOException, RDFHandlerExceptio
423429 */
424430 private void writeNodeEndTag (Node node ) throws IOException {
425431 if (node .getType () != null ) {
426- writeEndTag (node .getType ().getNamespace (), node .getType ().getLocalName ());
432+ var nodeTypeQName = new QName (node .getType ());
433+ writeEndTag (nodeTypeQName .getNamespace (), nodeTypeQName .getLocalName ());
427434 } else {
428435 writeEndTag (RDF .NAMESPACE , "Description" );
429436 }
@@ -442,7 +449,8 @@ private void writeNodeEmptyTag(Node node) throws IOException, RDFHandlerExceptio
442449 * Write out an empty property element.
443450 */
444451 private void writeAbbreviatedPredicate (IRI pred , Value obj ) throws IOException , RDFHandlerException {
445- writeStartOfStartTag (pred .getNamespace (), pred .getLocalName ());
452+ var predQName = new QName (pred );
453+ writeStartOfStartTag (predQName .getNamespace (), predQName .getLocalName ());
446454
447455 if (obj instanceof Resource ) {
448456 Resource objRes = (Resource ) obj ;
@@ -484,7 +492,7 @@ private void writeAbbreviatedPredicate(IRI pred, Value obj) throws IOException,
484492 writeCharacterData (objLit .getLabel ());
485493 }
486494
487- writeEndTag (pred .getNamespace (), pred .getLocalName ());
495+ writeEndTag (predQName .getNamespace (), predQName .getLocalName ());
488496 }
489497
490498 writeNewLine ();
@@ -565,4 +573,31 @@ public boolean isWritten() {
565573 return isWritten ;
566574 }
567575 }
576+
577+ private static class QName {
578+ private static final Pattern VALID_XML_ELEMENT_NAME = Pattern .compile ("[a-zA-Z_][a-zA-Z0-9_\\ -\\ .]*" );
579+
580+ private final String namespace ;
581+ private final String localName ;
582+
583+ public QName (IRI resource ) {
584+ if (!VALID_XML_ELEMENT_NAME .matcher (resource .getLocalName ()).matches ()) {
585+ var iriString = resource .getNamespace () + resource .getLocalName ();
586+ var sep = XMLUtil .findURISplitIndex (iriString );
587+ namespace = iriString .substring (0 , sep );
588+ localName = iriString .substring (sep );
589+ } else {
590+ localName = resource .getLocalName ();
591+ namespace = resource .getNamespace ();
592+ }
593+ }
594+
595+ public String getLocalName () {
596+ return localName ;
597+ }
598+
599+ public String getNamespace () {
600+ return namespace ;
601+ }
602+ }
568603}
0 commit comments