【原创】浅谈对<xsl:apply-templates/>的理解
前几天做XML的练习,目的是把给出的XML文档按要求的格式显示出来,用的是xslt。
给出的 C04Ex1.xml 文件内容如下:
1 <?xml version="1.0" encoding="UTF-8"?>
2 <?xml:stylesheet type="text/xsl" href="C04Ex1.xsl"?>
3 <collection>
4 <cd>
5 <title>Boys for Pele</title>
6 <artist>Tori Amos</artist>
7 <tracks>
8 <track type="vocal">
9 <name>Horses</name>
10 <length>3.5</length>
11 </track>
12 <track type="instrumental">
13 <name>Blood roses</name>
14 <length>3.2</length>
15 </track>
16 <track type="vocal">
17 <name>Father lucifer</name>
18 <length>3.8</length>
19 </track>
20 <track type="instrumental">
21 <name>Professional widow</name>
22 <length>4.1</length>
23 </track>
24 <track type="vocal">
25 <name>Mr. Zebra</name>
26 <length>3.6</length>
27 </track>
28 </tracks>
29 </cd>
30 <cd>
31 <title>The Ghosts that Hunt me</title>
32 <artist>Crash TestDummies</artist>
33 <tracks>
34 <track type="vocal">
35 <name>Winter song</name>
36 <length>4.3</length>
37 </track>
38 <track type="instrumental">
39 <name>Comin's back soon</name>
40 <length>4.1</length>
41 </track>
42 <track type="vocal">
43 <name>Superman's song</name>
44 <length>4.1</length>
45 </track>
46 <track type="vocal">
47 <name>Here on earth</name>
48 <length>3.1</length>
49 </track>
50 </tracks>
51 </cd>
52 </collection>
要求输出的格式如下图所示:
一开始,笔者的输出的结果如下:
读者可以发现比要求的格式多出了两行(上图中红圈所标示的内容)。
对应的xsl文档如下:
1 <?xml version="1.0" encoding="UTF-8"?>
2 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
3 <xsl:template match="/">
4 <html>
5 <body></body>
6 <xsl:apply-templates/>
7 </html>
8 </xsl:template>
9 <xsl:template match="collection">
10 <xsl:apply-templates/>
11 </xsl:template>
12
13 <xsl:template match="cd">
14 <center>
15 <font size="5"><b><xsl:value-of select="title"/>:</b></font>
16 <font size="5"><i><xsl:value-of select="artist"/></i></font>
17 </center>
18 <xsl:apply-templates/>
19 </xsl:template>
20
21 <xsl:template match="tracks">
22 <center>
23 <table border="1">
24 <tr>
25 <th>Name</th>
26 <th>Length</th>
27 <th>Type</th>
28 </tr>
29 <xsl:for-each select="track">
30 <tr>
31 <td><xsl:value-of select="name"/></td>
32 <td><xsl:value-of select="length"/></td>
33 <td><xsl:value-of select="@type"/></td>
34 </tr>
35 </xsl:for-each>
36 </table>
37 <br/><br/>
38 </center>
39 </xsl:template>
40 </xsl:stylesheet>
41
经过思考和测试,发现问题出在“<xsl:apply-templates/>”(在上文中已突出显示)。
由于写上述xsl文件的时候对<xsl:apply-templates/>的理解还不到位,只是机械的模仿一些例子把<xsl:apply-templates/>加到一些模板内。因此一开始的时候的那个问题总是无法解决。后来请教了同学后才对<xsl:apply-templates/>有了更深刻的理解。
经过自己总结得出如下的几个结论:
一、<xsl:apply-templates/>一般只会出现在只含有html标签的模板中,亦即通常不会出现在含有xsl标签的模板中;
二、<xsl:apply-templates/>的作用是通知解析器把当前匹配的节点的所有子节点和已定义的模板进行匹配,如有相符的则运用对应的模板,如无模板匹配的节点将按文本形式显示对应的内容;
三、<xsl:apply-templates/>只能用在当前节点的所有子节点都有模板可以匹配的模板中。
明白了以上几点,上述xsl文件的错误就很好理解了。
首先,我定义了用于匹配“cd”的模板,然后定义了“title”和“artist”的显示格式。接着,我加了一个<xsl:apply-templates/>。此时,由于匹配的节点是“cd”,而“title”和“artist”,还有后面的“tracks”都是“cd”的子节点,所以解析器为每个节点寻找匹配的模板。由于没有定义与“title”和“artist”匹配的模板,所以“title”和“artist”的内容又以文本的形式输出了一次(如果匹配“title”和“artist”的模板有定义,则又会按照定义的模板重新输出一次,正确的写法请参照下文中的可行版本1、2),而“tracks”节点能够找到对应的模板与之对应,故能正常显示。
根据对<xsl:apply-templates/>的进一步理解,笔者又写出了两个可行的版本,分别如下:
可行版本一:
1 <?xml version="1.0" encoding="UTF-8"?>
2 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
3 <xsl:template match="/">
4 <html>
5 <body></body>
6 <xsl:apply-templates/>
7 </html>
8 </xsl:template>
9 <xsl:template match="collection">
10 <xsl:apply-templates/>
11 </xsl:template>
12 <xsl:template match="cd">
13 <center>
14 <font size="5"><b><xsl:value-of select="title"/>:</b></font>
15 <font size="5"><i><xsl:value-of select="artist"/></i></font>
16 <xsl:for-each select="tracks">
17 <table border="1">
18 <tr>
19 <th>Name</th>
20 <th>Length</th>
21 <th>Type</th>
22 </tr>
23 <xsl:for-each select="track">
24 <tr>
25 <td><xsl:value-of select="name"/></td>
26 <td><xsl:value-of select="length"/></td>
27 <td><xsl:value-of select="@type"/></td>
28 </tr>
29 </xsl:for-each>
30 </table>
31 <br/><br/>
32 </xsl:for-each>
33 </center>
34 </xsl:template>
35 </xsl:stylesheet>
36
可行版本2:
1 <?xml version="1.0" encoding="UTF-8"?>
2 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
3 <xsl:template match="/">
4 <html>
5 <body><xsl:apply-templates/></body>
6 </html>
7 </xsl:template>
8
9 <xsl:template match="collection">
10 <xsl:apply-templates/>
11 </xsl:template>
12
13 <xsl:template match="cd">
14 <center>
15 <xsl:apply-templates/>
16 </center>
17 </xsl:template>
18
19 <xsl:template match="title">
20 <font size="5"><b><xsl:value-of select="."/>:</b></font>
21 </xsl:template>
22
23 <xsl:template match="artist">
24 <font size="5"><i><xsl:value-of select="."/></i></font>
25 </xsl:template>
26
27 <xsl:template match="tracks">
28 <table border="1">
29 <tr>
30 <th>Name</th>
31 <th>Length</th>
32 <th>Type</th>
33 </tr>
34 <xsl:apply-templates/>
35 </table>
36 <br/><br/>
37 </xsl:template>
38
39 <xsl:template match="track">
40 <tr>
41 <td><xsl:value-of select="name"/></td>
42 <td><xsl:value-of select="length"/></td>
43 <td><xsl:value-of select="@type"/></td>
44 </tr>
45 </xsl:template>
46 </xsl:stylesheet>
47
可行版本的显示效果如下图: