質問

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

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

そして、それはこのように見えるはずです:

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

私はこれのために動作しているXSLTを持っています、そしてそれは基本的にすべてのB要素のノードセットを取得し、次に「次のsibling」軸を使用して、現在のBノードに続くノードのノードセットを取得します(つまり、フォローシブン::* [position()= $ nodepos])。次に、再帰を使用して、別のB要素が見つかるまで結果ツリーに兄弟を追加します(もちろん、それをより一般的にするためにパラメーターを付けました)。

また、次のBノードのXMLの位置を送信し、その後のノードを次々と選択するソリューションがあります(再帰を使用して)A *[Position()= $ nodePos]選択を介して(再帰を使用します)。

問題は、変換を実行する時間がXMLファイルのサイズとともに容認できないほど増加することです。 XMLスパイでそれを調べるのは、それぞれの2つの方法で時間をかけるのは「フォローシブン」と「Position()=」であるようです。

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

ありがとう、

マイク

役に立ちましたか?

解決

はい、それをより効率的に行う方法があります:参照してください ムエンチアングループ. 。これを見ている場合は、詳細についてもっと助けが必要です。お知らせください。必要な鍵は次のようなものです。

<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には、Muenchianメソッドよりも使いやすい非常に便利なグループ化機能があります。

あなたの場合、それはあなたが使用するように聞こえます <xsl:for-each-group group-starting-with="b" /> または、要素名をパラメーター化するには、 <xsl:for-each-group group-starting-with="*[local-name() = 'b']" />. 。しかし、おそらくあなたはすでにそれを考えており、あなたの環境でXSLT 2.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>

コメントに記載されているように、パラメーターの可能性のある各値に対して、いくつかの異なるキーを定義することにより、キーのパフォーマンスの利点を維持できます。次に、使用するキーを使用して選択します <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>

他のヒント

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

これは細かい粒子の移動パターンです。

<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>
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top