Using fn:parse-xml to Parse Escaped XML in XPath
The fn:parse-xml() function, introduced in XPath and
XQuery 3.0, allows developers to dynamically convert serialized or
escaped XML text strings into fully queryable XML node trees directly
inside an XPath expression. This article explains the mechanics of how
fn:parse-xml() operates on escaped XML strings,
demonstrates how to chain path expressions onto its result, and
highlights key considerations for error handling and document
structure.
The Role of
fn:parse-xml()
In many data processing scenarios, XML payloads are stored as escaped
strings within other XML documents (such as CDATA sections or
entity-encoded text like
<root>...</root>) or passed as
string parameters. Standard XPath navigation cannot traverse these inner
structures because the host XML parser treats them purely as text
nodes.
The fn:parse-xml() function bridges this gap with the
following signature:
fn:parse-xml($arg as xs:string?) as document-node()?
It takes a single string argument, parses it according to the XML 1.0
rules for well-formedness, and returns a new
document-node().
How
fn:parse-xml() Processes Escaped Strings
When evaluating an escaped XML string directly within an XPath expression, the process occurs in three distinct phases:
Entity Decoding by the Host Parser:
Before the XPath expression evaluates the function argument, the host XML processor resolves entity references (e.g., converting<to<and&to&). As a result, the string passed intofn:parse-xml()is a raw XML markup string.In-Memory Tree Construction:
Thefn:parse-xml()function invokes a secondary XML parser on the string at runtime. If the string is well-formed XML, the parser instantiates a new document node hierarchy entirely in memory.Downstream XPath Navigation:
Because the return type is adocument-node(), you can append additional location path steps directly to the function call to query the newly parsed elements.
Example Walkthrough
Consider the following XML document where the
<payload> element contains an escaped XML string:
<response>
<status>200</status>
<payload><order id="101"><item sku="A-55">Widget</item></order></payload>
</response>To extract the SKU attribute directly using a single XPath 3.0 expression:
fn:parse-xml(/response/payload)/order/item/@sku
Execution Breakdown:
/response/payloadevaluates to the string"<order id="101"><item sku="A-55">Widget</item></order>".fn:parse-xml(...)parses this string and returns the root document node of the inner XML structure./order/item/@skunavigates down the newly generated node tree, returning the attribute nodesku="A-55".
Key Considerations
- Well-Formedness Requirement: The string provided to
fn:parse-xml()must represent a well-formed XML document with a single root element. If the string contains multiple top-level elements or is malformed, the processor raises a dynamic error (err:FODC0006). - Handling XML Fragments: For escaped XML snippets
that lack a single root element (such as lists of adjacent tags), use
the related
fn:parse-xml-fragment()function instead. - Empty and Null Input: If the input argument
evaluates to an empty sequence (
()),fn:parse-xml()returns an empty sequence without throwing an error.