如何用XPath 3.1/XQuery替换嵌套映射/数组中的模板字符串
使用XPath 3.1/XQuery实现模板变量替换的方法
需求说明
我有一个从JSON文件解析得到的映射$template,示例如下:
let $template := map{ "name" : "{{name}}", "aggregateRating": map{ "ratingValue": "{{ratingValue}}" }, "openingHoursSpecification": map{ "workingHours" : "{{workingHours}}", "workingDays": array{ "Friday", "Saturday", "Sunday", "{{workingDaysRemark}}" } } }
还有一个从HTML文档提取的映射$values,示例如下:
let $values := map { "name": "My comedy Name", "ratingValue": 9.4, "workingHours": "7 PM to 3 AM", "workingDaysRemark": "Except for statutory holidays" }
需要将$template中所有形如{{keyName}}的字符串值替换为$values(keyName),得到预期结果。
实现方案
通过递归遍历模板结构,结合正则替换完成变量填充,具体代码如下:
declare function local:replace-templates($node as item(), $values as map(*)) as item() { typeswitch ($node) case map(*) return map:merge( map:keys($node) ! map{ . : local:replace-templates($node(.), $values) } ) case array(*) return array{ $node[] ! local:replace-templates(., $values) } case xs:string return replace( $node, '\{\{(\w+)\}\}', function($match) { let $key := $match[1] return if (map:contains($values, $key)) then $values($key) else $match[0] } ) default return $node }; -- 调用示例 let $template := map{ "name" : "{{name}}", "aggregateRating": map{ "ratingValue": "{{ratingValue}}" }, "openingHoursSpecification": map{ "workingHours" : "{{workingHours}}", "workingDays": array{ "Friday", "Saturday", "Sunday", "{{workingDaysRemark}}" } } } let $values := map { "name": "My comedy Name", "ratingValue": 9.4, "workingHours": "7 PM to 3 AM", "workingDaysRemark": "Except for statutory holidays" } return local:replace-templates($template, $values)
代码说明
- 类型分支处理:用
typeswitch区分不同节点类型,针对性处理:- Map类型:遍历所有键值对,递归处理每个值后重新合并为新map
- Array类型:遍历数组元素,递归处理每个元素后重构数组
- 字符串类型:通过正则
\{\{(\w+)\}\}匹配模板变量,用$values中对应的键值替换;若键不存在则保留原模板字符串 - 其他类型:直接返回原值,确保数字、布尔值等非字符串类型不受影响
内容的提问来源于stack exchange,提问作者Fravadona
相关产品推荐
相关产品推荐

