Dynamic doctype in XSLT transform (correct use of result-document instruction)
I'm using XSLT and need to generate the doctype dynamically in the transformed output, based on a parameter. I hear that this cann't be done using XSLT 1.0, but can with version 2.0, using the result-document tag.
So far, from following the answer in this question, I have something like this:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="html" indent="yes"/>
<xsl:param name="doctype.system" select="'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'" />
<xsl:param name="doctype.public" select="'-//W3C//DTD XHTML 1.0 Strict//EN'" />
<xsl:template match="/">
<xsl:result-document doctype-public="{$doctype.public}" doctype-system="{$doctype.system}" method="html">
<html>
<head>
<xsl:apply-templates select="report/head/node()"/>
</head>
开发者_运维问答 <body>
<!-- ommitted for brevity -->
</body>
</html>
</xsl:result-document>
</xsl:template>
</xsl:stylesheet>
The problem with the above is no output is generated!
If I remove the results-document tags from the above, my transform is applied and a document is output, as expected.
Any clues? Am I using the result-document tag correctly?
UPDATE: In response to some of the comments here's a small version that works, and one that doesn't (omitting the parameterisation of the result-document instruction)
This works (no result-document):
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="html" indent="yes"/>
<xsl:template match="/">
<html>
<head>
</head>
<body>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Output:
<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body></body>
</html>
But this produces no output:
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="html" indent="yes"/>
<xsl:template match="/">
<xsl:result-document doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" method="html">
<html>
<head>
</head>
<body>
</body>
</html>
</xsl:result-document>
</xsl:template>
</xsl:stylesheet>
As you also found out, Xalan only supports XSLT 1.0, but if you've changed to Saxon 9, you could easily achive what you want.
Also, instead of defining parameters with your doctype settings, you could define a xsl:output
with a name and use as a format in xsl:result-document
:
<xsl:output name="my-xhtml-output" method="xml" encoding="UTF-8" indent="yes"
doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN"
doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"/>
In your xsl:result-document
you then use this output format:
<xsl:result-document href="{$filename}" format="my-xhtml-output">
...
</xsl:result-document>
Imo, this makes it easier to maintain different output formats if you have lots of them.
As you are using an XSLT 1.0 engine you will have to create the dynamic DOCTYPE using xsl:text
:
<?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" indent="yes" />
<xsl:param name="doctype.system" select="'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'" />
<xsl:param name="doctype.public" select="'-//W3C//DTD XHTML 1.0 Strict//EN'" />
<xsl:template match="/">
<xsl:text disable-output-escaping='yes'><!DOCTYPE html PUBLIC "</xsl:text>
<xsl:value-of select="$doctype.public" />
<xsl:text disable-output-escaping='yes'>" "</xsl:text>
<xsl:value-of select="$doctype.system" />
<xsl:text disable-output-escaping='yes'>"></xsl:text>
<!-- further processing here -->
<html>
</html>
</xsl:template>
</xsl:stylesheet>
精彩评论