XSLT输出左尖括号处理疑似Bug:XQuery调用xdmp:unquote时抛出异常
Let's break down what's happening here and how to fix this frustrating edge case:
The Problem Breakdown
You've run into a quirk where:
- When using
xdmp:xslt-evalto generate an attribute containing a left angle bracket (<), the attribute value fails to get properly escaped. - The code works in Query Console because the console adds an implicit safety net—its post-processing cleans up invalid characters to make output renderable. But your main XQuery module runs strictly by XML syntax rules, triggering the
XDMP-DOCATTRVALCHARerror. - As you observed, element content gets correctly escaped to
<, but attribute values don't—this violates XML's core rules, where<in attributes must always be escaped.
Why Query Console Works (But Your Module Doesn't)
Query Console does extra work behind the scenes to make output look clean, even if the underlying serialized string is technically invalid. It auto-escapes problematic characters in displayed XML, which masks the actual issue. Your main module doesn't get this safety net, so it hits the expected syntax error when trying to parse invalid XML.
Fixes to Try
1. Skip Serialization Altogether (Best Approach)
You don't need xdmp:quote() and xdmp:unquote() here. xdmp:xslt-eval returns nodes directly—just work with those nodes instead of converting them to strings and back:
let $transformed-node := xdmp:xslt-eval( <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"> <xsl:template match="A"> <NEW> <xsl:attribute name="Attribute" select="normalize-space(./string())"/> <xsl:value-of select="normalize-space(.)"/> </NEW> </xsl:template> </xsl:stylesheet>, document { <A>1 < 2</A> } ) return $transformed-node
This avoids the entire serialization/deserialization cycle, so MarkLogic handles all necessary escaping internally—no manual work needed.
2. Explicitly Escape Special Characters in XSLT
If you need to stick with serialized strings, manually escape XML attribute special characters (<, ", &) when creating the attribute in XSLT:
<xsl:attribute name="Attribute"> <xsl:value-of select="replace( replace( replace(normalize-space(./string()), '&', '&amp;'), '<', '&lt;' ), '"', '&quot;' )"/> </xsl:attribute>
This ensures the attribute value is XML-compliant before it ever gets serialized.
3. Force Strict XML Serialization with xdmp:quote
When calling xdmp:quote, specify explicit XML serialization options to enforce proper attribute escaping:
let $transformed := xdmp:xslt-eval( <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"> <xsl:template match="A"> <NEW> <xsl:attribute name="Attribute" select="normalize-space(./string())"/> <xsl:value-of select="normalize-space(.)"/> </NEW> </xsl:template> </xsl:stylesheet>, document { <A>1 < 2</A> } ) let $Q := xdmp:quote($transformed, <options xmlns="xdmp:quote"> <method>xml</method> <indent>yes</indent> </options> ) let $XML := xdmp:unquote($Q) return $XML
The method="xml" option tells xdmp:quote to follow strict XML serialization rules, which includes escaping special characters in attributes.
Final Note
The root issue here is unnecessary serialization—working directly with nodes is almost always safer and more efficient in MarkLogic. Only serialize to strings when you absolutely need to (e.g., for storing raw XML text in a document).
内容的提问来源于stack exchange,提问作者Neil Bradley

