显式脚本结束标记始终转换为自动关闭

时间:2008-12-03 09:49:28

标签: javascript xslt

我正在使用xslt将xml转换为aspx文件。在xslt中,我有一个脚本标记包含一个jquery.js文件。要使其与IE一起使用,脚本标记必须具有明确的结束标记。出于某种原因,这不适用于下面的xslt。

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
    xmlns="http://www.w3.org/1999/xhtml"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
    xmlns:asp="remove">    
    <xsl:output method="html"/>
    <xsl:template match="/">
        <html xmlns="http://www.w3.org/1999/xhtml">
            <head>
                <title>TEST</title>
                <script type="text/javascript" src="jquery-1.2.6.js"></script>

但是,如果我更改脚本标签,如下所示,它可以工作。

        <script type="text/javascript" src="jquery-1.2.6.js">
            // <![CDATA[ // ]]>
        </script>

我认为<xsl:output method="html" />可以解决问题,但似乎不起作用?

/纳斯

11 个答案:

答案 0 :(得分:7)

如果你自己创建XmlWriter,你需要将transform的OutputSettings传递给XmlWriter,例如:

XmlDocument doc = new XmlDocument();
doc.LoadXml("<book><author>Trudi Canavan</author><title>Voice of the Gods</title></book>");

XslCompiledTransform transform = new XslCompiledTransform();
transform.Load("XSLTFile1.xslt");

StringBuilder output = new StringBuilder();

// Here we pass the output setting to the writer, otherwise the transform
// may be set to Html, but the XmlWriter will be outputting Xml
XmlWriter writer = XmlWriter.Create(output, transform.OutputSettings);

transform.Transform(doc, writer);

Console.WriteLine(output.ToString());
Console.ReadKey();

答案 1 :(得分:4)

从XSLT生成HTML时,这是一个非常常见的问题。我怀疑问题的根源是XSLT本身是一个XML文档。即使您将XSLT程序作为序列化XML开始,到XSLT处理器获取它时,它已经被反序列化为“信息集”表示。在XML级别,空标签和自封闭标签是等效的;元素很简单,没有孩子。这意味着您的XSLT处理器可能永远不会看到脚本元素具有开始和结束标记的程序版本。

我通常使用适当逃脱的不间断空间来绕过这个。无论如何,你必须在script标签中放置一些内容。

顺便说一句 - 这不是让IE开心。如果查看HTML spec,您会发现需要结束标记。我相信有些人会觉得IE正确实现它具有讽刺意味。 : - )

答案 2 :(得分:3)

我在MSDN论坛网站上找到了这个答案:

<xsl:value-of select="' '"/>

如果你在xsl文件的末尾之前添加上面的xslt代码,它会强制元素有一些内容(在这种情况下是空格)而不是自我关闭本身。尝试过,它有效。

这就是它所创造的:

<script...> </script>

而不是

<script ... />.

答案 3 :(得分:1)

这是设计使然,我所知道的唯一解决方法是使用自定义XmlTextWriter

public class HtmlTextWriter : XmlTextWriter
{
    private readonly string[] fullEndElements = 
        new string[] { "script", "title" };

    private string lastStartElement = null;


    public HtmlTextWriter(TextWriter textWriter)
        : base(textWriter)
    {
    }

    public HtmlTextWriter(string filename, Encoding encoding)
        : base(filename, encoding)
    {
    }

    public HtmlTextWriter(Stream w, Encoding encoding)
        : base(stream, encoding)
    {
    }

    public override void WriteStartElement(string prefix, string localName, string ns)
    {
        lastStartElement = localName;
        base.WriteStartElement(prefix, localName, ns);
    }

    public override void WriteEndElement()
    {
        if (Array.IndexOf(fullEndElements, lastStartElement) > -1)
        {
            base.WriteFullEndElement();
        }
        else
        {
            base.WriteEndElement();
        }
    }
}

答案 4 :(得分:1)

Bart van Delfts的回答指出了我正确的方向,为这个暗示欢呼!

我使用[ javax.xml.transform.Transformer ]也遇到了这个问题每当我尝试解析格式化的html片段时,在我的情况下: -

<textarea></textarea>

节点的最终输出被带入我的jsp中: -

<textarea/>

这显然搞砸了以下任何代码,因为它被视为textarea元素的更多内容。

设置t.setOutputProperty(javax.xml.transform.OutputKeys.METHOD, "html");似乎提供了我期望的自我关闭行为。这个属性在我自己的测试中默认为“xml”,所以显然在它下面没有节点的xml标签非常高兴自我关闭。

希望这无论如何都有帮助。

答案 5 :(得分:1)

考虑这个例子,

<Discount>
       <!--<xsl:if test="Discount>0">-->
             <xsl:value-of select="Discount"/>
       <!--</xsl:if>-->
</Discount>

如果我正在使用产品的折扣。我在使用前检查它。它将返回

的输出
<Discount>value of the discount</Discount>

但如果我像上面那样取消评论上面的例子,

<Discount>
       <xsl:if test="Discount>0">
             <xsl:value-of select="Discount"/>
       </xsl:if>
</Discount>

它会在xslt之后返回o / p(如果折扣为&gt; 0),

<Discount/>

答案 6 :(得分:0)

这当然是针对MS的XSLT引擎的吗?多么奇怪。我不能说我在.NET 1.1或2.0中遇到过这种情况,并且我有很多变换做同样的事情,所以我建议你选择简单的解决方法。

答案 7 :(得分:0)

答案 8 :(得分:0)

对于那些使用Xalan 2.7.0(Java)的人,我遇到了同样的问题。我在原始源代码中采用了org / apache / xml / serializer / ToStream.java文件来解决这个问题。如果指定为outputProperty:

private static Properties XHTML() {
  Properties p = new Properties();
  p.setProperty(OutputKeys.METHOD, "xhtml");
  p.setProperty(OutputKeys.DOCTYPE_PUBLIC,
    "-//W3C//DTD XHTML 1.0 Strict//EN");
  p.setProperty(OutputKeys.DOCTYPE_SYSTEM,
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd");
  p.setProperty(OutputKeys.ENCODING, "UTF-8");
  p.setProperty("{http://xml.apache.org/xalan}indent-amount", "4");
  p.setProperty(OutputKeys.INDENT, "yes");
  p.setProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
  p.setProperty("{http://example.com}selfclosing","no");
  return p;
 }

请注意selfclosing上的最后一行。这是在此更新版本的ToStream.java中响应的属性,将阻止<div /><script />标记并输出<div></div><script></script>标记。它还包括这些例外,即HTML标准中指定的允许自动关闭的(例如“area”,“base”,“basefont”,“br”,“col”,“frame”,“hr”) “,”img“,”输入“,”链接“,”元“,”参数“)。它至少对我有用,现在网页在IE中也很好。

新的ToStream.java文件可以在http://bvandelft.ruhosting.nl/ToStream.java找到,并且serializer.jar的预编译版本(使用2.7)也可以在同一个URL上使用,但是serializer.jar(在其中编译)包含的ToStream版本)不允许发布1个URL :-p

答案 9 :(得分:0)

如上所述,有一些技巧可以将不可见的内容放入元素中,但在xslt中,您始终可以将精确的输出呈现为文本:

<xsl:text disable-output-escaping="yes">
    &lt;script src="jquery-2.0.3.js"&gt;&lt;/script&gt;
</xsl:text>

顺便说一下。我认为method =“html”也可以做到这一点,但是你不会像那样渲染xhtml,例如br不会被关闭。

答案 10 :(得分:0)

另一个快速黑客是在标记中添加Javascript注释:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">//</script>

这只会在脚本末尾添加注释 - 但要注意不要错误地评论任何内容!