Skip to content

Commit 4baa03e

Browse files
committed
[feature] Add the Query String parmeter '_output-doctype' to control the exist:output-doctype serialization option via HTTP GET to the REST Server
1 parent 936a796 commit 4baa03e

File tree

9 files changed

+169
-6
lines changed

9 files changed

+169
-6
lines changed

exist-core/src/main/java/org/exist/http/RESTServer.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,10 @@ private String getParameter(final HttpServletRequest request, final RESTServerPa
252252
* the returned XML.</li>
253253
* </ul>
254254
*
255+
* <li>_output-doctype: if set to "yes", the returned XML will include
256+
* a Document Type Declaration if one is present, if "no" the Document Type Declaration will be omitted.</li>
257+
* </ul>
258+
*
255259
* @param broker the database broker
256260
* @param transaction the database transaction
257261
* @param request the request
@@ -346,6 +350,14 @@ public void doGet(final DBBroker broker, final Txn transaction, final HttpServle
346350
if ((option = getParameter(request, Indent)) != null) {
347351
outputProperties.setProperty(OutputKeys.INDENT, option);
348352
}
353+
if ((option = getParameter(request, Output_Doctype)) != null) {
354+
// take user query-string specified output-doctype setting
355+
outputProperties.setProperty(EXistOutputKeys.OUTPUT_DOCTYPE, option);
356+
} else {
357+
// set output-doctype by configuration
358+
final String outputDocType = broker.getConfiguration().getProperty(Serializer.PROPERTY_OUTPUT_DOCTYPE, "no");
359+
outputProperties.setProperty(EXistOutputKeys.OUTPUT_DOCTYPE, outputDocType);
360+
}
349361
if ((option = getParameter(request, Source)) != null && !safeMode) {
350362
source = "yes".equals(option);
351363
}

exist-core/src/main/java/org/exist/http/RESTServerParameter.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,18 @@ enum RESTServerParameter {
346346
* <exist:property name = string
347347
* value = string/>
348348
*/
349-
Property;
349+
Property,
350+
351+
/**
352+
* Can be used in the Query String of a GET request
353+
* to indicate that the doctype of an XML document should also
354+
* be serialized if present.
355+
*
356+
* Contexts: GET
357+
*
358+
* The value of the parameter should be either "yes" or "no".
359+
*/
360+
Output_Doctype;
350361

351362
/**
352363
* Get the parameter key that is
@@ -366,6 +377,6 @@ public String queryStringKey() {
366377
* @return The parameter key, suitable for use in an XML document
367378
*/
368379
public String xmlKey() {
369-
return name().toLowerCase();
380+
return name().toLowerCase().replace('_', '-');
370381
}
371382
}

exist-core/src/main/java/org/exist/storage/serializers/Serializer.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ public abstract class Serializer implements XMLReader {
118118
protected final static Logger LOG = LogManager.getLogger(Serializer.class);
119119

120120
public static final String CONFIGURATION_ELEMENT_NAME = "serializer";
121+
public static final String OUTPUT_DOCTYPE_ATTRIBUTE = "output-doctype";
122+
public static final String PROPERTY_OUTPUT_DOCTYPE = "serialization.output-doctype";
121123
public static final String ENABLE_XINCLUDE_ATTRIBUTE = "enable-xinclude";
122124
public static final String PROPERTY_ENABLE_XINCLUDE = "serialization.enable-xinclude";
123125
public static final String ENABLE_XSL_ATTRIBUTE = "enable-xsl";

exist-core/src/main/java/org/exist/util/Configuration.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -652,6 +652,12 @@ private void configureHtmlToXmlParser(final Element parser) {
652652
*/
653653
private void configureSerializer( Element serializer )
654654
{
655+
final String outputDocType = getConfigAttributeValue( serializer, Serializer.OUTPUT_DOCTYPE_ATTRIBUTE );
656+
if (outputDocType != null) {
657+
config.put(Serializer.PROPERTY_OUTPUT_DOCTYPE, outputDocType);
658+
LOG.debug(Serializer.PROPERTY_OUTPUT_DOCTYPE + ": {}", config.get(Serializer.PROPERTY_OUTPUT_DOCTYPE));
659+
}
660+
655661
final String xinclude = getConfigAttributeValue( serializer, Serializer.ENABLE_XINCLUDE_ATTRIBUTE );
656662

657663
if( xinclude != null ) {

exist-core/src/test/java/org/exist/http/RESTServiceTest.java

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,13 @@ public class RESTServiceTest {
166166
" <header>{request:get-header('Authorization')}</header>\n" +
167167
"</authorization>\n";
168168

169+
private static final String XML_WITH_DOCTYPE =
170+
"<!DOCTYPE bookmap PUBLIC \"-//OASIS//DTD DITA BookMap//EN\" \"bookmap.dtd\">\n" +
171+
"<bookmap id=\"bookmap-1\"/>";
172+
173+
private static final XmldbURI TEST_DOCTYPE_COLLECTION_URI = XmldbURI.ROOT_COLLECTION_URI.append("rest-test-doctype");
174+
private static final XmldbURI TEST_XML_DOC_WITH_DOCTYPE_URI = XmldbURI.create("test-with-doctype.xml");
175+
169176
private static String credentials;
170177
private static String badCredentials;
171178

@@ -189,6 +196,10 @@ private static String getResourceUri() {
189196
return getServerUri() + XmldbURI.ROOT_COLLECTION + "/test/test.xml";
190197
}
191198

199+
private static String getResourceWithDocTypeUri() {
200+
return getServerUri() + TEST_DOCTYPE_COLLECTION_URI.append(TEST_XML_DOC_WITH_DOCTYPE_URI);
201+
}
202+
192203
/* About path components of URIs:
193204
194205
** reserved characters # http://tools.ietf.org/html/rfc3986#section-2.2
@@ -266,6 +277,11 @@ public static void setup() throws PermissionDeniedException, IOException, Trigge
266277
broker.saveCollection(transaction, col);
267278
}
268279

280+
try (final Collection col = broker.getOrCreateCollection(transaction, TEST_DOCTYPE_COLLECTION_URI)) {
281+
broker.storeDocument(transaction, TEST_XML_DOC_WITH_DOCTYPE_URI, new StringInputSource(XML_WITH_DOCTYPE), MimeType.XML_TYPE, col);
282+
broker.saveCollection(transaction, col);
283+
}
284+
269285
transaction.commit();
270286
} catch (EXistException | SAXException | LockException e) {
271287
throw new RuntimeException(e);
@@ -1206,6 +1222,86 @@ public void doDeleteEncodedPath() throws IOException {
12061222
}
12071223
}
12081224

1225+
/**
1226+
* By default there should be NO doctype serialized.
1227+
*/
1228+
@Test
1229+
public void getDocTypeDefault() throws IOException {
1230+
final HttpURLConnection connect = getConnection(getResourceWithDocTypeUri());
1231+
try {
1232+
connect.setRequestMethod("GET");
1233+
connect.connect();
1234+
1235+
final int r = connect.getResponseCode();
1236+
assertEquals("Server returned response code " + r, HttpStatus.OK_200, r);
1237+
String contentType = connect.getContentType();
1238+
final int semicolon = contentType.indexOf(';');
1239+
if (semicolon > 0) {
1240+
contentType = contentType.substring(0, semicolon).trim();
1241+
}
1242+
assertEquals("Server returned content type " + contentType, "application/xml", contentType);
1243+
1244+
final String response = readResponse(connect.getInputStream());
1245+
1246+
assertEquals("<bookmap id=\"bookmap-1\"/>\r\n", response);
1247+
1248+
} finally {
1249+
connect.disconnect();
1250+
}
1251+
}
1252+
1253+
@Test
1254+
public void getDocTypeNo() throws IOException {
1255+
final HttpURLConnection connect = getConnection(getResourceWithDocTypeUri() + "?_output-doctype=no");
1256+
try {
1257+
connect.setRequestMethod("GET");
1258+
connect.connect();
1259+
1260+
final int r = connect.getResponseCode();
1261+
assertEquals("Server returned response code " + r, HttpStatus.OK_200, r);
1262+
String contentType = connect.getContentType();
1263+
final int semicolon = contentType.indexOf(';');
1264+
if (semicolon > 0) {
1265+
contentType = contentType.substring(0, semicolon).trim();
1266+
}
1267+
assertEquals("Server returned content type " + contentType, "application/xml", contentType);
1268+
1269+
final String response = readResponse(connect.getInputStream());
1270+
1271+
assertEquals("<bookmap id=\"bookmap-1\"/>\r\n", response);
1272+
1273+
} finally {
1274+
connect.disconnect();
1275+
}
1276+
}
1277+
1278+
@Test
1279+
public void getDocTypeYes() throws IOException {
1280+
final HttpURLConnection connect = getConnection(getResourceWithDocTypeUri() + "?_output-doctype=yes");
1281+
try {
1282+
connect.setRequestMethod("GET");
1283+
connect.connect();
1284+
1285+
final int r = connect.getResponseCode();
1286+
assertEquals("Server returned response code " + r, HttpStatus.OK_200, r);
1287+
String contentType = connect.getContentType();
1288+
final int semicolon = contentType.indexOf(';');
1289+
if (semicolon > 0) {
1290+
contentType = contentType.substring(0, semicolon).trim();
1291+
}
1292+
assertEquals("Server returned content type " + contentType, "application/xml", contentType);
1293+
1294+
final String response = readResponse(connect.getInputStream());
1295+
1296+
assertEquals(
1297+
"<!DOCTYPE bookmap PUBLIC \"-//OASIS//DTD DITA BookMap//EN\" \"bookmap.dtd\">\r\n" +
1298+
"<bookmap id=\"bookmap-1\"/>\r\n", response);
1299+
1300+
} finally {
1301+
connect.disconnect();
1302+
}
1303+
}
1304+
12091305
private void chmod(final String resourcePath, final String mode) throws IOException {
12101306
final String uri = getCollectionUri() +"?_query=" + URLEncoder.encode(
12111307
"sm:chmod(xs:anyURI('" + resourcePath + "'), '" + mode + "')",

exist-distribution/src/main/config/conf.xml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -786,7 +786,11 @@
786786
Remember to add a statement like this to your client code:
787787
service.setProperty("compress-output", "yes");
788788
to uncompress the retrieved result in the client too.
789-
789+
790+
- output-doctype:
791+
should the Doctype Declaration for a document be serialized
792+
if it is present?
793+
790794
- enable-xinclude:
791795
should the database expand XInclude tags by default?
792796
@@ -811,7 +815,7 @@
811815
Set the parameter to "yes" to enable this feature.
812816
813817
-->
814-
<serializer add-exist-id="none" compress-output="no" enable-xinclude="yes"
818+
<serializer add-exist-id="none" compress-output="no" output-doctype="no" enable-xinclude="yes"
815819
enable-xsl="no" indent="yes" match-tagging-attributes="no"
816820
match-tagging-elements="no">
817821
<!--
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#
2+
# eXist-db Open Source Native XML Database
3+
# Copyright (C) 2001 The eXist-db Authors
4+
#
5+
6+
# http://www.exist-db.org
7+
#
8+
# This library is free software; you can redistribute it and/or
9+
# modify it under the terms of the GNU Lesser General Public
10+
# License as published by the Free Software Foundation; either
11+
# version 2.1 of the License, or (at your option) any later version.
12+
#
13+
# This library is distributed in the hope that it will be useful,
14+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16+
# Lesser General Public License for more details.
17+
#
18+
# You should have received a copy of the GNU Lesser General Public
19+
# License along with this library; if not, write to the Free Software
20+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21+
#
22+
23+
## XML Serialization options for the WevDAV
24+
## The file is read from EXIST_HOME/etc
25+
## Be careful changing the default values !
26+
#indent=yes
27+
#expand-xincludes=no
28+
#process-xsl-pi=no
29+
#encoding=UTF-8
30+
#omit-xml-declaration=no
31+
#output-doctype=yes

extensions/webdav/src/main/resources/webdav.properties

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@
2121
#
2222

2323
## XML Serialization options for the WevDAV
24-
## The file is read from EXIST_HOME
25-
## Be carefull changing the default values !
24+
## The file is read from the classpath
25+
## Be careful changing the default values !
2626
#indent=yes
2727
#expand-xincludes=no
2828
#process-xsl-pi=no

schema/conf.xsd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,7 @@
302302
</xs:simpleType>
303303
</xs:attribute>
304304
<xs:attribute name="compress-output" type="yes_no" default="no"/>
305+
<xs:attribute name="output-doctype" type="yes_no" default="no"/>
305306
<xs:attribute name="enable-xinclude" type="yes_no" default="yes"/>
306307
<xs:attribute name="enable-xsl" type="yes_no" default="no"/>
307308
<xs:attribute name="indent" type="yes_no" default="yes"/>

0 commit comments

Comments
 (0)