我正在尝试生成一个XML文件,该文件使用xsl列出指定文件夹中的XML文件:
XML 文件 :
<xml>
<folder>FolderPath-to-List</folder>
</xml>
预期成果:
<mergeData newRoot="newRoot">
<fileList>
<fileItem>path-to-file/file1.xml</fileItem>
<fileItem>path-to-file/file2.xml</fileItem>
<fileItem>path-to-file/file3.xml</fileItem>
<fileItem>path-to-file/file4.xml</fileItem>
</fileList>
</mergeData>
到目前为止,我能够在当前文件夹中使用 XSL 和嵌入式脚本/JScipt 函数收集文件列表,如下所示:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:user="http://tempuri.org/msxsl"
>
<msxsl:script language="JScript" implements-prefix="user">
<![CDATA[
var fso = new ActiveXObject("Scripting.FileSystemObject");
function ShowFolderFileList(folderspec)
{
var f, f1, fc, s;
f = fso.GetFolder(folderspec);
fc = new Enumerator(f.files);
s = '<fileItem>';
for (; !fc.atEnd(); fc.moveNext())
{
s += fc.item();
s += '<fileItem>n<fileItem>';
}
return(s);
}
]]>
</msxsl:script>
<xsl:template match="/">
<mergeData newRoot="Activity">
<fileList>
<xsl:value-of select="user:ShowFolderFileList('.')"/>
</fileList>
</mergeData>
</xsl:template>
</xsl:stylesheet>
但结果是,代替<fileItem>
和</fileItem>
,我有:
<fileItem>path-to-xmlfile.xml<fileItem>
我怎样才能得到<fileItem>path-to-xmlfile.xml</fileItem>
?
到目前为止,我如何从我的XML中获取"FolderPath-to-List"以代替"."以使其运行。
首先要注意的是,您目前正在执行此操作
<xsl:value-of select="user:ShowFolderFileList('.')"/>
实际上,您应该这样做以在XML中使用文件路径
<xsl:value-of select="user:ShowFolderFileList(string(xml/folder/text()))" />
请注意此处使用 "string()",因为 "text()" 实际上返回一个文本节点,而不是字符串的数据类型。
其次,当你以这种方式在XSLT中使用javascript函数时,我相信它们只能返回字符串和数字的简单数据类型。您的函数返回的是字符串,而不是实际的 XML,当您在字符串上使用 xsl:value-of 时,任何保留符号都将被转义。
现在,你可以有点调皮并这样做
<xsl:value-of select="user:ShowFolderFileList(string(xml/folder/text()))"
disable-output-escaping="yes" />
但这并不一定被认为是好的做法,因为禁用输出转义没有得到广泛支持(尽管显然它在 Mircosoft 的实现中有效)。
但是,我能想到的唯一另一种方法(在 XSLT 1.0 中)是返回一个文件名列表,用换行符分隔,并编写一个递归模板。试试这个 XSLT 作为示例:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:user="http://tempuri.org/msxsl"
exclude-result-prefixes="msxsl user">
<xsl:output method="xml" indent="yes"/>
<msxsl:script language="JScript" implements-prefix="user">
<![CDATA[
var fso = new ActiveXObject("Scripting.FileSystemObject");
function ShowFolderFileList(folderspec)
{
var f, f1, fc, s;
f = fso.GetFolder(folderspec);
fc = new Enumerator(f.files);
s="";
for (; !fc.atEnd(); fc.moveNext())
{
s += fc.item() + "n";
}
return s;
}
]]>
</msxsl:script>
<xsl:template match="/">
<mergeData newRoot="Activity">
<fileList>
<xsl:call-template name="files">
<xsl:with-param name="files" select="user:ShowFolderFileList(string(xml/folder/text()))"/>
</xsl:call-template>
</fileList>
</mergeData>
</xsl:template>
<xsl:template name="files">
<xsl:param name="files"/>
<xsl:if test="normalize-space($files) != ''">
<file>
<xsl:value-of select="substring-before($files, ' ')"/>
</file>
<xsl:if test="contains($files, ' ')">
<xsl:call-template name="files">
<xsl:with-param name="files" select="substring-after($files, ' ')"/>
</xsl:call-template>
</xsl:if>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
不过还有其他几个选项:
- 不要为此使用 XSLT!
- 升级到XSLT 2.0(Mircosoft不支持它,但你可以获得其他用于.Net的XSLT处理器)
看到这个问题,它基本上问了同样的事情:
XSLT:如何从某个目录中获取文件名?