第一节:理解XSL 有一天晚上我做了一个梦。这个梦真吓人。但如我告诉我的释梦师的,如果你没有读过写使用XML和我妈妈的菜谱赚钱的计划,这个梦就没什么意义。
不管怎么说,这个梦......
那是在公元2001年,我用我妈妈的菜谱建立了一个网站,而且行得不错。网站的节读数很高,得到的反馈也很多。后来就到了电话,是Michael Ovitz打来的。他告诉我他回来做生意,想把这些菜谱作为事业的起点。他认为其潜力不仅仅在于它一份菜谱,而是Sally Field领衔出演的一系列关于与恐怖份做斗争的身怀绝艺的技艺精湛的厨师的电影。他所要的是一250个菜谱的标题和它们组成成分的清单。而且他希望在15分内得到它们。我狂喜,我颤栗,然后我意识到我用的是HTML。
我从尖叫中醒来 - 冷汗顺着我的脸往下淌。
为什么是个噩梦呢?梦中的是发生在将来,一个XML和它的同伴XSL(扩展样式表 - eXtensible Stylesheet Languange)被广泛使用的时代。即使这样,我用HTML建立我的整个菜谱网站,不是XML。而且,HTML就是HTML - 我没有办法从中通过拷贝粘贴提取想要的信息。CSS此时也毫无用处。但是如果我在梦用了XSL,我就会很快产生那份清单,然后快乐地从别人的天和努力中榨取利益。
然而现在,XSL的允诺只是一个梦。关键在于从W3C的第一份草稿到发布第一份推荐稿至少要八个月(或至少一年)的时间。在完成之前,其规范可能要做根本性的改变。
尽管这样,微软还是正在打算在其IE 5的第二个beta版中支持XSL现有草稿的功能。坦率地说,我不知道为什么它会在这上面耗费资源。因为这件事对每个人来说,谁都不愿意花费时间在学习一种在其实现之前就过时的语言。
虽然如此,但理解XSL的要点还是很重要的 - 它会使Web开发者的生活更容易些。如果对XSL一无所知,对被经常吹捧的XML的一些优点的理解就会有困难。
那么就让我们看看其中的一些基本概念 - 不太可能改变的东西。
第二节:攀登结果树
你从本文中学到的最重要的一点是XSL不仅仅是应用样式。当使用XML处理器时,XSL源文档中的信息将被评价、重新安排,然后重新组装。我们最终得到的不只是XML数据的可爱的版本 - 而是可以被容易地添加、修改和重新排序的灵活的源信息。这个最终产品叫做结果树(Result Tree)。
这通过一系列测试产生。下面是一个简单的例子:
<xsl:template match="recipe_name">
<P>
<xsl:process-children/>
</P>
</xsl:template>
最先要解释的是以"/" 结束的标记符是空的。即此种类型的标记符的起始和结束标记符之前什么也不发生。在HTML中类似的例子是<img>标记符。因为一个图像所需的所有信息都包含在一个标记符中,所以就没有必要存在结束标记符</img>。组织良好的XML文档可以接受空标记符,同时XSL样式表必须是组织良好的XML。
让我们再回到例子,它告诉XSL处理器如果发现一套<recipe_name>标记符,就应该分离出内容然后用<p>和</p>包围起来。或者,如果你想炫耀你的XSL的知识,你可以说“添加到结果树中。”
这是一个相当简单的测试,而且很典型。XML元素的内容被表现信息所包围。
现在让我们看看书写菜谱的XSL样式表的完整例子。
在我讲述更多的XSL标记之前,我要解释一个可能被问到的问题。谁都知道在HTML中<p>本身就足够了,那么我为什么要使用结束的</p>标记符呢?
有人能回答吗?答案是:没有对应的结束标记符,那部分就不是组织良好的XML,于是会产生一个致命的错误。
第三节:一个XSL样式表
下面是一个完整的样式表。
<xsl:stylesheet>
<xsl:template match = "/">
<HTML>
<BODY>
<xsl:process-children/>
</BODY>
</HTML>
</xsl:template>
<xsl:template match = "author">
<H1>
<xsl:process-children/>'s fabulous
</H1>
</xsl:template>
<xsl:template match = "recipe_name">
<H2>
<xsl:process-children/>
</H2>
</xsl:template>
<xsl:template match = "meal">
<TABLE><TR><TD><H3>EAT FOR:</H3></TD>
<TD><H3><xsl:process-children/></H3></TD>
</TR></TABLE>
</xsl:template>
<xsl:template match = "directions">
<H4>DIRECTIONS</H4>
<P>
<xsl:process-children/>
</P>
</xsl:template>
<xsl:template match = "ingredients">
<B>INGREDIENTS</B><BR></BR>
<xsl:process-children/>
</xsl:template>
<xsl:template match = "item">
<BR>
<xsl:process-children/>
</BR>
</xsl:template>
</xsl:stylesheet>
其结果不会使我得到任何设计奖,但是它是一个能起作用的XSL。这里可能只有下面的命令需要解释:
<xsl:template match = "/">
<HTML>
<BODY>
<xsl:process-children/>
</BODY>
</HTML>
</xsl:template>
第一行的"/"告诉处理器这个节点应用到XML文档的根上。于是,这部分中的命令是结果树的基础。处理器被告之把<HTML>和<BODY>标记符放在文档的开始和结尾处,然后处理或打印所有的子元素。因为它是根元素,所以意味着“打印所有的东西。”
现在,如果你考虑几秒钟,就会觉得有点古怪。如果根层的process-children命令把源代码传递给结果树,那么所有与模板匹配的节点都可以与已经经过处理的源码一起工作。
然而,出现的问题是:XSL有一套确定哪些内容被传递给结果树的规则,其中最重要的规则是,最特定的匹配将会赢。显然,元素名的模板匹配比根层的匹配更特定。因此,所有模板匹配的节点将超越根层的规则。
注意用XML数据添加HTML标记符是多么的容易。当XSL处理器看到那些不在XSL词汇表中的标记符时,就会把他们传递给结果树。如果你花些时间,就可能发现其中巨大的潜力。XSL可以被用做一种转换语言。存储在一个XML文件中的数据可以用完全不同的标记符转换到另一个文件中。还有,信息可以被修改成与可以对应一套不同的标记符集的XML应用程序一起工作的形式。
而且还不只这些,如人们所期望的,样式表可以用匹配的标记符打开和关闭,其中是一套组织良好的单元。 很好,但是还有限制。
第四节:选择XSL
简单的<xsl:template match>还不能完全满足我们的要求。比如,我希望当<course>标记符出现时取消<meal>标记符的内容。这样的话我就不用担心节面上同时显示"dinner"和"appetizer"。我可能还希望通过在最后的ingredient后面插入大量的空白来调整版面。
如同某个广告部的人说的:所有这些都是可能的 - 还要更多。SL有一套用来把元素与其父成员或子成员匹配的工具。它也允许位置上的匹配。例如,可以在第一个和最后一个某个特定元素上应用特定的格式,等等。
现在让我们考虑一些更复杂的事,比如令我在梦中出汗的任务。我需要菜谱名和它们的成分的清单。现在,如果我的网页与数据库没有联系,我就不得不写一个查询语句。因为我对SQL不太熟,所以需要得到的DBA帮助。但是如果知道XSL,我就会摆脱这些麻烦。
<xsl:style sheet>
<xsl:template match = "/">
<xsl:for-each select ="list/recipe">
<TABLE>
<TR><TD>
<xsl:process select = "recipe_name"/></TD>
<TD>
<xsl:for-each select = "ingredients/item">
<BR><xsl:process-children/></BR>
</xsl:for-each>
</TD></TR>
</TABLE>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
结果并不神奇。但是在table标记符中加些花样将没问题。显然,我在XML中存储了信息,但是我认为最好还是仔细看看。
<xsl:template match = "/">
<xsl:for-each select ="list/recipe">
第一行很熟悉,只是简单地与模板相匹配。但是第二行却有些不同 - 在元素清单中出现的每个菜谱元素做每件事,直到</xsl:for-each>标记符。然后我开始HTML表格,用<xsl:process select="recipe_name"/>标记符把recipe_name元素中的内容输出到表格单元中。在关闭第一个表格单元后,事情开始变酷。下一行(<xsl:for-each select="ingredient/item">)开始一个附加的嵌套循环,允许我把全部ingredient输出到合适的显示信息中。样式表的其余部分应该很好理解。
但是等等,我知道你在想:“他说过酷了吗?什么这么酷?”
for-each函数是XSL的几个程序化的特征之一。还有if-then和选择函数。这些特征允许任何人都可以以任何能想到的方式(或至少是可行的方式)容易地操纵XML内容。如果你能实现这些特征,就很酷。
第五节:从规范到实现
既然你已经看到XML的一些功能,那么我想提出一个问题:通过把内容分离到组织良好和有效的XML文件中,XML对这些内容有哪些不能做的呢?如我前面显示的,数据可以被操纵然后放入你选择的版面中。或者数据可以被处理成可以被其它应用程序使用的形式。那么,还有其它的吗?
我们再一次面对扩展性的核心。一旦定义了数据,我们可以做任何想做的事。如果我们来到一个有能处理XML的字处理、电子表格和表现程序的时代,同一套数据几乎可以被用在任何用途上。
但是,哎!这依然是个梦。
我们只能希望浏览器能实现这些功能,但是我们没有理由乐观。即使Tim Bray,XML的教父,也说过对XSL的尝试只能在CSS标准完全实现之后才能实现。谁知道什么时候才能实现呢?而且这也不是唯一的问题。
XSL要排除另一个障碍。XSL规范有两个截然不同的部分。第一部分,是我们这里讨论的,处理数据结构。另一部分是一套用来应用样式的有格式的对象。这部分需要做大量工作。在我看来,现在需要很多人去做很多事。例如,应该有既适合屏幕又适合打印输出的命令。如果规范的制定者继续这种“无所不包”的尝试,此规范将最终很难实现,而且最终用户用起来也困难。但是现在,我们做不了什么 - 只能过我们自己快乐的小日子,同时盼望负责的同志们别把事情弄糟。
在这期间,做了甜梦吧!
---
转载自 http://bbs.xml.org.cn/dispbbs.asp?boardID=8&ID=7632