Problème de balises à fermeture automatique XSLT
J'utilise xslt pour transformer un fichier xml en html. Le moteur. net xslt continue de me servir des balises à fermeture automatique pour les balises vides.
Exemple:
<div class="test"></div>
Devient
<div class="test" />
Le premier est html valide, tandis que le second est HTML illégal et rend mal. Ma question Est : Comment puis-je dire au moteur xslt (XslCompiledTransform) de ne pas utiliser de balises à fermeture automatique.
Si ce n'est pas possible, Comment puis-je dire à mon navigateur (IE6+ dans ce cas) d'interpréter les balises à fermeture automatique correctement.
11 réponses
Si vous utilisez XmlWriter comme flux de sortie, utilisez plutôt HTMLTextWriter. XMLWriter reformatera votre sortie HTML en XML.
Changez votre méthode xsl:output
pour qu'elle soit html
(au lieu de xml
).
, Ou l'ajouter si vous n'avez pas déjà l'élément
<xsl:output method="html"/>
Une solution de contournement peut être d'insérer un élément de commentaire pour forcer la génération de fermeture non automatique:
<script type="text/javascript" src="nowhere.js">
<xsl:comment></xsl:comment>
</script>
Ce n'est pas une jolie soloution, mais ça marche: -)
/ Sten
Ceci est lié à la classe XslCompiledTransform
Voici une solution de contournement:
Vous ne pouvez pas dire à votre navigateur de gérer le HTML invalide en tant que HTML - vous avez de la chance qu'il comprenne du HTML malformé. :)
Certainement le faire dans votre feuille de style:
<xsl:output method="html"/>
Mais, si votre document source a des espaces de noms, cela ne fera pas l'affaire. Les processeurs XSLT semblent changer silencieusement la méthode de sortie en XML si des nœuds d'espace de noms sont présents dans la sortie.
Vous devez remplacer toutes les instances de <xsl:copy-of>
et <xsl:copy>
par des créations d'éléments avec juste le nom local, par exemple
<xsl:template match="*">
<xsl:element name="{local-name()}">
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
Voir
- http://www.biglist.com/lists/xsl-list/archives/200708/msg00538.html
- http://www.stylusstudio.com/xsllist/200509/post90860.html
- http://www.richardhallgren.com/removing-namespace-from-outgoing-messages/
Etc.
Pour moi, c'était un problème dans le script balise. Je l'ai résolu en le remplissant avec un point-virgule (;)
<script type="text/javascript" src="somewhere.js">;</script>
J'avais l'habitude de mettre un élément <xsl:text>
à l'intérieur, comme:
<script type="text/javascript" src="/scripts/jquery.js"><xsl:text> </xsl:text></script>
Il y a quelques choses que vous devez faire attention:
- dans votre utilisation xsl
- Définissez OutputSettings dans votre sortie XmlWriter
- dans le code Html de votre xsl, Ne définissez pas d'attributs dans la balise html comme ceci mais utilisez à la place.
Ceci est un morceau de code de travail:
string xmlStr = "<?xml version='1.0' encoding='UTF-8'?><Data></Data>";
XmlDocument doc = new XmlDocument();
doc.LoadXml(xmlStr);
string xslContents = @"
<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
xmlns:msxsl='urn:schemas-microsoft-com:xslt' exclude-result-prefixes='msxsl'>
<xsl:output method='html' version='4.0' omit-xml-declaration='yes' indent='yes'/>
<xsl:template match='Data'>
<html>
<body>
<div></div>
</body>
</html>
</xsl:template>
</xsl:stylesheet>";
XslCompiledTransform xsl = new XslCompiledTransform();
xsl.Load(XmlReader.Create(new StringReader(xslContents)));
StringWriter result = new StringWriter();
using (XmlWriter writer = XmlWriter.Create(result, xsl.OutputSettings))
{
xsl.Transform(doc, null, writer);
}
System.Diagnostics.Debug.Write( result.ToString());
Vient de rencontrer le même problème avec le XSL de PHP 5, avec output / @ method = html. Il semble que l'attribution d'un attribut de valeur vide entraînera la sortie d'éléments en tant que balises non-fermées non-fermées et non-fermées:
<input type="text" name="foo" value="{my-empty-value}" />
Résultats dans:
<input type="text" name="foo" value="">
Une solution possible consiste à ajouter conditionnellement l'attribut:
<xsl:if test="string-length(my-empty-value) > 0">
<xsl:attribute name="value">
<xsl:value-of select="my-empty-value" />
</xsl:attribute>
</xsl:if>
Résultant en:
<input type="text" name="foo" />
J'utilise ce qui suit chaque fois que je souhaite empêcher un élément de fermeture automatique:
<xsl:value-of select="''" />
Cela trompe le moteur de rendu en croyant qu'il y a du contenu à l'intérieur de l'élément, et empêche donc l'auto-fermeture.
C'est un peu une solution laide donc je recommande de le contenir dans un modèle descriptif et de l'appeler à chaque fois:
<xsl:template name="PreventSelfClosure">
<xsl:value-of select="''" />
</xsl:template>
<div class="test">
<xsl:call-template name="PreventSelfClosure"/>
</div>
Cela rendra alors le suivant:
<div class="test"></div>
Http://curtistimson.co.uk/post/xslt/how-to-prevent-self-closing-elements-in-xslt/
Le moyen simple que j'ai trouvé était de créer une nouvelle classe XmlTextWriter pour remplacer la méthode WriteEndElement, forçant la balise non fermante et transmettre le processus de sérialisation en tant que paramètre.
public class MyXmlTextWriter : XmlTextWriter
{
public MyXmlTextWriter(Stream stream) : base(stream, Encoding.UTF8)
{ }
public MyXmlTextWriter(TextWriter stream) : base(stream)
{ }
public override void WriteEndElement()
{
base.WriteFullEndElement();
}
}