1

まず、タイトルについてお詫び申し上げますが、私の問題を説明する良い方法がわかりません。したがって、コード サンプルは物事をより明確にします。

次の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 の異なる言語を含めることができ、ファイルには数百のノードを含めることができるため、リソースも問題になる可能性があることに注意してください。

4

1 に答える 1

0

あなたの要件を完全に理解しているかどうかはわかりませんが、最初に不足している言語のnode要素をs で埋め、次に埋められた要素をグループ化しようとするコードを書きました: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*">
  <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ません。そのアプローチでは、Saxon 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>

また、要素を埋めるためにどの戦略が意図されているのかわかりません(私が投稿したコメントも参照してください)。node/value最終的に、要素とそのコンテンツの連結にキーを設定することにしました@xml:lang。次に、言語が欠落している要素を埋めるときに、ある最初のvalue子に単純に一致させnodeます。つまり、基本的には、一部nodeに最初のvalue xml:lang="foo"with contentsがあるbar場合、一致は単にその言語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>
于 2013-07-29T15:02:14.047 に答える