【问题标题】:XSLT 1.0 grouping using keys based on attribute in parentXSLT 1.0 使用基于父级属性的键进行分组
【发布时间】:2012-03-11 00:27:23
【问题描述】:

使用 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 时要使用多少列。对于每个节点,我可以使用:

ceiling(position() div parent::*/@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 中不可行?

【问题讨论】:

    标签: xml xslt xslt-grouping


    【解决方案1】:
    <?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>
    

    【讨论】:

    • 非常感谢您的回答。我应该在我的原件中添加这件作品已经在模板中,所以我必须在命名模板中制作这部分。 @Dimitre,也感谢您包含 XSLT 2.0 方法。
    【解决方案2】:

    我。 XSLT 1.0:比其他答案更简单(无参数)且略短的解决方案

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-02
      • 2018-01-21
      • 1970-01-01
      • 2016-01-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多