- added xslt support for solr result formats.

try i.e.
http://localhost:8090/solr/select?q=*:*&start=0&rows=10&wt=xslt&tr=json.xsl
- added servlet-side mime-type configuration for streamed servlets. this
is used for the result formatters in solr result formats
pull/1/head
Michael Peter Christen 12 years ago
parent ad62609ec7
commit aab0b680c3

@ -0,0 +1,132 @@
<?xml version='1.0' encoding='UTF-8'?>
<!--
* 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.
-->
<!--
Simple transform of Solr query results to HTML
-->
<xsl:stylesheet version='1.0'
xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
>
<xsl:output media-type="text/html" encoding="UTF-8"/>
<xsl:variable name="title" select="concat('Solr search results (',response/result/@numFound,' documents)')"/>
<xsl:template match='/'>
<html>
<head>
<title><xsl:value-of select="$title"/></title>
<xsl:call-template name="css"/>
</head>
<body>
<h1><xsl:value-of select="$title"/></h1>
<div class="note">
This has been formatted by the sample "example.xsl" transform -
use your own XSLT to get a nicer page
</div>
<xsl:apply-templates select="response/result/doc"/>
</body>
</html>
</xsl:template>
<xsl:template match="doc">
<xsl:variable name="pos" select="position()"/>
<div class="doc">
<table width="100%">
<xsl:apply-templates>
<xsl:with-param name="pos"><xsl:value-of select="$pos"/></xsl:with-param>
</xsl:apply-templates>
</table>
</div>
</xsl:template>
<xsl:template match="doc/*[@name='score']" priority="100">
<xsl:param name="pos"></xsl:param>
<tr>
<td class="name">
<xsl:value-of select="@name"/>
</td>
<td class="value">
<xsl:value-of select="."/>
<xsl:if test="boolean(//lst[@name='explain'])">
<xsl:element name="a">
<!-- can't allow whitespace here -->
<xsl:attribute name="href">javascript:toggle("<xsl:value-of select="concat('exp-',$pos)" />");</xsl:attribute>?</xsl:element>
<br/>
<xsl:element name="div">
<xsl:attribute name="class">exp</xsl:attribute>
<xsl:attribute name="id">
<xsl:value-of select="concat('exp-',$pos)" />
</xsl:attribute>
<xsl:value-of select="//lst[@name='explain']/str[position()=$pos]"/>
</xsl:element>
</xsl:if>
</td>
</tr>
</xsl:template>
<xsl:template match="doc/arr" priority="100">
<tr>
<td class="name">
<xsl:value-of select="@name"/>
</td>
<td class="value">
<ul>
<xsl:for-each select="*">
<li><xsl:value-of select="."/></li>
</xsl:for-each>
</ul>
</td>
</tr>
</xsl:template>
<xsl:template match="doc/*">
<tr>
<td class="name">
<xsl:value-of select="@name"/>
</td>
<td class="value">
<xsl:value-of select="."/>
</td>
</tr>
</xsl:template>
<xsl:template match="*"/>
<xsl:template name="css">
<script>
function toggle(id) {
var obj = document.getElementById(id);
obj.style.display = (obj.style.display != 'block') ? 'block' : 'none';
}
</script>
<style type="text/css">
body { font-family: "Lucida Grande", sans-serif }
td.name { font-style: italic; font-size:80%; }
td { vertical-align: top; }
ul { margin: 0px; margin-left: 1em; padding: 0px; }
.note { font-size:80%; }
.doc { margin-top: 1em; border-top: solid grey 1px; }
.exp { display: none; font-family: monospace; white-space: pre; }
</style>
</xsl:template>
</xsl:stylesheet>

@ -0,0 +1,25 @@
<?xml version='1.0' encoding='UTF-8'?>
<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
<xsl:output media-type="application/json" encoding="UTF-8" method="text"/>
<xsl:template match='/'>
<xsl:text>[</xsl:text>
<xsl:for-each select="response/result/doc">
<xsl:if test="position()&gt;1"><xsl:text>,</xsl:text></xsl:if>
<xsl:apply-templates select="."/>
</xsl:for-each>
<xsl:text>]</xsl:text>
</xsl:template>
<xsl:template match="doc">
<xsl:text>{"id":"</xsl:text><xsl:apply-templates select="str[@name='id']"/>
<xsl:text>","url":"</xsl:text><xsl:apply-templates select="str[@name='sku']"/>
<xsl:text>","title":"</xsl:text><xsl:apply-templates select="str[@name='title']"/>
<xsl:text>"}</xsl:text>
</xsl:template>
<xsl:template match="str">
<xsl:value-of select="translate(.,'&quot;',&apos;&quot;&apos;)"/>
</xsl:template>
</xsl:stylesheet>

@ -1,3 +1,23 @@
/**
* select
* Copyright 2012 by Michael Peter Christen, mc@yacy.net, Frankfurt am Main, Germany
* First released 12.08.2012 at http://yacy.net
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program in the file lgpl21.txt
* If not, see <http://www.gnu.org/licenses/>.
*/
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
@ -21,10 +41,12 @@ import net.yacy.search.solr.SolrServlet;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.util.FastWriter;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.core.SolrCore;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.response.QueryResponseWriter;
import org.apache.solr.response.SolrQueryResponse;
import org.apache.solr.response.XSLTResponseWriter;
import de.anomic.server.serverObjects;
import de.anomic.server.serverSwitch;
@ -32,6 +54,11 @@ import de.anomic.server.serverSwitch;
// try
// http://localhost:8090/solr/select?q=*:*&start=0&rows=10&indent=on
/**
*
* http://wiki.apache.org/solr/SolrQuerySyntax
*
*/
public class select {
private static SolrServlet solrServlet = new SolrServlet();
@ -39,10 +66,40 @@ public class select {
static {
try {solrServlet.init(null);} catch (ServletException e) {}
RESPONSE_WRITER.putAll(SolrCore.DEFAULT_RESPONSE_WRITERS);
XSLTResponseWriter xsltWriter = new XSLTResponseWriter();
@SuppressWarnings("rawtypes")
NamedList initArgs = new NamedList();
xsltWriter.init(initArgs);
RESPONSE_WRITER.put("xslt", xsltWriter); // try i.e. http://localhost:8090/solr/select?q=*:*&start=0&rows=10&wt=xslt&tr=json.xsl
RESPONSE_WRITER.put("exml", new EnhancedXMLResponseWriter());
RESPONSE_WRITER.put("rss", new OpensearchResponseWriter()); //try http://localhost:8090/solr/select?wt=rss&q=olympia
}
/**
* get the right mime type for this streamed result page
* @param header
* @param post
* @param env
* @return
*/
public static String mime(final RequestHeader header, final serverObjects post, final serverSwitch env) {
String wt = post.get(CommonParams.WT, "xml");
if (wt == null || wt.length() == 0 || "xml".equals(wt) || "exml".equals(wt)) return "text/xml";
if ("xslt".equals(wt)) {
String tr = post.get("tr","");
if (tr.indexOf("json") >= 0) return "application/json";
}
if ("rss".equals(wt)) return "application/rss+xml";
if ("json".equals(wt)) return "application/json";
if ("python".equals(wt)) return "text/html";
if ("php".equals(wt) || "phps".equals(wt)) return "application/x-httpd-php";
if ("ruby".equals(wt)) return "text/html";
if ("raw".equals(wt)) return "application/octet-stream";
if ("javabin".equals(wt)) return "application/octet-stream";
if ("csv".equals(wt)) return "text/csv";
return "text/xml";
}
/**
* a query to solr, for documentation of parameters see:
* http://lucene.apache.org/solr/api-3_6_0/doc-files/tutorial.html

@ -875,7 +875,7 @@ public final class HTTPDFileHandler {
//requestHeader.put(httpHeader.CONNECTION_PROP_INPUTSTREAM, body);
//requestHeader.put(httpHeader.CONNECTION_PROP_OUTPUTSTREAM, out);
ResponseHeader header = new ResponseHeader(200);
header.put(HeaderFramework.CONTENT_TYPE, "text/xml"); // this is a hack; the actual content type should be given by the servlet, but there is no handover process for that at this time
header.put(HeaderFramework.CONTENT_TYPE, getMimeFromServlet(targetClass, requestHeader, args, "text/xml"));
conProp.remove(HeaderFramework.CONNECTION_PROP_PERSISTENT);
HTTPDemon.sendRespondHeader(conProp, out, httpVersion, 200, header);
invokeServlet(targetClass, requestHeader, args, out);
@ -1322,11 +1322,11 @@ public final class HTTPDFileHandler {
}
}
private static final Method rewriteMethod(final File classFile) throws InvocationTargetException {
private static final Method rewriteMethod(final File classFile, final String methodName) throws InvocationTargetException {
Method m = null;
// now make a class out of the stream
try {
if (templateMethodCache != null) {
if (templateMethodCache != null && "respond".equals(methodName)) {
final SoftReference<Method> ref = templateMethodCache.get(classFile);
if (ref != null) {
m = ref.get();
@ -1344,22 +1344,23 @@ public final class HTTPDFileHandler {
serverObjects.class,
serverSwitch.class };
try {
m = c.getMethod("respond", params);
m = c.getMethod(methodName, params);
} catch (NoSuchMethodException e) {
params = new Class[] {
RequestHeader.class,
serverObjects.class,
serverSwitch.class,
OutputStream.class};
m = c.getMethod("respond", params);
m = c.getMethod(methodName, params);
}
if (MemoryControl.shortStatus()) {
templateMethodCache.clear();
} else {
// storing the method into the cache
final SoftReference<Method> ref = new SoftReference<Method>(m);
templateMethodCache.put(classFile, ref);
// store the method into the cache
if (templateMethodCache != null && "respond".equals(methodName)) {
templateMethodCache.put(classFile, new SoftReference<Method>(m));
}
}
} catch (final ClassNotFoundException e) {
@ -1375,9 +1376,9 @@ public final class HTTPDFileHandler {
private static final Object invokeServlet(final File targetClass, final RequestHeader request, final serverObjects args, final OutputStream os) {
try {
if (os == null) {
return rewriteMethod(targetClass).invoke(null, new Object[] {request, args, switchboard});
return rewriteMethod(targetClass, "respond").invoke(null, new Object[] {request, args, switchboard});
}
return rewriteMethod(targetClass).invoke(null, new Object[] {request, args, switchboard, os});
return rewriteMethod(targetClass, "respond").invoke(null, new Object[] {request, args, switchboard, os});
} catch (final Throwable e) {
theLogger.logSevere("INTERNAL ERROR: " + e.toString() + ":" +
e.getMessage() +
@ -1390,6 +1391,21 @@ public final class HTTPDFileHandler {
}
}
private static final String getMimeFromServlet(final File targetClass, final RequestHeader request, final serverObjects args, final String dflt) {
try {
return (String) rewriteMethod(targetClass, "mime").invoke(null, new Object[] {request, args, switchboard});
} catch (final Throwable e) {
theLogger.logSevere("INTERNAL ERROR: " + e.toString() + ":" +
e.getMessage() +
" target exception at " + targetClass + ": " +
"; java.awt.graphicsenv='" + System.getProperty("java.awt.graphicsenv","") + "'");
Log.logException(e);
Log.logException(e.getCause());
if (e instanceof InvocationTargetException) Log.logException(((InvocationTargetException) e).getTargetException());
return dflt;
}
}
/**
* Tells if a filename ends with a suffix from a given list.
* @param filename the filename

@ -658,8 +658,11 @@ public final class serverCore extends AbstractBusyThread implements BusyThread {
listen();
} catch (final IOException e) {
Log.logException(e);
} catch (final Exception e) {
} catch (final Throwable e) {
Log.logException(e);
final Throwable targetException = (e instanceof InvocationTargetException) ? ((InvocationTargetException) e).getTargetException() : null;
Log.logException(e.getCause());
if (targetException != null) Log.logException(targetException);
} finally {
try {
if ((this.controlSocket != null) && (! this.controlSocket.isClosed())) {

@ -56,7 +56,7 @@ public class EmbeddedSolrConnector extends AbstractSolrConnector implements Solr
public static final String SELECT = "/select";
public static final String CONTEXT = "/solr";
private final static String[] confFiles = {"solrconfig.xml", "schema.xml", "stopwords.txt", "synonyms.txt", "protwords.txt", "currency.xml", "elevate.xml", "lang/"};
private final static String[] confFiles = {"solrconfig.xml", "schema.xml", "stopwords.txt", "synonyms.txt", "protwords.txt", "currency.xml", "elevate.xml", "xslt/example.xsl", "xslt/json.xsl", "lang/"};
private final CoreContainer cores;
private final String defaultCoreName;
@ -76,12 +76,20 @@ public class EmbeddedSolrConnector extends AbstractSolrConnector implements Solr
target = new File(conf, cf);
target.mkdirs();
for (String cfl: source.list()) {
Files.copy(new File(source, cfl), new File(target, cfl));
try {
Files.copy(new File(source, cfl), new File(target, cfl));
} catch (IOException e) {
Log.logException(e);
}
}
} else {
target = new File(conf, cf);
target.getParentFile().mkdirs();
Files.copy(source, target);
try {
Files.copy(source, target);
} catch (IOException e) {
Log.logException(e);
}
}
}
/*

Loading…
Cancel
Save