xml - 在 XSLT 中的 ForEach 下使用自定义函数选择不同的值
问题描述
在使用自定义函数在 ForEach 循环中迭代时,我需要忽略重复值。我有以下示例并分享正在尝试做的 xslt。我不能在 xslt 2.0 中应用 foreach 组,因为它会破坏现有的代码功能。我期待用自定义函数本身解决这个问题。
自定义功能:
<xsl:function name="OriginalBook.Genre">
<xsl:param name="book"/>
<xsl:for-each select="$book[price < 10]">
<xsl:element name="OriginalGenre">
<xsl:if test="book[not(preceding::genre)]">
<xsl:value-of select="current()/genre"/>
</xsl:if>
</xsl:element>
</xsl:for-each>
</xsl:function>
<xsl:template match="/">
<OriginalBook>
<xsl:copy-of select="OriginalBook.Genre(/catalog/book)"/>
</OriginalBook>
</xsl:template>
输入:
<?xml version="1.0"?>
<catalog>
<book>
<author>Gambardella, Matthew</author>
<title>XML Developer's Guide</title>
<genre>Computer</genre>
<price>9.95</price>
<publish_date>2000-10-01</publish_date>
</book>
<book>
<author>Ralls, Kim</author>
<title>XML Developer's Guide</title>
<genre>Computer</genre>
<price>5.95</price>
<publish_date>2000-12-16</publish_date>
</book>
<book>
<author>Corets, Eva</author>
<title>Maeve Ascendant</title>
<genre>Fantasy</genre>
<price>5.95</price>
<publish_date>2000-11-17</publish_date>
</book>
<book>
<author>Galos, Mike</author>
<title>Visual Studio 7: A Comprehensive Guide</title>
<genre>Computer</genre>
<price>49.95</price>
<publish_date>2001-04-16</publish_date>
</book>
</catalog>
期望的输出:
<OriginalBook>
<OriginalGenre>Computer</OriginalGenre>
<OriginalGenre>Fantasy</OriginalGenre>
</OriginalBook>
解决方案
对于它的价值,假设 XSLT 3 消除重复的经典方法是for-each-group group-by
,distinct-values
或map:merge
:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:map="http://www.w3.org/2005/xpath-functions/map"
exclude-result-prefixes="#all"
xmlns:mf="http://example.com/mf"
expand-text="yes"
version="3.0">
<xsl:function name="mf:grouping-example" as="element(OriginalGenre)*">
<xsl:param name="books" as="element(book)*"/>
<xsl:for-each-group select="$books[price < 10]" group-by="genre">
<OriginalGenre>{current-grouping-key()}</OriginalGenre>
</xsl:for-each-group>
</xsl:function>
<xsl:function name="mf:distinct-values-example" as="element(OriginalGenre)*">
<xsl:param name="books" as="element(book)*"/>
<xsl:for-each select="distinct-values($books[price < 10]/genre)">
<OriginalGenre>{.}</OriginalGenre>
</xsl:for-each>
</xsl:function>
<xsl:function name="mf:map-merge-example" as="element(OriginalGenre)*">
<xsl:param name="books" as="element(book)*"/>
<xsl:for-each
select="$books[price < 10]/genre!map { data() : . }
=> map:merge() => map:keys()">
<OriginalGenre>{.}</OriginalGenre>
</xsl:for-each>
</xsl:function>
<xsl:output indent="yes"/>
<xsl:template match="/">
<Results>
<Result-Grouping>
<xsl:sequence select="mf:grouping-example(catalog/book)"/>
</Result-Grouping>
<Result-distinct-values>
<xsl:sequence select="mf:distinct-values-example(catalog/book)"/>
</Result-distinct-values>
<Result-map-merge-example>
<xsl:sequence select="mf:map-merge-example(catalog/book)"/>
</Result-map-merge-example>
</Results>
</xsl:template>
</xsl:stylesheet>
顺序循环的“等效”不是xsl:for-each
,而是xsl:iterate
:
<xsl:function name="mf:iterate-example" as="element(OriginalGenre)*">
<xsl:param name="books" as="element(book)*"/>
<xsl:iterate select="$books[price < 10]/genre/data()">
<xsl:param name="genres" as="xs:string*" select="()"/>
<xsl:if test="not(. = $genres)">
<OriginalGenre>{.}</OriginalGenre>
</xsl:if>
<xsl:next-iteration>
<xsl:with-param name="genres" select="if (. = $genres) then $genres else ($genres, .)"/>
</xsl:next-iteration>
</xsl:iterate>
</xsl:function>
推荐阅读
- git - 在不获取其他分支的情况下增加浅克隆的深度
- javascript - 如何从数组中获取范围滑块内的值
- php - PDO 插入不接受“真”或“假”,但只接受 0 和 1
- c# - 实体框架并非全部检测模型上的更改
- mysql - 如何使用 ROW_NUMBER() 将行号添加到 MySQL 显示
- powershell - 在 Active Directory AD Powershell 中再次运行脚本
- angular - 如何增加ngbmodal的宽度
- ngrx - 如何破译ngrx API
- javascript - 如何在类外调用类内的函数
- talend - 在 talend Studio 之外编辑工作