KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > hp > hpl > jena > rdql > QueryResultsFormatter


1 /*
2  * (c) Copyright 2001, 2002, 2003, 2004, 2005 Hewlett-Packard Development Company, LP
3  * [See end of file]
4  */

5
6 package com.hp.hpl.jena.rdql;
7
8 import java.util.* ;
9 import java.io.* ;
10
11 import com.hp.hpl.jena.rdf.model.* ;
12 import com.hp.hpl.jena.vocabulary.* ;
13
14 /** <p>Takes a QueryResult object and returns formatted (in various ways)
15  * Useful for the scripting interface.
16  * May help for display in other contexts.</p>
17  *
18  * <p>Note: this is compute intensive and memory intensive.
19  * It needs to read all the results first (all the results are now in-memory - not kept here)
20  * in order to find things like the maximum length of a column value; then it needs
21  * to pass over the results again, turning them into Strings again, in order to return them.
22  * </p>
23  * <p>We prefer slow and less memory intensive because it is more rebust for scripting.</p>
24  *
25  * Don't keep QueryResultsFormatter's around unnecessarily!
26  *
27  * @author Andy Seaborne
28  * @version $Id: QueryResultsFormatter.java,v 1.15 2005/02/21 12:15:25 andy_seaborne Exp $
29  */

30
31 public class QueryResultsFormatter
32 {
33     QueryResults queryResults ;
34     QueryResultsMem all = null ;
35     int numRows = -2 ;
36     int numCols = -2 ;
37     int colWidths[] = null ;
38     static final String JavaDoc notThere = "<<unset>>" ;
39     
40     public static final String JavaDoc resultsNamespace = "http://jena.hpl.hp.com/2003/03/queryResults#" ;
41
42     /** Create a formatter for a QueryResults object */
43
44     public QueryResultsFormatter(QueryResults qresults)
45     {
46         queryResults = qresults ;
47     }
48
49     /** How wide is the result table */
50     public int numColumns() { return queryResults.getResultVars().size() ; }
51
52     /** How deep is the result table. Negative implies unknown */
53     public int numRows() { return numRows ; }
54
55     private void colWidths()
56     {
57         if ( all == null )
58             all = new QueryResultsMem(queryResults) ;
59             
60         numCols = queryResults.getResultVars().size() ;
61         numRows = 0 ;
62         colWidths = new int[numCols] ;
63
64         // Widths at least that of the variable name. Assumes we will print col headings.
65
for ( int i = 0 ; i < numCols ; i++ )
66             colWidths[i] = ((String JavaDoc)queryResults.getResultVars().get(i)).length() ;
67
68         // Preparation pass : find the maximum width for each column
69
for ( ; all.hasNext() ; )
70         {
71             numRows++ ;
72             ResultBinding env = (ResultBinding)all.next() ;
73             int col = -1 ;
74             for ( Iterator iter = queryResults.getResultVars().iterator() ; iter.hasNext() ; )
75             {
76                 col++ ;
77                 String JavaDoc rVar = (String JavaDoc)iter.next() ;
78                 String JavaDoc s = getVarAsString(env, rVar) ;
79                 if ( colWidths[col] < s.length() )
80                     colWidths[col] = s.length() ;
81             }
82         }
83         all.reset() ;
84     }
85
86     /** Forcefully clearup.
87      * As results might have been read into memory, this operation signals
88      * intermediate data is no longer needed.
89      */

90     public void close()
91     {
92         queryResults.close() ;
93         queryResults = null ;
94         all = null ;
95         colWidths = null ;
96     }
97
98     /** Encode the result set as RDF.
99      * @return Model Model contains the results
100      */

101
102     public Model toModel()
103     {
104         Model m = ModelFactory.createDefaultModel() ;
105         asRDF(m) ;
106         return m ;
107     }
108     
109     /** Encode the result set as RDF in the model provided.
110      *
111      * @param model The place where to put the RDF.
112      * @return Resource The resource for the result set.
113      */

114
115     public Resource asRDF(Model model)
116     {
117         Resource results = model.createResource() ;
118         results.addProperty(RDF.type, ResultSet.ResultSet) ;
119         
120         for (Iterator iter = queryResults.getResultVars().iterator(); iter.hasNext();)
121         {
122             String JavaDoc vName = (String JavaDoc) iter.next();
123             results.addProperty(ResultSet.resultVariable, vName) ;
124         }
125         
126         int count = 0 ;
127         for ( Iterator solutionsIter = queryResults ; solutionsIter.hasNext() ; )
128         {
129             count++ ;
130             ResultBinding env = (ResultBinding)solutionsIter.next() ;
131             Resource thisSolution = model.createResource() ;
132             results.addProperty(ResultSet.solution, thisSolution) ;
133             for (Iterator iter = queryResults.getResultVars().iterator() ; iter.hasNext() ; )
134             {
135                 Resource thisBinding = model.createResource() ;
136                 String JavaDoc rVar = (String JavaDoc)iter.next() ;
137                 Object JavaDoc tmp = env.get(rVar) ;
138                 RDFNode n = null ;
139                 if ( tmp == null )
140                     // This variable was not found in the results.
141
// Encode the result set with an explicit "not defined"
142
n = ResultSet.undefined ;
143                 else if ( ! (tmp instanceof RDFNode) )
144                 {
145                     System.err.println("Class wrong: "+tmp.getClass().getName()) ;
146                     continue ;
147                 }
148                 else
149                     n = (RDFNode)env.get(rVar) ;
150                     
151                 thisBinding.addProperty(ResultSet.variable, rVar) ;
152                 thisBinding.addProperty(ResultSet.value, n) ;
153                 thisSolution.addProperty(ResultSet.binding, thisBinding) ;
154             }
155         }
156         results.addProperty(ResultSet.size, count) ;
157         return results ;
158     }
159
160
161
162     // Generalise: there are two algorithms : the one pass and the two pass
163

164     /** Write out a compact form. This encodes all the information is a vaguely
165      * readable way but is suitable for reading in again. Used for testing.
166      */

167
168
169     public void dump(PrintWriter pw, boolean format)
170     {
171         if (queryResults.getResultVars().size() == 0)
172         {
173             pw.println("# ==== No variables ====");
174             pw.flush();
175             return;
176         }
177         else
178         {
179             pw.println("# Variables:");
180             for (Iterator iter = queryResults.getResultVars().iterator(); iter.hasNext();)
181             {
182                 String JavaDoc vName = (String JavaDoc) iter.next();
183                 pw.print("?" + vName+" ");
184             }
185             pw.println(".") ;
186             pw.println("# Data:");
187             pw.flush() ;
188         }
189
190         if (format)
191             dumpAligned(pw);
192         else
193             dumpRaw(pw);
194     }
195
196     // One pass algorithm
197
private void dumpRaw(PrintWriter pw)
198     {
199         numCols = queryResults.getResultVars().size() ;
200         for ( Iterator tableIter = queryResults ; tableIter.hasNext() ; )
201         {
202             ResultBinding env = (ResultBinding)tableIter.next() ;
203             for (Iterator iter = queryResults.getResultVars().iterator() ; iter.hasNext() ; )
204             {
205                 String JavaDoc rVar = (String JavaDoc)iter.next() ;
206                 String JavaDoc s = getVarAsString(env, rVar) ;
207                 pw.print("?") ;
208                 pw.print(rVar) ;
209                 pw.print(" ");
210                 pw.print(s);
211                 pw.print(" ");
212             }
213             pw.println(".") ;
214         }
215         queryResults.close() ;
216     }
217
218     // Dump formated : columns padded for readability.
219
// Requires reading all the data into memory - its a two pass algorithm.
220
private void dumpAligned(PrintWriter pw)
221     {
222         if ( all == null )
223             all = new QueryResultsMem(queryResults) ;
224  
225         if ( colWidths == null )
226             colWidths() ;
227
228         String JavaDoc row[] = new String JavaDoc[numCols] ;
229         int lineWidth = 0 ;
230         for ( int col = 0 ; col < numCols ; col++ )
231         {
232             String JavaDoc rVar = (String JavaDoc)queryResults.getResultVars().get(col) ;
233             row[col] = rVar ;
234             lineWidth += colWidths[col] ;
235         }
236
237         for ( Iterator tableIter = all ; tableIter.hasNext() ; )
238         {
239             ResultBinding env = (ResultBinding)tableIter.next() ;
240             for ( int col = 0 ; col < numCols ; col++ )
241             {
242                 StringBuffer JavaDoc sbuff = new StringBuffer JavaDoc(120) ;
243                 String JavaDoc rVar = (String JavaDoc)queryResults.getResultVars().get(col) ;
244                 sbuff.append('?') ;
245                 sbuff.append(rVar) ;
246                 sbuff.append(' ') ;
247                 String JavaDoc s = getVarAsString(env, rVar) ;
248
249                 int pad = colWidths[col] ;
250                 sbuff.append(s) ;
251
252                 for ( int j = 0 ; j < pad-s.length() ; j++ )
253                     sbuff.append(' ') ;
254                 // Always has a trailing space
255
sbuff.append(' ') ;
256                 pw.print(sbuff) ;
257             }
258             pw.println(" .") ;
259         }
260         all.close() ;
261         pw.flush() ;
262     }
263
264     /** Textual representation : default layout using " | " to separate columns
265      * @param printwriter Output
266      */

267     public void printAll(PrintWriter printwriter) { printAll(printwriter, " | ", null) ; }
268     
269     /** Textual representation : layout using given separator
270      * @param printwriter Output
271      * @param colSep Column separator
272      */

273     public void printAll(PrintWriter printwriter, String JavaDoc colSep) { printAll(printwriter, colSep, null) ; }
274     
275     /** Textual representation : layout using given separator
276      * @param printwriter Output
277      * @param colSep Column separator
278      * @param lineEnd String to add to end of lines
279      */

280     public void printAll(PrintWriter printwriter, String JavaDoc colSep, String JavaDoc lineEnd)
281     {
282         if ( queryResults.getResultVars().size() == 0 )
283         {
284             printwriter.println("==== No variables ====") ;
285             printwriter.flush() ;
286             return ;
287         }
288
289         if ( all == null )
290             all = new QueryResultsMem(queryResults) ;
291
292         if ( colWidths == null )
293             colWidths() ;
294
295         String JavaDoc row[] = new String JavaDoc[numCols] ;
296         int lineWidth = 0 ;
297         for ( int col = 0 ; col < numCols ; col++ )
298         {
299             String JavaDoc rVar = (String JavaDoc)queryResults.getResultVars().get(col) ;
300             row[col] = rVar ;
301             lineWidth += colWidths[col] ;
302             if ( col > 0 )
303                 lineWidth += colSep.length() ;
304         }
305         printRow(printwriter, row, colSep, lineEnd) ;
306
307         for ( int i = 0 ; i < lineWidth ; i++ )
308             printwriter.print('=') ;
309         printwriter.println() ;
310
311         for ( Iterator tableIter = all ; tableIter.hasNext() ; )
312         {
313             ResultBinding env = (ResultBinding)tableIter.next() ;
314             for ( int col = 0 ; col < numCols ; col++ )
315             {
316                 String JavaDoc rVar = (String JavaDoc)queryResults.getResultVars().get(col) ;
317                 row[col] = this.getVarAsString(env, rVar );
318             }
319             printRow(printwriter, row, colSep, lineEnd) ;
320         }
321         all.reset() ;
322         printwriter.flush() ;
323     }
324
325
326     private void printRow(PrintWriter pw, String JavaDoc[] row, String JavaDoc colSep, String JavaDoc lineEnd)
327     {
328         if ( row.length != numCols )
329             throw new RDQL_InternalErrorException("QueryResultsFormatter.printRow: Row length ("+row.length+") != numCols ("+numCols+")") ;
330
331         for ( int col = 0 ; col < numCols ; col++ )
332         {
333             String JavaDoc s = row[col] ;
334             int pad = colWidths[col] ;
335             StringBuffer JavaDoc sbuff = new StringBuffer JavaDoc(120) ;
336
337             if ( col > 0 )
338                 sbuff.append(colSep) ;
339
340             sbuff.append(s) ;
341             for ( int j = 0 ; j < pad-s.length() ; j++ )
342                 sbuff.append(' ') ;
343
344             pw.print(sbuff) ;
345         }
346         if ( lineEnd != null )
347             pw.print(lineEnd);
348         pw.println() ;
349     }
350
351     /** HTML representation */
352
353     public void printHTML(PrintWriter pw)
354     {
355         if ( all == null )
356         {
357             all = new QueryResultsMem(queryResults) ;
358             numRows = all.size() ;
359         }
360
361         pw.println("<table>");
362         // Column headings
363
pw.println(" <tr>");
364         for ( int ii = 0 ; ii < queryResults.getResultVars().size() ; ii++ )
365         {
366             String JavaDoc tmp = (String JavaDoc)queryResults.getResultVars().get(ii) ;
367             pw.print(" <th>") ;
368             pw.print(tmp) ;
369             pw.print("</th>") ;
370             pw.println() ;
371         }
372         pw.println(" </tr>");
373
374         for ( ; all.hasNext() ; )
375         {
376             pw.println(" <tr>");
377             ResultBinding env = (ResultBinding)all.next() ;
378             for ( int col = 0 ; col < queryResults.getResultVars().size() ; col++ )
379             {
380                 String JavaDoc rVar = (String JavaDoc)queryResults.getResultVars().get(col) ;
381                 RDFNode val = (RDFNode)env.get(rVar) ;
382                 // Use the unquoted form here - should also XML-escape it.
383
String JavaDoc s = (val==null)? notThere : val.toString() ;
384
385                 pw.print(" <td>") ;
386                 pw.print(s) ;
387                 pw.print("</td>") ;
388                 pw.println() ;
389             }
390             pw.println(" </tr>");
391         }
392         pw.println("</table>");
393         pw.flush() ;
394         all.reset() ;
395     }
396
397     /** This operation faithfully walks the results but does nothing with them.
398      * Used in timing operations. Be careful that a compiler does
399      * not optimize some or all of it away!
400      */

401
402     public void consume()
403     {
404         //numCols = queryResults.getResultVars().size() ;
405
for ( Iterator rowIter = queryResults ; rowIter.hasNext() ; )
406         {
407             ResultBinding result = (ResultBinding)rowIter.next() ;
408
409             for ( ResultBindingIterator iter = result.iterator() ; iter.hasNext() ; )
410             {
411                 iter.next() ;
412             }
413         }
414     }
415     
416     private String JavaDoc getVarAsString(ResultBinding env, String JavaDoc varName)
417     {
418         // Without adornment.
419
//Value val = env.getValue(rVar) ;
420
//String s = (val==null)? notThere : val.asQuotedString() ;
421
//return s ;
422

423         // Print in all details
424
Object JavaDoc obj = env.get(varName) ;
425                 
426         if ( obj != null )
427         {
428             if ( ! ( obj instanceof RDFNode ) )
429                 return "Found a "+(obj.getClass().getName()) ;
430             else if ( obj instanceof Literal )
431             {
432                 Literal l = (Literal)obj ;
433                 StringBuffer JavaDoc sb = new StringBuffer JavaDoc() ;
434                 sb.append('"').append(l.getLexicalForm()).append('"') ;
435                 
436                 if ( ! l.getLanguage().equals(""))
437                     sb.append("@").append(l.getLanguage()) ;
438                 if ( l.getDatatype() != null )
439                     sb.append("^^<").append(l.getDatatypeURI()).append(">") ;
440                 return sb.toString() ;
441             }
442             else if ( obj instanceof Resource )
443             {
444                 Resource r = (Resource)obj ;
445                 if ( r.isAnon() )
446                     return "anon:"+r.getId() ;
447                 else
448                     return "<"+r.getURI()+">" ;
449             }
450         }
451         return notThere ;
452     }
453 }
454
455 /*
456  * (c) Copyright 2001, 2002, 2003, 2004, 2005 Hewlett-Packard Development Company, LP
457  * All rights reserved.
458  *
459  * Redistribution and use in source and binary forms, with or without
460  * modification, are permitted provided that the following conditions
461  * are met:
462  * 1. Redistributions of source code must retain the above copyright
463  * notice, this list of conditions and the following disclaimer.
464  * 2. Redistributions in binary form must reproduce the above copyright
465  * notice, this list of conditions and the following disclaimer in the
466  * documentation and/or other materials provided with the distribution.
467  * 3. The name of the author may not be used to endorse or promote products
468  * derived from this software without specific prior written permission.
469  *
470  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
471  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
472  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
473  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
474  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
475  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
476  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
477  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
478  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
479  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
480  */

481
Popular Tags