XSLT问答:奇怪的转换

王朝html/css/js·作者佚名  2006-12-17
窄屏简体版  字體: |||超大  

XSLT问答:奇怪的转换

XSLT问答:奇怪的转换 XSLT问答:奇怪的转换body{font-size:small;font-family:verdana}pre,code{font-family: "courier new"}pre {background-color:#e1e1e1}XSLT问答:奇怪的转换原作:John E. Simpson 2002.4.24 翻译:onestab 问:我的CDATA部分可以不被当作CDATA编码吗?(Can I un-CDATA my CDATA Section)我在CDATA部分嵌入了一些HTML标签。(源文件不是我写的) 当我用XSLT将文件转换为HTML时,CDATA部分的标签比如<i> 到了浏览器中都变成了&lt;i&gt;。

有没有办法避免这种事情发生?

答:你没有提供文件例子,但我可以从你的描述推断你遇到的问题大致是这样的:<true_xmlwrapper> <![CDATA[ <html> <head><title>Weird EmbeddedMarkup</title></head> <body> <h1>Someone thought he was being clever...!</h1> <p><em>[etc.]</em></p> </body> </html> ]]></true_xmlwrapper>

我还可以假定你想要的转换结果应该是这样的:

<html> <head><title>Weird Embedded Markup</title></head> <body> <h1>Someone thought he was being clever...!</h1> <p><em>[etc.]</em></p> </body></html>

如果我的推断不错的话,你转换所用的XSLT里大约应该有这样的一个模板:

<xsl:template match='true_xmlwrapper'> <xsl:value-of select='.'/></xsl:template>

你可能已经发现,这解决了一个问题 -- 它只是去掉了开始和结束的<![CDATA[ ]]> 标记。 然而,写到结果树中的并非你想要的整洁的HTML代码,而是相当难看的:

&lt;html&gt; &lt;head&gt;&lt;title&gt;Weird EmbeddedMarkup&lt;/title&gt;&lt;/head&gt; &lt;body&gt; &lt;h1&gt;Someone thought he was being clever...!&lt;/h1&gt; &lt;p&gt;&lt;em&gt;[etc.]&lt;/em&gt;&lt;/em&gt; &lt;/body&gt;&lt;/html&gt;

这种输出结果有些出乎我们的意料。实际的输出结果似乎在这样说:“下面这些文字中的尖括号不作为标记定界符对待,而是看成普通字符。”你猜到吗?这就是CDATA部分对那些标记敏感的字符的处理建议。文件的作者理所当然地认为他是在帮后续程序做件好事 -- 像这样把HTML标记裹在CDATA部分防止它被别的程序误读(就像这可恶的XSLT处理器一样)。事实上,CDATA内的这种包装就是要告诉任何明白标记语言的程序:“这看起来像标记语言,实际上不是,甚至也不是HTML”。这样一来XSLT处理器所做的假定当然是合情合理的。原来如此。你可以这样试一试(在我的MSXML和Saxon XSLT处理器中是可行的):在你的XSLT样式表中,加入这个定级元素:<xsl:output method='text'/>

这看起来似乎与直觉不符,甚至怪异。如果问题出在转换环节的输入端,那么指定输出特性有什么用?如果文件中没有任何xsl:output元素,XSLT处理器就会试图根据转换后的结果树推测出样式表的用意,在进行推测时使用一系列测试,目的是判断结果树是不是HTML(缺省版本为HTML4.0, 不是XHTML);如果不是,就假定结果树是一个良构的XML普通解析实体(a well-formed XML general parsed entity)。(这个实体不一定是个良构的文件(document),比如,根节点可能含有两个子元素)对HTML结果树所进行的四项测试(必须全部通过)分别是:

结果树的根节点有一个子元素(即有一个根元素); 根元素的名称(不管其名称空间前缀)是"html"; 作为根的 html 元素本身没有与任何的namespace URI相联系;并且 这个根元素之前的任何文本节点只能是空白的文本节点(whitespace-only text nodes)。至于你所描述的那种文件的情形,这些测试几乎没有任何内容:乍看起来,它似乎包含有标记内容,但是无论怎么相似,实际上根据定义,一个CDATA部分只可能包含纯文本。这样在缺省情况下,在上述的结果树中没有“根元素”、html元素或其它任何东西。只不过是一个纯文本的字符串,而且它刚好以纯文本的 < 字符开始。这样结果树就没有通过HTML测试,处理器就猜测结果树只不过就是一个良构的一般解析实体,-- 在此处,它只包含有一个文本节点。

但是,如果指定了 method="text",你就跳过了处理器的缺省检测,告诉它不要对结果的类型做任何推测。

(使用这个小技巧有两个危险:首先,它是全局的 :你无法使它有选择地只作用于源/结果树中的某部分而不作用于其余部分;其次,也是更重要的,如果CDATA部分中的“标记”不是格式完好的,也将会被无条件地直接传到结果树。如果使用这个结果树的下游程序能读懂XML或HTML,则该下游程序将面临一场灾难。)

问:我的空白元素标签总是在末尾丢掉了一个空格。为使我的XHTML能够兼容旧的浏览器(比如Netscape 4.77),在XSLT转换中我对空白的XHTML元素的结束斜杠前增加了一个空格,就像这样:<xsl:template match='model/name'> <em>Model Name: </em> <xsl:apply-templates/><br /> <!-- Note space ^ --></xsl:template>

然而,转换后的结果却是这个样子:

<em>Model Name: </em> Nimbus 2000<br/>

<!-- No space ^ -->

这对于新的浏览器来说没有问题,但是旧的浏览器不把<br/>当作<br>,只是忽略它,这样不太好。我看过一些关于如何在XML控制空白的技术资料(例如Bob DuCharme系列),但是这些资料都是针对元素内容,而不是元素标签本身的。我承认XML对空白的处理方式有它这么做的理由,那么看来从XML的角度试图控制一个标签内部 的空白似乎有些异想天开。到底有没有人知道如何在转换后用Perl脚本(修正它)的做法?

答:一个Perl 脚本?在转换之后?<冷颤/> 我的意思是,我喜欢Perl,但还是... 对付这个问题还是有几种方法的。

首先,还记得空白元素可以用一对连续的起始/结束标签表示,例如:

<br></br>

这样,你就可以把它放到结果树中,而不用它的空白标签形式,<br/>(不管斜杠其面有没有空格),这样做有一个问题,就是一些旧版本的浏览器会把它理解为连续的两个

br元素。

另外一种较好的解决方案是这个月本栏目第一个问题的变形。就像我上面所说的,XSLT处理器对结果树进行有意识的猜测。我不明白为什么它认不出你的结果树是HTML4.0(新旧浏览器都可读懂)。但是你可以用这个顶级元素规定处理器的翻译:

<xsl:output method='html'/>

例如,在这种情况下,当你的样式表中含有XML兼容的<br/>标签(有无空白皆可),兼容的处理器就会以HTML兼容的<br>形式输出。

我想我的介绍对你的问题能有些启发;它强制地规定结果树不是XHTML,该怪罪的是愚笨的HTML4.0,不幸的是我们正处于浏览器和XHTML发展的过渡阶段,如果是我的话,我就会利用新浏览器的容忍性,而不是按照XHTML的严格要求写代码,但愿旧的浏览器的某些表现能如所愿。(浏览器在设计时往往不会遵从标准,也难怪它们对较新的标准的支持更加虚弱。)

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
 
 
© 2005- 王朝網路 版權所有 導航