package lux.functions;
import javax.xml.stream.XMLStreamException;
import lux.Evaluator;
import lux.index.IndexConfiguration;
import lux.search.highlight.TagFormatter;
import lux.search.highlight.XmlHighlighter;
import lux.xpath.FunCall;
import net.sf.saxon.expr.StaticProperty;
import net.sf.saxon.expr.XPathContext;
import net.sf.saxon.lib.ExtensionFunctionCall;
import net.sf.saxon.lib.ExtensionFunctionDefinition;
import net.sf.saxon.om.*;
import net.sf.saxon.pattern.NodeKindTest;
import net.sf.saxon.s9api.SaxonApiException;
import net.sf.saxon.s9api.XdmNode;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.value.EmptySequence;
import net.sf.saxon.value.SequenceType;
import net.sf.saxon.value.StringValue;
import net.sf.saxon.value.QNameValue;
import org.apache.lucene.search.Query;
/**
* <code>lux:highlight($node as node()?, $query as item(), $tag as item())</code><br/>
* <code>lux:highlight($node as node()?, $query as item())</code>
* <p>returns
* the given node with text matching the query surrounded by the given $tag (or B if no tag is given).
* The query may be a string or an element/document of the same types supported by lux:search.</p>
* <p>The tag may be specified as either a QName or a string; if a string, an element
* is created with no namespace.</p>
* @see Search
*/
public class Highlight extends ExtensionFunctionDefinition {
@Override
public SequenceType[] getArgumentTypes() {
return new SequenceType[] {
SequenceType.OPTIONAL_NODE,
SequenceType.SINGLE_ITEM,
SequenceType.SINGLE_ITEM,
};
}
@Override
public StructuredQName getFunctionQName() {
return new StructuredQName("lux", FunCall.LUX_NAMESPACE, "highlight");
}
@Override
public SequenceType getResultType(SequenceType[] suppliedArgumentTypes) {
return SequenceType.makeSequenceType(NodeKindTest.DOCUMENT, StaticProperty.ALLOWS_ZERO_OR_ONE);
}
@Override
public ExtensionFunctionCall makeCallExpression() {
return new HighlightCall();
}
@Override
public int getMinimumNumberOfArguments () {
return 2;
}
@Override
public int getMaximumNumberOfArguments () {
return 3;
}
class HighlightCall extends NamespaceAwareFunctionCall {
@Override
public Sequence call(XPathContext context, Sequence[] arguments)
throws XPathException {
NodeInfo docArg = (NodeInfo) arguments[0].head();
if (docArg == null) {
return EmptySequence.getInstance();
}
Item queryArg = arguments[1].head();
Evaluator eval = SearchBase.getEvaluator(context);
Query query = parseQuery(queryArg, eval);
IndexConfiguration indexConfiguration = eval.getCompiler().getIndexConfiguration();
TagFormatter formatter;
if (arguments.length < 3) {
formatter = new TagFormatter("B", null);
} else {
Item tagName = arguments[2].head();
if (tagName instanceof QNameValue) {
QNameValue qname = (QNameValue) tagName;
formatter = new TagFormatter (qname.getLocalName(), qname.getNamespaceURI());
} else if (tagName instanceof StringValue) {
formatter = new TagFormatter(tagName.getStringValue(), null);
} else {
throw new XPathException ("invalid tag name for lux:highlight: got a " + tagName.getClass().getSimpleName() + " when expecting a QName or string");
}
}
XmlHighlighter xmlHighlighter = new XmlHighlighter(eval.getCompiler().getProcessor(), indexConfiguration, formatter);
try {
XdmNode highlighted = xmlHighlighter.highlight(query, docArg);
return highlighted.getUnderlyingNode();
} catch (XMLStreamException e) {
throw new XPathException(e);
} catch (SaxonApiException e) {
throw new XPathException(e);
}
}
}
}
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */