大家晚上好,
我创建了一个小程序,可以对目录中包含的所有音频文件(以及所有子目录)进行排序。我正在收集C#中的所有信息,以便生成以下XML文件(下面的XML是一个精简版本,我删除了这里不需要的所有属性):
<Directory Name="Compilations" >
<Directory Name="Compil - 2010" >
<File MediaTitle="4 Min" MediaAlbum="AA" MediaYear="2010" MediaArtists="Madonna" />
<File MediaTitle="Beggin" MediaAlbum="AA" MediaYear="2010" MediaArtists="Madcon" />
</Directory>
</Directory>
我想要以下结果:
<MediaYear Year="2010">
<MediaArtists Artist="Madonna">
<MediaAlbum Album="AA">
<File MediaTitle="4 Min" MediaAlbum="AA" MediaYear="2010" MediaArtists="Madonna" />
</MediaAlbum>
</MediaArtists>
<MediaArtists Artist="Madcon">
<MediaAlbum Album="AA">
<File MediaTitle="Beggin" MediaAlbum="AA" MediaYear="2010" MediaArtists="Madcon" />
</MediaAlbum>
</MediaArtists>
</MediaYear>
所有“文件”事件应按以下方式排序:
我使用的XSLT代码如下:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common" exclude-result-prefixes="ext">
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*" />
<xsl:key match="File[@MediaYear != 0]" name="MediaYears" use="@MediaYear"/>
<xsl:template match="/">
<xsl:for-each select="//File[generate-id(.)= generate-id(key('MediaYears', @MediaYear)[1])]">
<xsl:sort select="@MediaYear"/>
<MediaYear>
<xsl:attribute name="Year">
<xsl:value-of select="@MediaYear"/>
</xsl:attribute>
<xsl:for-each select="key('MediaYears', @MediaYear)">
<xsl:copy>
<xsl:copy-of select="node() | @* | node()"/>
</xsl:copy>
</xsl:for-each>
</MediaYear>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
但是这段代码只适用于第一级排序,所以我想通过添加这段代码来添加第二级:
<xsl:key match="//File[@MediaArtists != '']" name="AlbumArtists" use="@MediaArtists"/>
<xsl:template match="/">
<xsl:variable name="VPass1">
<xsl:call-template name="YearProcess"/>
</xsl:variable>
<xsl:apply-templates mode="Artist_Display" select="ext:node-set($VPass1)"/>
</xsl:template>
我将现有的xsl:模板更改为以下内容:
<xsl:template match="/" name="YearProcess" mode="Year_Display">
我添加了以下模板:
<xsl:template match="/" mode="Artist_Display">
<xsl:for-each select="//File[generate-id(.)= generate-id(key('AlbumArtists', @MediaArtists)[1])]">
<xsl:sort select="ancestor::MediaYear[1]/@Year"/>
<xsl:sort select="@MediaArtists"/>
<MediaArtists>
<xsl:attribute name="AlbumArtists">
<xsl:value-of select="@MediaArtists"/>
</xsl:attribute>
<xsl:attribute name="AlbumYear">
<xsl:value-of select="ancestor::MediaYear[1]/@Year"/>
</xsl:attribute>
<xsl:for-each select="key('AlbumArtists', @MediaArtists)">
<xsl:copy>
<!--<xsl:copy-of select="ancestor::MediaYear[1]"/>-->
<xsl:copy-of select="node() | @* | node()"/>
</xsl:copy>
</xsl:for-each>
</MediaArtists>
</xsl:for-each>
</xsl:template>
我没有得到预期的结果,我对XSLT很新,请原谅我,如果答案已经存在,我搜索但我有点迷失,我不知道到底要搜索什么。< / p>
我很确定它不是很清楚,如果需要,代码可以在这里找到:
https://github.com/jaguar0076/FileManager/blob/master/FileManager/Stylesheet.xslt
我不知道去哪里,也许muenchian方法不是达到我想要的最佳方式。
感谢您提供的任何帮助,
罗德里格
编辑:标题已更改
答案 0 :(得分:2)
这是一个基于创建三个键的解决方案
<xsl:output method="xml" indent="yes"/>
<xsl:strip-space elements="*" />
<xsl:key match="File[@MediaYear != 0]" name="MediaYears" use="@MediaYear"/>
<!-- the following key has been designed on the assumption that MediaYear never contains a space-->
<xsl:key match="File[@MediaArtists != '']" name="MediaArtists" use="concat(@MediaYear, ' ', @MediaArtists)"/>
<!-- the following key has been designed on the assumption that MediaYear never contains a space
AND MediaArtists never contains a %-->
<xsl:key match="File[@MediaAlbum != '']" name="MediaAlbum" use="concat(@MediaYear, ' ', @MediaArtists, '%', @MediaAlbum)"/>
<xsl:template match="/">
<xsl:for-each select="//File[generate-id(.)= generate-id(key('MediaYears', @MediaYear)[1])]">
<xsl:sort select="@MediaYear"/>
<MediaYear Year="{@MediaYear}">
<xsl:variable name="MediaYear" select="@MediaYear"/>
<xsl:for-each select="//File[@MediaYear=$MediaYear and generate-id(.)= generate-id(key('MediaArtists', concat(@MediaYear, ' ', @MediaArtists))[1])]">
<xsl:sort select="@MediaArtists"/>
<MediaArtists Artist="{@MediaArtists}">
<xsl:variable name="MediaArtists" select="@MediaArtists"/>
<xsl:for-each select="//File[@MediaYear=$MediaYear and @MediaArtists=$MediaArtists and generate-id(.)= generate-id(key('MediaAlbum', concat(@MediaYear, ' ', @MediaArtists, '%', @MediaAlbum))[1])]">
<xsl:sort select="@MediaAlbum"/>
<MediaAlbum Album="{@MediaAlbum}">
<xsl:variable name="MediaAlbum" select="@MediaAlbum"/>
<xsl:for-each select="//File[@MediaYear=$MediaYear and @MediaArtists=$MediaArtists and @MediaAlbum=$MediaAlbum]">
<xsl:copy>
<xsl:copy-of select="node() | @* | node()"/>
</xsl:copy>
</xsl:for-each>
</MediaAlbum>
</xsl:for-each>
</MediaArtists>
</xsl:for-each>
</MediaYear>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
答案 1 :(得分:1)
如果您的处理器支持EXSLT(就像您的代码中所示),您可以使用set:distinct()函数而不是Muenchian分组。例如,像:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:set="http://exslt.org/sets"
extension-element-prefixes="set">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:key name="fileByYear" match="File" use="@MediaYear" />
<xsl:key name="fileByArtistYear" match="File" use="concat(@MediaArtists, '|', @MediaYear)" />
<xsl:key name="fileByAlbumArtistYear" match="File" use="concat(@MediaAlbum, '|', @MediaArtists, '|', @MediaYear)" />
<xsl:template match="/">
<xsl:for-each select="set:distinct(//File/@MediaYear)">
<xsl:sort select="." data-type="number" order="ascending"/>
<MediaYear Year="{.}">
<xsl:for-each select="set:distinct(key('fileByYear', .)/@MediaArtists)">
<xsl:sort select="." data-type="text" order="ascending"/>
<MediaArtists Artist="{.}">
<xsl:for-each select="set:distinct(key('fileByArtistYear', concat(., '|', ../@MediaYear))/@MediaAlbum)">
<xsl:sort select="." data-type="text" order="ascending"/>
<MediaAlbum Album="{.}">
<xsl:for-each select="key('fileByAlbumArtistYear', concat(., '|', ../@MediaArtists, '|', ../@MediaYear))">
<xsl:copy-of select="."/>
</xsl:for-each>
</MediaAlbum>
</xsl:for-each>
</MediaArtists>
</xsl:for-each>
</MediaYear>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
请注意,如果您的目录已经是特定年份,您可以使用它来保存一些处理。