📄 n3jenawriterpp.java
字号:
/*
* (c) Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007 Hewlett-Packard Development Company, LP
* [See end of file]
*/
package com.hp.hpl.jena.n3;
//import org.apache.commons.logging.*;
import com.hp.hpl.jena.rdf.model.*;
import com.hp.hpl.jena.shared.JenaException;
import com.hp.hpl.jena.vocabulary.RDF ;
import com.hp.hpl.jena.vocabulary.RDFS ;
import com.hp.hpl.jena.util.iterator.*;
import java.util.* ;
/** An N3 pretty printer.
* Tries to make N3 data look readable - works better on regular data.
*
* @author Andy Seaborne
* @version $Id: N3JenaWriterPP.java,v 1.20 2007/01/02 11:48:32 andy_seaborne Exp $
*/
public class N3JenaWriterPP extends N3JenaWriterCommon
/*implements RDFWriter*/
{
// This N3 writer proceeds in 2 stages. First, it analysises the model to be
// written to extract information that is going to be specially formatted
// (RDF lists, small anon nodes) and to calculate the prefixes that will be used.
final private boolean doObjectListsAsLists = getBooleanValue("objectLists", true) ;
// Data structures used in controlling the formatting
Set rdfLists = null ; // Heads of daml lists
Set rdfListsAll = null ; // Any resources in a daml lists
Set rdfListsDone = null ; // RDF lists written
Set roots = null ; // Things to put at the top level
Set oneRefObjects = null ; // Bnodes referred to once as an object - can inline
Set oneRefDone = null ; // Things done - so we can check for missed items
// Do we do nested (one reference) nodes?
boolean allowDeep = true ;
static final String objectListSep = " , " ;
// ----------------------------------------------------
// Prepatation stage
protected void prepare(Model model)
{
prepareLists(model) ;
prepareOneRefBNodes(model) ;
}
// Find well-formed RDF lists - does not find empty lists (this is intentional)
// Works by finding all tails, and work backwards to the head.
// RDF lists may, or may not, have a type element.
// Should do this during preparation, not as objects found during the write
// phase.
private void prepareLists(Model model)
{
Set thisListAll = new HashSet();
StmtIterator listTailsIter = model.listStatements(null, RDF.rest, RDF.nil);
// For every tail of a list
//tailLoop:
for ( ; listTailsIter.hasNext() ; )
{
// The resource for the current element being considered.
Resource listElement = listTailsIter.nextStatement().getSubject() ;
// The resource pointing to the link we have just looked at.
Resource validListHead = null ;
// Chase to head of list
for ( ; ; )
{
boolean isOK = checkListElement(listElement) ;
if ( ! isOK )
break ;
// At this point the element is exactly a DAML list element.
if ( N3JenaWriter.DEBUG ) out.println("# RDF list all: "+formatResource(listElement)) ;
validListHead = listElement ;
thisListAll.add(listElement) ;
// Find the previous node.
StmtIterator sPrev = model.listStatements(null, RDF.rest, listElement) ;
if ( ! sPrev.hasNext() )
// No daml:rest link
break ;
// Valid pretty-able list. Might be longer.
listElement = sPrev.nextStatement().getSubject() ;
if ( sPrev.hasNext() )
{
if ( N3JenaWriter.DEBUG ) out.println("# RDF shared tail from "+formatResource(listElement)) ;
break ;
}
}
// At head of a pretty-able list - add its elements and its head.
if ( N3JenaWriter.DEBUG ) out.println("# DAML list head: "+formatResource(validListHead)) ;
rdfListsAll.addAll(thisListAll) ;
if ( validListHead != null )
rdfLists.add(validListHead) ;
}
listTailsIter.close() ;
}
// Validate one list element.
private boolean checkListElement(Resource listElement)
{
if (!listElement.hasProperty(RDF.rest)
|| !listElement.hasProperty(RDF.first))
{
if (N3JenaWriter.DEBUG)
out.println(
"# RDF list element does not have required properties: "
+ formatResource(listElement));
return false;
}
// Must be exactly two properties (the ones we just tested for)
// or three including the RDF.type RDF.List statement.
int numProp = countProperties(listElement);
if ( numProp == 2)
// Must have exactly the properties we just tested for.
return true ;
if (numProp == 3)
{
if (listElement.hasProperty(RDF.type, RDF.List))
return true;
if (N3JenaWriter.DEBUG)
out.println(
"# RDF list element: 3 properties but no rdf:type rdf:List"
+ formatResource(listElement));
return false;
}
if (N3JenaWriter.DEBUG)
out.println(
"# RDF list element does not right number of properties: "
+ formatResource(listElement));
return false;
}
// Find bnodes that are objects of only one statement (and hence can be inlined)
// which are not RDF lists.
// Could do this testing at write time (unlike lists)
private void prepareOneRefBNodes(Model model)
{
NodeIterator objIter = model.listObjects() ;
for ( ; objIter.hasNext() ; )
{
RDFNode n = objIter.nextNode() ;
if ( testOneRefBNode(n) )
oneRefObjects.add(n) ;
objIter.close() ;
// N3JenaWriter.DEBUG
if ( N3JenaWriter.DEBUG )
{
out.println("# RDF Lists = "+rdfLists.size()) ;
out.println("# RDF ListsAll = "+rdfListsAll.size()) ;
out.println("# oneRefObjects = "+oneRefObjects.size()) ;
}
}
}
private boolean testOneRefBNode(RDFNode n)
{
if ( ! ( n instanceof Resource ) )
return false ;
Resource obj = (Resource)n ;
if ( ! obj.isAnon() )
return false ;
// In a list - done as list, not as embedded bNode.
if ( rdfListsAll.contains(obj) )
// RDF list (head or element)
return false ;
StmtIterator pointsToIter = obj.getModel().listStatements(null, null, obj) ;
if ( ! pointsToIter.hasNext() )
// Corrupt graph!
throw new JenaException("N3: found object with no arcs!") ;
Statement s = pointsToIter.nextStatement() ;
if ( pointsToIter.hasNext() )
return false ;
if ( N3JenaWriter.DEBUG )
out.println("# OneRef: "+formatResource(obj)) ;
return true ;
}
// ----------------------------------------------------
// Output stage
// Property order is:
// 1 - rdf:type (as "a")
// 2 - other rdf: rdfs: namespace items (sorted)
// 3 - all other properties, sorted by URI (not qname)
protected ClosableIterator preparePropertiesForSubject(Resource r)
{
Set seen = new HashSet() ;
boolean hasTypes = false ;
SortedMap tmp1 = new TreeMap() ;
SortedMap tmp2 = new TreeMap() ;
StmtIterator sIter = r.listProperties();
for ( ; sIter.hasNext() ; )
{
Property p = sIter.nextStatement().getPredicate() ;
if ( seen.contains(p) )
continue ;
seen.add(p) ;
if ( p.equals(RDF.type) )
{
hasTypes = true ;
continue ;
}
if ( p.getURI().startsWith(RDF.getURI()) ||
p.getURI().startsWith(RDFS.getURI()) )
{
tmp1.put(p.getURI(), p) ;
continue ;
}
tmp2.put(p.getURI(), p) ;
}
sIter.close() ;
ExtendedIterator eIter = null ;
if ( hasTypes )
eIter = new SingletonIterator(RDF.type) ;
ExtendedIterator eIter2 = WrappedIterator.create(tmp1.values().iterator()) ;
eIter = (eIter == null) ? eIter2 : eIter.andThen(eIter2) ;
eIter2 = WrappedIterator.create(tmp2.values().iterator()) ;
eIter = (eIter == null) ? eIter2 : eIter.andThen(eIter2) ;
return eIter ;
}
protected boolean skipThisSubject(Resource subj)
{
return rdfListsAll.contains(subj) ||
oneRefObjects.contains(subj) ;
}
// protected void writeModel(Model model)
// {
// super.writeModel(model) ;
//
//
// Before ...
protected void startWriting()
{
allocateDatastructures() ;
}
// Flush any unwritten objects.
// 1 - OneRef objects
// Normally there are "one ref" objects left
// However loops of "one ref" are possible.
// 2 - Lists
protected void finishWriting()
{
oneRefObjects.removeAll(oneRefDone);
for (Iterator leftOverIter = oneRefObjects.iterator(); leftOverIter.hasNext();)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -