【问题标题】:XSLT: Using variables in a key function (cont.)XSLT:在关键函数中使用变量(续)
【发布时间】:2012-02-01 15:35:23
【问题描述】:

我有以下 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 以“David”或“Jane”开头的元素的转换:

<?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() 函数。

提前致谢,李奥

【问题讨论】:

  • 当前问题和上一个问题有什么区别?
  • @Leo68:“只包含一个通用搜索键”是什么意思?我想我已经完全回答了你之前的问题。你现在有什么新的要求?请定义新要求并向我们展示一个示例。
  • @DimitreNovaatchev 正如我在问题中提到的,您的示例允许显示所选作者撰写的书籍。我的任务是从上面的 xml 中消除几个元素。在示例 xslt 中,我使用了几个键来实现这个目标;问题是如何使用内联 xsl 参数 pAuthors 和一个通用键而不是 author1-search、author2-search 等来重写这个 xslt。非常感谢你的帮助,狮子座
  • 在我的问题中,我明确表示我想重写示例 XSLT,它使用单个通用键和 pAuthors 参数消除了 @author 以“David”或“Jane”开头的元素.预期的结果是包含 ,可以从将示例 XSLT 应用于 XML 文件中推断出来。我还在回复您的评论时提供了进一步的解释。您还需要哪些其他信息?
  • @Leo68:不,你没有在问题中这么说。你现在这么说,只是在评论中,只有在被问到的时候。这些信息可以通过提供的代码来猜测,但依赖读者的猜测意味着这个问题没有很好地表述。请编辑问题并明确提供所需信息。请记住,在大多数情况下,您的代码可能并不重要并且可能会产生误导——真正需要的是源 XML 文档、想要的结果和转换的要求。

标签: xslt


【解决方案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>

【讨论】:

  • 非常感谢,这似乎是解决这个问题的方法。在我的示例和最初的问题中,我实际上想消除名字以(或者,也许,包含)David 或 Jane 开头的作者。你将如何更新你的转换来做到这一点?
  • @Leo68:在 XSLT 2.0 中,这很容易。我必须考虑一个 XSLT 1.0 解决方案,这似乎没有使用单个静态定义键的明显解决方案。非关键解决方案非常明显。
  • 感谢您的及时回复。唉,我只能使用 XSLT 1.0。当然,我将非常感谢使用单个键来查看解决方案,因为我必须从 XML 文件中删除许多元素。如果您认为它太复杂,也许可以使用 pAuthors 参数概述非关键解决方案?
  • Dimitre:非常感谢!我很欣赏你优雅的解决方案;然而,它似乎只解决了作者姓名在名字和姓氏之间包含空格的特殊情况。我想知道如果@author 可以具有值“David.Perry”、“David&Perry”或“Davidson”,是否可以使用单个键并在 pAuthors 参数中指定 David。换句话说,是否有可能消除以“大卫”开头的作者(或者甚至更好地包含“大卫”)?如果使用单个键的解决方案显得过于复杂,或许有使用 XSLT 1.0 的非键解决方案?
  • @Leo68:当然,有一个非关键的解决方案。如果您将此作为单独的问题提出,大多数人都可以提供答案。
猜你喜欢
  • 1970-01-01
  • 2018-12-28
  • 2017-04-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多