XSLT:在键函数中使用变量(续)

时间:2012-02-01 15:35:24

标签: xslt

我有以下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> 

和使用@author'或'Jane'开头的@author消除元素的转换:

<?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:strip-space elements="*"/>

  <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, 'Jane')]" use="@title"/>
  <xsl:template match="book [key('author2-search', @title)]" />

  <xsl:template match="@* | node()" name="identity">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

预期结果将是以下XML文件:

<titles> 
   <book title="XML Productivity" author="Jim Kim"/> 
   <book title="XSLT 1.0" author="Albert Jones"/> 
   <book title="XSLT 2.0" author="Albert Jones"/> 
</titles>

在对XSLT: Using variables in a key function问题的回复中,Dimitre Novatchev展示了使用迭代来显示由所选作者使用键编写的书籍的方法以及使用内联xsl参数的Exslt函数node-set()

  <xsl:param name="pAuthors"> 
      <x>David Perry</x> 
      <x>Jane Doe</x> 
     </xsl:param> 

是否可以应用此方法重写上面的转换,以便它使用pAuthors参数并只包含一个通用搜索键(而不是author1-search,author2-search等)?不支持XSLT 2.0和document()函数。

提前致谢,Leo

1 个答案:

答案 0 :(得分:1)

我认为,从代码中的猜测来看,OP是如何使用XSLT密钥来帮助消除任何作者从一组作者写的书。

此转化

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:ext="http://exslt.org/common">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

    <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:variable name="vBooksToExclude" select=
   "key('kBookByAuthor', $vParams)"/>

 <xsl:template match="node()|@*" name="identity">
     <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
     </xsl:copy>
 </xsl:template>

 <xsl:template match="book">
  <xsl:if test="count(.|$vBooksToExclude) != count($vBooksToExclude)">
    <xsl:call-template name="identity"/>
  </xsl:if>
 </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>

会产生想要的,正确的结果,其中任何包含来自提供的作者集(David Perry和Jane Doe)的作者的书都会被跳过

<titles>
   <book title="XML Productivity" author="Jim Kim"/>
   <book title="XSLT 1.0" author="Albert Jones"/>
   <book title="XSLT 2.0" author="Albert Jones"/>
</titles>

<强>解释

我们使用以下XPath表达式来确定节点$n是否属于节点集$s

count($n | $s) != count($s)

最终更新

正如OP所希望的那样,这里我们排除了从复制到输出的所有具有作者的书籍,其名字作为外部/全局参数中的许多值之一提供。 我们仍然使用一个密钥。

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:ext="http://exslt.org/common">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

    <xsl:param name="pAuthors">
        <x>David</x>
        <x>Jane</x>
    </xsl:param>

    <xsl:variable name="vParams" select=       "
      ext:node-set($pAuthors)/*"/>

  <xsl:key name="kBookByAuthor" match="book"
           use="substring-before(@author, ' ')"/>

  <xsl:variable name="vBooksToExclude" select=
   "key('kBookByAuthor', $vParams)"/>

 <xsl:template match="node()|@*" name="identity">
     <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
     </xsl:copy>
 </xsl:template>

 <xsl:template match="book">
  <xsl:if test="count(.|$vBooksToExclude) != count($vBooksToExclude)">
    <xsl:call-template name="identity"/>
  </xsl:if>
 </xsl:template>
</xsl:stylesheet>

将此转换应用于以下XML文档(添加了另一位David作者):

<titles>
    <book title="XML Today" author="David Perry"/>
    <book title="XML and Microsoft" author="David Perry"/>
    <book title="Just example" author="David Masters"/>
    <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>

生成想要的正确结果

<titles>
  <book title="XML Productivity" author="Jim Kim" />
  <book title="XSLT 1.0" author="Albert Jones" />
  <book title="XSLT 2.0" author="Albert Jones" />
</titles>