如何用XPath3.1+XSLT构建带错误捕获的鲁棒XML高阶解析器?
构建鲁棒的XML解析器(结合XPath 3.1与XSLT 3捕获动态错误)
由于XPath 3.1本身没有错误捕获机制,我们可以借助XSLT 3的<xsl:try>/<xsl:catch>特性,将解析逻辑封装到带错误处理的XSLT函数中,同时保留原有的闭包绑定实体定义的设计,最终实现返回指定map结构的高阶函数。
核心实现步骤
1. 重构高阶函数,保留闭包逻辑
原uml:documentation-parser高阶函数仍负责绑定外部实体定义,但返回的函数不再直接调用parse-xml(),而是调用带错误处理的XSLT函数,最终组装成要求的map结果:
<xsl:function name="uml:documentation-parser" as="function(element()) as map(*)"> <xsl:param name="entity-definitions" as="document-node()"/> <xsl:sequence select=" function($comment as element()) as map(*) { let $raw-body := $comment/@body return map { 'text': $raw-body, 'xml': uml:safe-parse($raw-body, $entity-definitions)?xml, 'err': uml:safe-parse($raw-body, $entity-definitions)?err } } "/> </xsl:function>
2. 实现带错误捕获的XSLT解析函数
创建uml:safe-parse函数,用<xsl:try>捕获parse-xml()抛出的err:FODC0006及其他解析错误,返回包含解析结果或错误信息的map:
<xsl:function name="uml:safe-parse" as="map(*)"> <xsl:param name="xml-fragment" as="xs:string?"/> <xsl:param name="entity-docs" as="document-node()"/> <xsl:try> <!-- 结合外部实体定义解析XML片段 --> <xsl:variable name="parsed" as="element()*"> <xsl:sequence select="parse-xml($xml-fragment, map { 'entity-resolver': function($entity-name as xs:string) as xs:string? { <!-- 根据你的实体定义文档结构,调整实体查找逻辑 --> $entity-docs//*[@name = $entity-name]/@value } })"/> </xsl:variable> <xsl:sequence select="map { 'xml': $parsed, 'err': () }"/> <!-- 专门捕获非良构XML错误 --> <xsl:catch errors="err:FODC0006"> <xsl:sequence select="map { 'xml': (), 'err': map { 'code': $err:code, 'message': $err:description, 'line': $err:line-number } }"/> </xsl:catch> <!-- 捕获其他可能的解析异常 --> <xsl:catch> <xsl:sequence select="map { 'xml': (), 'err': map { 'code': $err:code, 'message': $err:description } }"/> </xsl:catch> </xsl:try> </xsl:function>
3. 使用示例
调用高阶函数并处理每个ownedComment元素:
<!-- 绑定实体定义文档,生成解析器函数 --> <xsl:variable name="comment-parser" select="uml:documentation-parser(doc('external-entities.xml'))"/> <!-- 处理目标元素 --> <xsl:template match="ownedComment"> <xsl:variable name="result" select="$comment-parser(.)"/> <comment-record> <original-text>{$result?text}</original-text> <xsl:if test="exists($result?xml)"> <parsed-output>{$result?xml}</parsed-output> </xsl:if> <xsl:if test="exists($result?err)"> <parse-error code="{$result?err?code}"> {$result?err?message} <xsl:if test="$result?err?line"> <line-number>{$result?err?line}</line-number> </xsl:if> </parse-error> </xsl:if> </comment-record> </xsl:template>
关键细节说明
- 闭包特性保留:
uml:documentation-parser返回的函数仍绑定了外部实体定义,无需每次解析都传递实体文档 - 错误隔离:
<xsl:try>确保单个解析失败不会中断整个文档处理 - 结果结构严格匹配需求:返回的map包含
text(原始属性值)、xml(解析成功的元素序列,失败则为空)、err(错误信息map,成功则为空序列) - 实体解析逻辑可根据你的外部实体文件结构灵活调整
内容的提问来源于stack exchange,提问作者Frank Steimke
相关产品推荐
相关产品推荐

