All Downloads are FREE. Search and download functionalities are using the official Maven repository.

world.data.jdbc.internal.transport.NodeParser Maven / Gradle / Ivy

/*
 * dw-jdbc
 * Copyright 2017 data.world, Inc.

 * Licensed 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.
 *
 * This product includes software developed at data.world, Inc.(http://www.data.world/).
 */
package world.data.jdbc.internal.transport;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import world.data.jdbc.model.Blank;
import world.data.jdbc.model.Iri;
import world.data.jdbc.model.Literal;
import world.data.jdbc.model.Node;
import world.data.jdbc.vocab.Xsd;

import javax.annotation.Nullable;
import java.io.IOException;
import java.util.Map;

import static java.util.Objects.requireNonNull;
import static world.data.jdbc.internal.transport.ParserUtil.expect;
import static world.data.jdbc.internal.transport.ParserUtil.require;

/**
 * Parser for an RDF term within a document with media type
 * application/sparql-results+json
 * or application/rdf+json.
 */
final class NodeParser {
    private final JsonParser parser;
    private final boolean rdf;
    private boolean nonEmpty;
    private String type;
    private Iri datatype;
    private String value;
    private String language;

    /** Constructs a node parser for rdf terms w/'application/sparql-results+json'. */
    static NodeParser forSparqlResults(JsonParser parser) {
        return new NodeParser(parser, false);
    }

    /** Constructs a node parser for rdf object terms w/in 'application/rdf+json'. */
    static NodeParser forRdf(JsonParser parser) {
        return new NodeParser(parser, true);
    }

    private NodeParser(JsonParser parser, boolean rdf) {
        this.parser = requireNonNull(parser, "parser");
        this.rdf = rdf;
    }

    @Nullable
    Node[] parseRow(Map columnsByVar) throws IOException {
        Node[] nodes = new Node[columnsByVar.size()];
        nonEmpty = false;
        FieldParser.parseObject(parser, (String field, JsonToken token) -> {
            Response.Column column = columnsByVar.get(field);
            if (column != null && token == JsonToken.START_OBJECT) {
                Node node = parse();
                nodes[column.getIndex()] = node;
                nonEmpty |= node != null;
            }
        });
        return nonEmpty ? nodes : null;
    }

    @Nullable
    Node parse() throws IOException {
        type = value = language = null;
        datatype = Xsd.STRING;
        FieldParser.parseObject(parser, (String field, JsonToken token) -> {
            switch (field) {
                case "type":
                    expect(parser, token, JsonToken.VALUE_STRING);
                    type = parser.getText();
                    break;
                case "value":
                    expect(parser, token, JsonToken.VALUE_STRING);
                    value = parser.getText();
                    break;
                case "datatype":
                    expect(parser, token, JsonToken.VALUE_STRING);
                    datatype = new Iri(parser.getText().intern());
                    break;
                case "lang":  // for application/rdf+json
                case "xml:lang":  // for application/sparql-results+json
                    expect(parser, token, JsonToken.VALUE_STRING);
                    language = parser.getText().intern();
                    break;
            }
        });
        switch (require(parser, type, "type")) {
            case "uri":
                return new Iri(require(parser, value, "value"));
            case "literal":
            case "typed-literal":
                return new Literal(require(parser, value, "value"), datatype, language);
            case "bnode":
                return new Blank(stripBlankPrefix(require(parser, value, "value")));
            default:
                return null;  // Ignore the node to maintain forward/backward compatibility
        }
    }

    private String stripBlankPrefix(String id) {
        // rdf+json includes _: prefix in blank node labels, sparql-results+json does not
        return rdf && id.startsWith("_:") ? id.substring(2) : id;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy