2010-10-17 75 views
4

我想使用XSLT樣式錶轉換XHTML,但我甚至無法獲得基本樣式表以匹配任何內容。我確定我錯過了一些簡單的東西。xsltproc不會按名稱選擇元素

這裏是我的XHTML源文件(沒有大的意外):

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml"> 
<head> 
<meta name="generator" content= 
"HTML Tidy for Windows (vers 25 March 2009), see www.w3.org" /> 
... 
</body> 
</html> 

實際內容並不太大的關係,因爲我將在下面展示。順便說一句,我很確定這個文檔是完整的,因爲它是通過tidy -asxml創建的。

我更復雜的XPath表達式不返回任何結果,所以作爲一個理智的測試,我想非常簡單地使用下面的樣式錶轉換它:

<?xml version="1.0"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="text" omit-xml-declaration="yes" indent="no"/> 
    <xsl:template match="/"> 
     <xsl:text>---[</xsl:text> 
     <xsl:for-each select="html"> 
      <xsl:text>Found HTML element.</xsl:text> 
     </xsl:for-each> 
     <xsl:text>]---</xsl:text> 
    </xsl:template> 
</xsl:stylesheet> 

轉換是通過xsltproc --nonet stylesheet.xsl input.html完成,輸出是:「--- [] ---」(即它沒有找到html的子元素)。但是,如果我改變for-each部分:

<xsl:for-each select="*"> 
    <xsl:value-of select="name()"/> 
</xsl:for-each> 

然後我得到 「--- [HTML] ---」。同樣,如果我使用for-each select="*/*",我會得到「--- [headbody] ---」,正如我所期望的那樣。

爲什麼它可以通過*(與name()給出正確的名稱)找到子元素,但它不會直接使用元素名稱找到它?

回答

6

源XML中的html元素定義了一個名稱空間。你必須把它列入你的對手錶達,並在您xsl:stylesheet元素引用它:

<?xml version="1.0"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:html="http://www.w3.org/1999/xhtml"> 
    <xsl:output method="text" omit-xml-declaration="yes" indent="no"/> 
    <xsl:template match="/"> 
     <xsl:text>---[</xsl:text> 
     <xsl:for-each select="html:html"> 
      <xsl:text>Found HTML element.</xsl:text> 
     </xsl:for-each> 
     <xsl:text>]---</xsl:text> 
    </xsl:template> 
</xsl:stylesheet> 
+0

如果我這樣做,我得到「的XPath錯誤:未定義命名空間前綴」。我是否需要在樣式表中添加一些內容來說明如何解析名稱空間? – Tadmas 2010-10-17 18:57:46

+1

HTML名稱空間也需要在樣式表中聲明。通常,在樣式表的文檔元素上:'」,但它也可以在for-each元素上聲明:'' – 2010-10-17 19:02:26

+0

對不起,忘記了'xsl:stylesheet'元素中的命名空間參考。我更新了我的答案。 – 2010-10-17 19:04:06

4

更改樣式表:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="text" omit-xml-declaration="yes" indent="no"/> 
    <xsl:template match="/"> 
     <xsl:text>---[</xsl:text> 
     <xsl:for-each select="html"> 
      <xsl:text>Found HTML element.</xsl:text> 
     </xsl:for-each> 
     <xsl:text>]---</xsl:text> 
    </xsl:template> 
</xsl:stylesheet> 

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:x="http://www.w3.org/1999/xhtml" 
> 
    <xsl:output method="text" omit-xml-declaration="yes" indent="no"/> 
    <xsl:template match="/"> 
     <xsl:text>---[</xsl:text> 
     <xsl:for-each select="x:html"> 
      <xsl:text>Found HTML element.</xsl:text> 
     </xsl:for-each> 
     <xsl:text>]---</xsl:text> 
    </xsl:template> 
</xsl:stylesheet> 

說明

XML文檔聲明瞭一個默認名稱空間:,並且從聲明該默認名稱空間的頂層元素下降的所有無前綴的節點屬於此名稱空間。

另一方面,在XPath中,沒有前綴的名稱被認爲屬於「no namespace」。

因此,<xsl:for-each select="html">指令將選擇它的機身適用於屬於「沒有命名空間」的所有html元素 - 有在文檔中沒有這樣的 - 唯一html元素不屬於XHTML命名空間。

解決方案

的名字屬於一個默認的命名空間不能被引用前綴的。因此,我們需要將一個前綴綁定到該元素所屬的名稱空間。如果這個前綴是"x:",那麼我們可以引用任何這樣的元素前綴"x:"

0

不聲明命名空間,從而使樣式表接受任何命名空間的解決方法:

<xsl:template match="*[name()='html']" >