2

XSLT(Umbraco CMS用)を適切にコーディングしたいと思っていますが、困惑しています。私がやろうとしていることは:

特定のノードから開始し、各子ノードをdivに配置します。3人の子供ごとに、親divでラップします。

for-eachchooseおよびwhenステートメントの混乱の代わりに、apply-template構造を実装しようとしましたが、そのコツをつかむことができないようです。これが今のXSLTの混乱です(これは悪い習慣であり、パフォーマンスにとってひどいことだと確信していますが、現時点では本当に何をすべきかわかりません):

<div class="row four">
<h2>Smart Phones <a href="#" class="see-all">see all smart phones &rarr;</a></h2>
<div class="row three"> <!-- This div should be created again for every 3 divs -->
        <xsl:for-each select="umbraco.library:GetXmlNodeById('1063')/descendant::*[@isDoc and string(showInMainNavigation) = '1']">
            <xsl:choose>
                <xsl:when test="position() &lt; 3">
                    <div class="col">
                        <a href="{umbraco.library:NiceUrl(./@id)}">
                            <img class="phonePreviewImg" src="{./previewImage}" style="max-width:117px; max-height:179px;" />
                            <h4 class="phoneTitle"><xsl:value-of select="./@nodeName" />/h4>
                            <p class="phonePrice">$<xsl:value-of select="./price" /></p
                        </a>
                     </div>
                 </xsl:when>

                 <xsl:when test="position() = 3"> <!-- set this div to include class of `omega` -->
                    <div class="col omega">
                        <a href="{umbraco.library:NiceUrl(./@id)}">
                            <img class="phonePreviewImg" src="{./previewImage}" style="max-width:117px; max-height:179px;" />
                            <h4 class="phoneTitle"><xsl:value-of select="./@nodeName" />/h4>
                            <p class="phonePrice">$<xsl:value-of select="./price" /></p
                        </a>
                     </div>
                 </xsl:when>                                                                                
             </xsl:choose>
         </xsl:for-each>
     </div> <!-- End Row Three -->
</div> <!-- End Row Four -->

明らかに、このコードは「3つごとにラップ」を生成しません。誰かがこれを達成するために私が何をする必要があるかについていくつかの光を当てることができますか?

4

3 に答える 3

1

更新- 答えを改善しました

テンプレートを使用したエレガントなソリューションは思いつきませんが、ループを使用したこの不格好なソリューションは機能します。

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

  <xsl:template name="render">
    <xsl:param name="node"/>
    <xsl:param name="last"/>
    <div>
      <xsl:if test="$last">
        <xsl:attribute name="class">
          <xsl:text>omega</xsl:text>
        </xsl:attribute>
      </xsl:if>
      <xsl:value-of select="$node"/>
    </div>
  </xsl:template>

  <xsl:template match="/*">
    <root>
      <xsl:variable name="nodes" select="*[not(@skip)]"/>
      <xsl:for-each select="$nodes">
        <xsl:if test="(position() mod 3)=1">
          <xsl:variable name="position" select="position()"/>
          <div>
            <xsl:call-template name="render">
              <xsl:with-param name="node" select="."/>
              <xsl:with-param name="last" select="false()"/>
            </xsl:call-template>
            <xsl:if test="$nodes[$position+1]">
              <xsl:call-template name="render">
                <xsl:with-param name="node" select="$nodes[$position+1]"/>
                <xsl:with-param name="last" select="false()"/>
              </xsl:call-template>
            </xsl:if>
            <xsl:if test="$nodes[$position+2]">
              <xsl:call-template name="render">
                <xsl:with-param name="node" select="$nodes[$position+2]"/>
                <xsl:with-param name="last" select="true()"/>
              </xsl:call-template>
            </xsl:if>
          </div>
        </xsl:if>
      </xsl:for-each>
    </root>
  </xsl:template>

</xsl:stylesheet>

に適用されます:

<root>
  <node>1</node>
  <node skip="1">to be skipped</node>
  <node>2</node>
  <node>3</node>
  <node skip="1">to be skipped</node>
  <node skip="1">to be skipped</node>
  <node>4</node>
  <node skip="1">to be skipped</node>
  <node>5</node>
  <node>6</node>
  <node>7</node>
  <node skip="1">to be skipped</node>
</root>

生成:

<root>
  <div>
    <div>1</div>
    <div>2</div>
    <div class="omega">3</div>
  </div>
  <div>
    <div>4</div>
    <div>5</div>
    <div class="omega">6</div>
  </div>
  <div>
    <div>7</div>
  </div>
</root>

必要なノードを選択する XPath 変数selectを設定するために使用されるものと、各ノードに必要な結果を生成するために必要なコードでテンプレートを置き換える必要があります。$nodesrender

于 2012-11-20T16:47:39.927 に答える
1

これと同じくらいシンプルで短い

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="num[position() mod 3 = 1]">
   <div>
       <xsl:apply-templates mode="inGroup"
         select=".|following-sibling::*[not(position() >2)]"/>
   </div>
 </xsl:template>

 <xsl:template match="num" mode="inGroup">
  <p><xsl:apply-templates mode="inGroup"/></p>
 </xsl:template>
 <xsl:template match="text()"/>
</xsl:stylesheet>

この変換が次の XML ドキュメントに適用される場合:

<nums>
  <num>01</num>
  <num>02</num>
  <num>03</num>
  <num>04</num>
  <num>05</num>
  <num>06</num>
  <num>07</num>
  <num>08</num>
  <num>09</num>
  <num>10</num>
</nums>

必要な正しい結果が生成されます。

<div>
   <p>01</p>
   <p>02</p>
   <p>03</p>
</div>
<div>
   <p>04</p>
   <p>05</p>
   <p>06</p>
</div>
<div>
   <p>07</p>
   <p>08</p>
   <p>09</p>
</div>
<div>
   <p>10</p>
</div>
于 2012-11-20T17:46:26.250 に答える
0

テンプレートを使用したエレガントなソリューションは次のとおりです。

このXSLTの場合:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output omit-xml-declaration="yes" indent="yes" />
  <xsl:strip-space elements="*" />

  <xsl:param name="pNumInGroup" select="3" />

  <xsl:template match="/*">
    <html>
      <xsl:apply-templates select="*[position() mod $pNumInGroup = 1]" />
    </html>
  </xsl:template>

  <xsl:template match="node">
     <div>
        <xsl:for-each
          select=".|following-sibling::*[not(position() &gt; $pNumInGroup - 1)]">
          <div>
            <xsl:apply-templates />
          </div>
        </xsl:for-each> 
     </div>
  </xsl:template>

</xsl:stylesheet>

... @MiMoによって提供されるサンプルXMLに適用されます:

<root>
  <node>1</node>
  <node>2</node>
  <node>3</node>
  <node>4</node>
  <node>5</node>
  <node>6</node>
  <node>7</node>
</root>

...正しい結果が生成されます:

<html>
  <div>
    <div>1</div>
    <div>2</div>
    <div>3</div>
  </div>
  <div>
    <div>4</div>
    <div>5</div>
    <div>6</div>
  </div>
  <div>
    <div>7</div>
  </div>
</html>

パラメータ値が次のように変更された場合5

<xsl:param name="pNumInGroup" select="5" />

...正しい結果が引き続き生成されます:

<html>
  <div>
    <div>1</div>
    <div>2</div>
    <div>3</div>
    <div>4</div>
    <div>5</div>
  </div>
  <div>
    <div>6</div>
    <div>7</div>
  </div>
</html>

説明:

  • ドキュメントの上部にパラメータを定義しpNumInGroupます(デフォルト値は3)。これは、XSLTをより柔軟に使用できるため便利です(つまり、<div>グループごとに異なる数の要素が必要な場合は、それらをパラメーターとして渡すだけです)。
  • 最初のテンプレートはルートノードと一致し、それを再作成し、XSLTプロセッサに各グループの最初の要素にテンプレートを適用するように指示します(必要に応じて、モジュラー演算の復習です)。
  • <node>2番目のテンプレートは、前のテンプレートで選択された要素と一致します。それぞれについて、新しい<div>要素が作成され、そのラップされたグループに適切な残りのアイテムが入力されます。

注:本当に必要な<xsl:for-each>場合を除いて、私は通常、近づかないようにしています。最後のテンプレートの場合、実際には必要ありません(別のテンプレートを使用して、ラッピング/セカンダリロジックを簡単に指定できます)。ただし、XSLTを過度にテンプレート化するのではなく、「鮮明さ」のために、このルートを選択しました。<div>

于 2012-11-20T17:29:20.140 に答える