/** * Copyright 2014 National University of Ireland, Galway. * * This file is part of the SIREn project. Project and contact information: * * https://github.com/rdelbru/SIREn * * 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. */ package org.sindice.siren.qparser.keyword.processors; import java.util.List; import java.util.Properties; import org.apache.lucene.queryparser.flexible.core.QueryNodeException; import org.apache.lucene.queryparser.flexible.core.nodes.QueryNode; import org.apache.lucene.queryparser.flexible.core.processors.QueryNodeProcessorImpl; import org.sindice.siren.qparser.keyword.config.KeywordQueryConfigHandler.KeywordConfigurationKeys; import org.sindice.siren.qparser.keyword.nodes.DatatypeQueryNode; import org.sindice.siren.qparser.keyword.nodes.ProtectedQueryNode; /** * This processor replaces QNames occurring in a * {@link ProtectedQueryNode} by their namespace. * * <p> * * The QNames mapping is provided by {@link KeywordConfigurationKeys#QNAMES}. */ public class QNamesProcessor extends QueryNodeProcessorImpl { /** The property file containing the mapping */ private Properties qnames; private final StringBuilder sb = new StringBuilder(); @Override protected QueryNode preProcessNode(final QueryNode node) throws QueryNodeException { if (node instanceof ProtectedQueryNode || node instanceof DatatypeQueryNode) { if (qnames == null) { qnames = this.getQueryConfigHandler().get(KeywordConfigurationKeys.QNAMES); } if (qnames == null) { // the KeywordConfigurationKeys.QNAMES_PATH is not set return node; } // Replace the qname final CharSequence text; if (node instanceof ProtectedQueryNode) { text = ((ProtectedQueryNode) node).getText(); } else { text = ((DatatypeQueryNode) node).getDatatype(); } if (replace(text)) { if (node instanceof ProtectedQueryNode) { final ProtectedQueryNode pqn = (ProtectedQueryNode) node; pqn.setText(sb.toString()); pqn.setEnd(pqn.getText().length()); } else { ((DatatypeQueryNode) node).setDatatype(sb.toString()); } } } return node; } /** * Replace in the text the qualified name by its corresponding namespace. * This fills the attribute {@link #sb} with the text replacement. * @param text the String with the qualified name * @return true if there was a qualified name and that it has been replaced. */ private boolean replace(CharSequence text) { final int termLength = text.length(); int offset = 0; if ((offset = this.findDelimiter(text)) != termLength) { final CharSequence prefix = this.convertQName(text, offset); final CharSequence suffix = text.subSequence(offset + 1, termLength); // skip the QName delimiter sb.setLength(0); sb.append(prefix); sb.append(suffix); return true; } return false; } /** * Find the offset of the QName delimiter. If no delimiter is * found, return last offset, i.e., {@code termLength}. */ protected int findDelimiter(final CharSequence c) { final int len = c.length(); int ptr = 0; while (ptr < len - 1) { if (this.isQNameDelim(c.charAt(ptr))) { if (!this.isNameStartChar(c.charAt(ptr + 1))) { break; // if this is not a valid name start char, we can stop } return ptr; } ptr++; } return len; } /** * Based on <a>http://www.w3.org/TR/REC-xml/#NT-Name</a> */ protected boolean isNameStartChar(final char c) { return c == ':' || c == '_' || Character.isLetter(c); } /** * Return <code>true</code> if the character is a colon. */ protected boolean isQNameDelim(final char c) { return c == ':'; } /** * Convert the QName to the associated namespace. If the prefix is not a * qname, it just returns the original prefix. */ protected CharSequence convertQName(final CharSequence c, final int offset) { final String prefix = c.subSequence(0, offset).toString(); if (qnames.containsKey(prefix)) { return qnames.getProperty(prefix); } return c.subSequence(0, offset + 1); } @Override protected QueryNode postProcessNode(final QueryNode node) throws QueryNodeException { return node; } @Override protected List<QueryNode> setChildrenOrder(final List<QueryNode> children) throws QueryNodeException { return children; } }