1

私は XSLT が初めてで、次の for-each ステートメントで速度の問題がいくつかあります。これを最適化する方法について、誰かが私にいくつかの指針を教えてくれることを望んでいましたか?

以下の for-each は、約 4MB の XML をループしています。各ホテル ノードに説明と目的地があることを確認するためのテストです。また、各ホテルの評価が 2 より大きいが 6 ではないこともテストしています。XML の評価の可能な値は、0、1、2、3、4、5、または 6 です。理想的には、評価のみを選択したいと思います。 3、4、または 5 を選択し、その他は無視します。

<for-each select="response/results/hotel[
    not(@description = '') and
    @rating &gt; '2' and
    not(@rating = '6') and
    not(@destination = '')              ]">
  <call-template name="hotelparams"/>
  <call-template name="upropdata"/>
  <call-template name="request"/>
  <call-template name="Newline"/>
</for-each>

リクエストに応じて、以下で呼び出されるテンプレートを追加しました。出力は、mySQL にインポートされるタブ区切りのテキスト ファイルを作成しています。ところで、upropdata テンプレートは無視してください。まもなく削除されます...

<xsl:template name="hotelparams">
<xsl:value-of select="@itemcode"/><xsl:value-of select="$tab"/>
<xsl:value-of  select="@cheapestcurrency"/><xsl:value-of select="$tab"/>
<xsl:value-of select="@cheapestprice"/><xsl:value-of select="$tab"/>
<xsl:value-of select="@checkin"/><xsl:value-of select="$tab"/>
<xsl:value-of select="@checkout"/><xsl:value-of select="$tab"/>
<xsl:value-of select="@description"/><xsl:value-of select="$tab"/>
<xsl:value-of select="@destair"/><xsl:value-of select="$tab"/>
<xsl:value-of select="@destination"/><xsl:value-of select="$tab"/>
<xsl:value-of select="@destinationid"/><xsl:value-of select="$tab"/>
<xsl:value-of select="@engine"/><xsl:value-of select="$tab"/>
<xsl:value-of select="@hotelname"/><xsl:value-of select="$tab"/>
<xsl:value-of select="@image"/><xsl:value-of select="$tab"/>
<xsl:value-of select="@nights"/><xsl:value-of select="$tab"/>
<xsl:value-of select="@rating"/><xsl:value-of select="$tab"/>
<xsl:value-of select="@resultkey"/><xsl:value-of select="$tab"/>
<xsl:value-of select="@resultno"/><xsl:value-of select="$tab"/>
<xsl:value-of select="@supplierdestination"/><xsl:value-of select="$tab"/>
<xsl:value-of select="@type"/></xsl:template>

<xsl:template name="upropdata">
<xsl:value-of select="$tab"/>\N<xsl:value-of select="$tab"/>\N<xsl:value-of select="$tab"/>\N<xsl:value-of select="$tab"/>\N<xsl:value-of select="$tab"/>\N<xsl:value-of select="$tab"/>2011-01-01</xsl:template>

<xsl:template name="request">
<xsl:for-each select="/response/request/method"><xsl:value-of select="$tab"/><xsl:value-of select="./@sessionkey"/></xsl:for-each></xsl:template>
<xsl:template name="Newline">
<xsl:text>&#13;</xsl:text></xsl:template>
4

2 に答える 2

0

どうですか...

<xsl:for-each select="response/results/hotel
      [not(@description = '')]
      [@rating = (3,4,5)]">
  <xsl:call-template name="hotelparams"/>
  <xsl:call-template name="upropdata"/>
  <xsl:call-template name="request"/>
  <xsl:call-template name="Newline"/>
</xsl:for-each>

注:ノード名を指定しなかったため、宛先のチェックは含めていません。

また、空の説明属性の可能性を排除できる場合(つまり、ホテルに空でない説明があるか、説明属性がまったくない場合)、このわずかに省略された形式を使用できます...

<xsl:for-each select="response/results/hotel
      [not(@description)]
      [@rating = (3,4,5)]">
  <xsl:call-template name="hotelparams"/>
  etc...
</xsl:for-each>

また、2番目の述語の代替形式は...

      [@rating = (3 to 5)]

書くことができます...

      [(@rating &gt; 2) and (@rating &lt; 6)]

また

      [@rating &gt; 2][@rating &lt; 6]

...しかし、@ ratingを2回フェッチする必要があるため、これは効率が悪いと思われます。

于 2012-08-15T12:12:28.007 に答える
0

以下の for-each は、約 4MB の XML をループしています。各ホテル ノードに説明と目的地があることを確認するためのテストです。また、各ホテルの評価が 2 より大きいが 6 ではないこともテストしています。XML の評価の可能な値は、0、1、2、3、4、5、または 6 です。理想的には、評価のみを選択したいと思います。 3、4、または 5 を選択し、その他は無視します。

<for-each select="response/results/hotel[
    not(@description = '') and
    @rating &gt; '2' and
    not(@rating = '6') and
    not(@destination = '')              ]">
  <call-template name="hotelparams"/>
  <call-template name="upropdata"/>
  <call-template name="request"/>
  <call-template name="Newline"/>
</for-each>

パフォーマンスの問題の理由は、それ自体ではなく、呼び出されている (そして質問では提供されていない) テンプレートにあると思いxsl:for-eachます。

さまざまな代替方法で書き直すことができますが、パフォーマンスの向上は、あったとしても最小限 (ミリ秒) です。

提供されたコードは、属性の存在をまったくチェックしないことに注意してください@destinationhotel他の条件を満たすが、destination属性を持たない要素選択されます。

description属性についてもまったく同じです。

を指定する正しい方法の 1 つxsl:for-each、次のとおりです。

<xsl:for-each select="response/results/hotel[
     string(@description)
    and
     @rating > 2
    and
     not(@rating > 5)
    and
     string(@destination)
    ]">
  <xsl:call-template name="hotelparams"/>
  <xsl:call-template name="upropdata"/>
  <xsl:call-template name="request"/>
  <xsl:call-template name="Newline"/>
</xsl:for-each>

更新

OP は、呼び出されたテンプレートのコードを提供しました。

hotelparamsテンプレートには以下を使用します。

<xsl:sequence select=
 "string-join
  (
   (@itemcode,
    @cheapestcurrency,
    @cheapestprice,
    @checkin,
    @checkout,
    @description,
    @destair,
    @destination,
    @destinationid,
    @engine,
    @hotelname,
    @image,
    @nights,
    @rating,
    @resultkey,
    @resultno,
    @supplierdestination,
    @type),
   $tab
  )
 "/>

テンプレートupropdataを次のように置き換えます。

このコード:

 <xsl:sequence select="'&#9;\N&#9;\N&#9;\N&#9;\N&#9;\N2011-01-01'"/>

または、$tab実際に と異なる可能性がある場合は&#9;、これを 1 回だけ計算して、結果をグローバル変数に入れます。

<xsl:variable name="vUPropData" select=
"concat($tab,'\N',$tab,'\N',$tab,'\N'$tab,'\N',$tab,'\N2011-01-01')"/>

そして、次のようにします。

 <xsl:sequence select="$vUPropData"/>

requestテンプレートをのように置き換えます。

このコード:

<xsl:sequence select=
  "concat($tab,string-join(/response/request/method/@sessionkey, $tab))"/>

これはどのコンテキスト ノードにも依存しない (絶対式である) ため、これを 1 回だけ計算してグローバル変数に入れ (前の場合と同様)、このグローバル変数のみを参照します。

最後に、名前付きテンプレートで同じ単一の文字を生成しても意味がありません。Newlineテンプレートをグローバル変数またはグローバル パラメータに置き換えます。

このリファクタリングの後、コードの実行速度が大幅に向上すると思います

于 2012-08-15T13:03:37.900 に答える