📄 abbreviatedrdfxmlwriter.java
字号:
/* Sesame - Storage and Querying architecture for RDF and RDF Schema * Copyright (C) 2001-2005 Aduna * * Contact: * Aduna * Prinses Julianaplein 14 b * 3817 CS Amersfoort * The Netherlands * tel. +33 (0)33 465 99 87 * fax. +33 (0)33 465 99 87 * * http://aduna.biz/ * http://www.openrdf.org/ * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */package org.openrdf.rio.rdfxml;import java.io.IOException;import java.io.OutputStream;import java.io.Writer;import java.util.HashMap;import java.util.Iterator;import java.util.Map;import java.util.Stack;import org.openrdf.util.xml.XmlUtil;import org.openrdf.vocabulary.RDF;import org.openrdf.vocabulary.RDFS;import org.openrdf.model.BNode;import org.openrdf.model.Literal;import org.openrdf.model.Resource;import org.openrdf.model.URI;import org.openrdf.model.Value;import org.openrdf.model.impl.URIImpl;/** * An extension of RdfXmlWriter that outputs a more concise form of RDF/XML. The * resulting output is semantically equivalent to the output of an RdfXmlWriter * (it produces the same set of statements), but it is usually easier to read * for humans. * <p> * This is a quasi-streaming RdfDocumentWriter. Statements are cached as long as * the striped syntax is followed (i.e. the subject of the next statement is the * object of the previous statement) and written to the output when the stripe * is broken. * <p> * The abbreviations used are * <a href="http://www.w3.org/TR/rdf-syntax-grammar/#section-Syntax-typed-nodes">typed node elements</a>, * <a href="http://www.w3.org/TR/rdf-syntax-grammar/#section-Syntax-empty-property-elements">empty property elements</a> * and * <a href="http://www.w3.org/TR/rdf-syntax-grammar/#section-Syntax-node-property-elements">striped syntax</a>. * Note that these abbreviations require that statements are written in the * appropriate order. * <p> * Striped syntax means that when the object of a statement is the subject of * the next statement we can nest the descriptions in each other. * <p> * Example: * <pre> * <rdf:Seq> * <rdf:li> * <foaf:Person> * <foaf:knows> * <foaf:Person> * <foaf:mbox rdf:resource="..." /> * </foaf:Person> * </foaf:knows> * </foaf:Person> * </rdf:li> * </rdf:Seq> * </pre> * * Typed node elements means that we write out type information in the short * form of * <pre> * <foaf:Person> * ... * </foaf:Person> * </pre> * * instead of * * <pre> * <rdf:Description> * <rdf:type rdf:resource="http://xmlns.com/foaf/0.1/Person"/> * ... * </rdf:Description> * </pre> * * Empty property elements are of the form * * <pre> * <foaf:Person> * <foaf:homepage rdf:resource="http://www.cs.vu.nl/~marta"/> * </foaf:Person> * </pre> * * instead of * * <pre> * <foaf:Person> * <foaf:homepage> * <rdf:Description rdf:about="http://www.cs.vu.nl/~marta"/> * <foaf:homepage> * </foaf:Person> * </pre> * * @author Peter Mika (pmika@cs.vu.nl) */public class AbbreviatedRdfXmlWriter extends RdfXmlWriter { /*---------------------------------+ | Variables | +---------------------------------*/ /* * We implement striped syntax by using two stacks, one for predicates and * one for subjects/objects. * * The stack for subjects/objects contains elements of type * SubjectStackElement (inner class), the stack for predicates contains URI * objects. */ //Stack for remembering the subject of statements at each level private Stack _subjectStack = new Stack(); //Stack for remembering the predicate of statements private Stack _predicateStack = new Stack(); /*---------------------------------+ | Constructors | +---------------------------------*/ /** * Creates a new RdfXmlWriter that will write to the supplied OutputStream. * * @param out The OutputStream to write the RDF/XML document to. */ public AbbreviatedRdfXmlWriter(OutputStream out) { super(out); } /** * Creates a new RdfXmlWriter that will write to the supplied Writer. * * @param out The Writer to write the RDF/XML document to. */ public AbbreviatedRdfXmlWriter(Writer out) { super(out); } /*---------------------------------+ | Methods from interface RdfWriter | +---------------------------------*/ public void startDocument() throws IOException { if (_writingStarted) { throw new RuntimeException("Document writing has already started"); } // This export format needs the RDF Schema namespace to be defined: _setNamespace("rdfs", RDFS.NAMESPACE, false); super.startDocument(); } public void endDocument() throws IOException { if (!_writingStarted) { throw new RuntimeException("Document writing has not yet started"); } try { emptyStack(null); _writeNewLine(); _writeEndTag(RDF.NAMESPACE, "RDF"); _out.flush(); } finally { _writingStarted = false; } } /** * Write out the stack until we find subject. If subject == null, write out * the entire stack * @param subject */ private void emptyStack(Resource subject) throws IOException { // Write out the part of the subject stack (start tags) that // are not yet written for (int i = 0; i < _subjectStack.size() - 1; i++) { SubjectStackElement nextElement = (SubjectStackElement)_subjectStack.get(i); if (!nextElement.isWritten()) { if (i != 0) { _writeIndents(i * 2 - 1); URI nextPredicate = (URI)_predicateStack.get(i - 1); _writeStartOfStartTag( nextPredicate.getNamespace(), nextPredicate.getLocalName()); _writeEndOfStartTag(); _writeNewLine(); } _writeIndents(i * 2); _writeStartSubject(nextElement); nextElement.setIsWritten(true); } } URI lastPredicate = null; if (_predicateStack.size() > 0) { lastPredicate = (URI) _predicateStack.pop(); } SubjectStackElement lastElement = ((SubjectStackElement) _subjectStack.pop()); if (lastElement.getType() == null && lastPredicate != null) { //we can use an abbreviated predicate _writeIndents(_subjectStack.size() * 2 - 1); _writeAbbreviatedPredicate(lastPredicate, lastElement.getSubject()); } else { //we cannot use an abbreviated predicate, //either because there is no predicate (single type statement) //or because the type needs to written out as well if (lastPredicate != null) { _writeIndents(_subjectStack.size() * 2 - 1); _writeStartOfStartTag(lastPredicate.getNamespace(), lastPredicate.getLocalName()); _writeEndOfStartTag(); _writeNewLine(); } //write out an empty subject _writeIndents(_subjectStack.size() * 2); _writeEmptySubject(lastElement); _writeNewLine(); if (lastPredicate != null) { _writeIndents(_subjectStack.size() * 2 - 1); _writeEndTag(lastPredicate.getNamespace(), lastPredicate .getLocalName()); _writeNewLine(); } } // Write out the end tags until we find the subject boolean foundSubject = false; while (_subjectStack.size() > 0 && !foundSubject) { SubjectStackElement nextElement = _peekSubjectStack(0); if (subject != null && subject.equals(nextElement.getSubject())) { foundSubject = true; } else { _subjectStack.pop(); // We have already written out the subject/object, // but we still need to close the tag _writeIndents(_predicateStack.size() + _subjectStack.size()); _writeEndSubject(nextElement); if (_predicateStack.size() > 0) { URI nextPredicate = (URI)_predicateStack.pop(); _writeIndents(_predicateStack.size() + _subjectStack.size()); _writeEndTag( nextPredicate.getNamespace(), nextPredicate.getLocalName()); _writeNewLine(); } } } } public void writeStatement(Resource subj, URI pred, Value obj) throws IOException { if (!_writingStarted) { throw new RuntimeException("Document writing has not yet started"); } // Peek at the stack SubjectStackElement top = null; if (_subjectStack.size() > 0) { top = _peekSubjectStack(0); } if (top != null && !subj.equals(top.getSubject())) { // Different subject than we had before, empty the stack // until we find it emptyStack(subj); } // Stack is either empty or contains the same subject at top if (_subjectStack.size() == 0) { // Push subject _subjectStack.push( new SubjectStackElement(subj) ); } // Stack now contains at least one element top = _peekSubjectStack(0); // Check if current statement is a type statement if (pred != null && pred.equals(URIImpl.RDF_TYPE) && obj != null && obj instanceof URI) { if (!top.isWritten()) { top.setType( (URI)obj ); } else { _predicateStack.push(pred); _subjectStack.push( new SubjectStackElement(obj) ); } // Handling statement is finished } else { // Push predicate and object _predicateStack.push(pred); _subjectStack.push( new SubjectStackElement(obj) ); } } /** Write out the opening tag of the subject or object of a statement * up to (but not including) the end of the tag. * Used both in _writeStartSubject and _writeEmptySubject. * * @param element * @throws IOException */ private void _writeStartOfStartSubject(SubjectStackElement element) throws IOException { Value subj = element.getSubject(); if (element.getType() != null) { // We can use abbreviated syntax _writeStartOfStartTag( element.getType().getNamespace(), element.getType().getLocalName()); } else { // We cannot use abbreviated syntax _writeStartOfStartTag(RDF.NAMESPACE, "Description"); } if (subj instanceof BNode) { BNode bNode = (BNode)subj; _writeAttribute(RDF.NAMESPACE, "nodeID", bNode.getID()); } else { URI uri = (URI)subj; _writeAttribute(RDF.NAMESPACE, "about", uri.getURI()); } } /** * Write out the opening tag of the subject or object of a statement. * * @param element * @throws IOException */ private void _writeStartSubject(SubjectStackElement element) throws IOException { _writeStartOfStartSubject(element); _writeEndOfStartTag(); _writeNewLine(); } /** * Write out the closing tag for the subject or object of a statement. * * @param element * @throws IOException */ private void _writeEndSubject(SubjectStackElement element) throws IOException { if (element.getType() != null) { _writeEndTag(element.getType().getNamespace(), element.getType().getLocalName()); } else { _writeEndTag(RDF.NAMESPACE, "Description"); } _writeNewLine(); } /** * Write out the closing tag for the subject or object of a statement. * * @param element * @throws IOException */ private void _writeEmptySubject(SubjectStackElement element) throws IOException { _writeStartOfStartSubject(element); this._writeEndOfEmptyTag(); } /** * Write out an empty property element. * * @param pred * @param obj * @throws IOException */ private void _writeAbbreviatedPredicate(URI pred, Value obj) throws IOException { _writeStartOfStartTag(pred.getNamespace(), pred.getLocalName()); if (obj instanceof Literal) { Literal objLit = (Literal)obj; // language attribute if (objLit.getLanguage() != null) { _writeAttribute("xml:lang", objLit.getLanguage()); } // datatype attribute boolean isXmlLiteral = false; URI datatype = objLit.getDatatype(); if (datatype != null) { // Check if datatype is rdf:XMLLiteral String datatypeString = datatype.getURI(); isXmlLiteral = datatypeString.equals(RDF.XMLLITERAL); if (isXmlLiteral) { _writeAttribute(RDF.NAMESPACE, "parseType", "Literal"); } else { _writeAttribute(RDF.NAMESPACE, "datatype", objLit.getDatatype().getURI()); } } _writeEndOfStartTag(); // label if (isXmlLiteral) { // Write XML literal as plain XML _out.write(objLit.getLabel()); } else { _writeChars(objLit.getLabel()); } _writeEndTag(pred.getNamespace(), pred.getLocalName()); } else { Resource objRes = (Resource) obj; if (objRes instanceof BNode) { BNode bNode = (BNode)objRes; _writeAttribute(RDF.NAMESPACE, "nodeID", bNode.getID()); } else { URI uri = (URI)objRes; _writeAttribute(RDF.NAMESPACE, "resource", uri.getURI()); } _writeEndOfEmptyTag(); } _writeNewLine(); } public void writeComment(String comment) throws IOException { if (_subjectStack.size() > 0) { emptyStack(null); } _out.write("<!-- "); _out.write(comment); _out.write(" -->"); _writeNewLine(); } /** * Writes <tt>n</tt> indents. */ protected void _writeIndents(int n) throws IOException { for (int i = 0; i < n; i++) { _writeIndent(); } } private SubjectStackElement _peekSubjectStack(int distFromTop) { return (SubjectStackElement)_subjectStack.get(_subjectStack.size() - 1 - distFromTop); } /*--------------------------------+ | Inner class SubjectStackElement | +--------------------------------*/ static class SubjectStackElement { private Value _subject; //type == null means that we use <rdf:Description> private URI _type = null; private boolean _isWritten = false; /** * Creates a new SubjectStackElement for the supplied subject Value. */ public SubjectStackElement(Value subject) { _subject = subject; } public Value getSubject() { return _subject; } public void setType(URI type) { _type = type; } public URI getType() { return _type; } public void setIsWritten(boolean isWritten) { _isWritten = isWritten; } public boolean isWritten() { return _isWritten; } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -