1

XSLT に比較的慣れていないので、単純な質問であることを願っています。私はいくつかのフラットな XML ファイルを持っていますが、これはかなり大きくなる可能性があり (例: 7MB)、「より階層化」する必要があります。たとえば、フラット XML は次のようになります。

<D0011>
    <b/>
    <c/>
    <d/>
    <e/>
    <b/>
    ....
    ....
</D0011>

最終的には次のようになります。

<D0011>
  <b>
    <c/>
    <d/>
    <e/>
  </b>
  <b>
 ....
 ....
</D0011>

私はこれのために動作する XSLT を持っており、基本的にすべての b 要素のノードセットを取得し、「following-sibling」軸を使用して、現在の b ノードに続くノードのノードセットを取得します (つまり、following-sibling::* [position()=$nodePos])。次に、再帰を使用して、別の b 要素が見つかるまで兄弟を結果ツリーに追加します (もちろん、より汎用的にするためにパラメーター化しました)。

また、次の b ノードの XML 内の位置を送信し、*[position() = $nodePos] 選択を介して (再帰を使用して) 次々にノードを選択するソリューションもあります。

問題は、XML ファイルのサイズが大きくなると、変換の実行時間が許容できないほど長くなることです。XML Spy で調べてみると、それぞれのメソッドで時間がかかるのは「following-sibling」と「position()=」のようです。

私が本当に必要としているのは、上記の選択でノードの数を制限する方法です。そのため、実行される比較が少なくなります。位置がテストされるたびに、ノードセット内のすべてのノードがテストされ、その位置が正しいかどうかが確認されます。それを行う方法はありますか?他の提案はありますか?

ありがとう、

マイク

4

3 に答える 3

1

はい、それをはるかに効率的に行う方法があります。Muenchianのグループ化を参照してください。これを確認した後、詳細についてさらにサポートが必要な場合は、お知らせください。必要なキーは次のようなものです。

<xsl:key name="elements-by-group" match="*[not(self::b)]"
   use="generate-id(preceding-sibling::b[1])" />

次に、要素を反復処理し、<b>それぞれについて、を使用key('elements-by-group', generate-id())して、その直後に続く要素を取得します<b>

「XMLをより階層的にする」タスクはアップコンバージョンと呼ばれることもあり、シナリオはその典型的なケースです。ご存知かもしれませんが、XSLT 2.0には、ミュンヒアン法よりも使いやすい非常に便利なグループ化機能があります。

<xsl:for-each-group group-starting-with="b" />あなたの場合、要素名をパラメータ化するために、またはを使用するように聞こえます<xsl:for-each-group group-starting-with="*[local-name() = 'b']" />。しかし、おそらくあなたはすでにそれを考慮していて、あなたの環境でXSLT2.0を使用することはできません。

アップデート:

パラメータ化のリクエストに応えて、キーなしでそれを行う方法があります。ただし、XSLTプロセッサによっては、はるかに遅くなる場合があることに注意してください。

<xsl:template match="D0011">
   <xsl:for-each select="*[local-name() = $sep]">
      <xsl:copy>
         <xsl:copy-of select="following-sibling::*[not(local-name() = $sep)
               and generate-id(preceding-sibling::*[local-name() = $sep][1]) =
                    generate-id(current())]" />
      </xsl:copy>
   </xsl:for-each>      
</xsl:template>

コメントに記載されているように、パラメーターの可能な値ごとに1つずつ、いくつかの異なるキーを定義することで、キーのパフォーマンス上の利点を維持できます。次に、を使用して使用するキーを選択します<xsl:choose>

アップデート2:

グループ開始要素を/*/*[2]パラメーターではなく、に基づいて定義するには、次のコマンドを使用します。

<xsl:key name="elements-by-group"
   match="*[not(local-name(.) = local-name(/*/*[2]))]"
   use="generate-id(preceding-sibling::*
                           [local-name(.) = local-name(/*/*[2])][1])" />

<xsl:template match="D0011">
   <xsl:for-each select="*[local-name(.) = local-name(../*[2])]">
      <xsl:copy>
         <xsl:copy-of select="key('elements-by-group', generate-id())"/>
      </xsl:copy>
   </xsl:for-each>
</xsl:template>
于 2011-01-10T16:10:46.010 に答える
1
<xsl:key name="k1" match="D0011/*[not(self::b)]" use="generate-id(preceding-sibling::b[1])"/>

<xsl:template match="D0011">
  <xsl:copy>
    <xsl:apply-templates select="b"/>
  </xsl:copy>
</xsl:template>

<xsl:template match="D0011/b">
  <xsl:copy>
    <xsl:copy-of select="key('k1', generate-id())"/>
  </xsl:copy>
</xsl:template>
于 2011-01-10T16:14:37.563 に答える
0

これは、きめの細かいトラバーサル パターンです。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="node()|@*" name="identity">
        <xsl:copy>
            <xsl:apply-templates select="node()[1]|@*"/>
        </xsl:copy>
        <xsl:apply-templates select="following-sibling::node()[1]"/>
    </xsl:template>
    <xsl:template match="b[1]" name="group">
        <xsl:copy>
            <xsl:apply-templates select="following-sibling::node()[1]"/>
        </xsl:copy>
        <xsl:apply-templates select="following-sibling::b[1]" mode="group"/>
    </xsl:template>
    <xsl:template match="b[position()!=1]"/>
    <xsl:template match="b" mode="group">
        <xsl:call-template name="group"/>
    </xsl:template>
</xsl:stylesheet>

出力:

<D0011>
    <b>
        <c></c>
        <d></d>
        <e></e>
    </b>
    <b>
    ....
    ....
    </b>
</D0011>
于 2011-01-10T17:45:09.533 に答える