Package com.hp.hpl.jena.sparql.serializer

Source Code of com.hp.hpl.jena.sparql.serializer.FormatterElement

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.hp.hpl.jena.sparql.serializer;

import java.util.ArrayList ;
import java.util.Iterator ;
import java.util.List ;

import org.openjena.atlas.io.IndentedLineBuffer ;
import org.openjena.atlas.io.IndentedWriter ;

import com.hp.hpl.jena.graph.Node ;
import com.hp.hpl.jena.graph.Triple ;
import com.hp.hpl.jena.sparql.core.BasicPattern ;
import com.hp.hpl.jena.sparql.core.PathBlock ;
import com.hp.hpl.jena.sparql.core.TriplePath ;
import com.hp.hpl.jena.sparql.expr.Expr ;
import com.hp.hpl.jena.sparql.path.PathWriter ;
import com.hp.hpl.jena.sparql.syntax.* ;


public class FormatterElement extends FormatterBase
    implements ElementVisitor
{
    public static final int INDENT = 2 ;
   
    /** Control whether to show triple pattern boundaries - creates extra nesting */
    public static final boolean PATTERN_MARKERS = false ;
   
//    /** Control whether triple patterns always have a final dot - it can be dropped in some cases */
//    public static boolean PATTERN_FINAL_DOT = false ;

    /** Control whether (non-triple) patterns have a final dot - it can be dropped */
    public static final boolean GROUP_SEP_DOT = false ;
   
    /** Control whether the first item of a group is on the same line as the { */
    public static final boolean GROUP_FIRST_ON_SAME_LINE = false ;

    /** Control pretty printing */
    public static final boolean PRETTY_PRINT = true  ;

    /** Control whether disjunction has set of delimiters - as it's a group usually, these aren't needed */
    public static final boolean UNION_MARKERS = false ;
   
    /** Control whether a group of one is unnested - changes the query syntax tree */
    public static final boolean GROUP_UNNEST_ONE = false ;

    /** Control whether GRAPH indents in a fixed way or based on the layout size */
    public static final boolean GRAPH_FIXED_INDENT = true ;
   
    /** Control whether NOT EXIST/EXISTS indents in a fixed way or based on the layout size */
    public static final boolean ELEMENT1_FIXED_INDENT = true ;
   
    /** Control triples pretty printing */
    public static final int TRIPLES_SUBJECT_COLUMN = 8 ;
   
    // Less than this => rest of triple on the same line
    // Could be smart and make it depend on the property length as well.  Later.
    public static final int TRIPLES_SUBJECT_LONG = 12 ;    

    public static final int TRIPLES_PROPERTY_COLUMN = 20;
   
    public static final int TRIPLES_COLUMN_GAP = 2 ;

    public FormatterElement(IndentedWriter out, SerializationContext context)
    {
        super(out, context) ;
    }
   
    public static void format(IndentedWriter out, SerializationContext cxt, Element el)
    {
        FormatterElement fmt = new FormatterElement(out, cxt) ;
        fmt.startVisit() ;
        el.visit(fmt) ;
        fmt.finishVisit() ;
    }
   
   
    public static String asString(Element el)
    {
        SerializationContext cxt = new SerializationContext() ;
        IndentedLineBuffer b = new IndentedLineBuffer() ;
        FormatterElement.format(b, cxt, el) ;
        return b.toString() ;
    }

    public boolean topMustBeGroup() { return false ; }
   
    @Override
    public void visit(ElementTriplesBlock el)
    {
        if ( el.isEmpty() )
        {
            out.println("# Empty BGP") ;
            return ;
        }
        formatTriples(el.getPattern()) ;
    }
   
    @Override
    public void visit(ElementPathBlock el)
    {
        if ( el.isEmpty() )
        {
            out.println("# Empty BGP") ;
            return ;
        }
        // Could be neater.
        boolean first = true ;
        PathBlock pBlk = el.getPattern() ;
        for ( TriplePath tp : pBlk )
        {
            if ( ! first )
            {
                out.println(" .") ;
            }
            first = false ;
            if ( tp.isTriple() )
            {
                printSubject(tp.getSubject()) ;
                out.print(" ") ;
                printProperty(tp.getPredicate()) ;
                out.print(" ") ;
                printObject(tp.getObject()) ;
            }
            else
            {
                printSubject(tp.getSubject()) ;
                out.print(" ") ;
                PathWriter.write(out, tp.getPath(), context.getPrologue()) ;
                out.print(" ") ;
                printObject(tp.getObject()) ;
            }
        }
    }

    @Override
    public void visit(ElementDataset el)
    {
//        if ( el.getDataset() != null)
//        {
//            DatasetGraph dsNamed = el.getDataset() ;
//            out.print("DATASET ") ;
//            out.incIndent(INDENT) ;
//            Iterator iter = dsNamed.listNames() ;
//            if ( iter.hasNext() )
//            {
//                boolean first = false ;
//                for ( ; iter.hasNext() ; )
//                {
//                    if ( ! first )
//                        out.newline() ;
//                    out.print("FROM <") ;
//                    String s = (String)iter.next() ;
//                    out.print(s) ;
//                    out.print(">") ;
//                }
//            }
//            out.decIndent(INDENT) ;
//            out.newline() ;
//        }
        if ( el.getPatternElement() != null )
            visitAsGroup(el.getPatternElement()) ;
    }

    @Override
    public void visit(ElementFilter el)
    {
        out.print("FILTER ") ;
        Expr expr = el.getExpr() ;
        FmtExpr v = new FmtExpr(out, context) ;
       
        // This assumes that complex expressions are bracketted
        // (parens) as necessary except for some cases:
        //   Plain variable or constant
       
        boolean addParens = false ;
        if ( expr.isVariable() )
            addParens = true ;
        if ( expr.isConstant() )
            addParens = true ;
       
        if ( addParens )
            out.print("( ") ;
        v.format(expr) ;
        if ( addParens )
            out.print(" )") ;
    }

    @Override
    public void visit(ElementAssign el)
    {
        out.print("LET (") ;
        out.print("?"+el.getVar().getVarName()) ;
        out.print(" := ") ;
        FmtExpr v = new FmtExpr(out, context) ;
        v.format(el.getExpr()) ;
        out.print(")") ;
    }

    @Override
    public void visit(ElementBind el)
    {
        out.print("BIND(") ;
        FmtExpr v = new FmtExpr(out, context) ;
        v.format(el.getExpr()) ;
        out.print(" AS ") ;
        out.print("?"+el.getVar().getVarName()) ;
        out.print(")") ;
    }

    @Override
    public void visit(ElementUnion el)
    {
        if ( el.getElements().size() == 1 )
        {
            // If this is an element of just one, just do it inplace
            // Can't happen from a parsed query.
            // Now can :-)
           
            // SPARQL 1.1 inline UNION.
            // Same as OPTIONAL, MINUS
            out.print("UNION") ;
            out.incIndent(INDENT) ;
            out.newline() ;
            visitAsGroup(el.getElements().get(0)) ;
            out.decIndent(INDENT) ;
            return ;
        }

        if ( UNION_MARKERS )
        {
            out.print("{") ;
            out.newline() ;
            out.pad() ;
        }
           
        out.incIndent(INDENT) ;
       
        boolean first = true ;
        for ( Iterator<Element> iter = el.getElements().listIterator() ; iter.hasNext() ;)
        {
          
            Element subElement = iter.next() ;
            if ( ! first )
            {
                out.decIndent(INDENT) ;
                out.newline() ;
                out.print("UNION") ;
                out.newline() ;
                out.incIndent(INDENT) ;
            }
            visitAsGroup(subElement) ;
            first = false ;
        }
       
        out.decIndent(INDENT) ;

        if ( UNION_MARKERS )
        {
            out.newline() ;
            out.print("}") ;
        }
    }

   
    @Override
    public void visit(ElementGroup el)
    {
        if ( GROUP_UNNEST_ONE && el.getElements().size() == 1 )
        {
            // If this is an element of just one, we can remove the {} if it is a group.
            Element e = el.getElements().get(0) ;
            visitAsGroup(e) ;
            return ;
        }

//        if ( el.getElements().size() == 1 )
//        {
//            if ( el.getElements().get(0) instanceof ElementSubQuery )
//            {
//                visit((ElementSubQuery)el.getElements().get(0)) ;
//                return ;
//            }
//        }
       
        out.print("{") ;
        out.incIndent(INDENT) ;
        if ( GROUP_FIRST_ON_SAME_LINE )
            out.newline()
       
        int row1 = out.getRow() ;
        out.pad() ;
   
        boolean first = true ;
       
        for ( Iterator<Element> iter = el.getElements().listIterator() ; iter.hasNext() ;)
        {
            Element subElement = iter.next() ;
           if ( ! first )
            {
                // Need to move on after the last thing printed.
                if ( GROUP_SEP_DOT )
                    out.print(" . ") ;
                out.newline() ;   
            }
            subElement.visit(this) ;
            first = false ;
        }
        out.decIndent(INDENT) ;
       
        // Where to put the closing "}"
        int row2 = out.getRow() ;
        if ( row1 != row2 )
            out.newline() ;
        else
            out.print(' ') ;
       
        // Finally, close the group.
        out.print("}") ;
    }

    @Override
    public void visit(ElementOptional el)
    {
        out.print("OPTIONAL") ;
        out.incIndent(INDENT) ;
        out.newline() ;
        visitAsGroup(el.getOptionalElement()) ;
        out.decIndent(INDENT) ;
    }


    @Override
    public void visit(ElementNamedGraph el)
    {
        visitNodePattern("GRAPH", el.getGraphNameNode(), el.getElement()) ;
    }

    @Override
    public void visit(ElementService el)
    {
        String x = "SERVICE" ;
        if ( el.getSilent() )
            x = "SERVICE SILENT" ;
        visitNodePattern(x, el.getServiceNode(), el.getElement()) ;
    }

    @Override
    public void visit(ElementFetch el)
    {
        out.print("FETCH") ;
        out.print(" ") ;
        String nodeStr = ( el.getFetchNode() == null ) ? "*" : slotToString(el.getFetchNode()) ;
        out.print(nodeStr) ;
        //out.print(" ") ;
    }
   
   
    private void visitNodePattern(String label, Node node, Element subElement)
    {
        int len = label.length() ;
        out.print(label) ;
        out.print(" ") ;
        String nodeStr = ( node == null ) ? "*" : slotToString(node) ;
        out.print(nodeStr) ;
        len += nodeStr.length() ;
        if ( GRAPH_FIXED_INDENT )
        {
            out.incIndent(INDENT) ;
            out.newline() ; // NB and newline
        }
        else
        {
            out.print(" ") ;
            len++ ;
            out.incIndent(len) ;
        }
        visitAsGroup(subElement) ;
       
        if ( GRAPH_FIXED_INDENT )
            out.decIndent(INDENT) ;
        else
            out.decIndent(len) ;
    }

    private void visitElement1(String label, Element1 el)
    {

        int len = label.length() ;
        out.print(label) ;
        len += label.length() ;
        if ( ELEMENT1_FIXED_INDENT )
        {
            out.incIndent(INDENT) ;
            out.newline() ; // NB and newline
        }
        else
        {
            out.print(" ") ;
            len++ ;
            out.incIndent(len) ;
        }
        visitAsGroup(el.getElement()) ;
        if ( ELEMENT1_FIXED_INDENT )
            out.decIndent(INDENT) ;
        else
            out.decIndent(len) ;
    }

    @Override
    public void visit(ElementExists el)
    {
        visitElement1("EXISTS", el) ;
    }

    @Override
    public void visit(ElementNotExists el)
    {
        visitElement1("NOT EXISTS", el) ;
    }
   
    @Override
    public void visit(ElementMinus el)
    {
        out.print("MINUS") ;
        out.incIndent(INDENT) ;
        out.newline() ;
        visitAsGroup(el.getMinusElement()) ;
        out.decIndent(INDENT) ;
    }
   
    @Override
    public void visit(ElementSubQuery el)
    {
        out.print("{ ") ;
        out.incIndent(INDENT) ;
        // Messy - prefixes.
        el.getQuery().serialize(out) ;
        out.decIndent(INDENT) ;
        out.print("}") ;
    }

    public void visitAsGroup(Element el)
    {
        boolean needBraces = ! ( ( el instanceof ElementGroup ) || ( el instanceof ElementSubQuery ) ) ;
       
        if ( needBraces )
        {
            out.print("{ ") ;
            out.incIndent(INDENT) ;
        }
       
        el.visit(this) ;
       
        if ( needBraces )
        {
            out.decIndent(INDENT) ;
            out.print("}") ;
        }
    }

    // Work variables.
    // Assumes not threaded
   
    int subjectWidth = -1 ;
    int predicateWidth = -1 ;
   
    @Override
    protected void formatTriples(BasicPattern triples)
    {
        if ( ! PRETTY_PRINT )
        {
            super.formatTriples(triples) ;
            return ;
        }
       
        // TODO RDF Collections - spot the parsers pattern
        if ( triples.isEmpty() )
            return ;

        setWidths(triples) ;
        if ( subjectWidth > TRIPLES_SUBJECT_COLUMN )
            subjectWidth = TRIPLES_SUBJECT_COLUMN ;
        if ( predicateWidth > TRIPLES_PROPERTY_COLUMN )
            predicateWidth = TRIPLES_PROPERTY_COLUMN ;
       
        // Loops:
        List<Triple> subjAcc = new ArrayList<Triple>() ;    // Accumulate all triples with the same subject. 
        Node subj = null ;                  // Subject being accumulated
       
        boolean first = true ;             // Print newlines between blocks.
       
        int indent = -1 ;
        for ( Triple t : triples )
        {
            if ( subj != null && t.getSubject().equals(subj) )
            {
                subjAcc.add(t) ;
                continue ;
            }
           
            if ( subj != null )
            {
                if ( ! first )
                    out.println() ;
                formatSameSubject(subj, subjAcc) ;
                first = false ;
                // At end of line of a block of triples with same subject.
                // Drop through and start new block of same subject triples.
            }

            // New subject
            subj = t.getSubject() ;
            subjAcc.clear() ;
            subjAcc.add(t) ;
        }
       
        // Flush accumulator
        if ( subj != null && subjAcc.size() != 0 )
        {
            if ( ! first )
                out.println() ;
            first = false ;
            formatSameSubject(subj, subjAcc) ;
        }
    }
   
    private void formatSameSubject(Node subject, List<Triple> triples)
    {
        if ( triples == null || triples.size() == 0 )
            return ;
       
        // Do the first triple.
        Iterator<Triple> iter = triples.iterator() ;
        Triple t1 = iter.next() ;

//        int indent = TRIPLES_SUBJECT_COLUMN+TRIPLES_COLUMN_GAP ;
//        // Long subject => same line.  Works for single triple as well.
//        int s1_len = printSubject(t1.getSubject()) ;
//        //int x = out.getCol() ;

        int indent = subjectWidth + TRIPLES_COLUMN_GAP ;
        int s1_len = printSubject(t1.getSubject()) ;

        if ( s1_len > TRIPLES_SUBJECT_LONG )
        {
            // Too long - start a new line.
            out.incIndent(indent) ;
            out.println() ;
        }
        else
        {
            printGap() ;
            out.incIndent(indent) ;
        }

        // Remained of first triple
        printProperty(t1.getPredicate()) ;
        printGap() ;
        printObject(t1.getObject()) ;
       
        // Do the rest
       
        for ; iter.hasNext() ; )
        {
            Triple t = iter.next() ;
            out.println(" ;") ;
            printProperty(t.getPredicate()) ;
            printGap() ;
            printObject(t.getObject()) ;
            continue ;
            // print property list
        }

        // Finish off the block.
        out.decIndent(indent) ;
        out.print(" .") ;
    }
   
    private void setWidths(BasicPattern triples)
    {
        subjectWidth = -1 ;
        predicateWidth = -1 ;

        for ( Triple t : triples )
        {
            String s = slotToString(t.getSubject()) ;
            if ( s.length() > subjectWidth )
                subjectWidth = s.length() ;
           
            String p = slotToString(t.getPredicate()) ;
            if ( p.length() > predicateWidth )
                predicateWidth = p.length() ;
        }
    }
   
    private void printGap()
    {
        out.print(' ', TRIPLES_COLUMN_GAP) ;
    }
   
    // Indent must be set first.
    private int printSubject(Node s)
    {
        String str = slotToString(s) ;
        out.print(str) ;
        //out.pad(TRIPLES_SUBJECT_COLUMN) ;
        out.pad(subjectWidth) ;
        return str.length() ;
    }

    // Assumes the indent is TRIPLES_SUBJECT_COLUMN+GAP
    private int printProperty(Node p)
    {
        String str = slotToString(p) ;
        out.print(str) ;
        //out.pad(TRIPLES_PROPERTY_COLUMN) ;
        out.pad(predicateWidth) ;
        return str.length() ;
    }
   
    private int printObject(Node obj)
    {
        return printNoCol(obj) ;
    }
   
    private int printNoCol(Node node)
    {
        String str = slotToString(node) ;
        out.print(str) ;
        return str.length() ;
       
    }
   
}
TOP

Related Classes of com.hp.hpl.jena.sparql.serializer.FormatterElement

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.