欢迎访问:常州市武进区嘉泽中心小学网站 !今天是:
栏目列表
您现在的位置是:首页>>教师>>计算机技术>>网站制作技术>>文章内容
XSLT问答:奇怪的转换
发布时间:2008-11-20   点击:   来源:本站原创   录入者:佚名
  XSLT问答:奇怪的转换

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 Embedded

Markup</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 Embedded

Markup&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的 严格要求写代码,但愿旧的浏览器的某些表现能如所愿。(浏览器在设计时往往不会遵从标准,也难怪它们对较新的标准的支持更加虚弱。)


附件:
    关闭窗口
    打印文档
    账号登录
    保持登录 忘记密码?
    账号与武进教师培训平台同步