技巧用xslmessage调试样式表_第1页
技巧用xslmessage调试样式表_第2页
技巧用xslmessage调试样式表_第3页
已阅读5页,还剩3页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、技巧 : 用 xsl:message 调试样式表XSLT 中的回显打印级别 : 初级Elliotte Harold (),副教授 , Polytechnic University这篇技巧讨论了使用 xsl:message 元素帮助理解和调试可扩展样式表语言转换( Extensible Stylesheet Language Transformation , XSLT)样式表的不同方法。回显打印是调试困难问题的最古老的方法之一。不管怎么说,这仍然是最简单、最快捷的方法。如果不能 确定为何函数没有按预期工作,用 printf() 或类似的工具在控制台上打印

2、几个变量就可以了解幕后发生 了什么。当然, 必须有能够输出调试结果的控制台。 XSLT 不一定具有 printf() 这样的东西。 不过 XSLT 有一个与 printf() 对应的元素: xsl:message 。 xsl:message 元素不改变 XSLT 样式表生成的结果树,仅仅输出一 些消息让程序员看到。一般输出到控制台,但也可能是对话框或者日志文件。无论输出到哪里,都是一种 非常好的调试辅助手段。xsl:message 元素是可选的。没有要求处理程序一定支持它。不过大部分处理程序都支持它,而且通常把 消息输出到控制台。是否激活了某个模板? 如果输出不同于预期结果,首先要检查是否确实

3、激活了模板。有很多原因可能造成模板被跳过,比如:? match 属性中的元素名打错了? 错误的名称空间,尤其是当试图把默认名称空间中的元素与样式表中没有前缀的名称匹配时? 模式不匹配这仅仅是部分可能的原因 。还可能有其他原因造成应该被激活的模板没有激活。 为了检查是否执行了模板, 可以在模板的开头加上 xsl:message 元素说明处理程序确实执行到了这里。比方说,假设要将 XHTML 文 档转化成没有标记的普通文本。可以将类似 清单 1 所示的消息添加到模板中:清单 1. 用于调试的匹配 HTML 的模板规则<xsl:template match="/">&

4、lt;xsl:message>Matched root node</xsl:message><xsl:apply-templates select="*"/></xsl:template><xsl:template match="html" xmlns:html="/1999/xhtml"><xsl:message>Matched html element</xsl:message><book><xsl:ap

5、ply-templates select="html"/></book></xsl:template>运行该样式表的时候,如果看到 Matched root node 消息,就知道到了那里。如果没有看到 Matched html element 消息,就知道并没有执行到这里。这样就提供了确定问题所在的线索。很可能是xsl:apply-templates 的 select 属性或者 html template 的 match 属性错了(这个例子是后一种情况, 第二个模板应该与 html:html 匹配)。无论哪种情况,都会告诉您到哪里查找最可能出

6、问题的地方。包含 xsl:if 或 xsl:choose 语句的模板有多个分支。 可以在每个分支中加上 xsl:message 元素来确定执 行了哪一个(如果有的话)。比如,清单 2 显示了插入到 DocBook XSL 样式表中以确定为何转换无效的 代码: 清单 2. 增加了调试指令的 DocBook XSL 模板<xsl:choose><xsl:when test="caption"><xsl:message>CAPTION!</xsl:message><fo:table-and-caption id="$

7、id" xsl:use-attribute-sets="perties"><xsl:apply-templates select="caption" mode="htmlTable"/><fo:table xsl:use-attribute-sets="perties"><xsl:choose><xsl:when test="$fop.extensions != 0 or$passivetex.ext

8、ensions != 0"> <xsl:message>EXTENSIONS!</xsl:message> <xsl:attribute name="table-layout">fixed</xsl:attribute> </xsl:when></xsl:choose><xsl:attribute name="width"><xsl:choose><xsl:when test="width"><xsl:me

9、ssage>WIDTH ATTRIBUTE!</xsl:message><xsl:value-of select="width"/></xsl:when><xsl:otherwise><xsl:message>NO WIDTH ATTRIBUTE!</xsl:message>100%</xsl:otherwise></xsl:choose></xsl:attribute><xsl:call-template name="make-html-tab

10、le-columns"><xsl:with-param name="count" select="$numcols"/></xsl:call-template><xsl:apply-templates select="thead" mode="htmlTable"/><xsl:apply-templates select="tfoot" mode="htmlTable"/><xsl:choose>&l

11、t;xsl:when test="tbody"><xsl:message>TBODY!</xsl:message><xsl:apply-templates select="tbody" mode="htmlTable"/></xsl:when><xsl:otherwise><xsl:message>NO TBODY!</xsl:message><fo:table-body><xsl:apply-templates select=

12、"tr" mode="htmlTable"/></fo:table-body> </xsl:otherwise> </xsl:choose></fo:table></fo:table-and-caption><xsl:copy-of select="$footnotes"/></xsl:when><xsl:otherwise><xsl:message>NO CAPTION!</xsl:message><f

13、o:block id="$id" xsl:use-attribute-sets="perties"><fo:table table-layout="auto" xsl:use-attribute-sets="perties"><xsl:attribute name="width"><xsl:choose><xsl:when test="width"><x

14、sl:message>WIDTH ATTRIBUTE!</xsl:message><xsl:value-of select="width"/></xsl:when><xsl:otherwise><xsl:message>NO WIDTH ATTRIBUTE!</xsl:message> 100%</xsl:otherwise></xsl:choose></xsl:attribute><xsl:call-template name="make-ht

15、ml-table-columns"><xsl:with-param name="count" select="$numcols"/></xsl:call-template><!-<xsl:apply-templates mode="htmlTable"/>-><xsl:choose><xsl:when test="tbody"><xsl:message>TBODY!</xsl:message><xs

16、l:apply-templates select="tbody" mode="htmlTable"/></xsl:when><xsl:otherwise><xsl:message>NO TBODY!</xsl:message><fo:table-body><xsl:apply-templates select="tr" mode="htmlTable"/></fo:table-body></xsl:otherwise&g

17、t;</xsl:choose></fo:table></fo:block><xsl:copy-of select="$footnotes"/>v/xsl:otherwise>v/xsl:choose>XSLT模板可能比较复杂。要注意您的消息。我曾经多次犯过这样的错误,在错误的地方放上了NO TBODY!这样的消息声明。结果看到的消息完全是误导。调试困难的问题之前一定要安排好缩进和空白。通常,清 理缩进本身就能发现问题所在。检查节点和节点集有时候最好计算得到一个结果而不是原样输岀文字。这样可以减少偶然误导自己的可能性

18、。所幸的是, xsl:message元素的内容实际上是完整的XSLT模板。这就意味着可以包含的不仅仅是简单的字符串消息。比如清单3可以输岀激活模板的上下文节点的完整的祖先树:清单3.列举上下文节点祖先的模板<xsl:template match="foo"><xsl:message><xsl:for-each select="ancestor-or-self:*"><xsl:value-of select="name(.)"/> /</xsl:for-each></xs

19、l:message></xsl:template>也可打印当前元素的所有属性,如清单4所示:清单4.列举上下文节点属性的模板<xsl:template match="foo"><xsl:message><xsl:for-each select="attribute:*"><xsl:value-of select="name(.)"/>="<xsl:value-of select="."/>"</xsl:for-e

20、ach></xsl:message></xsl:template>基本上能够生成调试样式表需要的任何信息。但是,如果模板没有因为您所认为的原因而激活,复杂的模 板可能失败。有时候最好从一个简单的、仅仅确定上下文节点的表达式开始:<xsl:message><xsl:value-of select="name(.)"/>: <xsl:value-of select="."/></xsl:message>这个消息看起来似乎没有什么意义。无论如何总该知道匹配的是什么节点吧?但事实上并非

21、这么显而易见。这类调试的目标之一是发现代码思维模型偏离实际的地方。如果存在bug,某些代码很可能没有按照您的预期工作。因此,有必要检查一下您“知道的”每一点是否为真。如果最终发现某一处并不像您所想像的那样,这就是问题所在。用Artemus Ward的话来说,“并非我们清楚的事情带来麻烦。往往是我们自以为知道的东西造成困扰。”测试条件有时候问题仅在特定的条件下才岀现。可以应用xsl:if以便只有当其他某些条件满足时才生成输岀。这一点对于必须考虑限制输岀结果的大型文档尤其重要。比方说,如果要调试一个只有遇到包含行内图像的 段落时才会岀现问题的样式表。不需要对整本书中的每个段落都打印消息,只有那些包

22、含行内图像的段落才须如此。比如,清单 5中的模板只有当para元素包含image时才会输出消息:清单5.段落中包含图像时输岀消息的模板<xsl:template match="para"><xsl:if test="image"><xsl:message>Para: <xsl:value-of select="."/>"</xsl:message></xsl:if> v/xsl:template>可以逐个测试元素的值,将消息限制到只有岀现bug的一

23、种情况。比如清单6中,只有当段落包含特定的单词时才会输出消息:清单6.段落中包含字符串“BCEL时输出消息的模板<xsl:template match="para"><xsl:if test="contains(., 'BCEL')"><xsl:message>Para: <xsl:value-of select="."/>"</xsl:message></xsl:if></xsl:template>是否使用了预期的处理程序?

24、最难诊断的是XSLT处理程序造成的问题。如果使用的不是您预料的处理程序,这类问题尤其难以发现。 使用Java?语言的时候这种情况很常见,因为类路径问题意味着使用的常常不是您所希望的版本或品牌的 处理程序。比如,Sun的JDK 1.4.0捆绑了问题较多的 Xalan 2.2d10 。即使在类路径中添加了更稳定更健壮的Xalan 2.7,使用的可能仍然是较老的捆绑版本。确定所用处理程序最简单的办法是用xsl:message 元素打印出它的名字。xsl:vendor函数系统属性包含所用处理程序的名称。<xsl:message>Processor: <xsl:value-of sel

25、ect="system-property('xsl:vendor')"/></xsl:message>通常返回 Apache Software Foundation (Xalan XSLTC)或 SAXON from Michael Kay of ICL 之类的字符串。如果发现使用的是 Xalan ,而您想的本来是 Saxon ,这就可以解释一些问题。不过,您通常真正关心 的是库的版本。在 Xalan 中可以使用一个简单的扩展函数来得到库的版本,该函数调用 static org.apache.xalan.Version.getVersion

26、() 方法,如 清单 7 所示:清单 7. 输出 Xalan 版本号的样式表<?xml version="1.0" encoding="UTF-8"?><xsl:stylesheet version="1.0"xmlns:xsl="/1999/XSL/Transform" xmlns:pre="xalan:/org.apache.xalan.Version"><xsl:template match="/">&

27、lt;xsl:message>Processor: <xsl:value-of select="system-property('xsl:vendor')"/><xsl:text> <xsl:text><xsl:value-of select="pre:getVersion()"/></xsl:message></xsl:template></xsl:stylesheet>下面是使用 JDK 1.5.0_06 转换时得到的结果:$ java org.

28、apache.xalan.xslt.Process -IN test.xml -XSL test.xslProcessor: Apache Software Foundation (Xalan XSLTC) Xalan Java 2.4.1向 jre/lib/endorsed 添加最新版本的 Xalan 后的结果如下:$ java org.apache.xalan.xslt.Process -IN test.xml -XSL test.xslfile:/Users/elharo/Documents/articles/tips/test.xsl; Line #8; Column #18;Proc

29、essor: Apache Software Foundation Xalan Java 2.7.0值得一提的是, 2.4.1 和 2.7.0 版本之间的差别有时候很明显, 从后一个版本开始 Xalan 输出 URL 和每 个消息的行列号。当然只有在使用 Xalan 的时候才能用这种方法分辨。如果您认为自己在使用 Xalan 而实际上用的是其他 处理程序,很可能出现的问题会警告您这一点。但是其他大部分处理程序都由类似的功能。最新版本的Saxon 实际上在 xsl:vendor 字符串中包含了版本号,这一点非常方便。停止转换 在很少的情况下,可能会发现转换一团糟难以继续下去。也许因为输入与预料的

30、相差甚远,希望放弃或停止处理。这种情况下,使用terminate="yes" 属性的xsl:message元素可以停止转换。比如 清单8 中,如果输入中包含XHTML名称空间之外的任何元素则该模板放弃处理:清单8.如果文档包含非XHTML元素则停止处理的模板<xsl:template match="/"><xsl:for-each select="descendant:*"><xsl:if test="namespace-uri() != '/1999/x

31、html'"><xsl:message terminate="yes">Non-XHTML element encountered: <xsl:value-of select="name()"/></xsl:message></xsl:if></xsl:for-each><xsl:apply-templates select="*"/></xsl:template>理想情况下,结果树应该在生成任何输岀之前建立,以便在遇到这样的消息处理程序时可以什么也不输岀。不同的处理程序对此的处理相差很大。有一些处理程序,包括xsltproc ,在终止

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论