2010-10-17 8 views
4

J'essaye de transformer XHTML en utilisant une feuille de style XSLT, mais je ne peux même pas obtenir une feuille de style de base pour correspondre à quoi que ce soit. Je suis sûr qu'il me manque quelque chose de simple.xsltproc ne sélectionne pas les éléments par leur nom

Voici mon document source XHTML (pas de grandes surprises):

<!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> 

Le contenu réel ne pas trop d'importance, que je vais démontrer ci-dessous. En passant, je suis sûr que le document est bien formé puisqu'il a été créé via tidy -asxml.

Mes plus complexes expressions XPath ne revenaient pas de résultats, donc comme un test de bon sens, je suis en train de transformer très simplement en utilisant la feuille de style suivante:

<?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> 

La transformation se fait via xsltproc --nonet stylesheet.xsl input.html, et la sortie est: "--- [] ---" (ie, il n'a pas trouvé d'élément enfant de html). Cependant, si je change la section for-each à:

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

Puis-je obtenir "--- [html] ---". Et de même, si j'utilise for-each select="*/*" je reçois "--- [headbody] ---" comme je m'y attendais.

Pourquoi peut-il trouver l'élément enfant via * (avec name() donnant le nom correct) mais il ne le trouvera pas en utilisant directement le nom de l'élément?

Répondre

6

L'élément html dans votre source XML définit un espace de noms. Vous devez inclure dans votre expression de correspondance et la référence dans votre élément 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

Si je fais ça, je reçois "erreur XPath: namespace prefix non défini". Ai-je besoin d'ajouter quelque chose à la feuille de style pour dire comment résoudre l'espace de noms? – Tadmas

+1

L'espace de noms HTML devra également être déclaré dans la feuille de style. Généralement, sur l'élément de document de la feuille de style: '', mais il peut aussi être déclaré sur l'élément for-each: '' –

+0

Désolé, nous avons oublié la référence d'espace de noms dans l'élément 'xsl: stylesheet'. J'ai mis à jour ma réponse. –

4

Changer votre feuille de style:

<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> 

Explication:

Le document XML a déclaré un espace de noms par défaut: , et tous les nœuds non préfixés qui descendent de l'élément supérieur déclarant cet espace de noms par défaut appartiennent à cet espace de noms. De l'autre côté, dans XPath, tout nom non préfixé est considéré comme appartenant à "aucun espace de noms".

Par conséquent, l'instruction <xsl:for-each select="html"> choisira et appliquer son corps à tous html éléments qui appartiennent à « aucun espace de noms » - et il n'y en a pas comme dans le document - le seul élément html n'appartient à l'espace de noms xhtml.

Solution:

Les noms qui appartiennent à un espace de noms par défaut ne peut être référencé sans préfixe. Par conséquent, nous devons lier un préfixe à l'espace de noms auquel un élément appartient.Si ce préfixe est "x:", alors nous pouvons référencer un tel élément préfixé avec "x:".

0

Une solution de contournement sans déclarer l'espace de noms, de sorte que la feuille de style accepte tout espace de noms:

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