In REST Assured, which XmlConfig switches decide whether a DOCTYPE in a response parses?
answer
- allowDocTypeDeclaration defaults to false
- declaring and fetching are two switches
- features are applied after construction
- the standalone twin sets an extra feature
- XML mode only for the three booleans
basics
~20 sXmlConfig.allowDocTypeDeclaration(boolean) decides it, and its default is false, so a body carrying a DOCTYPE fails to parse. disableLoadingOfExternalDtd() is a separate switch that only stops the parser fetching the referenced DTD, and validating(boolean) likewise defaults to false.
solid answer
~50 s`XmlConfig` carries three parser booleans — `validating` (default `false`), `namespaceAware` (default `true`) and `allowDocTypeDeclaration` (default `false`) — and REST Assured passes all three to `new XmlSlurper(...)` in XML compatibility mode. Because `allowDocTypeDeclaration` is `false`, a legacy body that opens with `<!DOCTYPE sprayDiary SYSTEM "...">` fails at parse time, before any GPath step runs. `disableLoadingOfExternalDtd()` is a different switch: it puts the `nonvalidating/load-external-dtd` feature into the feature map so the parser will not fetch the DTD it was pointed at. Permitting the declaration and refusing to fetch it are independent, so a legacy endpoint usually needs both together. `feature(uri, enabled)` and `property(name, value)` are the general escape hatch, and they are applied after construction, so a feature can override one of the booleans. Every `XmlConfig` method returns a new instance, so assign the result and scope it with `given().config(...)` rather than relaxing the whole suite.
code
java · 21 linesimport io.restassured.config.RestAssuredConfig;
import static io.restassured.RestAssured.given;
import static io.restassured.config.XmlConfig.xmlConfig;
import static org.hamcrest.Matchers.equalTo;
// The legacy endpoint still emits:
// <!DOCTYPE sprayDiary SYSTEM "http://orchard.example/dtd/spray-diary.dtd">
RestAssuredConfig config = RestAssuredConfig.newConfig().xmlConfig(
xmlConfig()
.allowDocTypeDeclaration(true) // default false: lets the DOCTYPE through
.disableLoadingOfExternalDtd()); // and never fetch what it points at
given()
.config(config) // scoped to this call, not global
.when()
.get("/blocks/spray-diary")
.then()
.statusCode(200)
.body("sprayDiary.block[0].@name", equalTo("Northfield"));go deeper
Recall that XmlConfig, not the DSL, holds the XML parser switches, and that allowDocTypeDeclaration is off by default so a DOCTYPE-bearing body will not parse untouched.
Explain that the three booleans reach the parser through the XmlSlurper constructor in XML mode, and that features and properties are applied afterwards and can therefore override them.
Recognise the failure by its shape - every path failing at once - and scope the relaxation to the single legacy call while pairing it with disableLoadingOfExternalDtd so nothing is fetched.
Own the policy: which parser relaxations a suite is allowed to carry, where they are recorded and reviewed, and how you stop a one-endpoint exception becoming a global default nobody remembers setting.
## The switches and their defaults `io.restassured.config.XmlConfig` holds three parser booleans and two open-ended maps, plus the namespace declarations. Only the first group concerns DOCTYPEs and DTDs: | Setting | Default | What it controls | |---|---|---| | `allowDocTypeDeclaration(boolean)` | `false` | whether a `<!DOCTYPE ...>` in the body is tolerated at all | | `validating(boolean)` | `false` | whether the parser validates the document as it parses | | `namespaceAware(boolean)` | `true` | whether parsing takes namespaces into account | | `disableLoadingOfExternalDtd()` | not set | shortcut that adds one feature: `nonvalidating/load-external-dtd` = `false` | | `feature(uri, enabled)` / `features(Map)` | empty | any SAX feature, applied after the parser is built | | `property(name, value)` / `properties(Map)` | empty | any SAX property, applied after the parser is built | The three booleans go straight into `new XmlSlurper(validating, namespaceAware, allowDocTypeDeclaration)` — and only in `XmlPath.CompatibilityMode.XML`. Each one's Javadoc says so explicitly, and the HTML branch calls the single-argument constructor over tagsoup, which those arguments never reach. ## Why a DOCTYPE fails out of the box An orchard spray-diary service with a SOAP-era ancestry still emits: ```xml <!DOCTYPE sprayDiary SYSTEM "http://orchard.example/dtd/spray-diary.dtd"> <sprayDiary season="2026">...</sprayDiary> ``` With `allowDocTypeDeclaration` left at its default `false`, the slurper is built with the underlying reader's `disallow-doctype-decl` feature turned on, and parsing fails on the declaration itself — before any GPath step is evaluated. There is no partial read and no useful path-level message: a standalone `XmlPath` wraps the cause in an `XmlPathException` reading *Failed to parse the XML document*. The tell is that **every** path against that response fails at once, including trivially correct ones. ## Two DTD switches, doing two different jobs 1. `allowDocTypeDeclaration(true)` permits the declaration to exist. Without it nothing else matters, because the parse dies at the first line. 2. `disableLoadingOfExternalDtd()` stops the parser from going out and *fetching* what the declaration points at. It is a shortcut for `feature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false)`. They are independent, and a legacy endpoint typically wants both: tolerate the declaration, refuse the network fetch. Skipping the second leaves your suite quietly dependent on a DTD host that may be slow, firewalled, or gone. ## An asymmetry between the two config classes The DSL-side `XmlConfig` and the standalone-side `XmlPathConfig` both offer `disableLoadingOfExternalDtd()`, with the same name and near-identical Javadoc, and they do **not** do the same thing: - `XmlConfig.disableLoadingOfExternalDtd()` adds exactly one feature: `nonvalidating/load-external-dtd` = `false`. - `XmlPathConfig.disableLoadingOfExternalDtd()` adds two: that one **and** `disallow-doctype-decl` = `false`. So `new XmlPath(xml).using(xmlPathConfig().with().disableLoadingOfExternalDtd())` reads a DOCTYPE-bearing document on its own, while the same-named call on the DSL side does not — there you also need `allowDocTypeDeclaration(true)`. If you have ever ported a working standalone snippet into a `given().config(...)` chain and watched it stop working, this is why. ## Features and properties are the real escape hatch - `feature(uri, enabled)` and `features(Map)` set any SAX feature by URI; `property(name, value)` and `properties(Map)` set any SAX property. - Both maps are applied **after** the slurper is constructed, so a feature can override a constructor boolean: setting `disallow-doctype-decl` to `false` directly has the same net effect as `allowDocTypeDeclaration(true)`. - Unlike the three booleans, features and properties are applied in both compatibility modes. - Every one of these methods returns a **new** `XmlConfig` rather than mutating the receiver, so chain them and assign the result; a stray `xmlConfig().allowDocTypeDeclaration(true);` on its own line does nothing. - Applying it is the usual three-way choice: `RestAssured.config = ...` globally, `RequestSpecBuilder.setConfig(...)` on a spec, or `given().config(...)` for one call. ## Judgment - Leave `allowDocTypeDeclaration` at `false` unless a specific endpoint forces your hand. A parser that refuses DOCTYPEs is the safer default, and it is the shipped one. - When you must switch it on, scope it: `given().config(...)` on the one call, not `RestAssured.config` for the whole suite. The blast radius of a global relaxation is every test in the run. - Pair it with `disableLoadingOfExternalDtd()` so the parser never dials out to resolve the declaration. - Treat the switch as a documented exception with a named endpoint beside it in review, not as a knob someone flips to make a red test go green. - Keep `validating(false)`. Turning validation on couples your assertions to a schema fetched at parse time, which is a different job from asserting on values.
- How would you tell a DOCTYPE parse failure apart from a wrong path?By its blast radius. A wrong path fails one assertion and reads back null or an empty string; a rejected DOCTYPE fails the parse, so every path against that response fails together — including one you know is right. Standalone, the wrapper is an `XmlPathException` saying it failed to parse the document.
- Why might a snippet that works with a standalone XmlPath stop working inside given().config(...)?Because `XmlPathConfig.disableLoadingOfExternalDtd()` also sets `disallow-doctype-decl` to `false`, while the DSL-side `XmlConfig` version sets only the external-DTD feature despite the same name and Javadoc. On the DSL side you additionally need `allowDocTypeDeclaration(true)`.
saying these in an interview costs you the question
- Thinks disableLoadingOfExternalDtd also permits the DOCTYPE
- Assumes allowDocTypeDeclaration defaults to true
- Flips the switch globally on RestAssured.config to fix one endpoint
- Expects these booleans to apply in HTML compatibility mode
- Treats a parse failure as a bad path expression
- Calls xmlConfig() setters without assigning the returned instance