If you’re getting error msg 6825 that reads “ELEMENTS option is only allowed in RAW, AUTO, and PATH modes of FOR XML“, it’s probably because you’re trying to use the ELEMENTS
directive while using EXPLICIT
mode of the FOR XML
clause.
As the message alludes to, this option is not available when using the EXPLICIT
mode (it’s only allowed with the RAW
, AUTO
, and PATH
modes).
However, SQL Server does provide us with an equivalent that provides the same result. When using EXPLICIT
mode, we can use the ELEMENT
directive instead. We apply this to the column names, instead of the end of the query. We can alternatively use the ELEMENTXSINIL
directive to ensure that elements are generated even if the column contains a NULL value.
Example of Error
Here’s an example of code that produces the error:
SELECT
1 AS Tag,
NULL AS Parent,
p.PetId AS [Pet!1!PetId],
NULL AS [Details!2!PetName],
NULL AS [Details!2!PetType]
FROM Pets p
INNER JOIN PetTypes pt ON p.PetTypeId = pt.PetTypeId
UNION ALL
SELECT
2 AS Tag,
1 AS Parent,
p.PetId,
p.PetName,
pt.PetType
FROM Pets p
INNER JOIN PetTypes pt ON p.PetTypeId = pt.PetTypeId
ORDER BY [Pet!1!PetId], [Details!2!PetName]
FOR XML EXPLICIT, ELEMENTS;
Result:
Msg 6825, Level 16, State 1, Line 10 ELEMENTS option is only allowed in RAW, AUTO, and PATH modes of FOR XML.
The reason I got the error is because I used the ELEMENTS
directive instead of the ELEMENT
directive.
Solution
The solution to the above issue is to use the ELEMENT
directive instead of the ELEMENTS
directive:
SELECT
1 AS Tag,
NULL AS Parent,
p.PetId AS [Pet!1!PetId],
NULL AS [Details!2!PetName!ELEMENT],
NULL AS [Details!2!PetType!ELEMENT]
FROM Pets p
INNER JOIN PetTypes pt ON p.PetTypeId = pt.PetTypeId
UNION ALL
SELECT
2 AS Tag,
1 AS Parent,
p.PetId,
p.PetName,
pt.PetType
FROM Pets p
INNER JOIN PetTypes pt ON p.PetTypeId = pt.PetTypeId
ORDER BY [Pet!1!PetId], [Details!2!PetName!ELEMENT]
FOR XML EXPLICIT;
Result:
<Pet PetId="1"> <Details> <PetName> Fluffy </PetName> <PetType> Cat </PetType> </Details> </Pet> <Pet PetId="2"> <Details> <PetName> Fetch </PetName> <PetType> Dog </PetType> </Details> </Pet> <Pet PetId="3"> <Details> <PetName> Scratch </PetName> <PetType> Cat </PetType> </Details> </Pet>
When using the ELEMENT
directive, we need to add it to the individual columns that we want to be elements. In the above example I added !ELEMENT
to two columns, but left the PetId
column as an attribute.
Dealing with NULL Values
When using the ELEMENT
directive, if a column contains a NULL value, an element is not generated. If we want an element to be generated for NULL values, we can use the ELEMENTXSINIL
directive instead of ELEMENT
.