Clientside XSLT in Mozilla/Firefox fails - xslt

I have a result document that renders in Chrome, but not Mozilla/Firefox.
I believe it is because there is top level leading whitespace (two blank lines before the <!DOCTYPE html).
How can I change this transform to not have leading whitespace (fiddle)?
XML:
<?xml-stylesheet href="/css/my.xsl" type="text/xsl"?>
<webpage>
<title>Book</title>
<auth>Mike</auth>
<container-content>
<p>foo1</p>
<p>foo2</p>
</container-content>
</webpage>
XSLT:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="1.0">
<xsl:output
method="xml"
indent="yes"
encoding="UTF-8"
omit-xml-declaration="yes"
doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN"/>
<xsl:strip-space elements="*"/>
<xsl:template match="text()"/>
<xsl:template match="/">
<html>
<head>
<meta http-equiv="Content-Type"
content="text/html; charset=utf-8"/>
</head>
<body>
<xsl:copy-of select="//container-content/*"/>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Result:
- a blank line here -
- and here -
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
</head>
<body>
<p>foo1</p>
<p>foo2</p>
</body>
</html>
Alternatively, I may be incorrect, and the two blank lines are not the cause of the failed render in Mozilla/Firefox. I have a hard time troubleshooting client side transforms.
Side note: I've developed in Saxon 6.5, thinking Saxon best approximates what browsers do. I could be wrong. I note Xalan does not put in leading whitespace.

I just ran your stylesheet with Saxon 6.5 and indeed, it outputs two blank lines, which are removed if you change the xsl:output to be without indentation and with xml declaration. However, I believe this to be a bug in Saxon 6.5 (a small one, as the whitespace is not significant).
Running it with other XSLT 1.0 processors show no whitepace. However, as said in my comment, the whitespace is insignificant, as browsers do not serialize anyway. (note: apparently, browsers do some kind of serialization, in the sense that they look to whether you use XML or HTML output).
I ran your example with Firefox and it "just works". Since your stylesheet does a simple copy of the XML, it shows just the text. If I change the xsl:output to HTML and add a few lines to be sure I am running it correctly (I added an <h1>Hello</h1>, it shows the HTML.
I'm not sure what you expect the browser to show, but my guess is not XML, but (X)HTML. XSLT 1.0 is not very good with XHTML (it is supported in XSLT 2.0, but that is not supported by browsers), but works fine with HTML.
I modified your stylesheet as follows:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="1.0">
<xsl:strip-space elements="*"/>
<xsl:template match="text()"/>
<xsl:template match="/">
<html>
<head />
<body>
<xsl:apply-templates />
</body>
</html>
</xsl:template>
<xsl:template match="title">
<h1><xsl:value-of select="."/></h1>
</xsl:template>
<xsl:template match="auth">
<p>Author: <xsl:value-of select="." /></p>
</xsl:template>
</xsl:stylesheet>
And in Firefox and Chrome it renders as follows:
Note (1): if you do not run it from a web server (either local or remote), it will not run in either Firefox or Chrome because of security restrictions.
Note (2): to view the rendered XML or HTML, use the Inspect Element feature of the developer tools of either Chrome or Firefox.
Note (3): you do not need to use the meta-tag, as the specification requires this meta tag to be output as soon as it recognizes that HTML is output.
Note (4) if you are unsure whether or not Firefox is loading your stylesheet correctly, have a look using Firebug, it should show something like this (mark the "200 OK"):

If you want to transform to XHTML then you need to make sure you use the XHTML namespace for your result elements so put
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.w3.org/1999/xhtml"
version="1.0">
on your stylesheet, as otherwise with output method xml your elements in no namespace are not recognized as XHTML elements by Mozilla.
As your input p elements are also in no namespace you can not copy them through but have to write a template for them
<xsl:template match="*">
<xsl:element name="{local-name()}"><!-- assumes you have the namespace declaration suggested above -->
<xsl:apply-templates/>
</xsl:element>
</xsl:template>
and then use <xsl:apply-templates select="//container-content/*"/> instead of the copy-of. And in that case the <xsl:template match="text()"/> needs to be removed as otherwise the text of the transformed p elements would not show up.

Related

Why doesn't my SVG display when I try to use the XSLT output method "html"?

Apologies if this is a simple question as I'm fairly novice at XSLT. I'm having an issue where the SVG image I'm generating in XSLT won't display if my output method is set to html. If I open the desired xml file, transform it, and view it in browser (IE v11), the whole document loads with exception to the SVG image itself. In IE, if I right click the document and select "view source" I can see the SVG information sitting there, right where its expected to be.
If I set the output method to xml and open in IE, the SVG images do appear but the document structure isn't there (but to reiterate: the goal is to output in html as it's used in other processes further down the line)
Below is a snippet of a small, simple testing XSLT and the post transformation xml seen from "view source" (leaving out unrelated stuff). I'm trying to get this working on a small scale before I tackle the larger picture.
Also to note, the svg:text tag does display the text mentioned, although it seems more like a simple text entry than part of an image.
For those familiar with it, the majority of functionality comes from RenderX's XSLT barcode generator.
XSLT:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
xmlns="http://www.w3.org/1999/xhtml" xmlns:svg="http://www.w3.org/2000/svg">
<xsl:import href="code128.xsl"/>
<xsl:output method='html' media-type="image/svg" encoding='UTF-8' indent='yes'/>
<xsl:template match="/">
<html lang="en">
<head>
<title>SVG bar code examples</title>
</head>
<body>
<h1>SVG bar code examples</h1>
<ul>
<xsl:apply-templates select="//barcode"/>
</ul>
</body>
</html>
</xsl:template>
<xsl:template match="barcode">
<li>
<xsl:call-template name="barcode-code128">
.
<!--Parameters here-->
.
</xsl:call-template>
</li>
</xsl:template>
</xsl:stylesheet>
Post Transformation XML:
<?xml version="1.0" encoding="utf-8"?>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:svg="http://www.w3.org/2000/svg">
<head>
<title>SVG bar code examples</title>
</head>
<body>
<h1>SVG bar code examples</h1>
<ul>
<li>
<svg:svg width="29.494444444444443mm" height="12.7mm" viewBox="0 0 10618 4572">
<svg:path d="M 686 686 l 0 2286 138 0 0 -2286 z m ..."(truncated due to length)>
<svg:text x="6068" y="4420" text-anchor="middle" font-family=...
</svg:svg>
</li>
.
<!--More SVG images here-->
.
</ul>
</body>
</html>
If you want to use the output method html then you should use HTML syntax and neither HTML 4 nor HTML5 or what is simply called HTML now supports namespaces, in particular not prefixed element names. So for your SVG elements to be recognized in text/html you need simply svg, path and text as the element names without any prefix, the only allowed "namespace" declaration would be xmlns="http://www.w3.org/2000/svg" on the svg element.
I am also not sure about IE's SVG support, perhaps it is only enabled in standards compliant rendering mode, meaning, for method="html" it is recommended to have <xsl:output method="html" indent="yes" version="5" doctype-system="about:legacy-doctype"/>, as that doctype-system is supposed to set older browsers distinguishing between quirks mode and standard compliant mode to the latter mode.
If your used library creates prefixed elements then you would need to run them through an additional transformation step to strip the namespace prefix which, in a single transformation, is in XSLT 1 only possible using a proprietary extension function to convert a result tree fragment into a node-set:
<xsl:template match="barcode">
<li>
<xsl:variable name="barcode-rtf">
<xsl:call-template name="barcode-code128">
.
<!--Parameters here-->
.
</xsl:call-template>
</xsl:variable>
<xsl:apply-templates select="msxml:node-set($barcode-rtf)/node()" xmlns:msxml="urn:schemas-microsoft-com:xslt" mode="strip-svg-prefix"/>
</li>
</xsl:template>
<xsl:template match="#* | node()" mode="strip-svg-prefix">
<xsl:copy>
<xsl:apply-templates select="#* | node()" mode="strip-svg-prefix"/>
</xsl:copy>
</xsl:template>
<xsl:template match="svg:*" mode="strip-svg-prefix" xmlns:svg="http://www.w3.org/2000/svg">
<xsl:element name="{local-name()}" namespace="http://www.w3.org/2000/svg">
<xsl:apply-templates select="#* | node()" mode="strip-svg-prefix"/>
</xsl:copy>
</xsl:template>
Note that, for text/html and HTML 4 or HTML5 as the transformation target with method="html", I would recommend to use no namespace at all for the HTML elements, i.e. to remove the XHTML namespace declaration you have. Otherwise serialization of empty elements might not give the proper HTML syntax.

xml trans to html with xslt ,but I can't get the value of "version"

Unable to get the value, and I can't find the namespace file for help
<?xml version="1.0" encoding="UTF-8"?>
<xsl:transform version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:an="http://checklist.nist.gov/xcodf/1.1" exclude-result-prefixes="an">
<xsl:output method="html" indent="yes"/>
<xsl:template match="/">
<html>
<body>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<xsl:template match="an:Banchmark">
<h2>My CD Collection</h2>
<h3><xsl:value-of select="an:status"/></h3>
<p><xsl:value-of select="an:version"/></p>
</xsl:template>
</xsl:transform
And output is
<html>
<body>
<h2>My CD Collection</h2>
<h3>draft</h3>
<p>0.6.3</p>
</body>
</html>`enter code here`
You failed to show what you have tried so far, but a far as HTML output is
concerned, you probably should include in your script xsl:output command,
specifying method="html".
One of possible examples, e.g. to generate XHTML output is:
<xsl:output method="html"
doctype-public="-//W3C//DTD XHTML 1.1//EN"
doctype-system= "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"/>
You can give other values for both doctype-... attributes, according to your
needs.
Version attribute is usually not needed, but if for some reason you have to,
you can specify it with version="..." attribute in xsl:output.

Choose XSL transform acoording to document content

I have a large number of XHTML documents which are created by different publishers, determined by a meta tag:
<meta name="citation_publisher" content="ACME publisher"/>
or in a different document
<meta name="citation_publisher" content="BETA publisher"/>
etc.
I have written stylesheets (about 1 page each) such as,
acme.xsl
beta.xsl
etc.
However I do not know the name of the publisher until I read the XHTML file.
It is possible, though very messy, to write a gigantic stylesheet of the form:
<xsl:choose>
<xsl:when test="$publisher='ACME publisher'">
<!-- acme.xsl sheet-->
</xsl:when>
<xsl:when test="$publisher='BETA publisher'">
<!-- beta.xsl sheet-->
</xsl:when>
</xsl:choose>
but there are at least 100 XSL files.
Is there any way, in XSL1, to select the stylesheet chunk according to the publisher? It would be nice to have the stylesheets as separate files and <xsl:import> them rather than have a single huge file.
UPDATE:
I think #Dimitre has answered the question correctly (and so I have accepted). I suspect that #MichaelKay's is actually better , but it does depend on having a pipeline managing the transformer. I shall try the <xsl:include> as a prototype and see whether it has downsides.
I wouldn't attempt to do this within a single XSLT stylesheet. It sounds to me like a good candidate for XProc, or some similar pipeline technology (e.g. Orbeon). Step 1, use XPath to classify the document, Step 2, transform it using the stylesheet chosen according to the results of Step 1.
but there are at least 100 XSL files. Is there any way, in XSL1, to
select the stylesheet chunk according to the publisher? It would be
nice to have the stylesheets as separate files and <xsl:import> them
rather than have a single huge file.
Here is one way to do this (I am showing working just with two content publisher types and this can be done for as many as needed):
Primary stylesheet:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:import href="unknown.xsl"/>
<xsl:import href="acme.xsl"/>
<xsl:import href="beta.xsl"/>
</xsl:stylesheet>
acme.xsl:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/*[meta[#content='ACME publisher']]">
<xsl:value-of select="x * y"/>
</xsl:template>
</xsl:stylesheet>
beta.xsl:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/*[meta[#content='BETA publisher']]">
<xsl:value-of select="x + y"/>
</xsl:template>
</xsl:stylesheet>
unknown.xsl:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="/*">
<xsl:message terminate="yes">Error: Unknown content source</xsl:message>
</xsl:template>
</xsl:stylesheet>
When the transformation specified in the primary stylesheet is applied on this XML document:
acme.xml:
<t>
<meta name="citation_publisher" content="ACME publisher"/>
<x>6</x>
<y>4</y>
</t>
the wanted, correct result (x*y) is produced:
24
When the same transformation is applied on this XML document:
beta.xml:
<t>
<meta name="citation_publisher" content="BETA publisher"/>
<x>6</x>
<y>4</y>
</t>
again the correct result (x+y) is produced:
10
Finally, when the same transformation is applied on this XML document:
other.xml:
<t>
<meta name="citation_publisher" content="OTHER publisher"/>
<x>6</x>
<y>4</y>
</t>
the result of the transformation is the wanted termination with error message:
Error: Unknown content source
Processing terminated by xsl:message at line 5

Generate html from xsl without DOCTYPE

Is it possible to generate html-output with xsl that has no doctype added to the output? If I don´t set any doctype myself it produces one on its own.
EDIT :
Since I don´t think that this is possible, I solved my problem bysimply cutting away the DOCTYPE after the html is generated with followiing regex: '<&!DOCTYPE[^>]*>'
Quickly tested with Saxon, yes this is possible...I'm not sure what xslt library you're using so it could be a symptom of that.
If I use Saxon to run this transform against ANY xml file (which generates a minimum viable HTML5 document, minus DOCTYPE) :
<?xml version="1.0" encoding="utf-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" encoding="iso-8859-1" indent="yes"/>
<xsl:template match="/">
<html>
<head>
<title>Test</title>
</head>
<body>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
I get this output :
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>Test</title>
</head>
<body></body>
</html>

xslt import/include 2 files with the same template

I've got an interesting question on XSLT import/include.
I have 2 XSLT files with the same rule.
Receipt XSLT: (is run by itself)
<xsl:template match="Booking" mode="extraStyle">
<link rel="stylesheet" href="../css/receipt.css" type="text/css" media="screen"/>
</xsl:template>
EmailCommon XSLT: (serves as template library for Email docs, isn't run by itself)
<xsl:template match="Booking" mode="extraStyle">
<link rel="stylesheet" href="../css/email.css" type="text/css" media="screen"/>
</xsl:template>
So that depending on the document type I insert correct CSS files.
What I'm trying to do is to include these two documents into yet another XSLT:
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
exclude-result-prefixes="msxsl"
version="1.0">
<xsl:include href="receipt.xsl"/>
<xsl:include href="email.xsl"/>
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
Nevertheless, because the rules are the same in both included stylesheets it boils down to the Last-in-first rule and I end up only including email.css.
I was wondering if something smart could be done in this case?
The only thing I was thinking is to using different mode, but then it wouldn't be as intuitive, rather then accumalate the code of all identical rules. Don't know how and whether at all it could be done in XSLT.
Thanks for help!
P.S. Sorry, I'm really trying to understand the formating rules on this site, but I simply can't :( gggrrr
I think making the template modes different is your best option.
<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:include href="receipt.xsl"/>
<xsl:include href="email.xsl"/>
<xsl:template match="Booking">
<xsl:apply-templates select="." mode="extraStyleReceipt" />
<xsl:apply-templates select="." mode="extraStyleEmail" />
</xsl:template>
</xsl:stylesheet>