XSLT:在一个div中每隔三个div包装一次

XSLT:在一个div中每隔三个div包装一次,xslt,umbraco,Xslt,Umbraco,我正在寻找一些XSLT(用于Umbraco CMS)的正确编码,我有点被难住了。我想做的是: 从某个节点开始,将每个子节点放入一个div;对于每3个孩子,用父div包装。 我没有为每个、选择和when语句设置混乱的,而是尝试实现了一个应用模板结构,但我似乎无法掌握它的窍门;下面是我现在的XSLT(我确信这是一种糟糕的做法&对性能很糟糕,但我现在真的不知道该怎么办): 智能手机 /h4> $ 显然,此代码不会生成“每三个换行一次”。有人能告诉我需要做些什么来完成这项任务吗?更新-改进了答案 我

我正在寻找一些XSLT(用于Umbraco CMS)的正确编码,我有点被难住了。我想做的是:

从某个节点开始,将每个子节点放入一个div;对于每3个孩子,用父div包装。

我没有为每个、
选择
when
语句设置混乱的
,而是尝试实现了一个
应用模板
结构,但我似乎无法掌握它的窍门;下面是我现在的XSLT(我确信这是一种糟糕的做法&对性能很糟糕,但我现在真的不知道该怎么办):


智能手机
/h4>

$


显然,此代码不会生成“每三个换行一次”。有人能告诉我需要做些什么来完成这项任务吗?

更新-改进了答案

我想不出一个使用模板的优雅解决方案,但这个带有循环的笨重解决方案可以:

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

1.
略过
2.
3.
略过
略过
4.
略过
5.
6.
7.
略过
产生:

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

1.
2.
3.
4.
5.
6.
7.

您需要将用于设置
$nodes
变量的
select
render
模板替换为生成每个节点所需结果所需的代码。

这是一个使用模板的优雅解决方案

当此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>
<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>
<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>
<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>
…仍然生成正确的结果:

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

1.
2.
3.
4.
5.
6.
7.
说明:

<?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>
<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>
<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>
<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>
  • 我们在文档顶部定义了一个
    pNumInGroup
    参数(默认值为
    3
    )。这很有用,因为它允许更灵活地使用XSLT(即,如果每个组需要不同数量的
    元素,只需将它们作为参数传递即可)
  • 第一个模板匹配根节点,重新创建它,并告诉XSLT处理器将模板应用于每个分组的第一个元素(以防需要)
  • 第二个模板与上一个模板选择的
    元素相匹配。对于每一个,将创建一个新的
    元素,并使用适合该包装组的剩余项填充该元素

注意:除非我真的需要,否则我通常远离
;对于最后一个模板,我实际上并不需要它(我可以很容易地用另一个模板指定包装/secondary
逻辑)。然而,为了“简洁”而不是过度模板化XSLT,我选择了这条路线。

如此简单和简短:

<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文档时:

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

01
02
03
04
05
06
07
08
09
10
生成所需的正确结果:

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

01

02

03

04

05

06

07

08

09

十,


我将如何实现这一点?我需要将这段代码放到更大的XSL文档中的某个位置(在choose>when语句中)。我试过做
,但运气不好。@motoxer4533,好的XSLT代码没有任何条件指令(
xsl:choose
xsl:when
xsl:other
xsl:if
)或
xsl:calltemplate
xsl:for each
指令。XSLT的精神是使用模板和匹配模式。如果您不知道如何将有效的解决方案集成到代码中,那么请阅读一本关于XSLT的好书;不幸的是,“阅读一本好的XSLT书籍”所需的时间并不是我目前拥有的奢侈品。@motoxer4533,这一次是必要的,没有人可以替代它——我想是罗蒙诺夫告诉俄罗斯沙皇:“科学中没有“沙皇之路”:)我强烈建议对XSLT有一个坚实的介绍,或者根本不使用XSLT。