如何在使用XSLT转换的HTML中删除不正确的xmlns属性

时间:2011-07-21 22:56:39

标签: html xslt xml-namespaces

我正在尝试使用xslt转换.html文档。由于某种原因生成的html在head元素上有一个额外的xmlns属性,在title元素上有一个空的xmlns属性。

example.html的:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
  <head><title>foo</title></head>
  <body><h1>bar</h1><img src="baz.jpg" /></body>
</html>

template.xsl:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
     xmlns="http://www.w3.org/1999/xhtml">

  <xsl:output doctype-system="about:legacy-compat" method="html"
     omit-xml-declaration="yes" />

  <xsl:template match="/html/head">
    <head>
      <meta name="description" content="something added to the head element"/>
      <xsl:apply-templates select="./@*|./node()" />
    </head>
  </xsl:template>

  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

我一直在用xsltproc和php测试转换。

运行xsltproc:

$ xsltproc -html template.xsl example.html 
<!DOCTYPE html SYSTEM "about:legacy-compat">
<html xmlns="http://www.w3.org/1999/xhtml">
<head xmlns="http://www.w3.org/1999/xhtml"><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="description" content="something added to the head element"></meta><title xmlns="">foo</title></head><body>
<h1>bar</h1>
<img src="baz.jpg">
</body>
</html>

使用PHP:

<?php

$xmldoc = new DomDocument ();
$xmldoc->loadHTMLFile ("example.html");

$xsldoc = new DomDocument ();
$xsldoc->load ("template.xsl");

$xslt = new XSLTProcessor();
$xslt->importStylesheet($xsldoc);

echo $xslt->transformToXML ($xmldoc);

我希望源文档中的所有元素都在html命名空间中,所以我不明白为什么apply-templates似乎从title元素中删除了命名空间。我也不明白为什么将html命名空间添加到head元素。

3 个答案:

答案 0 :(得分:2)

在这种特定情况下,您应该使用一种身份转换来修改以删除默认命名空间:

<xsl:template match="@*|node()[not(self::*)]">
  <xsl:copy/>
 </xsl:template>

 <xsl:template match="*">
  <xsl:element name="{local-name()}">
   <xsl:apply-templates select="node()|@*"/>
  </xsl:element>
 </xsl:template>

显然请务必从XSLT中删除此行:

xmlns="http://www.w3.org/1999/xhtml"

您的最终模板:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:output doctype-system="about:legacy-compat" method="html"
        omit-xml-declaration="yes" />

    <xsl:template match="/html/head">
        <head>
            <meta name="description" content="something added to the head element"/>
            <xsl:apply-templates select="./@*|./node()" />
        </head>
    </xsl:template>

    <xsl:template match="@*|node()[not(self::*)]">
        <xsl:copy/>
    </xsl:template>

    <xsl:template match="*">
        <xsl:element name="{local-name()}">
            <xsl:apply-templates select="node()|@*"/>
        </xsl:element>
    </xsl:template>

</xsl:stylesheet>

答案 1 :(得分:1)

http://www.w3.org/1999/xhtml命名空间用于XHTML。因此,您应该将输出模式设置为xml而不是html,并为XHTML输出正确的doctype,或者将其呈现为html,而不使用任何命名空间。

请注意,XSLT不太适合生成HTML5,但如果您注意细节(例如哪些元素必须为空等等),则它非常适合生成HTML 4或XHTML。

答案 2 :(得分:0)

我无法解释或重现您的结果。

首先,带有match =“/ html / head”的模板不应与输入文档中的任何内容匹配,因为/ html / head元素位于命名空间中。

有了Saxon,我得到的输出是这个,我认为是正确的:

<!DOCTYPE html
  SYSTEM "about:legacy-compat">
<html xmlns="http://www.w3.org/1999/xhtml">  
   <head>
      <title>foo</title>
   </head>   
   <body>
      <h1>bar</h1><img src="baz.jpg"></img></body>  
</html>

因此,要么您正在做与您所说的不同的事情(例如,使用不同的样式表或与所示的不同的源文档),或者您正在使用的XSLT处理器中存在错误。