我有以下XML文件:
<titles>
<book title="XML Today" author="David Perry"/>
<book title="XML and Microsoft" author="David Perry"/>
<book title="XML Productivity" author="Jim Kim"/>
<book title="XSLT 1.0" author="Albert Jones"/>
<book title="XSLT 2.0" author="Albert Jones"/>
<book title="XSLT Manual" author="Jane Doe"/>
</titles>
我想删除一些元素并应用以下XSLT:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl">
<xsl:output method="xml" indent="yes"/>
<xsl:key name="author1-search" match="book[starts-with(@author, 'David')]" use="@title"/>
<xsl:template match="book [key('author1-search', @title)]" />
<xsl:key name="author2-search" match="book[starts-with(@author, 'Jim')]" use="@title"/>
<xsl:template match="book [key('author2-search', @title)]" />
<xsl:template match="/">
<xsl:apply-templates />
</xsl:template>
</xsl:stylesheet>
是否可以使用内联xsl变量
<xsl:variable name="Author">
<name>David</name>
<name>Jim</name>
</xsl:variable>
而不是“author1-search”,“author2-search”等,以循环显示名称?
我只能使用XSLT 1.0(目前不支持2.0)。
提前致谢,
利奥
答案 0 :(得分:6)
不,模式(在XSLT 1.0中)不能包含变量/参数引用。
执行此类任务的一种方法就是这样:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:param name="pAuthor" select="'David Perry'"/>
<xsl:key name="kBookaByAuthor" match="book"
use="@author"/>
<xsl:template match="/">
Books written by <xsl:value-of select="$pAuthor"/> :<xsl:text/>
<xsl:apply-templates
select="key('kBookaByAuthor', $pAuthor)"/>
</xsl:template>
<xsl:template match="book">
<!-- One can do more formatting here -->
<xsl:text>
 </xsl:text>
<xsl:value-of select="@title"/>
</xsl:template>
</xsl:stylesheet>
在提供的XML文档上应用此转换时:
<titles>
<book title="XML Today" author="David Perry"/>
<book title="XML and Microsoft" author="David Perry"/>
<book title="XML Productivity" author="Jim Kim"/>
<book title="XSLT 1.0" author="Albert Jones"/>
<book title="XSLT 2.0" author="Albert Jones"/>
<book title="XSLT Manual" author="Jane Doe"/>
</titles>
产生了想要的正确结果:
Books written by David Perry :
XML Today
XML and Microsoft
更新:在评论中,OP已澄清:
“我认为我在最初的问题中完全明确了我的要求。 正如我在我的问题和我的第一个评论中所提到的那样 有助于我看到处理多个方法的方法 作者“
以下是真正使用密钥的解决方案(请注意@ Flynn1179的答案中的“密钥”不构建任何索引,只是一个常量序列字符串 - 所以使用key()
的函数xsl:key
实际上是在字符串列表中找到一个字符串 - 与O(N)相比,通常是O(1)用于搜索一个真正的指数):
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common">
<xsl:output method="text"/>
<xsl:param name="pAuthors">
<x>David Perry</x>
<x>Jane Doe</x>
</xsl:param>
<xsl:variable name="vParams" select=
"ext:node-set($pAuthors)/*"/>
<xsl:key name="kBookByAuthor" match="book"
use="@author"/>
<xsl:template match="/">
Books written by : <xsl:text/>
<xsl:apply-templates select="$vParams"/>
<xsl:apply-templates select=
"key('kBookByAuthor', $vParams)"/>
</xsl:template>
<xsl:template match="book">
<!-- One can do more formatting here -->
<xsl:text>
 </xsl:text>
<xsl:value-of select="concat('"', @title, '"')"/>
</xsl:template>
<xsl:template match="x">
<xsl:if test="not(position() = 1)">, </xsl:if>
<xsl:value-of select="."/>
</xsl:template>
</xsl:stylesheet>
将此转换应用于提供的XML文档(上图)时,会生成所需的正确结果:
Books written by : David Perry, Jane Doe
"XML Today"
"XML and Microsoft"
"XSLT Manual"
请注意:在此解决方案中,使用Exslt函数node-set()
。 这只是为了方便起见。在实际使用中,参数的值将在外部指定,然后不需要ext:node-set()
函数。
效率:此解决方案使用XSLT中键的真正功能。使用MSXML(3,4和6)XSLT处理器进行的实验表明,如果我们搜索10000位作者,使用不同XSLT处理器的转换时间范围为:32ms到45ms。
<强>有趣的是,通过@ Flynn1179提出的解决方案不确实使密钥索引,并与许多XSLT处理器需要(对于作者的相同数量(10000))从1044ms到5564ms 强>:
MSXML3 :5564毫秒,
MSXML4 :2526ms,
MSXML6 :4867毫秒,
AltovaXML :1044ms。
对于使用真正的键索引(32ms到45ms)获得的性能,非常低劣。
答案 1 :(得分:2)
XSLT 1.0中的模式不允许包含变量或参数引用,因此您不能在这些键定义或模板匹配属性中使用变量或参数引用。
答案 2 :(得分:2)
您可以在XSLT表单中的自己的命名空间中包含一个元素,而不是使用变量,并参考它,如下所示:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:my="my:my">
<xsl:key name="authors" use="document('')/*/my:authors/my:name" match="/" />
<my:authors>
<my:name>David Perry</my:name>
<my:name>Jim Kim</my:name>
</my:authors>
<xsl:template match="book[not(key('authors',@author))]" />
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
book
模板与其作者没有相应my:name
元素的模板匹配,并且不输出任何内容。身份模板输出其他所有内容,包括您关心的书籍元素。密钥有点像黑客,它基本上匹配名称所在的整个文档,而不是匹配匹配的my:name
元素。既然你只关心它的存在,这应该不是问题。
或者,如果您希望传入作者列表,则可以使用:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="authors" select="'David Perry,Jim Kim'" />
<xsl:template match="book">
<xsl:if test="contains(concat(',',$authors,','),concat(',',@author,','))">
<xsl:call-template name="identity" />
</xsl:if>
</xsl:template>
<xsl:template match="@* | node()" name="identity">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
<xsl:if>
中使用的变量而非模板中的变量匹配,但它执行相同的工作。这个特殊的代码需要指定为逗号分隔列表的作者列表,但是如果您更愿意使用不同的格式,它应该很容易适应它。