Search code examples
restxsltexist-dbmedia-type

eXistdb REST api with _xsl and _query parameter not returning text/html


I have just started learning the eXist database and am intrigued by the REST api built into it.

The application that I am using requires querying a file and then applying an xslt stylesheet to the result, but the REST api is not returning the correct media type (text/html). I am using the _xsl and _query parameters (along with _wrap=no to avoid eXist wrapping results when using _query).

According to eXist by Erik Siegel and Adam Retter (O'Reilly, 2014), when using the _xsl parameter,

Applying an XSLT stylesheet in this manner always changes the response's Internet media type to text/html.

(page 98, bold added by me), however, I am getting back application/xml (confirmed using the LiveHTTPHeaders plugin in Firefox).

Consider the following documents in the database

/db/apps/testing/example.xml

<items>
    <item>This is item 1</item>
    <item>This is item 2</item>
</items>

/db/apps/testing/example.xsl

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

    <xsl:template match="/">
        <html>
            <head><title>Testing</title></head>
                <body>                
                    <ul>
                        <xsl:apply-templates select="*"/>
                    </ul>
                </body>
        </html>
    </xsl:template>

    <xsl:template match="items">
        <xsl:apply-templates select="*"/>
    </xsl:template>

    <xsl:template match="item">
        <li><xsl:value-of select="."/></li>
    </xsl:template>

</xsl:stylesheet>

Then this url (applying the stylesheet to the whole document)

http://localhost:8080/exist/rest/db/apps/testing/example.xml?_xsl=/db/apps/testing/example.xsl

returns an html page (which is correctly rendered as the media type is text/html), but this url (first selecting only one item element and then applying the stylesheet)

http://localhost:8080/exist/rest/db/apps/testing/example.xml?_query=/items/item[1]&wrap=no&_xsl=/db/apps/testing/example.xsl

returns an xml file (application/xml)

<html>
    <head>
        <title>Testing</title>
    </head>
    <body>
        <ul>
            <li>This is item 1</li>
        </ul>
    </body>
</html>

The result here is correct, but it is served with the wrong media-type.

It seems that adding the _query parameter in order to first select only part of the document causes the media-type to be application/xml instead of text/html, and the behavior described by Siegel and Retter is only true if the _xsl parameter occurs by itself.

Is there a way to cause the second url which first filters the file to return text/html as well? Or is this behavior impossible with the REST api?

(Note: I know that I can pass parameters to an XQuery script and have that script both filter and transform the data, but I am interested in using the REST api to do the work here if possible.)


Solution

  • I looked at the code of eXist and do not see any way to get the results you want by using a GET request on the REST interface. However, you can do a POST. Here is an illustration of how it can be done using wget. Note that whereas you put your files under /db/apps/testing/, when I uploaded your files to my eXist instance for testing I put them under /db/testing/ (no apps). Adjust the paths as needed in what follows.

    Create a file named post.xml with the following:

    <?xml version="1.0" encoding="UTF-8"?>
    <query xmlns="http://exist.sourceforge.net/NS/exist"
           wrap="no">
      <text>/items/item[1]</text>
      <properties>
        <property name="stylesheet" value="/db/testing/example.xsl"/>
        <property name="media-type" value="text/html"/>
      </properties>
    </query>
    

    Then issue this command:

    wget -S --post-file=post.xml --header='Content-Type: application/xml'
         http://localhost:8080/exist/rest/db/testing/example.xml
    

    Or the equivalent. You need to have the content of post.xml as the content of the POST request, and the Content-Type header must be application/xml. The -S option dumps the response headers to the screen. So when I run the above, I get this on the console:

    --2016-06-15 12:12:10--  http://localhost:8080/exist/rest/db/testing/example.xml
    Resolving localhost (localhost)... ::1, 127.0.0.1
    Connecting to localhost (localhost)|::1|:8080... connected.
    HTTP request sent, awaiting response... 
      HTTP/1.1 200 OK
      Date: Wed, 15 Jun 2016 16:12:10 GMT
      Set-Cookie: [...]
      Expires: Thu, 01 Jan 1970 00:00:00 GMT
      Last-Modified: Tue, 14 Jun 2016 12:21:56 GMT
      Content-Type: text/html;charset=UTF-8
      Transfer-Encoding: chunked
      Server: Jetty(8.1.9.v20130131)
    Length: unspecified [text/html]
    Saving to: ‘example.xml’
    
    example.xml                                              [ <=>                                                                                                                  ]     154  --.-KB/s    in 0s      
    
    2016-06-15 12:12:10 (6.67 MB/s) - ‘example.xml’ saved [154]
    

    Note how the response's Content-Type is text/html. wget saves the results in a local file named example.xml which contains the expected data:

    <html>
        <head>
            <title>Testing</title>
        </head>
        <body>
            <ul>
                <li>This is item 1</li>
            </ul>
        </body>
    </html>