2011-06-26 16 views
3

- 修正された質問 -要素をコンテンツ(XSLT 2.0)でグループ化する方法は?

私はすでに解決しようとしているすべての方々に感謝していますが、これはすでに試したことがありますので、もっと明確にすべきだと思います。問題をより透明にするためにXMLを少し拡張しました。

XMLは実際には翻訳されたコンテンツを含むさまざまなファイルのコンパイルであり、ユニークな英語の文字列のみを含む統一されたドキュメントを取得し、各文字列ごとに1つの翻訳されたものを(手作業によるレビューとクリーニング後に)翻訳メモリに使用することができます。だからこそ、冗長な情報を持つ大きなファイルになりました。

各パララインには英語のマスター(ファイル内で数十回繰り返すことができます)と翻訳の変形が含まれています。かなりの場合、すべての翻訳バージョンが同じであるので簡単ですので、1行で終了しますが、それ以外の場合はもっと複雑かもしれません。

だから、今日、私は同じ英語のコンテンツを含む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 --> 

現在の解決策は、英語のマスター列間の差異の無関係な、最初ENタグを取り、その後、他のすべてをグループ化し、だから、私に次のような出力

<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> 

を提供します。私が狙うすると、次を得るためにしている間:

<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

入力へ
<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の答えは

にアップデートを満たすためにXSLT 1.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> 

を要求質問のリクエスト

2種類のキーが必要な場合でも、同じ種類のソリューションを利用できます。このXSLT 1

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> 

oを適用した場合

<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> 

:これは心に来る最初の簡単なソリューションです。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> 

:Muenchianは複合(2-part)キーでグループ化します。 - これと同じ文書に@empoによるソリューションを適用し、その結果が(<Australian>が失われている<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グルーピング、:私はスタイルシートを適用サクソン9と

<?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

関連する問題