Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/xml/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby 如何使用xslt应用两个模板并按大小和使用的模板对结果进行分组_Ruby_Xml_Xslt_Xslt 1.0_Nokogiri - Fatal编程技术网

Ruby 如何使用xslt应用两个模板并按大小和使用的模板对结果进行分组

Ruby 如何使用xslt应用两个模板并按大小和使用的模板对结果进行分组,ruby,xml,xslt,xslt-1.0,nokogiri,Ruby,Xml,Xslt,Xslt 1.0,Nokogiri,我正在尝试解析一个XML并生成一个可以用于打印的HTML XML中元素的内容像卡片一样呈现,正面和背面都有信息。一页可以放八张卡片。 为了使HTML/CSS世界中的定位工作更轻松,我想按如下方式预先安排XSLT输出: 对于输入中的16个元素,我希望先获得前8个元素的正面输出,然后以不同的顺序获得前8个元素的背面输出,以便在使用双面打印时与相应的正面匹配,然后获得下8个元素的正面输出,以此类推 背面的顺序是这样的:前半部分按相反顺序,后半部分按相反顺序。例如背面卡片4、3、2、1、8、7、6、5

我正在尝试解析一个XML并生成一个可以用于打印的HTML

XML中元素的内容像卡片一样呈现,正面和背面都有信息。一页可以放八张卡片。 为了使HTML/CSS世界中的定位工作更轻松,我想按如下方式预先安排XSLT输出: 对于输入中的16个元素,我希望先获得前8个元素的正面输出,然后以不同的顺序获得前8个元素的背面输出,以便在使用双面打印时与相应的正面匹配,然后获得下8个元素的正面输出,以此类推

背面的顺序是这样的:前半部分按相反顺序,后半部分按相反顺序。例如背面卡片4、3、2、1、8、7、6、5

或者对于以下输入(为了简单起见,我仅使用每页4张卡片作为示例):


首先是前线
先到后
前线第二名
倒数第二
第三个是前线
倒数第三
第四是前线
倒数第四
第五名为前线
后面第五个
我希望获得以下输出:

<html><body>
   <div>
     <div class="card1 front">First for the front</div>
     <div class="card2 front">Second for the front</div>
     <div class="card3 front">Third for the front</div>
     <div class="card4 front">Fourth for the front</div>
   </div>
   <div>
     <div class="card2 back">Second to the back</div>
     <div class="card1 back">First to the back</div>
     <div class="card4 back">Fourth to the back</div>
     <div class="card3 back">Third to the back</div>
   </div>
   <div>
     <div class="card1 front">Fifth for the front</div>
   </div>
   <div>
     <div class="card1 back">Fifth to the back</div>
   </div>
 </body></html>

首先是前线
前线第二名
第三个是前线
第四是前线
倒数第二
先到后
倒数第四
倒数第三
第五名为前线
后面第五个
我想在下一个匹配和模式中处理元素两次,但我不知道如何将其与我想应用的排序/分组相结合


我真的很感谢有一个指向正确方向的指针。

此XSLT 1.0转换实现了所需的结构:

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="html" encoding="UTF-8" indent="yes" />

  <xsl:template match="/cards">
    <html>
      <body>
        <xsl:for-each select="card[position() mod 4 = 1]">
          <xsl:variable name="thisPage" select="
            . | following-sibling::card[position() &lt; 4]
          " />
          <div class="front">
            <xsl:apply-templates select="$thisPage/question" />
          </div>
          <div class="back">
            <xsl:apply-templates select="$thisPage/answer">
              <xsl:sort select="substring('2143', position(), 1)" data-type="number" />
            </xsl:apply-templates>
          </div>
        </xsl:for-each>
      </body>
    </html>
  </xsl:template>

  <xsl:template match="card/*">
    <div class="card">
      <xsl:value-of select="normalize-space()" />
    </div>
  </xsl:template>
</xsl:transform>

也就是说,通过组合CSS中的
position:absolute
nth child
,您还可以在背面实现独立于源代码顺序的整个定位。这样一来,XSLT中的特殊排序就没有必要了。

让我们把它变成通用的-我们希望每页都有
$rows
$cols
卡片,并且在答案端,每行都需要按相反的顺序打印

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

  <xsl:param name="rows" select="2" />
  <xsl:param name="cols" select="2" />
  <xsl:variable name="pageSize" select="$rows * $cols" />

  <xsl:template match="/">
    <html>
      <body>
        <xsl:apply-templates select="cards/card[position() mod $pageSize = 1]" />
      </body>
    </html>
  </xsl:template>

  <xsl:template match="card">
    <!-- fronts -->
    <div>
      <xsl:call-template name="printRows">
        <xsl:with-param name="element" select="1"/>
        <xsl:with-param name="order" select="'ascending'" />
      </xsl:call-template>
    </div>
    <!-- backs -->
    <div>
      <xsl:call-template name="printRows">
        <xsl:with-param name="element" select="2"/>
        <xsl:with-param name="order" select="'descending'" />
      </xsl:call-template>
    </div>
  </xsl:template>

  <xsl:template name="printRows">
    <xsl:param name="element" />
    <xsl:param name="order" />
    <xsl:variable name="thePage"
        select=". | following-sibling::card[position() &lt; $pageSize]" />
    <!-- split into rows -->
    <xsl:for-each select="$thePage[position() mod $cols = 1]">
      <xsl:variable name="theRow"
          select=". | following-sibling::card[position() &lt; $cols]" />
      <!-- and process each row in appropriate order -->
      <xsl:apply-templates select="$theRow/*[$element]">
        <xsl:sort select="position()" order="{$order}" data-type="number" />
      </xsl:apply-templates>
    </xsl:for-each>
  </xsl:template>

  <xsl:template match="question">
    <div class="card{(count(../preceding-sibling::card) mod $pageSize) + 1} front">
      <xsl:value-of select="." />
    </div>
  </xsl:template>

  <xsl:template match="answer">
    <div class="card{(count(../preceding-sibling::card) mod $pageSize) + 1} back">
      <xsl:value-of select="." />
    </div>
  </xsl:template>
</xsl:stylesheet>
其中
emptyDivs
模板

<xsl:template name="emptyDivs">
  <xsl:param name="num"/>
  <xsl:if test="$num &gt; 0">
    <div class="padding back" />
    <xsl:call-template name="emptyDivs">
      <xsl:with-param name="num" select="$num - 1" />
    </xsl:call-template>
  </xsl:if>
</xsl:template>

这将为两行乘两列的页面生成以下输出:

<html>
  <body>
    <div>
      <div class="card1 front">First for the front</div>
      <div class="card2 front">Second for the front</div>
      <div class="card3 front">Third for the front</div>
      <div class="card4 front">Fourth for the front</div>
    </div>
    <div>
      <div class="card2 back">Second to the back</div>
      <div class="card1 back">First to the back</div>
      <div class="card4 back">Fourth to the back</div>
      <div class="card3 back">Third to the back</div>
    </div>
    <div>
      <div class="card1 front">Fifth for the front</div>
    </div>
    <div>
      <div class="padding back"></div>
      <div class="card1 back">Fifth to the back</div>
    </div>
  </body>
</html>

首先是前线
前线第二名
第三个是前线
第四是前线
倒数第二
先到后
倒数第四
倒数第三
第五名为前线
后面第五个
或两行三列的以下内容:

<html>
  <body>
    <div>
      <div class="card1 front">First for the front</div>
      <div class="card2 front">Second for the front</div>
      <div class="card3 front">Third for the front</div>
      <div class="card4 front">Fourth for the front</div>
      <div class="card5 front">Fifth for the front</div>
    </div>
    <div>
      <div class="card3 back">Third to the back</div>
      <div class="card2 back">Second to the back</div>
      <div class="card1 back">First to the back</div>
      <div class="padding back"></div>
      <div class="card5 back">Fifth to the back</div>
      <div class="card4 back">Fourth to the back</div>
    </div>
  </body>
</html>

首先是前线
前线第二名
第三个是前线
第四是前线
第五名为前线
倒数第三
倒数第二
先到后
后面第五个
倒数第四

您能使用XSLT 2.0吗?“首先是前8个元素的正面输出,然后是前8个元素的背面输出,顺序相反,”我在您的示例输出中看不到这一点。为什么顺序是2、1、4、3?我使用ruby和nokogiri库进行xslt处理。因此,只有XSLT1.0或者如果您知道另一个适用于ruby的优秀XSLT2.0库,我才可以使用它。XSLT1.0也可以使用它。但您需要澄清后端排序背后的逻辑。据我所知,Ruby没有XSLT2.0库,Nokogiri是最好的选择。我已经为你重新标记了这个问题。
<html>
  <body>
    <div>
      <div class="card1 front">First for the front</div>
      <div class="card2 front">Second for the front</div>
      <div class="card3 front">Third for the front</div>
      <div class="card4 front">Fourth for the front</div>
    </div>
    <div>
      <div class="card2 back">Second to the back</div>
      <div class="card1 back">First to the back</div>
      <div class="card4 back">Fourth to the back</div>
      <div class="card3 back">Third to the back</div>
    </div>
    <div>
      <div class="card1 front">Fifth for the front</div>
    </div>
    <div>
      <div class="padding back"></div>
      <div class="card1 back">Fifth to the back</div>
    </div>
  </body>
</html>
<html>
  <body>
    <div>
      <div class="card1 front">First for the front</div>
      <div class="card2 front">Second for the front</div>
      <div class="card3 front">Third for the front</div>
      <div class="card4 front">Fourth for the front</div>
      <div class="card5 front">Fifth for the front</div>
    </div>
    <div>
      <div class="card3 back">Third to the back</div>
      <div class="card2 back">Second to the back</div>
      <div class="card1 back">First to the back</div>
      <div class="padding back"></div>
      <div class="card5 back">Fifth to the back</div>
      <div class="card4 back">Fourth to the back</div>
    </div>
  </body>
</html>