以文本方式查看主题 - 中文XML论坛 - 专业的XML技术讨论区 (http://bbs.xml.org.cn/index.asp) -- 『 XSL/XSLT/XSL-FO/CSS 』 (http://bbs.xml.org.cn/list.asp?boardid=8) ---- 添加多个样式表支持[推荐] (http://bbs.xml.org.cn/dispbbs.asp?boardid=8&rootid=&id=7633) |
-- 作者:宇宙人 -- 发布时间:5/18/2004 4:40:00 PM -- 添加多个样式表支持[推荐] [B][center]添加多个样式表支持[/center][/B] Benoit Marchal(bmarchal@pineapplesoft.com) 顾问,Pineapple Software 2001 年 9 月 这个月,我们不辞辛劳的专栏作家将多个样式表的支持添加到 XM 内容管理项目中。 在这样做时,他涉及到了 TrAX URIResolver 并编写伪属性的解析器。如往常一样,可在 developerWorks 开放源码专区获得完整的源代码。 在“使用 XML”专栏文章中,Beno顃 Marchal 每个月都报告其关于一个或多个开放源码 XML 开发项目的进展。 您可以随着他的进展,遵循他的设计决策和编码选择,也可以提出一些建议以及在您自己的项目中重用该开放源代码。 多个样式表 <xsl:template match="db:article">
然而,我自己在 ananas.org(我完全用 XM 维护的网站)上的经历说明了我最初的计划不能很好地工作。 我还收到一些读者的建议,建议我解决那些他们察觉是缺陷的问题。最后, 当我开始着手内容生成(稍后将在本文中介绍)时,更觉得有必要添加多个样式表的支持了。 获取代码 读者建议用巧妙的命名约定来选择样式表,但对于解决方案的最好提议来自一位同事, 他提醒我使用 xml-stylesheet 处理指令。 如果您不熟悉 xml-stylesheet,则可以看于 1999 年 7 月发表的小的 W3C 建议书,其中介绍了它,xml-stylesheet 是通过 Internet Explorer 5.0 而得到普及。处理指令将样式表(XSL 或 CSS)与 XML 文档相关联。 例如: <?xml version="1.0"?>
一般而言,处理指令对应用程序特定的数据进行编码。您已经熟悉了处理指令,因为大多数 XML 文档都是以 XML 声明开始, 该声明本身就是特殊的处理指令。一条处理指令包含一个目标(在上面示例中, xml-stylesheet),后跟数据。 用 <? 和 ?> 定界符将处理指令包起来。目标确定应用程序, 而对应用程序不能识别的目标,其会忽略这些处理指令。 数据格式完全是自由的。XML 不指定将什么东西放进去(当然,除了 XML 声明)。 事实上,由于历史原因,处理指令可以包含 PostScript 图像或脚本等……但决不包含标记。 象声明一样,xml-stylesheet 有特殊地位,因为它是由 W3C 定义的。 它必须出现在文档的开始(即,在第一个元素之前),并且包含几个所谓的 伪属性。这个数据之所以称为伪属性, 是因为其语法与 XML 属性相似。 最重要的伪属性是 href,它包含指向样式表的 URI。其它有用的伪属性有 type 和 alternate。type 是样式表的 MIME 类型, 它用来区别 CSS 和 XSL。如果有多个 xml-stylesheet 指令, 则 alternate 表明哪一个替代主样式表。处理器应该用备用样式表列表提示用户。 然而,因为 XM 以批处理方式工作,所以它使用不同的策略,完全忽略备用样式表。 虽然 xml-stylesheet 是一种 W3C 标准,但 TrAX 处理器忽略它,除非另行告知。 应用程序必须明确地调用 getAssociatedStylesheet() 来检索处理指令,如下: Source document = new StreamSource(file), if(null != stylesheet)
然而,getAssociatedStylesheet() 带来 XM 必须避免的两个问题。首先,getAssociatedStylesheet() 使高速缓存常用样式表变得困难。其次,它假设样式表存储在与文档相同的目录中。 我喜欢将样式表存储在不同的目录中,因为我发现,如果样式表都被分组在一个目录中,可以易于维护和共享样式表。 还传递样式表参数 清单 1:样本参数 <xsl:stylesheet ...> <xsl:param name="sponsor" select="'none'"/> <xsl:template match="articleinfo"> 还有,如何传递这些参数?W3C 没有提议一种机制,所以定义新的处理指令似乎也就不足为奇了。XM 可以识别 xm-xsl-param 和 xml-stylesheet。xm-xsl-param 的语法与其它处理指令相似,并且使用两个伪属性 name 和 value: <?xml version="1.0"?> 显而易见,TrAX 不支持 xm-xsl-param,但因为我已经确定 XM 需要替换 getAssociatedStylesheet(),所以解析 xm-xsl-param 的工作不是很多。 但这不是意味着要对文档解析两次吗?一次用于处理指令,另一次是使用 XSLT 处理器。实际上, 解析两次不会引起更多麻烦,因为处理指令必须出现在文档开始,所以 XM 只是重新解析文档的一小部分。 ProcessingInstructionHandler 和 PseudoAttributeTokenizer 处理程序截取 4 个事件。setDocumentLocator() 和 startDocument() 用于初始化。 大多数工作都发生在 processingInstruction() 中。至于 startElement(), 它用来停止解析,因为它标记这个开始的结束。要停止解析,startElement() 抛出一个异常。 这种作法近乎黑客所使用的手段,这是有争议的;异常一般用于报告错误,然而 startElement() 中没有错误,但 SAX 没有提供更“光明正大”的解决方案来停止解析。 虽然伪属性的语法与 XML 属性相类似,但 SAX 解析器不对它们进行译码。XM 使用它自己的解析器 PseudoAttributeTokenizer 来对伪属性进行译码。 PseudoAttributeTokenizer 每次扫描缓冲区一个字符,查找伪属性。 它使用一种典型的算法,这种算法可以在每本编译器书籍中找到。 如果您不熟悉方面的内容,那么我推荐您阅读以 Pascal 闻名的 Niklaus Wirth 的 Compiler Construction(请参阅参考资料)。 要简化该代码,getc() 方法返回缓冲区中的下一个字符,而 putc() 替换缓冲区中 getc() 下一次调用的字符。 PseudoAttributeTokenizer 的公用接口由三个方法组成:hasMoreTokens() 测试缓冲区中是否还有伪属性,nextName() 返回下一个名称,nextValue() 返回下一个值。 让我们研究一下 nextName()。它通过调用 eatSpaces() 来除去前导空格。接下来, 只要它发现有数字或字母,就一直循环下去,并将字符累积在变量(token)中。因为名称只包含数字和字母, 所以任何其它字符都可以表示这个循环的结束。nextName() 特别关注读入缓冲区的、返回的最后一个字符, 其中,它将用于 nextValue()。 清单 2:nextName() 示例 public String nextName()
nextValue() 与 nextName() 相似,但它先识别等号字符(由 nextName() 将它留在缓冲区中)和引号字符。nextValue() 还译码预先定义的实体(<、> 以及类似的)。 有了 tokenizer,就很容易译码处理指令。以下代码摘自 ProcessingInstructionHandler,它用来识别 xml-stylesheet。xm-xsl-param 的代码与这类似: 清单 3:ProcessingInstructionHandler 摘录 if(target.equals("xml-stylesheet"))
请记住,XM 会忽略备用样式表。W3C 建议书考虑到 HTTP,所以提供了优先于备用样式表的缺省样式表。XM 使用与这相同的规则, 应用它自己的缺省样式表,而不考虑备用样式表。 TemplatesManager 正如前面所解释的那样,XM 不会将文档和样式表混在一起。它使用两个目录:文档目录和规则目录。TrAX 提供 URIResolver 接口以控制 XSLT 处理器如何装入文件。XSLT 处理器的 URIResolver 与 SAX 解析器的 EntityResolver 相似; 当该处理器装入已导入的样式表(通过 xsl:import 或 xsl:include 元素)或文档(通过 document() 函数)时, 该处理器调用它的 resolve() 方法。 TemplatesManager 使用内部类 ReferenceResolver,该类从规则目录装入样式表: 清单 4:ReferenceResolver 示例 protected class ReferenceResolver public ReferenceResolver(File rulesDir) public Source resolve(String href,String base)
StylingMover 自动生成内容 例如,许多网站都包含下载区。如果经常更改文件列表, 则要维护一个带总是最新列表的 XML 文档是困难的。最好使用一种软件来自动生成列表。 该文档可能类似于清单 6。同样可以从 SQL 数据库、邮箱或者甚至远程网站生成文档! 清单 6:由 XM 读取的目录 <?xml version="1.0" encoding="UTF-8"?>
上个月的专栏文章中介绍了 Mover,其用于简化添加自动内容生成的过程。 这个月,我已经在代码中预先包含了目录生成,并打算下个月再讲述它。同时, 如果您对此感兴趣,可回顾一下 DirectoryReader、WalkHandler 和 WalkMover。 轮到您了 我已经将 ananas.org 网站的代码(.xml 文档和 .xsl 样式表)添加到 CVS 资源库中, 您可以从那出发来设计您自己的网站。 如果安装了早期版本的 XM,则需要更新软件以利用这个月的改进:将 rules.xsl 文件重命名为 default.xsl,并将它移到 rules 目录。 这与用于选择样式表的新标准匹配。 参考资料 参与本文的论坛。 |
W 3 C h i n a ( since 2003 ) 旗 下 站 点 苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》 |
58.594ms |