XSLT:如何获得此输出?

时间:2017-10-09 08:11:11

标签: xml xslt

这是XML:

<list title="Shopping list">
   <item>Orange juice</item>
   <item>Bread</item>
   <item>
      <list title="Cake ingredients">
         <item>Flour</item>
         <item>Eggs</item>
         <item>Milk</item>
         <item>Sugar</item>
         <item>
            <list title="Chocolate icing ingredients"
      </list>
      <item>Cocoa powder</item>
      <item>Icing mixture</item>
      <item>Unsalted butter</item>
</list>
</item>
</list>
</item>
</list>  

所需的输出是:

购物清单:
1面包
蛋糕成分
2.1巧克力糖霜成分:
2.1.1可可粉
2.1.2结冰混合物
2.1.3无盐黄油
2.2鸡蛋
2.3面粉
2.4牛奶
2.5糖
3橙汁

我该怎么做呢?我能够使用position()对一些节点进行编号并对某些元素进行排序,但我无法完成所有这些操作。

1 个答案:

答案 0 :(得分:0)

你没有明确说明,但我注意到了:

  • 要包含在特定级别的元素应包括:
    • “leaf”item个元素(没有后代节点), 要打印的文字是他们的内容,
    • list元素 - “非叶”item元素的子元素, 但这次要打印的文本是title属性。
  • 特定级别的所需订购是要打印的文本。

要获得所需的递归,脚本应该以 将模板应用于根list元素,然后应用模板 对于下一级别的元素。

我为这两种情况写了一个“通用”模板(list和叶item 元件)。

此模板有两个可选参数:

  • nr - 元素编号(在此级别),
  • prefix - 来自更高级别的累计数字。

pref变量包含要打印的“组合”(多级)数字 并且还可以在递归模板应用程序中使用。

此模板的最后一部分包含list的2个变体 和item分别。

list变体:

  • 打印title属性,
  • 选择下一级别的元素
  • 并在排序循环中将模板应用于它们。

item变体只打印内容。

所以整个脚本如下所示:

<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text"/>

  <xsl:template match="/">
    <xsl:apply-templates select="list"/>
  </xsl:template>

  <xsl:template match="list | item[not(*)]">
    <xsl:param name="nr" required="no" select="0"/>
    <xsl:param name="prefix" required="no" select="''"/>
    <xsl:variable name="pref" select="
      if ($nr = 0) then ''
      else if ($prefix) then concat($prefix, '.', $nr)
      else $nr"/>
    <xsl:value-of select="
      if ($pref) then concat($pref, ' ')
      else ''"/>
    <xsl:if test="name()='list'">
      <xsl:value-of select="concat(@title, '&#xA;')"/>
      <xsl:variable name="items" select="item[not(*)] | item/list"/>
      <xsl:for-each select="$items">
        <xsl:sort select="if (name() = 'list') then @title else ."/>
        <xsl:apply-templates select=".">
          <xsl:with-param name="nr" select="position()"/>
          <xsl:with-param name="prefix" select="$pref"/>
        </xsl:apply-templates>
      </xsl:for-each>
    </xsl:if>
    <xsl:if test="name()!='list'">
      <xsl:value-of select="concat(., '&#xA;')"/>
    </xsl:if>
  </xsl:template>
</xsl:transform>

“你的”输出和“我的”之间的唯一区别是 我的脚本也打印了list元素的数字(实际上是 只有蛋糕成分)。

我想,你刚刚忘记了前面的号码 这个元素。

另请注意, 2.1。没有 2 之前看起来不自然。