2012-03-11 2 views
3

Использование XSLT 1.0 Мне нужно преобразовать это:XSLT 1.0 группировка с помощью клавиш на основе атрибута в родительских

<form> 
<question NumOfColumns="3"> 
<title>Colors</title> 
<answer>red</answer> 
<answer>orange</answer> 
<answer>yellow</answer> 
<answer>green</answer> 
<answer>blue</answer> 
<answer>indigo</answer> 
<answer>violet</answer> 
</question> 

</form> 

в этом:

<h2 class="question">Colors</h2> 
<div class="answersrow"> 
<input type="checkbox" name="colors" value="red" id="red" /> <label for="red">red</label> 
<input type="checkbox" name="colors" value="orange" id="orange" /> <label for="orange">orange</label> 
<input type="checkbox" name="colors" value="yellow" id="yellow" /> <label for="yellow">yellow</label> 
</div> 
<div class="answersrow"> 
<input type="checkbox" name="colors" value="green" id="green" /> <label for="green">green</label> 
<input type="checkbox" name="colors" value="blue" id="blue" /> <label for="blue">blue</label> 
<input type="checkbox" name="colors" value="indigo" id="indigo" /> <label for="indigo">indigo</label> 
</div> 
<div class="answersrow"> 
<input type="checkbox" name="colors" value="green" id="green" /> <label for="green">green</label> 
</div> 

NumOfColumns в узле вопроса говорит, сколько столбцов использовать при выводе ответных div. Для каждого узла, я могу получить свою строку с помощью:

потолок (положение() DIV родитель :: */@ NumOfColumns)

Это работает нормально; Я могу вывести правильное целое число. Но я не могу заставить клавиши/группировку работать, и я не уверен, где проблема.

Я думал, что ключ будет:

<xsl:key name="answersrow" match="form/question/answer[ceiling(position() div parent::*/@NumOfColumns) = parent::*/@NumOfColumns]" use="." /> 

и тогда я мог бы получить узлы с:

<xsl:for-each select="key('answersrow', answer)"> 

Нет везения. У кого-нибудь есть решение? Или это не выполнимо в XSLT 1.0?

ответ

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

    <xsl:template match="question"> 
     <h2 class="{local-name()}"> 
      <xsl:apply-templates select="title"/> 
     </h2> 
     <!--Select the answers that will begin the groups. 
      Apply templates in mode group and pass in the number of columns --> 
     <xsl:variable name="cols" select="@NumOfColumns"/> 
     <xsl:apply-templates select="answer[position() mod $cols = 1]" 
      mode="group" > 
      <xsl:with-param name="cols" select="$cols"/> 
     </xsl:apply-templates> 
    </xsl:template> 

    <!--Group the answers as children of the div --> 
    <xsl:template match="answer" mode="group"> 
     <xsl:param name="cols"/> 
     <div class="answersrow"> 
      <xsl:apply-templates 
        select=".|following-sibling::answer[position() &lt; $cols]"/> 
     </div> 
    </xsl:template> 

    <!--normal rendering for each answer --> 
    <xsl:template match="answer"> 
     <input type="checkbox" name="colors" value="{.}" id="{.}" /> 
     <label for="{.}"> 
     <xsl:value-of select="."/> 
     </label> 
    </xsl:template> 

</xsl:stylesheet> 
+0

Большое спасибо за ответы. Я должен был добавить в своем оригинале, что эта часть уже была внутри шаблона, поэтому мне пришлось сделать эту часть внутри именованного шаблона. @Dimitre, спасибо также за включение подхода XSLT 2.0. – devjeff

0

И. XSLT 1.0: проще, чем другие ответы (без Params) и немного короче раствора:

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

<xsl:variable name="vNumCols" select="/*/*/@NumOfColumns"/> 

<xsl:template match="/*"> 
    <h2 class="question"><xsl:value-of select="*/title"/></h2> 
    <xsl:apply-templates select= 
     "*/answer[position() mod $vNumCols = 1]"/> 
</xsl:template> 

<xsl:template match="answer"> 
    <div class="answersrow"> 
    <xsl:apply-templates mode="inGroup" select= 
    ". | following-sibling::*[not(position() >= $vNumCols)]"/> 
    </div> 
</xsl:template> 

<xsl:template match="answer" mode="inGroup"> 
    <input type="checkbox" name="colors" 
      value="{.}" id="{.}" /> 
    <label for="{.}"><xsl:value-of select="."/></label> 
</xsl:template> 
</xsl:stylesheet> 

Когда это преобразование применяется на прилагаемом документе XML:

<form> 
    <question NumOfColumns="3"> 
     <title>Colors</title> 
     <answer>red</answer> 
     <answer>orange</answer> 
     <answer>yellow</answer> 
     <answer>green</answer> 
     <answer>blue</answer> 
     <answer>indigo</answer> 
     <answer>violet</answer> 
    </question> 
</form> 

Требуется, правильный результат:

<h2 class="question">Colors</h2> 
<div class="answersrow"> 
    <input type="checkbox" name="colors" value="red" id="red"/> 
    <label for="red">red</label> 
    <input type="checkbox" name="colors" value="orange" id="orange"/> 
    <label for="orange">orange</label> 
    <input type="checkbox" name="colors" value="yellow" id="yellow"/> 
    <label for="yellow">yellow</label> 
</div> 
<div class="answersrow"> 
    <input type="checkbox" name="colors" value="green" id="green"/> 
    <label for="green">green</label> 
    <input type="checkbox" name="colors" value="blue" id="blue"/> 
    <label for="blue">blue</label> 
    <input type="checkbox" name="colors" value="indigo" id="indigo"/> 
    <label for="indigo">indigo</label> 
</div> 
<div class="answersrow"> 
    <input type="checkbox" name="colors" value="violet" id="violet"/> 
    <label for="violet">violet</label> 
</div> 

II. Решение XSLT 2.0:

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 
<xsl:strip-space elements="*"/> 

<xsl:variable name="vNumCols" select="/*/*/@NumOfColumns" as="xs:integer"/> 

<xsl:template match="/*"> 
    <h2 class="question"><xsl:value-of select="*/title"/></h2> 

    <xsl:for-each-group select="*/answer" 
     group-adjacent="(position() -1) idiv $vNumCols"> 
    <div class="answersrow"> 
     <xsl:apply-templates select="current-group()"/> 
    </div> 
    </xsl:for-each-group> 
</xsl:template> 

<xsl:template match="answer"> 
    <input type="checkbox" name="colors" 
      value="{.}" id="{.}" /> 
    <label for="{.}"><xsl:value-of select="."/></label> 
</xsl:template> 
</xsl:stylesheet>