我正在尝试使用表格输出它。请给我一个使用分组技术和添加值的示例。但是,输出应显示在表格中。
xml文件:
<?xml version="1.0"?>
<Library>
<Book code="123">
<BookName>XML</BookName>
<Category>Programming</Category>
<Quantity>10</Quantity>
<Price>100</Price>
</Book>
<Book code="345">
<BookName>Photoshop</BookName>
<Category>Design</Category>
<Quantity>50</Quantity>
<Price>200</Price>
</Book>
<Book code="123">
<BookName>XML</BookName>
<Category>Programming</Category>
<Quantity>5</Quantity>
<Price>100</Price>
</Book>
<Book code="345">
<BookName>Photoshop</BookName>
<Category>Design</Category>
<Quantity>10</Quantity>
<Price>200</Price>
</Book>
<Book code="456">
<BookName>Illustrator</BookName>
<Category>Design</Category>
<Quantity>100</Quantity>
<Price>300</Price>
</Book>
</Library>
myxsl-FO
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" version="1.0">
<xsl:output encoding="UTF-8" indent="yes" method="xml" standalone="no" omit-xml-declaration="no"/>
<xsl:template match="Library">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master master-name="A4-landscape" page-height="300mm" page-width="150mm" margin="1in">
<fo:region-body margin="1in"/>
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="A4-landscape">
<fo:flow flow-name="xsl-region-body">
<fo:table border-top-style="solid" border-top-width="thick">
<fo:table-body font-size="12pt" font-family="times new roman">
<fo:table-row border-bottom-style="solid" border-bottom-color="#000" border-bottom-width="thick">
<fo:table-cell padding-top="1mm" padding-bottom="1mm">
<fo:block font-weight="bold">Category</fo:block>
</fo:table-cell>
<fo:table-cell padding-top="1mm" padding-bottom="1mm">
<fo:block font-weight="bold">Book Code</fo:block>
</fo:table-cell>
<fo:table-cell padding-top="1mm" padding-bottom="1mm">
<fo:block font-weight="bold">Quantity</fo:block>
</fo:table-cell>
<fo:table-cell padding-top="1mm" padding-bottom="1mm">
<fo:block font-weight="bold">Price</fo:block>
</fo:table-cell>
<fo:table-cell padding-top="1mm" padding-bottom="1mm">
<fo:block font-weight="bold">Total</fo:block>
</fo:table-cell>
</fo:table-row>
<xsl:for-each select="Book">
<xsl:sort select="Category"/>
<xsl:sort select="@code"/>
<fo:table-row>
<fo:table-cell padding-top="3mm" padding-bottom="3mm">
<fo:block font-weight="bold">
<xsl:value-of select="Category"/>
</fo:block>
</fo:table-cell>
<fo:table-cell padding-top="3mm" padding-bottom="3mm">
<fo:block font-weight="bold">
<xsl:value-of select="@code"/>
</fo:block>
</fo:table-cell>
<fo:table-cell padding-top="3mm" padding-bottom="3mm">
<fo:block font-weight="bold">
<xsl:value-of select="Quantity"/>
</fo:block>
</fo:table-cell>
<fo:table-cell padding-top="3mm" padding-bottom="3mm">
<fo:block font-weight="bold">
<xsl:value-of select="Price"/>
</fo:block>
</fo:table-cell>
<fo:table-cell padding-top="3mm" padding-bottom="3mm">
<fo:block font-weight="bold">
<xsl:value-of select="number(Quantity)*number(Price)"/>
</fo:block>
</fo:table-cell>
</fo:table-row>
</xsl:for-each>
</fo:table-body>
</fo:table>
</fo:flow>
</fo:page-sequence>
</fo:root>
</xsl:template>
</xsl:stylesheet>
而不是xsl:for-each如果我尝试使用xsl:for-each-group,则会抛出错误,指出xsl:for-each-group不能位于该位置。
我目前的输出:
但是我想要的输出如下图所示:
感谢
答案 0 :(得分:2)
如评论中所述,如果您使用的是XSLT 1.0,则 xsl:for-each-group 命令不可用。在XSLT 1.0中,分组通常使用名为Muenchian Grouping的技术完成。值得一读并理解它,因为一旦你理解它,它在XSLT 1.0中是一个非常有用的技术。
在Muenchian Grouping中,您首先要定义一个用于查找组中元素的键。在您的情况下,您按类别和代码进行分组,因此它们的键将如下所示:
<xsl:key name="GroupByCategoryCode" match="Book" use="concat(Category, '|', @code)"/>
现在,在XSLT 2.0中,你可能会写这个......
<xsl:for-each-group select="Library/Book" group-by="concat(Category, '|', @code)">
然而,在XSLT 1.0中你必须写这个(我添加了很多缩进以提高可读性)
<xsl:for-each
select="Library/Book
[
generate-id() =
generate-id
(
key('GroupByCategoryCode', concat(Category, '|', @code))[1]
)
]">
(在这里使用xsl:apply-templates也可以。)
这样做的目的是查看所有 Book 元素,并检查其“Category”和“Code”的组合,以查看它是否是键中该元素的第一次出现。实际上,它将选择“类别”和“代码”的明显出现。
在XSLT 2.0中,您将使用“current-group”然后迭代组中的所有元素。在XSLT 1.0中,您只需使用密钥
<xsl:for-each select="key('GroupByCategoryCode', concat(Category, '|', @code))">
虽然在这种特殊情况下,你不需要为每个人做一个,因为你只是在每个组中总结数量。
<xsl:value-of
select="sum(key('GroupByCategoryCode', concat(Category, '|', @code))/Quantity)"/>
或者,为了提高可读性... ...
<xsl:variable name="currentGroup" select="key('GroupByCategoryCode', concat(Category, '|', @code))"/>
<xsl:value-of select="sum($currentGroup/Quantity)"/>
试试这个XSLT。为了简单起见(因为我不知道xsl-fo),我正在输出HTML来演示原理。您需要做的就是用他们的xsl-fo等价物替换HTML标签
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="GroupByCategoryCode" match="Book" use="concat(Category, '|', @code)"/>
<xsl:template match="/">
<html>
<body>
<h1>Books Information</h1>
<table border="1">
<tr>
<th>Category</th>
<th>Book Code</th>
<th>Quantity</th>
<th>Unit Price</th>
<th>Price</th>
</tr>
<xsl:apply-templates select="Library/Book[generate-id() = generate-id(key('GroupByCategoryCode', concat(Category, '|', @code))[1])]">
<xsl:sort select="Category"/>
<xsl:sort select="@code"/>
</xsl:apply-templates>
</table>
</body>
</html>
</xsl:template>
<xsl:template match="Book">
<xsl:variable name="currentGroup" select="key('GroupByCategoryCode', concat(Category, '|', @code))"/>
<tr>
<td>
<xsl:value-of select="Category"/>
</td>
<td>
<xsl:value-of select="@code"/>
</td>
<td>
<xsl:value-of select="sum($currentGroup/Quantity)"/>
</td>
<td>
<xsl:value-of select="Price"/>
</td>
<td>
<xsl:value-of select="sum($currentGroup/Quantity) * Price"/>
</td>
</tr>
</xsl:template>
</xsl:stylesheet>
编辑:要显示“重复”一词而不是重复类别的类别,您可以将其视为按类别分组,并仅显示组中第一个的类别名称。
因此,将以下密钥添加到XSLT,以允许您按类别查找图书
<xsl:key name="GroupByCategory" match="Book" use="Category"/>
然后,您需要选择不同的类别(这应该围绕现有的 xsl:apply-templates )
<xsl:for-each select="Library/Book[generate-id() = generate-id(key('GroupByCategory', Category)[1])]">
然后在匹配图书的模板中,您可以确定是否显示类别名称或“已定义”,如此
<xsl:choose>
<xsl:when test="position() = 1">
<xsl:value-of select="Category" />
</xsl:when>
<xsl:otherwise>
<xsl:text>Repeated</xsl:text>
</xsl:otherwise>
</xsl:choose>
试试这个XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="GroupByCategoryCode" match="Book" use="concat(Category, '|', @code)"/>
<xsl:key name="GroupByCategory" match="Book" use="Category"/>
<xsl:template match="/">
<html>
<body>
<h1>Books Information</h1>
<table border="1">
<tr>
<th>Category</th>
<th>Book Code</th>
<th>Quantity</th>
<th>Unit Price</th>
<th>Price</th>
</tr>
<xsl:for-each select="Library/Book[generate-id() = generate-id(key('GroupByCategory', Category)[1])]">
<xsl:sort select="Category"/>
<xsl:apply-templates select="key('GroupByCategory', Category)[generate-id() = generate-id(key('GroupByCategoryCode', concat(Category, '|', @code))[1])]">
<xsl:sort select="@code"/>
</xsl:apply-templates>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>
<xsl:template match="Book">
<xsl:variable name="Category">
<xsl:choose>
<xsl:when test="position() = 1">
<xsl:value-of select="Category" />
</xsl:when>
<xsl:otherwise>
<xsl:text>Repeated</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:variable name="currentGroup" select="key('GroupByCategoryCode', concat(Category, '|', @code))"/>
<tr>
<td>
<xsl:value-of select="$Category"/>
</td>
<td>
<xsl:value-of select="@code"/>
</td>
<td>
<xsl:value-of select="sum($currentGroup/Quantity)"/>
</td>
<td>
<xsl:value-of select="Price"/>
</td>
<td>
<xsl:value-of select="sum($currentGroup/Quantity) * Price"/>
</td>
</tr>
</xsl:template>
</xsl:stylesheet>