如何获取集合中已处理XML文件的文件名?
解决方案:在XSLT 3.0批量处理中全局获取当前文件名
针对你遇到的问题,有两种可靠的方法可以让所有模板都能获取当前处理的文件名,以下是具体实现:
方法一:使用隧道参数(推荐)
隧道参数是XSLT 2.0+的特性,能在模板调用链中自动传递参数,无需在每个<xsl:apply-templates>中显式声明,非常适合需要全局共享数据的场景。
修改后的代码
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet xmlns:fn="http://www.w3.org/2005/xpath-functions" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="3.0" expand-text="true"> <xsl:mode on-no-match="shallow-skip"/> <xsl:output method="text" encoding="UTF-8"/> <xsl:param name="files" select="uri-collection('file:///C:/Tmp/ProjectA')"/> <xsl:template match="/"> <xsl:result-document href="out.txt" method="text"> <xsl:for-each select="$files"> <!-- 提前提取当前文件的文件名 --> <xsl:variable name="file-name" select="tokenize(., '/')[last()]"/> <!-- 传递隧道参数给后续所有模板 --> <xsl:apply-templates select="doc(.)/root"> <xsl:with-param name="current-file" select="$file-name" tunnel="yes"/> </xsl:apply-templates> </xsl:for-each> </xsl:result-document> </xsl:template> <!-- 业务规则验证模板,接收隧道参数 --> <xsl:template match="list[not(ancestor-or-self::descr)]"> <xsl:param name="current-file" tunnel="yes"/> <!-- 直接使用传递过来的文件名 --> <xsl:value-of select="$current-file"/> <xsl:text> </xsl:text> <xsl:text>Lists not allowed unless in descr.</xsl:text> <xsl:text> </xsl:text> <xsl:text>------------------------------------------------</xsl:text> <xsl:text> </xsl:text> <xsl:apply-templates select="node()|@*"/> </xsl:template> <!-- 其他需要文件名的模板,只需添加同名隧道参数即可 --> <xsl:template match="another-violating-node"> <xsl:param name="current-file" tunnel="yes"/> <!-- 使用$current-file输出文件名 --> ... </xsl:template> </xsl:stylesheet>
关键说明
- 在遍历文件时提前提取文件名,避免重复计算
- 通过
tunnel="yes"标记参数为隧道参数,它会自动传递给所有后续调用的模板,无需在每个<xsl:apply-templates>中重复传递 - 任何需要使用文件名的模板,只需添加
<xsl:param name="current-file" tunnel="yes"/>即可直接使用
方法二:直接从节点获取文档URI
如果不想使用参数,可以通过当前节点的根文档节点获取原文件的URI,再提取文件名。这种方法无需修改主模板,只需在需要的模板中添加以下逻辑:
修改后的业务规则模板
<xsl:template match="list[not(ancestor-or-self::descr)]"> <!-- 获取当前节点所在文档的URI,再提取文件名 --> <xsl:variable name="doc-uri" select="document-uri(root(.))"/> <xsl:value-of select="tokenize($doc-uri, '/')[last()]"/> <xsl:text> </xsl:text> <xsl:text>Lists not allowed unless in descr.</xsl:text> <xsl:text> </xsl:text> <xsl:text>------------------------------------------------</xsl:text> <xsl:text> </xsl:text> <xsl:apply-templates select="node()|@*"/> </xsl:template>
关键说明
root(.)会获取当前节点所属的根文档节点document-uri()返回该文档的原始URI,通过tokenize提取最后一段即为文件名- 缺点是每个需要文件名的模板都要重复编写这段逻辑,适合模板数量较少的场景
注意事项
- 确保使用的XSLT处理器支持XSLT 3.0(如Saxon HE/PE/EE),
uri-collection是XSLT 3.0的特性 - 如果处理的文件路径包含反斜杠(Windows路径),可以用
tokenize($doc-uri, '[/\\]')来兼容正反斜杠
内容的提问来源于stack exchange,提问作者Zug_Bug
相关产品推荐
相关产品推荐

