2009-11-10 51 views
6

2场我旁边的xml:分组通过XSL

<page> 
    <document> 
     <id>1001</id> 
     <cur>USD</cur> 
     <date>01.01.2009</date> 
     <amount>10</amount> 
    </document> 
    <document> 
     <id>1001</id> 
     <cur>USD</cur> 
     <date>02.01.2009</date> 
     <amount>15</amount> 
    </document> 
    <document> 
     <id>1001</id> 
     <cur>JPY</cur> 
     <date>01.01.2009</date> 
     <amount>5</amount> 
    </document> 
    <document> 
     <id>1002</id> 
     <cur>USD</cur> 
     <date>01.01.2009</date> 
     <amount>5</amount> 
    </document> 
    ... 
</page> 

,我需要把它转换成HTML。记录应当由IDCUR进行分组。并且在每组总数量应该被显示之后。因此,我们希望是这样的:

Bill: id=1001, cur=USD 
     date=01.01.2009 amount=10 
     date=02.01.2009 amount=15 
     total amount=25 
Bill: id=1001, cur=JPY 
     date=01.01.2009 amount=5 
     total amount=5 
Bill: id=1002, cur=USD 
     date=01.01.2009 amount=5 
     total amount=5 
... 

我怎样才能做到这一点使用XSL?

当我试图找到在谷歌的答案,我发现Muenchian方法,但是当我们通过2场要组结果它太复杂了。我是xsl的初学者,对我来说有点困难。 我还发现XSLT 2.0操作者的for-each-基。它受主流浏览器的支持吗?通常是使用它还是我们只应该依赖xslt 1.0?

+0

XSLT 2.0是不是普遍的是,并依靠这将是一个错误,除非你能控制的地方发生转变。如果我是你,我会给它一些认真的想法,并真正考虑将转换放在服务器端。 – 2009-11-10 08:51:46

+0

没有,可惜的是我不能做到这一点,改造的,应在客户端(这不是我的决定) – Roman 2009-11-10 09:25:24

+0

我知道那种感觉,我从来没有过任何的成功尝试在客户端上运行的转换,在唯恐不任何跨浏览器兼容性。 – 2009-11-10 09:51:48

回答

3

你可以用XSLT 1.0

我这里使用的是创建一个具有两个字段,ID和CUR复合键的方法做到这一点。之后我将这些模板应用到每个组中的第一个文档。然后在模板中循环遍历各个文档,最后我总结文档数量字段。

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

<xsl:key name="idcur" match="document" use="concat(id,cur)"/> 

<xsl:template match="/page"> 
    <xsl:apply-templates select="document[generate-id() = generate-id(key('idcur',concat(id,cur))[1])]"/> 
</xsl:template> 

<xsl:template match="document"> 
<xsl:variable name="document" select="key('idcur',concat(id,cur))"/> 
Bill: id=<xsl:value-of select="id"/>, cur=<xsl:value-of select="cur"/> 
    <xsl:for-each select="$document"> 
     date=<xsl:value-of select="date"/> amount=<xsl:value-of select="amount"/> 
    </xsl:for-each> 
     total amount=<xsl:value-of select="sum($document/amount)"/> 
</xsl:template> 
</xsl:stylesheet> 

输出:

Bill: id=1001, cur=USD 
     date=01.01.2009 amount=10 
     date=02.01.2009 amount=15 
     total amount=25 
Bill: id=1001, cur=JPY 
     date=01.01.2009 amount=5 
     total amount=5 
Bill: id=1002, cur=USD 
     date=01.01.2009 amount=5 
     total amount=5 
+0

对于代码的可读性起见,我建议使用''了在XSL文本字符串。这样,输出格式更容易控制,并且代码格式可以具有正确的缩进。 – Tomalak 2009-11-10 09:36:47

+0

有效点!但我认为这不是最终的解决方案。 – 2009-11-10 09:50:34

+0

非常感谢!这不仅是一个很好的解决方案,而且也是我之前读过的关于xsl的所有理论的一个有用的例子。 – Roman 2009-11-11 10:54:54

0

Concatening两个字段创建一个复合键是不安全的,除非你有绝对的把握所有这些创建密钥的唯一身份。 这种方法更安全,我认为:

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

<xsl:output method="text"/> 

<xsl:key name="ids" match="document" use="id"/> 
<xsl:key name="currencies" match="document" use="cur"/> 

<xsl:template match="/page"> 
    <xsl:apply-templates select="document[generate-id() = generate-id(key('ids',id)[1])]"/> 
</xsl:template> 

<xsl:template match="document"> 
    <xsl:for-each select="key('ids',id)[generate-id() = generate-id(key('currencies', cur)[id=current()/id][1])]"> 
    <xsl:variable name="bills" select="key('ids', id)[cur = current()/cur]"/> 
    <xsl:text>Bill: id=</xsl:text> 
    <xsl:value-of select="id"/> 
    <xsl:text>, cur=</xsl:text> 
    <xsl:value-of select="cur"/> 
    <xsl:for-each select="$bills"> 
     <xsl:text>&#10;date=</xsl:text> 
     <xsl:value-of select="date"/> 
     <xsl:text> amount=</xsl:text> 
     <xsl:value-of select="amount"/> 
    </xsl:for-each> 
    <xsl:text>&#10;total amount=</xsl:text> 
    <xsl:value-of select="sum($bills/amount)"/> 
    <xsl:text>&#10;</xsl:text> 
    </xsl:for-each> 
</xsl:template> 
</xsl:stylesheet>