annotate src/org/qmul/eecs/c4dm/sia/midi/MidiParser.java @ 37:cb7f70e10a0c

New
author stevenh
date Tue, 26 Feb 2013 13:30:46 +0000
parents
children fa9030705e93
rev   line source
stevenh@37 1 package org.qmul.eecs.c4dm.sia.midi;
stevenh@37 2
stevenh@37 3 import java.io.File;
stevenh@37 4 import java.io.FileNotFoundException;
stevenh@37 5 import java.io.FileOutputStream;
stevenh@37 6 import java.io.IOException;
stevenh@37 7 import java.util.ArrayList;
stevenh@37 8 import java.util.Collection;
stevenh@37 9 import java.util.HashMap;
stevenh@37 10 import java.util.Iterator;
stevenh@37 11 import java.util.List;
stevenh@37 12 import java.util.Vector;
stevenh@37 13
stevenh@37 14 import javax.sound.midi.InvalidMidiDataException;
stevenh@37 15 import javax.sound.midi.MetaMessage;
stevenh@37 16 import javax.sound.midi.MidiEvent;
stevenh@37 17 import javax.sound.midi.MidiMessage;
stevenh@37 18 import javax.sound.midi.MidiSystem;
stevenh@37 19 import javax.sound.midi.Sequence;
stevenh@37 20 import javax.sound.midi.ShortMessage;
stevenh@37 21 import javax.sound.midi.SysexMessage;
stevenh@37 22 import javax.sound.midi.Track;
stevenh@37 23
stevenh@37 24 import org.qmul.eecs.c4dm.sia.model.Datapoint;
stevenh@37 25 import org.qmul.eecs.c4dm.sia.model.DimensionValue;
stevenh@37 26 import org.qmul.eecs.c4dm.sia.rdf.Namespaces;
stevenh@37 27
stevenh@37 28 import com.hp.hpl.jena.ontology.OntClass;
stevenh@37 29 import com.hp.hpl.jena.ontology.OntModel;
stevenh@37 30 import com.hp.hpl.jena.ontology.OntResource;
stevenh@37 31 import com.hp.hpl.jena.rdf.model.AnonId;
stevenh@37 32 import com.hp.hpl.jena.rdf.model.ModelFactory;
stevenh@37 33 import com.hp.hpl.jena.rdf.model.NodeIterator;
stevenh@37 34 import com.hp.hpl.jena.rdf.model.Property;
stevenh@37 35 import com.hp.hpl.jena.rdf.model.RDFNode;
stevenh@37 36 import com.hp.hpl.jena.rdf.model.Resource;
stevenh@37 37 import com.hp.hpl.jena.rdf.model.Statement;
stevenh@37 38 import com.hp.hpl.jena.rdf.model.StmtIterator;
stevenh@37 39 import com.hp.hpl.jena.util.iterator.ExtendedIterator;
stevenh@37 40 import com.hp.hpl.jena.vocabulary.RDF;
stevenh@37 41 import com.sun.media.sound.MidiUtils;
stevenh@37 42
stevenh@37 43 public class MidiParser {
stevenh@37 44
stevenh@37 45 public static final int TIME_DIMENSION = 1;
stevenh@37 46 public static final int PITCH_DIMENSION = 2;
stevenh@37 47 public static final int CHANNEL_DIMENSION = 3;
stevenh@37 48
stevenh@37 49 // The ontology loaded as dataset
stevenh@37 50 private static final String ontology = "file:src/rdf/siaDatapointOntology.n3";
stevenh@37 51
stevenh@37 52 // The final output file
stevenh@37 53 private static final String finalModelFileName = "src/rdf/midiModel";
stevenh@37 54
stevenh@37 55 public static void main(String[] args)
stevenh@37 56 {
stevenh@37 57 // First create a Jena ontology model
stevenh@37 58 OntModel ontModel = ModelFactory
stevenh@37 59 .createOntologyModel(); // OntModelSpec.OWL_MEM
stevenh@37 60
stevenh@37 61 // Then read the data from the file into the ontology model
stevenh@37 62 ontModel.read(ontology, "N3");
stevenh@37 63
stevenh@37 64 // Set the value of SIA_NS_URI as the namespace for 'sia' found in
stevenh@37 65 // the ontology. This must be done before we use any of the sia.model classes.
stevenh@37 66 Namespaces.SIA_NS_URI = ontModel.getNsPrefixURI("sia");
stevenh@37 67 OntClass datapointClass = ontModel.getOntClass(Datapoint.RESOURCE_URI);
stevenh@37 68 Resource datapointResource = ontModel.getOntResource(datapointClass);
stevenh@37 69 Property siaDimValProperty = ontModel.createProperty(DimensionValue.PROPERTY_URI);
stevenh@37 70 Property siaDimensionProperty = ontModel.createProperty(DimensionValue.DIMENSION_URI);
stevenh@37 71 Property siaValueProperty = ontModel.createProperty(DimensionValue.VALUE_URI);
stevenh@37 72
stevenh@37 73 String midiFileName = "/Volumes/USB DISK/portable/ewerts/Cantata_16_no_5-mids/score.mid";
stevenh@37 74
stevenh@37 75 File midiFile1 = new File(midiFileName);
stevenh@37 76
stevenh@37 77 Sequence sequence = null;
stevenh@37 78 try {
stevenh@37 79 sequence = MidiSystem.getSequence(midiFile1);
stevenh@37 80 } catch (InvalidMidiDataException e) {
stevenh@37 81 e.printStackTrace();
stevenh@37 82 System.exit(1);
stevenh@37 83 } catch (IOException e) {
stevenh@37 84 e.printStackTrace();
stevenh@37 85 System.exit(1);
stevenh@37 86 }
stevenh@37 87
stevenh@37 88 MidiUtils.TempoCache tempoCache = new MidiUtils.TempoCache(sequence);
stevenh@37 89
stevenh@37 90 Track[] tracks = sequence.getTracks();
stevenh@37 91 int numTracks = tracks.length;
stevenh@37 92 float divisionType = sequence.getDivisionType();
stevenh@37 93 List<Datapoint> datapoints = new ArrayList<Datapoint>();
stevenh@37 94
stevenh@37 95 HashMap<Integer, Integer> trackDimensionMap = getTrackToDimensionIndexMap(sequence);
stevenh@37 96
stevenh@37 97 if (trackDimensionMap.isEmpty())
stevenh@37 98 {
stevenh@37 99 try {
stevenh@37 100 throw new Exception("Couldn't find any track to dimension mappings");
stevenh@37 101 } catch (Exception e) {
stevenh@37 102 e.printStackTrace();
stevenh@37 103 System.exit(1);
stevenh@37 104 }
stevenh@37 105 }
stevenh@37 106
stevenh@37 107 long maxTick = 0;
stevenh@37 108
stevenh@37 109 for (int trackIdx = 0; trackIdx < numTracks; trackIdx++)
stevenh@37 110 {
stevenh@37 111 System.out.println("Track " + trackIdx + ":");
stevenh@37 112 int numEvents = tracks[trackIdx].size();
stevenh@37 113 for (int eventIdx = 0; eventIdx < numEvents; eventIdx++)
stevenh@37 114 {
stevenh@37 115 MidiEvent event = tracks[trackIdx].get(eventIdx);
stevenh@37 116 long tick = event.getTick();
stevenh@37 117 MidiMessage midiMessage = event.getMessage();
stevenh@37 118
stevenh@37 119 int midiMessageLength = midiMessage.getLength();
stevenh@37 120 byte[] messageBytes = midiMessage.getMessage();
stevenh@37 121 int status = midiMessage.getStatus();
stevenh@37 122 System.out.println("tick = " + tick + " midiMessageLength = " + midiMessageLength + " status byte = " + status);
stevenh@37 123
stevenh@37 124 int s = status & 0x80;
stevenh@37 125 if (s == 0x80)
stevenh@37 126 {
stevenh@37 127 System.out.println("STATUS MESSAGE (s = " + s + ")");
stevenh@37 128 }
stevenh@37 129 else
stevenh@37 130 {
stevenh@37 131 System.out.println("not a status message (s = " + s + ")");
stevenh@37 132 }
stevenh@37 133
stevenh@37 134 // Determine the type of this message (short, sysex or meta)
stevenh@37 135 if (midiMessage instanceof ShortMessage)
stevenh@37 136 {
stevenh@37 137 System.out.print("ShortMessage ");
stevenh@37 138
stevenh@37 139 // Determine which command is being issued
stevenh@37 140 ShortMessage shortMessage = (ShortMessage)midiMessage;
stevenh@37 141 int messageCommand = shortMessage.getCommand();
stevenh@37 142 int channel = shortMessage.getChannel();
stevenh@37 143 int data1 = shortMessage.getData1();
stevenh@37 144 int data2 = shortMessage.getData2();
stevenh@37 145
stevenh@37 146 if (messageCommand == ShortMessage.ACTIVE_SENSING)
stevenh@37 147 {
stevenh@37 148 System.out.print("ignoring ACTIVE_SENSING");
stevenh@37 149 }
stevenh@37 150 else if (messageCommand == ShortMessage.CHANNEL_PRESSURE)
stevenh@37 151 {
stevenh@37 152 System.out.print("ignoring CHANNEL_PRESSURE");
stevenh@37 153 }
stevenh@37 154 else if (messageCommand == ShortMessage.CONTINUE)
stevenh@37 155 {
stevenh@37 156 System.out.print("ignoring CONTINUE");
stevenh@37 157 }
stevenh@37 158 else if (messageCommand == ShortMessage.CONTROL_CHANGE)
stevenh@37 159 {
stevenh@37 160 System.out.print("ignoring CONTROL_CHANGE");
stevenh@37 161 }
stevenh@37 162 else if (messageCommand == ShortMessage.END_OF_EXCLUSIVE)
stevenh@37 163 {
stevenh@37 164 System.out.print("ignoring END_OF_EXCLUSIVE");
stevenh@37 165 }
stevenh@37 166 else if (messageCommand == ShortMessage.MIDI_TIME_CODE)
stevenh@37 167 {
stevenh@37 168 System.out.print("ignoring MIDI_TIME_CODE");
stevenh@37 169 }
stevenh@37 170 else if (messageCommand == ShortMessage.NOTE_OFF)
stevenh@37 171 {
stevenh@37 172 System.out.println("NOTE_OFF");
stevenh@37 173 long microsecs = MidiUtils.tick2microsecond(sequence, tick, tempoCache);
stevenh@37 174 System.out.println(" microsecs = " + microsecs);
stevenh@37 175 }
stevenh@37 176 else if (messageCommand == ShortMessage.NOTE_ON)
stevenh@37 177 {
stevenh@37 178 if (tick > maxTick)
stevenh@37 179 {
stevenh@37 180 maxTick = tick;
stevenh@37 181 }
stevenh@37 182 System.out.println("NOTE_ON");
stevenh@37 183 long microsecs = MidiUtils.tick2microsecond(sequence, tick, tempoCache);
stevenh@37 184 System.out.println(" microsecs = " + microsecs);
stevenh@37 185
stevenh@37 186 DimensionValue timeDimVal = new DimensionValue();
stevenh@37 187 timeDimVal.setDimension(TIME_DIMENSION);
stevenh@37 188 timeDimVal.setValue(tick);
stevenh@37 189
stevenh@37 190 DimensionValue dimVal = new DimensionValue();
stevenh@37 191 dimVal.setDimension(trackDimensionMap.get(trackIdx));
stevenh@37 192 dimVal.setValue(data1);
stevenh@37 193
stevenh@37 194 Datapoint datapoint = new Datapoint();
stevenh@37 195 Vector<DimensionValue> dimVals = new Vector<DimensionValue>();
stevenh@37 196 dimVals.add(timeDimVal);
stevenh@37 197 dimVals.add(dimVal);
stevenh@37 198
stevenh@37 199 datapoint.setDimensionValues(dimVals);
stevenh@37 200 datapoints.add(datapoint);
stevenh@37 201
stevenh@37 202 // RDF
stevenh@37 203 Resource datapointBnode = ontModel.createResource(AnonId.create());
stevenh@37 204 ontModel.add(datapointBnode, RDF.type, datapointResource);
stevenh@37 205
stevenh@37 206 Resource timeDimValBnode = ontModel.createResource(AnonId.create());
stevenh@37 207 Resource pitchDimValBnode = ontModel.createResource(AnonId.create());
stevenh@37 208
stevenh@37 209 ontModel.add(datapointBnode, siaDimValProperty, timeDimValBnode);
stevenh@37 210 ontModel.addLiteral(timeDimValBnode, siaDimensionProperty, TIME_DIMENSION);
stevenh@37 211 ontModel.addLiteral(timeDimValBnode, siaValueProperty, tick);
stevenh@37 212
stevenh@37 213 ontModel.add(datapointBnode, siaDimValProperty, pitchDimValBnode);
stevenh@37 214 ontModel.addLiteral(pitchDimValBnode, siaDimensionProperty, trackDimensionMap.get(trackIdx).intValue());
stevenh@37 215 ontModel.addLiteral(pitchDimValBnode, siaValueProperty, data1);
stevenh@37 216 }
stevenh@37 217 else if (messageCommand == ShortMessage.PITCH_BEND)
stevenh@37 218 {
stevenh@37 219 System.out.print("ignoring PITCH_BEND");
stevenh@37 220 }
stevenh@37 221 else if (messageCommand == ShortMessage.POLY_PRESSURE)
stevenh@37 222 {
stevenh@37 223 System.out.print("ignoring POLY_PRESSURE");
stevenh@37 224 }
stevenh@37 225 else if (messageCommand == ShortMessage.PROGRAM_CHANGE)
stevenh@37 226 {
stevenh@37 227 System.out.print("ignoring PROGRAM_CHANGE");
stevenh@37 228 }
stevenh@37 229 else if (messageCommand == ShortMessage.SONG_POSITION_POINTER)
stevenh@37 230 {
stevenh@37 231 System.out.print("ignoring SONG_POSITION_POINTER");
stevenh@37 232 }
stevenh@37 233 else
stevenh@37 234 {
stevenh@37 235 System.out.print("unrecognised midi message command (" + messageCommand + ")");
stevenh@37 236 }
stevenh@37 237 System.out.print(", channel " + channel + ", data1 = [" + data1 + "], data2 = [" + data2 + "]");
stevenh@37 238 System.out.println();
stevenh@37 239 }
stevenh@37 240 else if (midiMessage instanceof MetaMessage)
stevenh@37 241 {
stevenh@37 242 System.out.println("MetaMessage");
stevenh@37 243
stevenh@37 244 MetaMessage metaMessage = (MetaMessage)midiMessage;
stevenh@37 245 byte[] metaMessageData = metaMessage.getData();
stevenh@37 246 int metaMessageLength = metaMessage.getLength();
stevenh@37 247 int metaMessageType = metaMessage.getType();
stevenh@37 248 System.out.println("metaMessageType = " + metaMessageType + ", metaMessageLength = " + metaMessageLength);
stevenh@37 249
stevenh@37 250 // Determine message type
stevenh@37 251 if (metaMessageType == 81)
stevenh@37 252 {
stevenh@37 253 if (divisionType == Sequence.PPQ)
stevenh@37 254 {
stevenh@37 255 // Do nothing - we've dealt with PPQ tempo data elsewhere
stevenh@37 256 }
stevenh@37 257 else
stevenh@37 258 {
stevenh@37 259 try {
stevenh@37 260 throw new Exception("Not yet implemented SMPTE tempo metadata");
stevenh@37 261 } catch (Exception e) {
stevenh@37 262 e.printStackTrace();
stevenh@37 263 System.exit(1);
stevenh@37 264 }
stevenh@37 265 }
stevenh@37 266 }
stevenh@37 267
stevenh@37 268 for (int dataIdx = 0; dataIdx < metaMessageData.length; dataIdx++)
stevenh@37 269 {
stevenh@37 270 System.out.println("\tmetaMessageData[" + dataIdx + "] = " + (metaMessageType == 81 ? metaMessageData[dataIdx] : (char)metaMessageData[dataIdx]));
stevenh@37 271 }
stevenh@37 272
stevenh@37 273 }
stevenh@37 274 else if (midiMessage instanceof SysexMessage)
stevenh@37 275 {
stevenh@37 276 // We can safely ignore these messages
stevenh@37 277 System.out.println("ignoring SysexMessage");
stevenh@37 278 }
stevenh@37 279 else
stevenh@37 280 {
stevenh@37 281 System.out.println("Unknown MidiMessage type (" + midiMessage.getClass().toString() + ")");
stevenh@37 282 }
stevenh@37 283
stevenh@37 284 for (int byteIdx = 0; byteIdx < midiMessageLength; byteIdx++)
stevenh@37 285 {
stevenh@37 286 byte messageByte = messageBytes[byteIdx];
stevenh@37 287 System.out.println("\tbyte[" + byteIdx + "] = " + messageByte);
stevenh@37 288 }
stevenh@37 289 }
stevenh@37 290 }
stevenh@37 291
stevenh@37 292 // Data integrity start - set any 'missing' dimensions to zero value
stevenh@37 293 // Note the highest dimension for later use
stevenh@37 294 Collection<Integer> values = trackDimensionMap.values();
stevenh@37 295 Iterator<Integer> valuesIter = values.iterator();
stevenh@37 296 int maxDimension = 0;
stevenh@37 297 while (valuesIter.hasNext())
stevenh@37 298 {
stevenh@37 299 Integer value = valuesIter.next();
stevenh@37 300 if (value > maxDimension)
stevenh@37 301 {
stevenh@37 302 maxDimension = value;
stevenh@37 303 }
stevenh@37 304 }
stevenh@37 305
stevenh@37 306 // Iterate over all datapoints
stevenh@37 307 ExtendedIterator<? extends OntResource> datapointIter = datapointClass.listInstances();
stevenh@37 308 OntResource datapointIndividual;
stevenh@37 309 OntModel ontModelTemp = ModelFactory
stevenh@37 310 .createOntologyModel(); // OntModelSpec.OWL_MEM
stevenh@37 311
stevenh@37 312 while (datapointIter.hasNext())
stevenh@37 313 {
stevenh@37 314 datapointIndividual = datapointIter.next();
stevenh@37 315
stevenh@37 316 // Find all Dimension Values for this datapoint
stevenh@37 317 NodeIterator dimValIter = datapointIndividual.listPropertyValues(siaDimValProperty);
stevenh@37 318
stevenh@37 319 // Create a hashmap of dimensions for this datapoint
stevenh@37 320 HashMap<Integer, Boolean> dimensions = new HashMap<>();
stevenh@37 321 while (dimValIter.hasNext())
stevenh@37 322 {
stevenh@37 323 RDFNode dimVal = dimValIter.next();
stevenh@37 324 NodeIterator dims = ontModel.listObjectsOfProperty(dimVal.asResource(), siaDimensionProperty);
stevenh@37 325 while (dims.hasNext())
stevenh@37 326 {
stevenh@37 327 int dim = dims.next().asLiteral().getInt();
stevenh@37 328 dimensions.put(dim, true);
stevenh@37 329 System.out.println(dim);
stevenh@37 330 }
stevenh@37 331 }
stevenh@37 332
stevenh@37 333 for (int i = 2; i <= maxDimension; i++)
stevenh@37 334 {
stevenh@37 335 if (!dimensions.containsKey(i))
stevenh@37 336 {
stevenh@37 337 Resource zeroValDimValBnode = ontModel.createResource(AnonId.create());
stevenh@37 338
stevenh@37 339 Resource dpResource = datapointIndividual.asResource();
stevenh@37 340 ontModelTemp.add(dpResource, siaDimValProperty, zeroValDimValBnode);
stevenh@37 341 ontModelTemp.addLiteral(zeroValDimValBnode, siaDimensionProperty, i);
stevenh@37 342 ontModelTemp.addLiteral(zeroValDimValBnode, siaValueProperty, 0);
stevenh@37 343 }
stevenh@37 344 }
stevenh@37 345
stevenh@37 346 }
stevenh@37 347 ontModel.add(ontModelTemp);
stevenh@37 348 // Data integrity end
stevenh@37 349
stevenh@37 350 System.out.println("done");
stevenh@37 351
stevenh@37 352 // Print out what we've got now
stevenh@37 353 System.out.println("------------------");
stevenh@37 354 StmtIterator stmtIterator = ontModel.listStatements();
stevenh@37 355 printStmts(stmtIterator);
stevenh@37 356
stevenh@37 357 // Write rdf to file
stevenh@37 358 File outFileRdf = new File(finalModelFileName + ".rdf");
stevenh@37 359 File outFileN3 = new File(finalModelFileName + ".n3");
stevenh@37 360 FileOutputStream outFileOutputStreamRdf = null;
stevenh@37 361 FileOutputStream outFileOutputStreamN3 = null;
stevenh@37 362
stevenh@37 363 // RDF/XML version
stevenh@37 364 try {
stevenh@37 365 outFileOutputStreamRdf = new FileOutputStream(outFileRdf);
stevenh@37 366 ontModel.writeAll(outFileOutputStreamRdf, "RDF/XML", null);
stevenh@37 367 } catch (FileNotFoundException e) {
stevenh@37 368 System.out.println("Unable to write to file: "
stevenh@37 369 + outFileRdf.getAbsolutePath());
stevenh@37 370 e.printStackTrace();
stevenh@37 371 System.exit(1);
stevenh@37 372 }
stevenh@37 373
stevenh@37 374 try {
stevenh@37 375 outFileOutputStreamRdf.close();
stevenh@37 376 } catch (IOException e1) {
stevenh@37 377 e1.printStackTrace();
stevenh@37 378 System.exit(1);
stevenh@37 379 }
stevenh@37 380
stevenh@37 381 // N3 version
stevenh@37 382 try {
stevenh@37 383 outFileOutputStreamN3 = new FileOutputStream(outFileN3);
stevenh@37 384 ontModel.writeAll(outFileOutputStreamN3, "N3", null);
stevenh@37 385 } catch (FileNotFoundException e) {
stevenh@37 386 System.out.println("Unable to write to file: "
stevenh@37 387 + outFileN3.getAbsolutePath());
stevenh@37 388 e.printStackTrace();
stevenh@37 389 System.exit(1);
stevenh@37 390 }
stevenh@37 391
stevenh@37 392 try {
stevenh@37 393 outFileOutputStreamN3.close();
stevenh@37 394 } catch (IOException e1) {
stevenh@37 395 e1.printStackTrace();
stevenh@37 396 System.exit(1);
stevenh@37 397 }
stevenh@37 398
stevenh@37 399 System.out.println("Model written to files: "
stevenh@37 400 + outFileRdf.getAbsolutePath() + " and " + outFileN3.getAbsolutePath());
stevenh@37 401
stevenh@37 402 System.out.println("max tick: " + maxTick);
stevenh@37 403
stevenh@37 404 }
stevenh@37 405
stevenh@37 406 private static HashMap<Integer, Integer> getTrackToDimensionIndexMap(Sequence sequence) {
stevenh@37 407
stevenh@37 408 int numTracks = sequence.getTracks().length;
stevenh@37 409 int siaDatapointDimension = 2; // Dimension 1 is reserved for time
stevenh@37 410
stevenh@37 411 HashMap<Integer, Integer> trackDimensionMap = new HashMap<Integer, Integer>();
stevenh@37 412 Track[] tracks = sequence.getTracks();
stevenh@37 413
stevenh@37 414 for (int trackIdx = 0; trackIdx < numTracks; trackIdx++)
stevenh@37 415 {
stevenh@37 416 boolean trackIsAudible = false;
stevenh@37 417 int numEvents = tracks[trackIdx].size();
stevenh@37 418
stevenh@37 419 for (int eventIdx = 0; eventIdx < numEvents; eventIdx++)
stevenh@37 420 {
stevenh@37 421 MidiEvent event = tracks[trackIdx].get(eventIdx);
stevenh@37 422 MidiMessage midiMessage = event.getMessage();
stevenh@37 423
stevenh@37 424 // Determine the type of this message (short, sysex or meta)
stevenh@37 425 if (midiMessage instanceof ShortMessage)
stevenh@37 426 {
stevenh@37 427 // Determine which command is being issued
stevenh@37 428 ShortMessage shortMessage = (ShortMessage)midiMessage;
stevenh@37 429 int messageCommand = shortMessage.getCommand();
stevenh@37 430
stevenh@37 431 if (messageCommand == ShortMessage.NOTE_ON)
stevenh@37 432 {
stevenh@37 433 trackIsAudible = true;
stevenh@37 434 break;
stevenh@37 435 }
stevenh@37 436 }
stevenh@37 437 }
stevenh@37 438
stevenh@37 439 if (trackIsAudible)
stevenh@37 440 {
stevenh@37 441 trackDimensionMap.put(trackIdx, siaDatapointDimension);
stevenh@37 442 siaDatapointDimension++;
stevenh@37 443 }
stevenh@37 444 }
stevenh@37 445
stevenh@37 446 return trackDimensionMap;
stevenh@37 447 }
stevenh@37 448
stevenh@37 449 private static void printStmts(StmtIterator iter) {
stevenh@37 450 Statement statement;
stevenh@37 451
stevenh@37 452 while (iter.hasNext()) {
stevenh@37 453 statement = iter.nextStatement();
stevenh@37 454 System.out.println(" | <" + statement.getSubject() + "> | <"
stevenh@37 455 + statement.getPredicate() + "> | <"
stevenh@37 456 + statement.getObject() + "> | ");
stevenh@37 457 }
stevenh@37 458
stevenh@37 459 // And an empty line to make it pretty
stevenh@37 460 System.out.println();
stevenh@37 461 }
stevenh@37 462 }