2011-06-26 120 views
3

- 修改後的問題 -如何按內容對元素進行分組(XSLT 2.0)?

感謝所有提供潛在解決方案的人,但這些都與我已經嘗試的一致,所以我認爲我應該更清楚。我稍微擴展了XML以使問題更加透明。

XML實際上是包含翻譯內容的各種文件的彙編,其目的是獲得僅包含唯一英文字符串的統一文檔,並且(在人工審閱和清理後)爲每個字符串翻譯一個,所以它可以用於翻譯記憶。這就是爲什麼它現在是一個大量的冗餘信息文件。

每個para行包含英文master(可在文件中重複數十次)和翻譯變體。在某些情況下,由於所有翻譯版本都是平等的,所以我最終只用一行代碼,但在其他情況下可能會更復雜。

因此,假設我今天有一個包含相同的英文內容10條線(#1),2度不同的德國人的變化,3種不同的法國變化,以及語言環境剩下的只有一個變化,我需要得到:

1個帕拉有:1 EN/2 DE(v1和v2)/ 3 FR(V1,V2和V3)/ ...

而這種重複每個分組唯一英語值在我的名單

的修改XML:

<Books> 
<!--First English String (#1) with number of potential translations --> 
<Para> 
    <EN>English Content #1</EN> 
    <DE>German Trans of #1 v1</DE> 
    <FR>French Trans of #1 v1</FR> 
    <!-- More locales here --> 
</Para> 
<Para> 
    <EN>English Content #1</EN> 
    <DE>German Trans of #1 v2</DE> 
    <FR>French Trans of #1 v1</FR> 
    <!-- More locales here --> 
</Para> 
<Para> 
    <EN>English Content #1</EN> 
    <DE>German Trans of #1 v1</DE> 
    <FR>French Trans of #1 v2</FR> 
    <!-- More locales here --> 
</Para> 
<!--Second English String (#2) with number of potential translations --> 
<Para> 
    <EN>English Content #2</EN> 
    <DE>German Trans of #2 v1</DE> 
    <FR>French Trans of #2 v1</FR> 
    <!-- More locales here --> 
</Para> 
<Para> 
    <EN>English Content #2</EN> 
    <DE>German Trans of #2 v3</DE> 
    <FR>French Trans of #2 v1</FR> 
    <!-- More locales here --> 
</Para> 
<Para> 
    <EN>English Content #2</EN> 
    <DE>German Trans of #2 v2</DE> 
    <FR>French Trans of #2 v1</FR> 
    <!-- More locales here --> 
</Para> 
<!--Loads of additional English Strings (#3 ~ #n) with number of potential translations --> 

目前的解決方案提供給我下面的輸出

<Books> 
<Para> 
    <EN>English Content #1</EN> 
    <DE>German Trans of #1 v1</DE> 
    <DE>German Trans of #1 v2</DE> 
    <DE>German Trans of #2 v1</DE> 
    <DE>German Trans of #2 v3</DE> 
    <DE>German Trans of #2 v2</DE> 
    <FR>French Trans of #1 v1</FR> 
    <FR>French Trans of #1 v1</FR> 
    <FR>French Trans of #1 v2</FR> 
    <FR>French Trans of #2 v1</FR> 
</Para> 
</Books> 

所以,只取第一個EN標記,然後把所有的人,不相干的英語主路線之間的差異。而我的目標就是要練好以下幾點:

<Books> 
<!-- First Grouped EN string and linked grouped translations --> 
<Para> 
    <EN>English Content #1</EN> 
    <DE>German Trans of #1 v1</DE> 
    <DE>German Trans of #1 v2</DE> 
    <FR>French Trans of #1 v1</FR> 
    <FR>French Trans of #1 v2</FR> 
</Para> 
<!-- Second Grouped EN string and linked grouped translations --> 
<Para> 
    <EN>English Content #2</EN> 
    <DE>German Trans of #2 v1</DE> 
    <DE>German Trans of #2 v3</DE> 
    <DE>German Trans of #2 v2</DE> 
    <FR>French Trans of #2 v1</FR> 
</Para> 
<!-- 3d to n Grouped EN string and linked grouped translations --> 
</Books> 
+0

你舉的例子是混亂的,特別是由於重複''值。你是否也可以在XSLT上展示自己的第一步,展示你的現有邏輯? –

+0

對於按內容對元素進行分組的好問題+1。 –

+0

好問題,+1。請參閱我的答案,以獲得即使對於具有完全相同翻譯的緊密語言也能正常工作的解決方案:) –

回答

0

隨着撒克遜9,當我將樣式表應用

<xsl:stylesheet 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    version="2.0"> 

    <xsl:strip-space elements="*"/> 
    <xsl:output indent="yes"/> 

    <xsl:template match="Books"> 
    <xsl:copy> 
     <xsl:for-each-group select="Para" group-by="EN"> 
     <xsl:apply-templates select="."/> 
     </xsl:for-each-group> 
    </xsl:copy> 
    </xsl:template> 

    <xsl:template match="Para"> 
    <xsl:copy> 
     <xsl:copy-of select="EN"/> 
     <xsl:for-each-group select="current-group()/(* except EN)" group-by="node-name(.)"> 
     <xsl:for-each-group select="current-group()" group-by="."> 
      <xsl:copy-of select="."/> 
     </xsl:for-each-group> 
     </xsl:for-each-group> 
    </xsl:copy> 
    </xsl:template> 

</xsl:stylesheet> 

到輸入

<Books> 
<!--First English String (#1) with number of potential translations --> 
<Para> 
    <EN>English Content #1</EN> 
    <DE>German Trans of #1 v1</DE> 
    <FR>French Trans of #1 v1</FR> 
    <!-- More locales here --> 
</Para> 
<Para> 
    <EN>English Content #1</EN> 
    <DE>German Trans of #1 v2</DE> 
    <FR>French Trans of #1 v1</FR> 
    <!-- More locales here --> 
</Para> 
<Para> 
    <EN>English Content #1</EN> 
    <DE>German Trans of #1 v1</DE> 
    <FR>French Trans of #1 v2</FR> 
    <!-- More locales here --> 
</Para> 
<!--Second English String (#2) with number of potential translations --> 
<Para> 
    <EN>English Content #2</EN> 
    <DE>German Trans of #2 v1</DE> 
    <FR>French Trans of #2 v1</FR> 
    <!-- More locales here --> 
</Para> 
<Para> 
    <EN>English Content #2</EN> 
    <DE>German Trans of #2 v3</DE> 
    <FR>French Trans of #2 v1</FR> 
    <!-- More locales here --> 
</Para> 
<Para> 
    <EN>English Content #2</EN> 
    <DE>German Trans of #2 v2</DE> 
    <FR>French Trans of #2 v1</FR> 
    <!-- More locales here --> 
</Para> 
</Books> 

我得到的結果

<Books> 
    <Para> 
     <EN>English Content #1</EN> 
     <DE>German Trans of #1 v1</DE> 
     <DE>German Trans of #1 v2</DE> 
     <FR>French Trans of #1 v1</FR> 
     <FR>French Trans of #1 v2</FR> 
    </Para> 
    <Para> 
     <EN>English Content #2</EN> 
     <DE>German Trans of #2 v1</DE> 
     <DE>German Trans of #2 v3</DE> 
     <DE>German Trans of #2 v2</DE> 
     <FR>French Trans of #2 v1</FR> 
    </Para> 
</Books> 
+0

感謝馬丁,作品像一個魅力。我欠你一個大個子! – Wokoman

+0

@Martin Honnen請檢查此[SO](http://stackoverflow.com/q/33788966/1066779)一次。 – Rembo

2

壓縮擴大XSLT 2.0答案履行問題的更新請求

<xsl:stylesheet version="2.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output omit-xml-declaration="yes" indent="yes"/> 
    <xsl:strip-space elements="*"/> 

    <xsl:template match="Books"> 
     <xsl:copy> 
      <xsl:for-each-group select="*" 
       group-by="EN"> 
       <xsl:copy> 
        <xsl:copy-of select="EN"/> 
        <xsl:for-each-group select="current-group()/*[not(local-name()='EN')]" 
         group-by="."> 
         <xsl:sort select="local-name()"/> 
         <xsl:copy-of select="."/> 
        </xsl:for-each-group> 
       </xsl:copy> 
      </xsl:for-each-group> 
     </xsl:copy> 
    </xsl:template> 

</xsl:stylesheet> 

擴展XSLT 1.0的答案履行其在更新問題請求

即使您需要兩種不同類型的密鑰,仍然可以使用相同類型的解決方案。這是進入想到的第一簡單的解決方案:

<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output omit-xml-declaration="yes" indent="yes"/> 
    <xsl:strip-space elements="*"/> 

    <xsl:key name="main" match="Para" use="EN"/> 
    <xsl:key name="locale" match="Para/*[not(self::EN)]" use="concat(../EN,.)"/> 

    <xsl:template match="Books"> 
     <xsl:copy> 
      <xsl:apply-templates select="Para[ 
       generate-id() 
       = generate-id(key('main',EN)[1])]" mode="EN"/> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="*" mode="EN"> 
     <xsl:copy> 
      <xsl:copy-of select="EN"/> 
      <xsl:apply-templates select="../Para/*[ 
       generate-id() 
       = generate-id(key('locale',concat(current()/EN,.))[1])]" mode="locale"> 
       <xsl:sort select="local-name()"/> 
      </xsl:apply-templates> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="*" mode="locale"> 
     <xsl:copy> 
      <xsl:value-of select="."/> 
     </xsl:copy> 
    </xsl:template> 

</xsl:stylesheet> 

當應用於ö

n the new provided input, produces: 

<Books> 
    <Para> 
     <EN>English Content #1</EN> 
     <DE>German Trans of #1 v1</DE> 
     <DE>German Trans of #1 v2</DE> 
     <FR>French Trans of #1 v1</FR> 
     <FR>French Trans of #1 v2</FR> 
    </Para> 
    <Para> 
     <EN>English Content #2</EN> 
     <DE>German Trans of #2 v1</DE> 
     <DE>German Trans of #2 v3</DE> 
     <DE>German Trans of #2 v2</DE> 
     <FR>French Trans of #2 v1</FR> 
    </Para> 
</Books> 

此XSLT 1。0變換做你問什麼的,它可以作爲出發點,以創建一個結果樹更多,如果你喜歡有意義的:

<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output omit-xml-declaration="yes" indent="yes"/> 
    <xsl:strip-space elements="*"/> 


    <xsl:key name="locale" match="Para/*[not(local-name()='EN')]" use="text()"/> 

    <xsl:template match="Books"> 
     <xsl:copy> 
      <Para> 
       <xsl:copy-of select="Para[1]/EN"/> 
       <xsl:apply-templates select="Para/*[ 
        generate-id() 
        = generate-id(key('locale',text())[1])]" mode="group"> 
        <xsl:sort select="local-name()"/> 
       </xsl:apply-templates> 
      </Para> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="*" mode="group"> 
     <xsl:copy> 
      <xsl:value-of select="."/> 
     </xsl:copy> 
    </xsl:template> 

</xsl:stylesheet> 

說明:

  • xsl:key用於組中的所有元素通過內容(但EN)第一PARA/EN節點
  • 與分組的Meunchian方法的
  • 簡單直接拷貝到輸出分組爲請求(具有相同的內容元素報告一次)的其他元件

當施加到在問題所提供的輸入,結果樹是:

<Books> 
    <Para> 
     <EN>Some English Content</EN> 
     <DE>German Trans v1</DE> 
     <DE>German Trans v2</DE> 
     <FR>French Trans v1</FR> 
     <FR>French Trans v2</FR> 
    </Para> 
</Books> 

同樣的結果(和更短的變換)用XSLT 2.0 xsl:for-each-group

<xsl:stylesheet version="2.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output omit-xml-declaration="yes" indent="yes"/> 
    <xsl:strip-space elements="*"/> 

    <xsl:template match="Books"> 
     <xsl:copy> 
      <Para> 
       <xsl:copy-of select="Para[1]/EN"/> 
       <xsl:for-each-group select="Para/*[not(local-name()='EN')]" 
          group-by="."> 
        <xsl:sort select="local-name()"/> 
        <xsl:copy> 
         <xsl:value-of select="."/> 
        </xsl:copy> 
       </xsl:for-each-group> 
      </Para> 
     </xsl:copy> 
    </xsl:template> 

</xsl:stylesheet> 
+0

很好的答案,但是可能有相同的翻譯語言(EN-US,EN-AU),在這種情況下,除了第一種以外,所有這些密切的語言翻譯都會丟失。我知道這是一個非常特殊的情況,但請注意:) –

1

這TRANSFORMA重刑

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 
<xsl:key name="kLangByValAndText" 
    match="Para/*[not(self::EN)]" 
    use="concat(name(), '+++', .)"/> 

<xsl:template match="/"> 
    <Books> 
    <Para> 
    <xsl:copy-of select="/*/Para[1]/EN"/> 
    <xsl:for-each select= 
    "/*/*/*[generate-id() 
      = 
      generate-id(key('kLangByValAndText', 
          concat(name(), '+++', .) 
          ) 
          [1] 
         ) 
      ] 
    "> 
    <xsl:sort select="name()"/> 
    <xsl:copy-of select="."/> 
    </xsl:for-each> 
    </Para> 
    </Books> 
</xsl:template> 
</xsl:stylesheet> 

當這個XML文檔施加(提供一個的擴展版本,使其更有趣):

<Books> 
    <Para> 
     <EN>Some English Content</EN> 
     <DE>German Trans v1</DE> 
     <FR>French Trans v1</FR> 
     <!-- More locales here --> 
    </Para> 
    <Para> 
     <EN>Some English Content</EN> 
     <EN-US>Some English Content</EN-US> 
     <DE>German Trans v1</DE> 
     <FR>French Trans v1</FR> 
     <!-- More locales here --> 
    </Para> 
    <Para> 
     <EN>Some English Content</EN> 
     <Australian>Some English Content</Australian> 
     <DE>German Trans v1</DE> 
     <FR>French Trans v2</FR> 
     <!-- More locales here --> 
    </Para> 
    <!-- Much more para's hereafter containing variety of <EN> Content --> 
</Books> 

可生產想要的,正確的結果

<Books> 
    <Para> 
     <EN>Some English Content</EN> 
     <Australian>Some English Content</Australian> 
     <DE>German Trans v1</DE> 
     <EN-US>Some English Content</EN-US> 
     <FR>French Trans v1</FR> 
     <FR>French Trans v2</FR> 
    </Para> 
</Books> 

說明:複合(2部分)鍵上的Muenchian分組。

請注意:僅在翻譯分組(另一種答案做了這個問題)失去<Australian>翻譯 - 由@empo應用解決了這一相同的文檔,其結果是(<Australian>丟失! ):

<Books> 
    <Para> 
     <EN>Some English Content</EN> 
     <DE>German Trans v1</DE> 
     <EN-US>Some English Content</EN-US> 
     <FR>French Trans v1</FR> 
     <FR>French Trans v2</FR> 
    </Para> 
</Books> 
+0

請檢查此[SO](http://stackoverflow.com/q/33788966/1066779)一次。 – Rembo

0

另一個muenchian分組的,與用於子級化合物的鍵:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output indent="yes" /> 
    <xsl:key name="english" match="EN" use="." /> 
    <xsl:key name="others" match="Para/*[not(self::EN)]" use="concat(../EN, '&#160;', ., '&#160;', name())" /> 
    <xsl:template match="/Books"> 
    <Books> 
     <xsl:for-each select="Para/EN[generate-id() = generate-id(key('english', .)[1])]"> 
     <Para> 
      <xsl:copy-of select=".|key('english', .)/../*[not(self::EN)][generate-id() = generate-id(key('others', concat(current(), '&#160;', ., '&#160;', name()))[1])]" /> 
     </Para> 
     </xsl:for-each> 
    </Books> 
    </xsl:template> 
</xsl:stylesheet> 
+0

很抱歉,我正在尋找更簡潔的代碼......我想我無法再減少它了。 :) – Erlock

相關問題