更改值后,输出中的XSLT 1.0组元素

时间:2014-09-22 17:55:55

标签: xml xslt xslt-1.0

基本上我是一名新手,他的任务是处理一些大型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>

我试过寻找一些解决方案,但我还没有达到解决方案,任何帮助将不胜感激。

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

由于

2 个答案:

答案 0 :(得分:0)

应用此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>

因此,您可以使用找到的副本执行任何操作。请注意,对每个preceding-sibling::节点使用genre会使算法O(N²)(又称10倍<genre/>个节点会使代码长100倍。

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

答案 1 :(得分:0)

由于您似乎使用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>

注意:

恕我直言,您对Xalan命名空间的声明:

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

不正确,应阅读:

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

修复后,您可以使用Xalan扩展库中的类似函数:xalan:distinct()和xalan:nodeset()(并不是说它有很大的不同)。