1 5 6 package com.hp.hpl.jena.n3; 7 8 import org.apache.commons.logging.Log; 9 import org.apache.commons.logging.LogFactory; 10 11 import com.hp.hpl.jena.util.iterator.* ; 12 import com.hp.hpl.jena.rdf.model.*; 13 import com.hp.hpl.jena.shared.JenaException; 14 import com.hp.hpl.jena.vocabulary.OWL ; 15 import com.hp.hpl.jena.vocabulary.XSD ; 16 import com.hp.hpl.jena.vocabulary.RDF ; 17 18 import java.util.* ; 19 import java.io.* ; 20 import java.text.* ; 21 22 27 28 public class N3JenaWriterCommon implements RDFWriter 29 { 30 static Log logger = LogFactory.getLog(N3JenaWriterCommon.class) ; 31 32 37 39 Map writerPropertyMap = null ; 40 41 final boolean doAbbreviatedBaseURIref = getBooleanValue("abbrevBaseURI", true) ; 42 boolean alwaysAllocateBNodeLabel = false ; 43 44 RDFErrorHandler errorHandler = null; 46 47 static final String NS_W3_log = "http://www.w3.org/2000/10/swap/log#" ; 48 49 Map prefixMap = new HashMap() ; Map bNodesMap = null ; int bNodeCounter = 0 ; 52 53 static Map wellKnownPropsMap = new HashMap() ; 55 static { 56 wellKnownPropsMap.put(NS_W3_log+"implies", "=>" ) ; 57 wellKnownPropsMap.put(OWL.sameAs.getURI(), "=" ) ; 58 wellKnownPropsMap.put(RDF.type.getURI(), "a" ) ; 59 } 60 61 IndentedWriter out = null ; 63 String baseURIref = null ; 64 String baseURIrefHash = null ; 65 66 int minGap = getIntValue("minGap", 1) ; 68 String minGapStr = pad(minGap) ; 69 70 int indentProperty = getIntValue("indentProperty", 6) ; 72 73 int widePropertyLen = getIntValue("widePropertyLen", 20) ; 77 78 int propertyCol = getIntValue("propertyColumn", 8) ; 80 81 int indentObject = propertyCol ; 83 84 int subjectColumn = getIntValue("subjectColumn", indentProperty) ; 86 int shortSubject = subjectColumn-minGap; 88 89 boolean useWellKnownPropertySymbols = getBooleanValue("usePropertySymbols", true) ; 90 91 boolean allowTripleQuotedStrings = getBooleanValue("useTripleQuotedStrings", true) ; 92 boolean allowDoubles = getBooleanValue("useDoubles", true) ; 93 94 97 public RDFErrorHandler setErrorHandler(RDFErrorHandler errHandler) 98 { 99 RDFErrorHandler old = errorHandler; 100 errorHandler = errHandler; 101 return old; 102 } 103 104 public Object setProperty(String propName, Object propValue) 105 { 106 if ( ! ( propValue instanceof String ) ) 107 { 108 logger.warn("N3.setProperty: Property for '"+propName+"' is not a string") ; 109 propValue = propValue.toString() ; 110 } 111 112 propName = absolutePropName(propName) ; 114 if ( writerPropertyMap == null ) 115 writerPropertyMap = new HashMap() ; 116 Object oldValue = writerPropertyMap.get(propName); 117 writerPropertyMap.put(propName, propValue); 118 return oldValue; 119 } 120 121 144 145 public void write(Model baseModel, Writer _out, String base) 146 { 147 if (!(_out instanceof BufferedWriter)) 148 _out = new BufferedWriter(_out); 149 out = new IndentedWriter(_out); 150 151 153 if ( base != null ) 154 { 155 baseURIref = base ; 156 if ( !base.endsWith("#")) 157 baseURIrefHash = baseURIref+"#" ; 158 } 159 160 processModel(baseModel) ; 161 } 162 163 166 167 public synchronized void write(Model model, OutputStream output, String base) 168 { 169 try { 170 Writer w = new BufferedWriter(new OutputStreamWriter(output, "UTF-8")) ; 171 write(model, w, base) ; 172 try { w.flush() ; } catch (IOException ioEx) {} 173 } catch (java.io.UnsupportedEncodingException ex) 174 { 175 System.err.println("Failed to create UTF-8 writer") ; 176 } 177 } 178 179 186 188 194 196 protected void startWriting() {} 197 protected void finishWriting() {} 198 protected void prepare(Model model) {} 199 200 protected void processModel(Model baseModel) 201 { 202 prefixMap = baseModel.getNsPrefixMap() ; 203 Model model = ModelFactory.withHiddenStatements( baseModel ); 204 bNodesMap = new HashMap() ; 205 206 String base2 = (String )prefixMap.get("") ; 209 210 if ( base2 == null && baseURIrefHash != null ) 211 prefixMap.put("", baseURIrefHash) ; 212 213 for ( Iterator iter = prefixMap.keySet().iterator() ; iter.hasNext() ; ) 214 { 215 String prefix = (String )iter.next() ; 216 if ( prefix.indexOf('.') != -1 ) 217 iter.remove() ; 218 } 219 220 startWriting() ; 221 prepare(model) ; 222 223 writeHeader(model) ; 224 writePrefixes(model) ; 225 226 if (prefixMap.size() != 0) 227 out.println(); 228 229 writeModel(model) ; 231 232 finishWriting() ; 234 bNodesMap = null ; 235 } 236 237 protected void writeModel(Model model) 238 { 239 boolean doingFirst = true; 241 ResIterator rIter = model.listSubjects(); 242 for (; rIter.hasNext();) 243 { 244 Resource subject = rIter.nextResource(); 248 if ( skipThisSubject(subject) ) 249 { 250 if (N3JenaWriter.DEBUG) 251 out.println("# Skipping: " + formatResource(subject)); 252 continue; 253 } 254 255 if (doingFirst) 257 doingFirst = false; 258 else 259 out.println(); 260 261 writeOneGraphNode(subject) ; 262 263 264 } 265 rIter.close(); 266 } 267 268 protected void writeOneGraphNode(Resource subject) 269 { 270 out.incIndent(indentProperty) ; 273 writeSubject(subject); 274 writePropertiesForSubject(subject) ; 275 out.decIndent(indentProperty) ; 276 out.println(" ."); 277 } 278 279 protected void writePropertiesForSubject(Resource subj) 280 { 281 ClosableIterator iter = preparePropertiesForSubject(subj); 282 for (; iter.hasNext();) 284 { 285 Property property = (Property) iter.next(); 286 287 writeObjectList(subj, property); 289 290 if (iter.hasNext()) 291 out.println(" ;"); 292 } 293 iter.close(); 294 } 295 296 protected boolean skipThisSubject(Resource r) { return false ; } 300 301 302 305 protected void writeSubject(Resource subject) 306 { 307 String subjStr = formatResource(subject); 308 out.print(subjStr); 309 311 314 if (subjStr.length() < shortSubject ) 315 { 316 out.print(pad(subjectColumn - subjStr.length()) ); 317 } 318 else 319 out.println(); 321 } 322 323 protected void writeHeader(Model model) 324 { 325 if (baseURIref != null && !baseURIref.equals("") ) 326 out.println("# Base: " + baseURIref); 327 } 328 329 protected void writePrefixes(Model model) 330 { 331 for (Iterator pIter = prefixMap.keySet().iterator(); pIter.hasNext();) 332 { 333 String p = (String ) pIter.next(); 334 String u = (String ) prefixMap.get(p); 335 336 if (doAbbreviatedBaseURIref && p.equals("")) 338 { 339 if (baseURIrefHash != null && u.equals(baseURIrefHash)) 340 u = "#"; 341 if (baseURIref != null && u.equals(baseURIref)) 342 u = ""; 343 } 344 345 String tmp = "@prefix " + p + ": "; 346 out.print(tmp); 347 out.print(pad(16 - tmp.length())); 348 out.println(" <" + u + "> ."); 350 } 351 352 } 353 354 protected void writeObjectList(Resource resource, Property property) 355 { 356 String propStr = formatProperty(property) ; 357 358 363 366 StmtIterator sIter = resource.listProperties(property); 367 for (; sIter.hasNext();) 368 { 369 Statement stmt = sIter.nextStatement() ; 370 String objStr = formatNode(stmt.getObject()) ; 371 372 out.print(propStr); 373 out.incIndent(indentObject); 374 375 if ( (propStr.length()+minGap) <= widePropertyLen ) 376 { 377 381 int padding = calcPropertyPadding(propStr) ; 382 out.print(pad(padding)) ; 383 384 } 388 else 389 out.println(); 391 392 394 out.print(objStr) ; 395 out.decIndent(indentObject); 396 397 if ( sIter.hasNext() ) 398 { 399 out.println(" ;") ; 400 } 401 } 402 sIter.close() ; 403 404 } 405 406 protected String formatNode(RDFNode node) 407 { 408 if (node instanceof Literal) 409 return formatLiteral((Literal) node); 410 else 411 return formatResource((Resource)node) ; 412 } 413 414 protected void writeObject(RDFNode node) 415 { 416 if (node instanceof Literal) 417 { 418 writeLiteral((Literal) node); 419 return; 420 } 421 422 Resource rObj = (Resource) node; 423 424 out.print(formatResource(rObj)); 425 } 426 427 protected void writeLiteral(Literal literal) 428 { 429 out.print(formatLiteral(literal)) ; 430 } 431 432 protected ClosableIterator preparePropertiesForSubject(Resource r) 433 { 434 Set properties = new HashSet() ; 436 437 StmtIterator sIter = r.listProperties(); 438 for ( ; sIter.hasNext() ; ) 439 properties.add(sIter.nextStatement().getPredicate()) ; 440 sIter.close() ; 441 return WrappedIterator.create(properties.iterator()) ; 442 } 443 444 445 protected String formatResource(Resource r) 447 { 448 if ( r.isAnon() ) 449 { 450 if ( ! alwaysAllocateBNodeLabel ) 451 { 452 StmtIterator sIter = r.getModel().listStatements(null, null, r) ; 454 455 if ( ! sIter.hasNext() ) 456 { 457 sIter.close() ; 458 464 return "[]" ; 466 } 467 sIter.close() ; 468 } 469 if ( ! bNodesMap.containsKey(r) ) 470 bNodesMap.put(r, "_:b"+(++bNodeCounter)) ; 471 return (String )bNodesMap.get(r) ; 472 473 } 474 475 477 if ( r.equals(RDF.nil) ) 478 return "()" ; 479 480 return formatURI(r.getURI()) ; 481 } 482 483 protected String formatLiteral(Literal literal) 484 { 485 String datatype = literal.getDatatypeURI() ; 486 String lang = literal.getLanguage() ; 487 String s = literal.getLexicalForm() ; 488 489 if ( datatype != null ) 490 { 491 if ( datatype.equals(XSD.integer.getURI()) ) 494 { 495 try { 496 new java.math.BigInteger (s) ; 497 return s ; 498 } catch (NumberFormatException nfe) {} 499 } 502 503 if ( this.allowDoubles && datatype.equals(XSD.xdouble.getURI()) ) 504 { 505 if ( s.indexOf('.') >= 0 || 507 s.indexOf('e') >= 0 || 508 s.indexOf('E') >= 0 ) 509 { 510 try { 511 Double.parseDouble(s) ; 512 return s ; 513 } catch (NumberFormatException nfe) {} 514 } 516 } 517 } 518 StringBuffer sbuff = new StringBuffer () ; 520 boolean singleQuoteLiteral = true ; 521 522 String quoteMarks = "\"" ; 523 524 if ( this.allowTripleQuotedStrings && 526 ( s.indexOf("\n") != -1 || 527 s.indexOf("\r") != -1 || 528 s.indexOf("\f") != -1 ) ) 529 { 530 quoteMarks = "\"\"\"" ; 531 singleQuoteLiteral = false ; 532 } 533 534 sbuff.append(quoteMarks); 535 string(sbuff, s, singleQuoteLiteral) ; 536 sbuff.append(quoteMarks); 537 538 if ( lang != null && lang.length()>0) 540 { 541 sbuff.append("@") ; 542 sbuff.append(lang) ; 543 } 544 545 if ( datatype != null ) 547 { 548 sbuff.append("^^") ; 549 sbuff.append(formatURI(datatype)) ; 550 } 551 return sbuff.toString() ; 552 } 553 554 protected String formatProperty(Property p) 555 { 556 String prop = p.getURI() ; 557 if ( this.useWellKnownPropertySymbols && wellKnownPropsMap.containsKey(prop) ) 558 return (String )wellKnownPropsMap.get(prop); 559 560 return formatURI(prop) ; 561 } 562 563 protected String formatURI(String uriStr) 564 { 565 String matchURI = "" ; 566 String matchPrefix = null ; 567 568 if ( doAbbreviatedBaseURIref && uriStr.equals(baseURIref) ) 569 return "<>" ; 570 571 for ( Iterator pIter = prefixMap.keySet().iterator() ; pIter.hasNext() ; ) 578 { 579 String p = (String )pIter.next() ; 580 String u = (String )prefixMap.get(p) ; 581 if ( uriStr.startsWith(u) ) 582 if ( matchURI.length() < u.length() ) 583 { 584 matchPrefix = p ; 585 matchURI = u ; 586 } 587 } 588 if ( matchPrefix != null ) 589 { 590 String localname = uriStr.substring(matchURI.length()) ; 591 592 if ( checkQName(matchPrefix, localname) ) 593 return matchPrefix+":"+localname ; 594 595 } 597 598 return "<"+uriStr+">" ; 602 } 603 604 static boolean checkQName(String ns, String local) 608 { 609 return checkQNameNamespace(ns) && checkQNameLocalname(local) ; 610 } 611 612 static boolean checkQNameNamespace(String s) 613 { 614 return checkQNamePart(s) ; 615 } 616 static boolean checkQNameLocalname(String s) 617 { 618 return checkQNamePart(s) ; 619 } 620 621 622 static boolean checkQNamePart(String s) 623 { 624 boolean isOK = true ; 625 CharacterIterator cIter = new StringCharacterIterator(s) ; 626 627 for ( char ch = cIter.first() ; 628 ch != java.text.CharacterIterator.DONE ; 629 ch = cIter.next() ) 630 { 631 if ( Character.isLetterOrDigit(ch) ) 632 continue ; 633 switch (ch) 634 { 635 case '_': case '-': 636 continue ; 637 } 638 isOK = false ; 640 break ; 641 } 642 return isOK ; 643 } 644 645 final static String WS = "\n\r\t" ; 646 647 protected static void string(StringBuffer sbuff, String s, boolean singleQuoteLiteral) 648 { 649 for (int i = 0; i < s.length(); i++) { 650 char c = s.charAt(i); 651 652 if (c == '\\' || c == '"' ) 654 { 655 sbuff.append('\\') ; 656 sbuff.append(c) ; 657 continue ; 658 } 659 660 668 if ( singleQuoteLiteral && ( c == '\n' || c == '\r' || c == '\f' ) ) 670 { 671 if (c == '\n') sbuff.append("\\n"); 672 if (c == '\t') sbuff.append("\\t"); 673 if (c == '\r') sbuff.append("\\r"); 674 if (c == '\f') sbuff.append("\\f"); 675 continue ; 676 } 677 678 sbuff.append(c) ; 680 681 } 690 } 691 692 protected int calcPropertyPadding(String propStr) 693 { 694 int padding = propertyCol - propStr.length(); 695 if (padding < minGap) 696 padding = minGap; 697 return padding ; 698 } 699 700 protected static String pad(int cols) 701 { 702 StringBuffer sb = new StringBuffer () ; 703 for ( int i = 0 ; i < cols ; i++ ) 704 sb.append(' ') ; 705 return sb.toString() ; 706 } 707 708 710 protected int countProperties(Resource r) 711 { 712 int numProp = 0 ; 713 StmtIterator sIter = r.listProperties() ; 714 for ( ; sIter.hasNext() ; ) 715 { 716 sIter.nextStatement() ; 717 numProp++ ; 718 } 719 sIter.close() ; 720 return numProp ; 721 } 722 723 protected int countProperties(Resource r, Property p) 724 { 725 int numProp = 0 ; 726 StmtIterator sIter = r.listProperties(p) ; 727 for ( ; sIter.hasNext() ; ) 728 { 729 sIter.nextStatement() ; 730 numProp++ ; 731 } 732 sIter.close() ; 733 return numProp ; 734 } 735 736 737 protected int countArcsTo(Resource resource) 738 { 739 return countArcsTo(null, resource) ; 740 } 741 742 protected int countArcsTo(Property prop, Resource resource) 743 { 744 int numArcs = 0 ; 745 StmtIterator sIter = resource.getModel().listStatements(null, prop, resource) ; 746 for ( ; sIter.hasNext() ; ) 747 { 748 sIter.nextStatement() ; 749 numArcs++ ; 750 } 751 sIter.close() ; 752 return numArcs ; 753 } 754 755 756 protected Iterator rdfListIterator(Resource r) 757 { 758 List list = new ArrayList() ; 759 760 for ( ; ! r.equals(RDF.nil); ) 761 { 762 StmtIterator sIter = r.getModel().listStatements(r, RDF.first, (RDFNode)null) ; 763 list.add(sIter.nextStatement().getObject()) ; 764 if ( sIter.hasNext() ) 765 throw new JenaException("N3: Multi valued list item") ; 767 sIter = r.getModel().listStatements(r, RDF.rest, (RDFNode)null) ; 768 r = (Resource)sIter.nextStatement().getObject() ; 769 if ( sIter.hasNext() ) 770 throw new JenaException("N3: List has two tails") ; 771 } 772 return list.iterator() ; 773 } 774 775 777 protected String getStringValue(String prop, String defaultValue) 778 { 779 String p = getPropValue(prop) ; 780 781 if ( p == null ) 782 return defaultValue ; 783 return p ; 784 } 785 786 protected boolean getBooleanValue(String prop, boolean defaultValue) 787 { 788 String p = getPropValue(prop) ; 789 790 if ( p == null ) 791 return defaultValue ; 792 793 if ( p.equalsIgnoreCase("true") ) 794 return true ; 795 796 if ( p.equals("1") ) 797 return true ; 798 799 return false ; 800 } 801 802 protected int getIntValue(String prop, int defaultValue) 803 { 804 String p = getPropValue(prop) ; 805 if ( p == null ) 806 return defaultValue ; 807 try { 808 return Integer.parseInt(p) ; 809 } catch (NumberFormatException ex) 810 { 811 logger.warn("Format error for property: "+prop) ; 812 return defaultValue ; 813 } 814 } 815 816 818 protected String getPropValue(String prop) 819 { 820 prop = absolutePropName(prop) ; 821 if ( writerPropertyMap != null && writerPropertyMap.containsKey(prop) ) 822 { 823 Object obj = writerPropertyMap.get(prop) ; 824 if ( ! ( obj instanceof String ) ) 825 logger.warn("getPropValue: N3 Property for '"+prop+"' is not a string") ; 826 return (String )obj ; 827 } 828 String s = System.getProperty(prop) ; 829 if ( s == null ) 830 s = System.getProperty(localPropName(prop)) ; 831 return s ; 832 } 833 834 protected String absolutePropName(String propName) 835 { 836 if ( propName.indexOf(':') == -1 ) 837 return N3JenaWriter.propBase + propName ; 838 return propName ; 839 } 840 841 protected String localPropName(String propName) 842 { 843 if ( propName.startsWith(N3JenaWriter.propBase) ) 844 propName = propName.substring(N3JenaWriter.propBase.length()) ; 845 return propName ; 846 } 847 848 849 } 850 851 877 | Popular Tags |