/* * Copyright Aduna (http://www.aduna-software.com/) (c) 1997-2006. * * Licensed under the Aduna BSD-style license. */ package org.openrdf.query.parser.sparql; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.openrdf.query.MalformedQueryException; import org.openrdf.query.parser.sparql.ast.ASTIRI; import org.openrdf.query.parser.sparql.ast.ASTPrefixDecl; import org.openrdf.query.parser.sparql.ast.ASTQName; import org.openrdf.query.parser.sparql.ast.ASTQueryContainer; import org.openrdf.query.parser.sparql.ast.SyntaxTreeBuilderTreeConstants; import org.openrdf.query.parser.sparql.ast.VisitorException; /** * Processes the prefix declarations in a SPARQL query model. * * @author Arjohn Kampman */ class PrefixDeclProcessor { /** * Processes prefix declarations in queries. This method collects all * prefixes that are declared in the supplied query, verifies that prefixes * are not redefined and replaces any {@link ASTQName} nodes in the query * with equivalent {@link ASTIRI} nodes. * * @param qc * The query that needs to be processed. * @return A map containing the prefixes that are declared in the query (key) * and the namespace they map to (value). * @throws MalformedQueryException * If the query contains redefined prefixes or qnames that use * undefined prefixes. */ public static Map<String, String> process(ASTQueryContainer qc) throws MalformedQueryException { List<ASTPrefixDecl> prefixDeclList = qc.getPrefixDeclList(); // Build a prefix --> IRI map Map<String, String> prefixMap = new LinkedHashMap<String, String>(); for (ASTPrefixDecl prefixDecl : prefixDeclList) { String prefix = prefixDecl.getPrefix(); String iri = prefixDecl.getIRI().getValue(); if (prefixMap.containsKey(prefix)) { throw new MalformedQueryException("Multiple prefix declarations for prefix '" + prefix + "'"); } prefixMap.put(prefix, iri); } QNameProcessor visitor = new QNameProcessor(prefixMap); try { qc.jjtAccept(visitor, null); } catch (VisitorException e) { throw new MalformedQueryException(e); } return prefixMap; } private static class QNameProcessor extends ASTVisitorBase { private Map<String, String> prefixMap; public QNameProcessor(Map<String, String> prefixMap) { this.prefixMap = prefixMap; } @Override public Object visit(ASTQName qnameNode, Object data) throws VisitorException { String qname = qnameNode.getValue(); int colonIdx = qname.indexOf(':'); assert colonIdx >= 0 : "colonIdx should be >= 0: " + colonIdx; String prefix = qname.substring(0, colonIdx); String localName = qname.substring(colonIdx + 1); String namespace = prefixMap.get(prefix); if (namespace == null) { throw new VisitorException("QName '" + qname + "' uses an undefined prefix"); } // Replace the qname node with a new IRI node in the parent node ASTIRI iriNode = new ASTIRI(SyntaxTreeBuilderTreeConstants.JJTIRI); iriNode.setValue(namespace + localName); qnameNode.jjtReplaceWith(iriNode); return null; } } }