基于位置分组的XSLT提取:解决result-document重复写入报错
解决方案:用XSLT分组提取节点并避免重复写入文件
问题核心
需要提取XML中所有以<s>开头的节点(如<sSubAssCou>、<sTest>),同时记录两个索引:
svIndex:节点在其父节点中的位置mvIndex:节点父节点的父节点<mSubAssetType>的位置
按节点名称分组写入独立文件时,Saxon抛出XTDE1490错误(同一URI多次写入),需用for-each-group解决分组写入问题。
实现代码(XSLT 2.0+)
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="xml" indent="yes"/> <xsl:template match="/"> <!-- 按节点本地名称分组,筛选所有以"s"开头的节点 --> <xsl:for-each-group select="//*[starts-with(local-name(), 's')]" group-by="local-name()"> <!-- 每个组对应一个输出文件,文件名使用节点名称 --> <xsl:result-document href="{current-grouping-key()}.xml"> <root> <xsl:for-each select="current-group()"> <!-- 计算mSubAssetType的位置 --> <xsl:variable name="mvIndex" select="count(ancestor::mSubAssetType/preceding-sibling::mSubAssetType) + 1"/> <!-- 计算当前节点在父节点中的位置 --> <xsl:variable name="svIndex" select="count(preceding-sibling::*) + 1"/> <!-- 输出带索引的节点副本 --> <xsl:copy> <xsl:attribute name="mvIndex" select="$mvIndex"/> <xsl:attribute name="svIndex" select="$svIndex"/> <xsl:copy-of select="@* | node()"/> </xsl:copy> </xsl:for-each> </root> </xsl:result-document> </xsl:for-each-group> </xsl:template> </xsl:stylesheet>
关键说明
- 分组逻辑:
通过for-each-group按节点本地名称分组,确保每种节点类型只触发一次<xsl:result-document>调用,彻底避免重复写入同一URI的XTDE1490错误。 - 索引计算:
mvIndex:计数目标节点的祖先<mSubAssetType>的前置兄弟节点数量,加1得到其在同级中的位置。svIndex:计数当前节点的所有前置兄弟节点数量,加1得到其在父节点中的位置。
- 节点输出:
为每个匹配节点添加mvIndex和svIndex属性后,复制原节点的所有属性和子节点,保留原始数据结构。
调整建议
- 如果XML结构中
<mSubAssetType>的层级有变化,需修改ancestor::mSubAssetType的路径,确保定位正确。 - 输出文件名可自定义,比如改为
{current-grouping-key()}_output.xml,避免与现有文件冲突。 - 若使用XSLT 3.0,可结合
xsl:mode on-no-match="shallow-copy"进一步简化代码。
内容的提问来源于stack exchange,提问作者Jose L Martinez-Avial
相关产品推荐
相关产品推荐

