2013-07-28 60 views
1

對於初學者,我對標題表示歉意,但我不知道描述我的問題的好方法。因此代碼示例將使事情更加清晰。使用xslt 2進行多值分組

假設我有下面的XML樹:

<root> 
<node> 
<value xml:lang="en">Some English Content</value> 
<value xml:lang="fr">Some French Content</value> 
<value xml:lang="de">Some German Content</value> 
</node> 
<node> 
<value xml:lang="en">Some English Content</value> 
<value xml:lang="de">Some German Content</value> 
</node> 
<node> 
<value xml:lang="en">Some Other English Content</value> 
<value xml:lang="fr">Some Other French Content</value> 
<value xml:lang="de">Some Other German Content</value> 
</node> 
<node> 
<value xml:lang="en">Some English Content</value> 
<value xml:lang="fr">Some French Content</value> 
<value xml:lang="de">Some German Content</value> 
</node> 
<node> 
<value xml:lang="fr">Some French Content</value> 
<value xml:lang="de">Some German Content</value> 
</node> 
</root> 

所以基本上有各種節點集,與一些本地化字符串,我希望將基於內容這些集合。節點1,2,4和5是大約相同的主題,但並非所有的字符串都可以在所有語言環境中使用,所以我不能真正使用引用字符串(比如英語,因爲它在節點5中不可用)。節點3包含不同的內容,所以它應該是不同組的一部分。

可能聽起來很複雜,但是這是我希望得到(使用XSLT 2)結果:

<values> 
<group> 
    <value xml:lang="en">Some English Content</value> 
    <value xml:lang="fr">Some French Content</value> 
    <value xml:lang="de">Some German Content</value> 
</group> 
<group> 
    <value xml:lang="en">Some Other English Content</value> 
    <value xml:lang="fr">Some Other French Content</value> 
    <value xml:lang="de">Some Other German Content</value> 
</group> 
</values> 

任何想法與此如何最划算?請注意,一個節點中最多可以有40種不同的語言,並且文件中可以包含數百個節點,因此資源也可能成爲問題。

+0

如果有喜歡的'元素會發生什麼<值XML:LANG = 「FR」>其他一些法語內容<值XML:LANG = 「DE」>德國一些內容' ? –

回答

0

我不知道我完全理解你的要求,但我寫了一些代碼,首先嚐試填補node元素與value S爲缺少語言,然後組上填充要素:

<xsl:stylesheet 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    version="2.0" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    xmlns:mf="http://example.com/mf" 
    exclude-result-prefixes="xs mf"> 

<xsl:param name="sep" as="xs:string" select="'|'"/> 

<xsl:output indent="yes"/> 

<xsl:variable name="main-doc" select="/"/> 

<xsl:variable name="languages" as="xs:string*"> 
    <xsl:perform-sort select="distinct-values(root/node/value/@xml:lang)"> 
    <xsl:sort select="."/> 
    </xsl:perform-sort> 
</xsl:variable> 

<xsl:key name="k1" match="node/value" use="concat(@xml:lang, $sep, .)"/> 

<xsl:template match="root"> 
    <values> 
    <xsl:variable name="filled" as="element(node)*"> 
     <xsl:apply-templates select="node" mode="fill"/> 
    </xsl:variable> 
    <xsl:for-each-group select="$filled" group-by="string-join(value, $sep)"> 
     <group> 
     <xsl:copy-of select="value"/> 
     </group> 
    </xsl:for-each-group> 
    </values> 
</xsl:template> 

<xsl:template match="node" mode="fill"> 
    <xsl:copy> 
    <xsl:variable name="this" as="element(node)" select="."/> 
    <xsl:for-each select="$languages"> 

     <value xml:lang="{.}"> 
     <xsl:value-of 
      select="if ($this/value[lang(current())]) 
        then $this/value[lang(current())] 
        else (key('k1', 
          concat($this/value[1]/@xml:lang, $sep, $this/value[1]), 
          $main-doc)/../value[lang(current())])[1]"/> 
     </value> 
    </xsl:for-each> 
    </xsl:copy> 
</xsl:template> 

</xsl:stylesheet> 

由於你可以看到,我需要一些命令來填充元素,所以我排序在不同的@xml:lang,我不知道你想要的。根據這一做法輸出爲您發佈與撒克遜9.5輸入是

<values> 
    <group> 
     <value xml:lang="de">Some German Content</value> 
     <value xml:lang="en">Some English Content</value> 
     <value xml:lang="fr">Some French Content</value> 
    </group> 
    <group> 
     <value xml:lang="de">Some Other German Content</value> 
     <value xml:lang="en">Some Other English Content</value> 
     <value xml:lang="fr">Some Other French Content</value> 
    </group> 
</values> 

我也不能肯定其戰略是預期的一個來填補元素(也看到我張貼的評論)。最後,我決定在@xml:lang和它們的內容的連接上鍵入node/value元素,然後在填充缺少語言的元素時,我簡單地匹配第value孩子node所具有的元素。所以這基本上意味着如果一些node具有內容bar的第一個value xml:lang="foo",則該匹配僅僅在該語言foo和內容bar上,並且我們複製value內容以查找缺失的語言。

如果你不想排序,你可以使用屬性的初始序列的順序生活,那麼你可以省略排序,樣式表則是

<xsl:stylesheet 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    version="2.0" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    xmlns:mf="http://example.com/mf" 
    exclude-result-prefixes="xs mf"> 

<xsl:param name="sep" as="xs:string" select="'|'"/> 

<xsl:output indent="yes"/> 

<xsl:variable name="main-doc" select="/"/> 

<xsl:variable name="languages" as="xs:string*" select="distinct-values(root/node/value/@xml:lang)"/> 

<xsl:key name="k1" match="node/value" use="concat(@xml:lang, $sep, .)"/> 

<xsl:template match="root"> 
    <values> 
    <xsl:variable name="filled" as="element(node)*"> 
     <xsl:apply-templates select="node" mode="fill"/> 
    </xsl:variable> 
    <xsl:for-each-group select="$filled" group-by="string-join(value, $sep)"> 
     <group> 
     <xsl:copy-of select="value"/> 
     </group> 
    </xsl:for-each-group> 
    </values> 
</xsl:template> 

<xsl:template match="node" mode="fill"> 
    <xsl:copy> 
    <xsl:variable name="this" as="element(node)" select="."/> 
    <xsl:for-each select="$languages"> 

     <value xml:lang="{.}"> 
     <xsl:value-of 
      select="if ($this/value[lang(current())]) 
        then $this/value[lang(current())] 
        else (key('k1', 
          concat($this/value[1]/@xml:lang, $sep, $this/value[1]), 
          $main-doc)/../value[lang(current())])[1]"/> 
     </value> 
    </xsl:for-each> 
    </xsl:copy> 
</xsl:template> 

</xsl:stylesheet> 

這樣的輸出是你問:

<values> 
    <group> 
     <value xml:lang="en">Some English Content</value> 
     <value xml:lang="fr">Some French Content</value> 
     <value xml:lang="de">Some German Content</value> 
    </group> 
    <group> 
     <value xml:lang="en">Some Other English Content</value> 
     <value xml:lang="fr">Some Other French Content</value> 
     <value xml:lang="de">Some Other German Content</value> 
    </group> 
</values> 
+0

謝謝馬丁。最後它在我的真實生活內容中並沒有很好地發揮作用,但是你確實讓我走上了正確的道路。 – Wokoman