使用XSL 1.0对引用的元素属性求和

时间:2014-04-03 17:47:10

标签: xml xslt xslt-1.0

问题:

我有一个XML列表项,我想显示一个包含其名称和属性的表。这是相当简单的,除了一些项目的属性是其他项目的总和。在以下示例中,我想显示食物名称和总卡路里。有些物品具有“卡路里”属性;其他人有一份成分清单,总卡路里应该是该清单中每个项目的卡路里总和。

对于含有其他聚合食品的集合食品不起作用的解决方案我没问题。我被限制为xsl 1.0。

<?xml version="1.0" encoding="ISO-8859-1"?>
<FoodList>
  <SimpleFood name="Banana" calories="50"/>
  <SimpleFood name="IceCream" calories="100"/>
  <AggregateFood name="BananaSplit">
    <IngredientList>
      <Ingredient typeRef="Banana"/>
      <Ingredient typeRef="IceCream"/>
      <Ingredient typeRef="IceCream"/>
    </IngredientList>
  </AggregateFood>
</FoodList>

这是基本样式表:

<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
  <html>
  <body>
    <xsl:variable name="foods" select="FoodList/*"/>
    <xsl:for-each select="$foods">
      <tr>
        <td>
          <xsl:value-of select="@name"/>
        </td>
        <td>
          <xsl:choose>
            <xsl:when test="local-name()='SimpleFood'">
              <xsl:value-of select="@calories"/>
            </xsl:when>
            <xsl:when test="local-name()='AggregateFood'">
              <!--                              -->
              <!-- YOUR AWESOME CODE GOES HERE! -->
              <!--                              -->
            </xsl:when>
          </xsl:choose>
        </td>
      </tr>
    </xsl:for-each>
  </body>
  </html>
</xsl:template>
</xsl:stylesheet>

这是我想看到的输出:

<?xml version="1.0" encoding="UTF-8"?>
<html>
  <body>
    <tr>
      <td>Banana</td>
      <td>50</td>
    </tr>
    <tr>
      <td>IceCream</td>
      <td>100</td>
    </tr>
    <tr>
      <td>BananaSplit</td>
      <td>250</td>
    </tr>
  </body>
</html>

ATTEMPTS:

<xsl:value-of select="sum($foods/*[@name=current()/IngredientList/Ingredient/@typeRef]/@calories)"/>

这不仅不起作用(返回0卡路里),但是找到与成分列表中的成分相匹配的每个元素的想法是有缺陷的,因为它会单独计算重复的冰淇淋成分并返回150卡路里而不是正确的250(如果有人能够向我展示这个版本的工作版本,那将是很酷的,为了个人的好奇心)。

另一次尝试:

<xsl:variable name="ingredients">
  <xsl:for-each select="IngredientList/Ingredient">
    <xsl:element name="Ingredient">
      <xsl:attribute name="calories">
        <xsl:value-of select="$foods/x:*[@name=current()/@typeRef]"/>
      </xsl:attribute>
    </xsl:element>
  </xsl:for-each>
</xsl:variable>
<xsl:value-of select="sum($ingredients/@calories)"/>

与copy-element相同的是:

<xsl:variable name="ingredients">
  <xsl:for-each select="IngredientList/Ingredient">
    <xsl:copy-of select="$foods/x:*[@name=current()/@typeRef]"/>
  </xsl:for-each>
</xsl:variable>
<xsl:value-of select="sum($ingredients/@calories)"/>

上述两项工作都没有:(我想将它们作为建议发布,但要让球滚动;也许你可以找到一个简单的错误。

我已经格式化了示例代码,以便您可以通过在线xsl转换器传递它,例如在此处找到的:http://www.freeformatter.com/xsl-transformer.html。除非我可以使用这样的工具获得所需的输出,否则我可能不会“接受”答案。

谢谢!

1 个答案:

答案 0 :(得分:1)

使用模板,密钥和exsl:node-set我写的

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:exsl="http://exslt.org/common" exclude-result-prefixes="exsl">

<xsl:key name="by-name" match="SimpleFood" use="@name"/>

<xsl:template match="/">
  <html>
    <body>
      <xsl:apply-templates/>
    </body>
  </html>
</xsl:template>

<xsl:template match="FoodList">
  <table>
    <thead>
      <tr>
        <th>Name</th>
        <th>Calories</th>
      </tr>
    </thead>
    <tbody>
      <xsl:apply-templates/>
    </tbody>
  </table>
</xsl:template>

<xsl:template match="SimpleFood">
  <tr>
    <td><xsl:value-of select="@name"/></td>
    <td><xsl:value-of select="@calories"/></td>
  </tr>
</xsl:template>

<xsl:template match="AggregateFood">
  <tr>
    <td><xsl:value-of select="@name"/></td>
    <td>
      <xsl:variable name="ing-cals">
        <xsl:for-each select="IngredientList/Ingredient">
          <cal><xsl:value-of select="key('by-name', @typeRef)/@calories"/></cal>
        </xsl:for-each>
      </xsl:variable>
      <xsl:value-of select="sum(exsl:node-set($ing-cals)/cal)"/>
    </td>
  </tr>
</xsl:template>

</xsl:stylesheet>

输出

<html>
   <body>
      <table>
         <thead>
            <tr>
               <th>Name</th>
               <th>Calories</th>
            </tr>
         </thead>
         <tbody>

            <tr>
               <td>Banana</td>
               <td>50</td>
            </tr>

            <tr>
               <td>IceCream</td>
               <td>100</td>
            </tr>

            <tr>
               <td>BananaSplit</td>
               <td>250</td>
            </tr>

         </tbody>
      </table>
   </body>
</html>