From 244645a7845322a9e1ab12bbcd7328fcd3313a24 Mon Sep 17 00:00:00 2001
From: Thorsten Vitt <thorsten.vitt@uni-wuerzburg.de>
Date: Wed, 11 Sep 2013 11:59:14 +0200
Subject: [PATCH] [HTML] embedded=true only returns the HTML body's contents.

Fails if the stylesheet doesn't output XHTML. The children
of the <body> element are wrapped in a <div class="body">,
no XML declaration is included.
---
 .../services/aggregator/html/HTML.java        | 46 ++++++++++++-------
 .../services/aggregator/html/HTMLWriter.java  | 10 +++-
 .../WEB-INF/stylesheets/extractbody.xsl       | 29 ++++++++++++
 3 files changed, 66 insertions(+), 19 deletions(-)
 create mode 100644 src/main/webapp/WEB-INF/stylesheets/extractbody.xsl

diff --git a/src/main/java/info/textgrid/services/aggregator/html/HTML.java b/src/main/java/info/textgrid/services/aggregator/html/HTML.java
index 6bda0f0..653d212 100644
--- a/src/main/java/info/textgrid/services/aggregator/html/HTML.java
+++ b/src/main/java/info/textgrid/services/aggregator/html/HTML.java
@@ -50,8 +50,8 @@
 @Description("Creates an HTML representation of the given TEI document, or aggregation of TEI documents. This is currently extremely experimental and probably broken.")
 public class HTML {
 
-
 	private static final String TO_HTML_XSL = "/WEB-INF/stylesheets/db2xhtml.xsl";
+	private static final String EXTRACT_BODY_XSL = "/WEB-INF/stylesheets/extractbody.xsl";
 
 	ITextGridRep repository = TextGridRepProvider.getInstance();
 
@@ -59,6 +59,8 @@ public class HTML {
 			.getLogger("info.textgrid.services.aggregator.html.HTML");
 
 	private XsltExecutable toHtml;
+	private XsltExecutable extractBody;
+
 	final Processor xsltProcessor;
 
 	@Context
@@ -83,6 +85,22 @@ XsltExecutable getToHtml() {
 		return toHtml;
 	}
 
+	XsltExecutable getExtractBody() {
+		if (extractBody == null) {
+			try {
+				URL stylesheet;
+				stylesheet = servlet.getResource(EXTRACT_BODY_XSL);
+				extractBody = xsltProcessor.newXsltCompiler().compile(
+						new StreamSource(stylesheet.toString()));
+			} catch (final MalformedURLException e) {
+				throw new IllegalStateException(e);
+			} catch (final SaxonApiException e) {
+				throw new IllegalStateException(e);
+			}
+		}
+		return extractBody;
+	}
+
 	public HTML(final ITextGridRep repository) throws IOException {
 		this.repository = repository;
 		xsltProcessor = new Processor(false);
@@ -102,8 +120,7 @@ public void onRemoval(
 										notification.getKey(),
 										notification.getCause()));
 					}
-				})
-.build(new CacheLoader<URI, XsltExecutable>() {
+				}).build(new CacheLoader<URI, XsltExecutable>() {
 
 					@Override
 					public XsltExecutable load(final URI url) throws Exception {
@@ -127,7 +144,7 @@ public XsltExecutable load(final URI url) throws Exception {
 
 	/**
 	 * Returns an appropriate stylesheet for the given URI.
-	 *
+	 * 
 	 * Basically, we try the following options in order:
 	 * <ol>
 	 * <li>The stylesheet is cached -> return the cached version.
@@ -135,7 +152,7 @@ public XsltExecutable load(final URI url) throws Exception {
 	 * <li>The stylesheet is non-public TextGrid internal -> load & do not cache
 	 * it.
 	 * </ol>
-	 *
+	 * 
 	 * @param uri
 	 *            the URI of the stylesheet to load
 	 * @param sid
@@ -148,8 +165,8 @@ public XsltExecutable load(final URI url) throws Exception {
 	 *             if saxon fails to compile the stylesheet.
 	 */
 	protected XsltExecutable getStylesheet(final URI uri,
-			final Optional<String> sid,
-			final boolean forceLoad) throws SaxonApiException, IOException {
+			final Optional<String> sid, final boolean forceLoad)
+			throws SaxonApiException, IOException {
 		XsltExecutable executable = null;
 
 		// (1) try cached version, if it exists
@@ -201,18 +218,13 @@ private static boolean isPublic(final ObjectType metadata) {
 	@Path(value = "/{object}")
 	@Produces(value = "text/xml")
 	public Response get(
-			@Description("The TextGrid URI of the TEI document or aggregation to transform")
-			@PathParam("object") final URI uri,
-			@Description("If given, an alternative XSLT stylesheet to use")
-			@QueryParam("stylesheet") final URI xsluri,
-			@Description("If true, check for an <?xsl-stylesheet?> processing instruction in the document to render")
-			@QueryParam("pi") final boolean pi,
+			@Description("The TextGrid URI of the TEI document or aggregation to transform") @PathParam("object") final URI uri,
+			@Description("If given, an alternative XSLT stylesheet to use") @QueryParam("stylesheet") final URI xsluri,
+			@Description("If true, check for an <?xsl-stylesheet?> processing instruction in the document to render") @QueryParam("pi") final boolean pi,
 			@Description("If true and a stylesheet has been given, force reloading the stylesheet, do not cache") @QueryParam("refreshStylesheet") final boolean refreshStylesheet,
-			@Description("Session ID to access protected resources")
-			@QueryParam("sid") final String sid,
+			@Description("Session ID to access protected resources") @QueryParam("sid") final String sid,
 			@Description("If true, pass the information the stylesheet that its result will be embedded into some website") @QueryParam("embedded") final boolean embedded,
-			@Description("URL of the CSS that should be referenced in the HTML that is created")
-			@QueryParam("css") final URI css,
+			@Description("URL of the CSS that should be referenced in the HTML that is created") @QueryParam("css") final URI css,
 			@Description("The requested content type. E.g., text/html or text/xml") @QueryParam("mediatype") final String mediaType,
 			@Context final Request request) throws ObjectNotFoundFault,
 			MetadataParseFault, IoFault, AuthFault,
diff --git a/src/main/java/info/textgrid/services/aggregator/html/HTMLWriter.java b/src/main/java/info/textgrid/services/aggregator/html/HTMLWriter.java
index a971b0d..ade4ff5 100644
--- a/src/main/java/info/textgrid/services/aggregator/html/HTMLWriter.java
+++ b/src/main/java/info/textgrid/services/aggregator/html/HTMLWriter.java
@@ -319,8 +319,14 @@ public void write(final OutputStream out) throws IOException,
 			logger.log(Level.INFO, MessageFormat.format("Ready for transformation of {0} after {1}", rootURI, stopwatch.toString()));
 			final Serializer serializer = service.xsltProcessor
 					.newSerializer(out);
-			transformer
-.setDestination(serializer);
+			if (embedded) {
+				final XsltTransformer extractBody = service.getExtractBody()
+						.load();
+				extractBody.setDestination(serializer);
+				transformer.setDestination(extractBody);
+			} else {
+				transformer.setDestination(serializer);
+			}
 			transformer.transform();
 
 		} catch (final Exception e) {
diff --git a/src/main/webapp/WEB-INF/stylesheets/extractbody.xsl b/src/main/webapp/WEB-INF/stylesheets/extractbody.xsl
new file mode 100644
index 0000000..1390103
--- /dev/null
+++ b/src/main/webapp/WEB-INF/stylesheets/extractbody.xsl
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+        xmlns:xs="http://www.w3.org/2001/XMLSchema"
+        xmlns="http://www.w3.org/1999/xhtml"
+        xpath-default-namespace="http://www.w3.org/1999/xhtml"
+        exclude-result-prefixes="xs"
+        version="2.0">
+
+<!-- 
+        Extracts the contents of the body of an XHTML document and wraps it in a <div class="body">.
+        Used by the html export when embedded=true is specified.        
+ -->
+
+<xsl:output method="xhtml" omit-xml-declaration="yes"/>
+        
+<xsl:template match="/">
+        <xsl:choose>
+                <xsl:when test="//body">
+                        <div class="body">
+                                <xsl:copy-of select="//body/*"/>
+                        </div>
+                </xsl:when>
+                <xsl:otherwise>
+                        <xsl:copy-of select="/*"/>
+                </xsl:otherwise>
+        </xsl:choose>
+</xsl:template>
+        
+</xsl:stylesheet>
\ No newline at end of file
-- 
GitLab