1

カテゴリのリストを含む xml ドキュメントがあります。

<categories>
    <category id="1" parent="0">Configurations</category>
    <category id="11" parent="13">LCD Monitor</category>
    <category id="12" parent="13">CRT Monitor</category>
    <category id="13" parent="1"">Monitors</category>
    <category id="123" parent="122">Printer</category>
    ...
</categories>

そして製品のリスト:

<products>
  <product>
    ...
   <category>12</category>
    ...
  </product>
    ...
</products>

製品のカテゴリが 12 の場合、「構成/モニター/CRT モニター」に変換する必要があります (カテゴリ 12 を取得すると、親 (13) など)。親が 0 の場合、停止します。

XSL 変換を使用してこれを行うエレガントな方法はありますか?

4

4 に答える 4

4

これがエレガントと見なされるかどうかはわかりませんが、次のように入力します。

<root>
    <categories>
        <category id="1" parent="0">Configurations</category>
        <category id="11" parent="13">LCD Monitor</category>
        <category id="12" parent="13">CRT Monitor</category>
        <category id="13" parent="1">Monitors</category>
        <category id="123" parent="122">Printer</category>
    </categories>
    <products>
        <product>
             <category>12</category>
        </product>
        <product>
             <category>11</category>
        </product>
     </products>
</root>

このXSLT:

<?xml version="1.0"?>

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/">
  <root>
  <xsl:apply-templates select="//product"/>
  </root>
</xsl:template>

<xsl:template match="product">
  <product>
    <path>
      <xsl:call-template name="catwalk">
        <xsl:with-param name="id"><xsl:value-of select="category"/>
        </xsl:with-param>
      </xsl:call-template>
    </path>
  </product>
</xsl:template>

<xsl:template name="catwalk">
  <xsl:param name="id"/>
  <xsl:if test="$id != '0'">
    <xsl:call-template name="catwalk">
      <xsl:with-param name="id"><xsl:value-of select="//category[@id = $id]/@parent"/>
      </xsl:with-param>
    </xsl:call-template>
    <xsl:value-of select="//category[@id = $id]"/><xsl:text>/</xsl:text>
  </xsl:if>
</xsl:template>

</xsl:stylesheet>

この出力が得られます:

<?xml version="1.0" encoding="utf-8"?>
  <root>
  <product>
    <path>Configurations/Monitors/CRT Monitor/
    </path>
  </product>
  <product>
     <path>Configurations/Monitors/LCD Monitor/
     </path>
  </product>
  </root>

パスにはまだ余分な末尾のスラッシュがあります。最初のレベルにいないときにのみスラッシュが発行されるようにするには、条件付きXSLTをもう少し必要とします。

カテゴリ階層が正しいことが重要です。そうでない場合、変換は、メモリが不足した場合にのみ停止する無限ループに簡単に入る可能性があります。実際のシステムでこのようなものを実装している場合、呼び出しごとにインクリメントするパラメーターをcatWalkテンプレートに追加してテストに追加し、親が見つかったかどうかに関係なく、10回の呼び出し後にループを停止したいと思います。 。

于 2009-03-12T12:01:59.390 に答える
3

の使用を<xsl:key>お勧めします。

<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:output method="text" />

  <xsl:key name="category" match="categories/category" use="@id" />

  <xsl:template match="/">
    <xsl:apply-templates select="//products/product" />
  </xsl:template>

  <xsl:template match="product">
    <xsl:apply-templates select="key('category', category)" />
    <xsl:text>&#10;</xsl:text>
  </xsl:template>

  <xsl:template match="category">
    <xsl:if test="@parent &gt; 0">
      <xsl:apply-templates select="key('category', @parent)" />
      <xsl:text>/</xsl:text>
    </xsl:if>
    <xsl:value-of select="."/>
  </xsl:template>

</xsl:stylesheet>

これにより、次が生成されます。

構成/モニター/LCD モニター
構成/モニター/CRT モニター

次の XML でテストした場合:

<data>
  <categories>
    <category id="1" parent="0">Configurations</category>
    <category id="11" parent="13">LCD Monitor</category>
    <category id="12" parent="13">CRT Monitor</category>
    <category id="13" parent="1">Monitors</category>
    <category id="123" parent="122">Printer</category>
  </categories>
  <products>
    <product>
      <category>11</category>
    </product>
    <product>
      <category>12</category>
    </product>
  </products>
</data>
于 2009-03-12T12:59:12.433 に答える
1

これで十分に近づくはずです(ここにxsltコードを配置するのに苦労したので、エスケープしました。うまくいけばうまくいきます。

<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:output omit-xml-declaration="yes"/>

  <xsl:template match="/">
    <xsl:call-template name="OutputCategoryTree">
      <xsl:with-param name="productId" select="12"/>
    </xsl:call-template>
  </xsl:template>

  <xsl:template name="OutputCategoryTree">
    <xsl:param name="productId"/>
    <xsl:variable name="parentId" select="/categories/category[@id=$productId]/@parent"/>
    <xsl:if test="$parentId!=0"> 
      <xsl:call-template name="OutputCategoryTree">
        <xsl:with-param name="productId" select="/categories/category[@id=$productId]/@parent"/>
      </xsl:call-template>
    </xsl:if>/
    <xsl:value-of select="/categories/category[@id=$productId]"/>
  </xsl:template>
</xsl:stylesheet>

大まかなサンプルコードで申し訳ありませんが、生成されます

/ Configurations / Monitors / CRT Monitor

于 2009-03-12T12:02:32.773 に答える
1

カテゴリ ドキュメントをノードのフラット リストから階層に変換することから始めることを検討してください。これにより、入力ドキュメントの変換の問題が大幅に簡素化されます。また、製品のリストが大きい場合は、カテゴリ階層のすべてのステップでカテゴリのフラット リストを検索する方法よりもはるかに優れたパフォーマンスを発揮します。

<xsl:template match="categories">
    <categories>
        <xsl:apply-templates select="category[@parent='0']"/>
    </categories>
</xsl:template>

<xsl:template match="category">
    <category id='{@id}'>
       <xsl:value-of select="text()"/>
       <xsl:apply-templates select="/categories/category[@parent=current()/@id]"/>
    </category>
</xsl:template>

これにより、次のようなものが生成されます。

<categories>
    <category id="1">Configurations
       <category id="13">Monitors
          <category id="11">LCD Monitor</category>
           <category id="12">CRT Monitor</category>
       </category>
    </category>
    ...
</categories>

変換されたカテゴリ ドキュメントをパラメーターとして XSLT に渡した (またはdocument()関数を使用して変数に読み取った) と仮定すると、製品のテンプレートは非常に単純になります。

<xsl:template match="product"/>
   <xsl:variable name="c" select="$categories/categories/category[@id=current()/category]"/>
   <xsl:foreach select="$c/ancestor-or-self::category">
      <xsl:value-of select="text()"/>
      <xsl:if test="position() != last()">
         <xsl:text>/</xsl:text>
      </xsl:if>
   </xsl:foreach>
</xsl:template>
于 2009-03-12T17:56:10.227 に答える