能否在构造元素中嵌套map?如何对map应用模板匹配?
XSLT中用Map替代中间XML结构后的模板处理方案
问题背景
创建中间文档时,原本习惯用元素/属性实现结构,但想用map简化操作,却遇到Saxon报错:
Cannot add a map as a child of a constructed element
原以为map会自动序列化为XML结构,示例代码如下:
<xsl:variable name="foo"> <foo> <xsl:map> <xsl:map-entry key="'bar'" select="'wibble'"/> </xsl:map> </foo> </xsl:variable>
虽然可以在map中嵌套元素,但上述报错符合预期。现在需要了解:若将整个中间结构改为map,如何对其执行apply-templates或match操作?
解决方案
1. 明确Map的类型本质
XSLT中的map属于序列类型,并非XML节点,因此无法直接作为元素子节点,也不能用常规的节点模板匹配逻辑。处理map需要使用专门针对map的函数和模板匹配规则。
2. 对Map执行apply-templates
要对map应用模板,需先将map转换为可被模板处理的序列,常用方式是通过map:entries()函数提取所有键值对条目:
<!-- 定义一个map变量 --> <xsl:variable name="my-map" as="map(xs:string, xs:string)"> <xsl:map> <xsl:map-entry key="'bar'" select="'wibble'"/> <xsl:map-entry key="'baz'" select="'wobble'"/> </xsl:map> </xsl:variable> <!-- 对map的键值对条目应用模板 --> <xsl:apply-templates select="map:entries($my-map)"/>
3. 编写匹配Map的模板
模板可以直接匹配map类型,或者匹配map:entries()返回的键值对条目:
- 匹配整个map:
<xsl:template match=".[instance of map(*)]"> <div class="map-wrapper"> <!-- 遍历map的所有条目并应用模板 --> <xsl:apply-templates select="map:entries(.)"/> </div> </xsl:template> - 匹配map的键值对条目:
<xsl:template match=".[instance of map:entry(xs:string, xs:string)]"> <div class="entry"> <span class="key">Key: {map:key(.)}</span> <span class="value">Value: {map:value(.)}</span> </div> </xsl:template>
4. 替代方案:直接遍历Map
如果不需要使用模板机制,也可以用xsl:for-each直接遍历map的键或条目:
<!-- 遍历map的所有键 --> <xsl:for-each select="map:keys($my-map)"> <entry key="{.}" value="{$my-map(.)}"/> </xsl:for-each> <!-- 或者遍历map的所有条目 --> <xsl:for-each select="map:entries($my-map)"> <entry key="{map:key(.)}" value="{map:value(.)}"/> </xsl:for-each>
内容的提问来源于stack exchange,提问作者MrD at KookerellaLtd
相关产品推荐
相关产品推荐

