XLST 1.0更改值后对输出中的元素进行分组



基本上我是一个xlst新手,负责对一个大型xls文件进行一些更改,该文件负责处理德国市场电影元数据的转换。

xls文件看起来像这样:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:str="http://exslt.org/strings" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns:redirect="http://xml.apache.org/xalan/redirect" extension-element-prefixes="redirect" xmlns:xalan="http://xml.apache.org/xslt" exclude-result-prefixes="xalan str">
<xsl:output method="xml" indent="yes" xalan:indent-amount="4"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/metadata">
    <xsl:variable name="featureID" select="substring(mpm_product_id, 7, string-length(mpm_product_id))"/>
    <xsl:variable name="smallcase" select="'abcdefghijklmnopqrstuvwxyz'" />
    <xsl:variable name="uppercase" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" />
    <Metadata>
    <some values...>
    <xsl:for-each select="genres/genre">
                    <Genre>
                            <xsl:choose>
                              <!-- Mappings for German Genres -->
                                <xsl:when test="/metadata/base/territory_code='DE'">
                                    <xsl:choose>
                                        <xsl:when test=".= 'Action'">Action und Abenteuer</xsl:when>
                                        <xsl:when test=".= 'Adventure'">Action und Abenteuer</xsl:when>
                                        <xsl:when test=".= 'Animation'">Zeichentrick</xsl:when>
                                        <xsl:when test=".= 'Anime'">Zeichentrick</xsl:when>
                                        <xsl:when test=".= 'Bollywood'">Bollywood</xsl:when>
                                        <xsl:when test=".= 'Classics'">Drama > Klassiker</xsl:when>
                                        <xsl:when test=".= 'Comedy'">Komödie</xsl:when>
                                        <xsl:when test=".= 'Concert Film'">Musik</xsl:when>
                                        <xsl:when test=".= 'Crime'">Kriminalfilm > Drama</xsl:when>
                                        <xsl:when test=".= 'Drama'">Drama</xsl:when>
                                        <xsl:when test=".= 'Fantasy'">Drama > Sci-Fi und Fantasy</xsl:when>
                                        <xsl:when test=".= 'Foreign'">International</xsl:when>
                                        <xsl:when test=".= 'Horror'">Kriminalfilm > Horror</xsl:when>
                                        <xsl:when test=".= 'Independent'">Independentfilm &amp; Arthouse</xsl:when>
                                        <xsl:when test=".= 'Japanese Cinema'">International > Japan</xsl:when>
                                        <xsl:when test=".= 'Jidaigeki'">International > Japan</xsl:when>
                                        <xsl:when test=".= 'Kids &amp; Family'">Kinderfilm > Familie</xsl:when>
                                        <xsl:when test=".= 'Music Documentary'">Musik > Dokumentation</xsl:when>
                                        <xsl:when test=".= 'Music Feature Film'">Musik</xsl:when>
                                        <xsl:when test=".= 'Musicals'">Musik > Musical</xsl:when>
                                        <xsl:when test=".= 'Mystery'">Drama > Mystery</xsl:when>
                                        <xsl:when test=".= 'Nonfiction - Documentary'">Dokumentation</xsl:when>
                                        <xsl:when test=".= 'Regional Indian'">International > Indien &amp; Pakistan</xsl:when>
                                        <xsl:when test=".= 'Romance'">Drama > Romanze</xsl:when>
                                        <xsl:when test=".= 'Science Fiction'">Science Fiction und Fantasy</xsl:when>
                                        <xsl:when test=".= 'Short Films'">Independentfilm &amp; Arthouse > Experimentalfilm</xsl:when>
                                        <xsl:when test=".= 'Special Interest'">Hobby</xsl:when>
                                        <xsl:when test=".= 'Sports'">Sport</xsl:when>
                                        <xsl:when test=".= 'Thrillers'">Thriller</xsl:when>
                                        <xsl:when test=".= 'Tokusatsu'">International > Japan</xsl:when>
                                        <xsl:when test=".= 'Urban'">Drama > Alltag</xsl:when>
                                        <xsl:when test=".= 'Westerns'">Western</xsl:when>
                                        <xsl:otherwise>
                                            <xsl:value-of select="." />
                                        </xsl:otherwise>
                                     </xsl:choose>
                                </xsl:when>

                            </xsl:choose> 
                    </Genre>
                </xsl:for-each>
       <More values...>
    </Metadata>
</xsl:template>

问题是当类型被转换时,我们以重复的值结束,例如当输入包含元素时

<genres>
    <genre>Comedy</genre>
    <genre>Adventure</genre>
    <genre>Action</genre>
</genres>

改造后我们有

<Genre>Komödie</Genre>
<Genre>Action und Abenteuer</Genre>
<Genre>Action und Abenteuer</Genre>

我已经试着为此寻找一些解决方案,但我还没有找到解决方案,任何帮助都将不胜感激。

编辑澄清:我需要的是从输出中消除重复的流派元素。这些元素可以不相邻,我们不能通过第二次转换来运行输出,因为我们不能修改处理这一问题的服务的代码。

感谢

由于您似乎正在使用Xalan作为XSLT处理器,因此可以通过使用该处理器支持的几个扩展函数轻松解决此问题。下面是一个使用EXSLT的示例(根据xmlns:str命名空间声明判断,您似乎已经在使用它了):

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:set="http://exslt.org/sets"
xmlns:exsl="http://exslt.org/common"
xmlns:str="http://exslt.org/strings" 
xmlns:xalan="http://xml.apache.org/xslt" 
xmlns:redirect="http://xml.apache.org/xalan/redirect" 
exclude-result-prefixes="set exsl str xalan"
extension-element-prefixes="redirect">
<xsl:output method="xml" indent="yes" xalan:indent-amount="4"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/metadata">
    <xsl:variable name="featureID" select="substring(mpm_product_id, 7, string-length(mpm_product_id))"/>
    <xsl:variable name="smallcase" select="'abcdefghijklmnopqrstuvwxyz'" />
    <xsl:variable name="uppercase" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" />
    <Metadata>
        <xsl:variable name="genres">
            <xsl:for-each select="genres/genre">
                <Genre>
                    <xsl:choose>
                        <xsl:when test="/metadata/base/territory_code='DE'">
                            <xsl:choose>
                                <xsl:when test=".= 'Action'">Action und Abenteuer</xsl:when>
                                <xsl:when test=".= 'Adventure'">Action und Abenteuer</xsl:when>
                                <xsl:when test=".= 'Animation'">Zeichentrick</xsl:when>
                                <xsl:when test=".= 'Anime'">Zeichentrick</xsl:when>
                                <xsl:when test=".= 'Bollywood'">Bollywood</xsl:when>
                                <xsl:when test=".= 'Classics'">Drama > Klassiker</xsl:when>
                                <xsl:when test=".= 'Comedy'">Komödie</xsl:when>
                                <xsl:when test=".= 'Concert Film'">Musik</xsl:when>
                                <xsl:when test=".= 'Crime'">Kriminalfilm > Drama</xsl:when>
                                <xsl:when test=".= 'Drama'">Drama</xsl:when>
                                <xsl:when test=".= 'Fantasy'">Drama > Sci-Fi und Fantasy</xsl:when>
                                <xsl:when test=".= 'Foreign'">International</xsl:when>
                                <xsl:when test=".= 'Horror'">Kriminalfilm > Horror</xsl:when>
                                <xsl:when test=".= 'Independent'">Independentfilm &amp; Arthouse</xsl:when>
                                <xsl:when test=".= 'Japanese Cinema'">International > Japan</xsl:when>
                                <xsl:when test=".= 'Jidaigeki'">International > Japan</xsl:when>
                                <xsl:when test=".= 'Kids &amp; Family'">Kinderfilm > Familie</xsl:when>
                                <xsl:when test=".= 'Music Documentary'">Musik > Dokumentation</xsl:when>
                                <xsl:when test=".= 'Music Feature Film'">Musik</xsl:when>
                                <xsl:when test=".= 'Musicals'">Musik > Musical</xsl:when>
                                <xsl:when test=".= 'Mystery'">Drama > Mystery</xsl:when>
                                <xsl:when test=".= 'Nonfiction - Documentary'">Dokumentation</xsl:when>
                                <xsl:when test=".= 'Regional Indian'">International > Indien &amp; Pakistan</xsl:when>
                                <xsl:when test=".= 'Romance'">Drama > Romanze</xsl:when>
                                <xsl:when test=".= 'Science Fiction'">Science Fiction und Fantasy</xsl:when>
                                <xsl:when test=".= 'Short Films'">Independentfilm &amp; Arthouse > Experimentalfilm</xsl:when>
                                <xsl:when test=".= 'Special Interest'">Hobby</xsl:when>
                                <xsl:when test=".= 'Sports'">Sport</xsl:when>
                                <xsl:when test=".= 'Thrillers'">Thriller</xsl:when>
                                <xsl:when test=".= 'Tokusatsu'">International > Japan</xsl:when>
                                <xsl:when test=".= 'Urban'">Drama > Alltag</xsl:when>
                                <xsl:when test=".= 'Westerns'">Western</xsl:when>
                            <xsl:otherwise>
                                <xsl:value-of select="." />
                            </xsl:otherwise>
                         </xsl:choose>
                        </xsl:when>
                    </xsl:choose> 
                </Genre>
            </xsl:for-each> 
        </xsl:variable>
        <xsl:copy-of select="set:distinct(exsl:node-set($genres)/Genre)"/>
    </Metadata>
</xsl:template>
</xsl:stylesheet>

应用于您的输入示例,结果为:

<?xml version="1.0" encoding="UTF-8"?>
<Metadata>
    <Genre>Komödie</Genre>
    <Genre>Action und Abenteuer</Genre>
    <Genre>B-Grade</Genre>
</Metadata>

注意:

IMHO,您对Xalan命名空间的声明:

xmlns:xalan="http://xml.apache.org/xslt" 

不正确,应为:

xmlns:xalan="http://xml.apache.org/xalan" 

一旦修复了这个问题,就可以使用Xalan扩展库中类似的函数:Xalan:distinct()和Xalan:nodeset()(并没有太大区别)。

应用此XSLT(style.xsl

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
    xmlns:str="http://exslt.org/strings"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="1.0"
    xmlns:redirect="http://xml.apache.org/xalan/redirect"
    extension-element-prefixes="redirect"
    xmlns:xalan="http://xml.apache.org/xslt"
    exclude-result-prefixes="xalan str">
    <xsl:output method="xml" indent="yes" xalan:indent-amount="4"/>
    <xsl:strip-space elements="*"/>
    <xsl:template match="/metadata">
        <xsl:variable name="featureID" select="substring(mpm_product_id, 7, string-length(mpm_product_id))"/>
        <xsl:variable name="smallcase" select="'abcdefghijklmnopqrstuvwxyz'" />
        <xsl:variable name="uppercase" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" />
        <Metadata>
            <xsl:if test="/metadata/base/territory_code='DE'">
                <!-- Applying template is the way XSLT works -->
                <xsl:apply-templates select="genres/genre">
                    <xsl:with-param name="ifs" select="document('ifs.xml')/ifs"/>
                </xsl:apply-templates>
            </xsl:if>
        </Metadata>
    </xsl:template>
    <xsl:template match="genre">
        <xsl:param name="ifs"/>
        <!-- if if/@test=current() then we'll display if/text() -->
        <xsl:variable name="this-if"        select="$ifs/if[@test=current()]"/>
        <!-- gets all 'ifs' using previous 'genre' that have same value as $this-if -->
        <xsl:variable name="previous-if"    select="$ifs/if[string(.)=string($this-if) and @test=current()/preceding-sibling::genre]"/>
        <Genre>
            <xsl:choose>
                <xsl:when test="$previous-if"> <!-- Duplicate -->
                    <xsl:text>Node genre=&quot;</xsl:text>
                    <xsl:value-of select="current()"/>
                    <xsl:text>&quot; (if=</xsl:text>
                    <xsl:value-of select="$this-if"/>
                    <xsl:text>; id:</xsl:text>
                    <xsl:value-of select="generate-id()"/>
                    <xsl:text> is a duplicate of if/@test=&quot;</xsl:text>
                    <xsl:value-of select="$previous-if/@test"/>
                    <xsl:text>&quot;</xsl:text>
                </xsl:when>
                <!-- Not duplicate + there is a 'if' entry -->
                <xsl:when test="$this-if">
                    <xsl:apply-templates select="$this-if"/>
                </xsl:when>
                <!-- Not duplicate + there is no 'if' entry -->
                <xsl:otherwise>
                    <xsl:value-of select="."/>
                </xsl:otherwise>
            </xsl:choose>
        </Genre>
    </xsl:template>
    <xsl:template match="if">
        <xsl:value-of select="."/>
    </xsl:template>
</xsl:stylesheet>

到此源(source.xml

<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="style.xsl"?>
<metadata>
    <base>
        <territory_code>DE</territory_code>
    </base>
    <genres>
        <genre>Comedy</genre>
        <genre>Adventure</genre>
        <genre>Action</genre>
        <genre>B-Grade</genre>
    </genres>
</metadata>

使用这个新的XML文件来处理if的测试值(ifs.xml):

<?xml version="1.0" encoding="utf-8"?>
<ifs>
    <if test="Action">Action und Abenteuer</if>
    <if test="Adventure">Action und Abenteuer</if>
    <if test="Animation">Zeichentrick</if>
    <if test="Anime">Zeichentrick</if>
    <if test="Bollywood">Bollywood</if>
    <if test="Classics">Drama &gt; Klassiker</if>
    <if test="Comedy">Komödie</if>
    <if test="Concert Film">Musik</if>
    <if test="Crime">Kriminalfilm &gt; Drama</if>
    <if test="Drama">Drama</if>
    <if test="Fantasy">Drama &gt; Sci-Fi und Fantasy</if>
    <if test="Foreign">International</if>
    <if test="Horror">Kriminalfilm &gt; Horror</if>
    <if test="Independent">Independentfilm &amp; Arthouse</if>
    <if test="Japanese Cinema">International &gt; Japan</if>
    <if test="Jidaigeki">International &gt; Japan</if>
    <if test="Kids &amp; Family">Kinderfilm &gt; Familie</if>
    <if test="Music Documentary">Musik &gt; Dokumentation</if>
    <if test="Music Feature Film">Musik</if>
    <if test="Musicals">Musik &gt; Musical</if>
    <if test="Mystery">Drama &gt; Mystery</if>
    <if test="Nonfiction - Documentary">Dokumentation</if>
    <if test="Regional Indian">International &gt; Indien &amp; Pakistan</if>
    <if test="Romance">Drama &gt; Romanze</if>
    <if test="Science Fiction">Science Fiction und Fantasy</if>
    <if test="Short Films">Independentfilm &amp; Arthouse &gt; Experimentalfilm</if>
    <if test="Special Interest">Hobby</if>
    <if test="Sports">Sport</if>
    <if test="Thrillers">Thriller</if>
    <if test="Tokusatsu">International &gt; Japan</if>
    <if test="Urban">Drama &gt; Alltag</if>
    <if test="Westerns">Western</if>
</ifs>

你得到

<Metadata>
    <Genre>Komödie</Genre>
    <Genre>Action und Abenteuer</Genre>
    <Genre>Node genre="Action" (if=Action und Abenteuer; id:id0xe2bc950 is a duplicate of if/@test="Adventure"</Genre>
    <Genre>B-Grade</Genre>
</Metadata>

因此,您可以对找到的重复项执行任何操作。请注意,对每个genre节点使用preceding-sibling::会使算法成为O(N²)(也就是说,10倍多的<genre/>节点会使代码变长100倍)。

顺便说一句,有一个ifs.xml来处理测试/值将使if比XSL中的原始编码测试更具可扩展性。

相关内容

  • 没有找到相关文章

最新更新