copy-of with search and replace relative paths - xslt

I want to insert an html snippet from an external file into my output document with copy-of like described here: https://stackoverflow.com/a/5976762/18427492
The html snipped is a navigation bar and also used by other (python) scripts to generate other html files.
I need to replace the path in "href" to match a relative path that i have in a XSLT variable.
Full file content (Template file to be copied):
<ul class="nav">
<li class="fineprint">MyNiceGame Developer Mode Documentation</li>
<li class="switchlang"><img src="/deco/dco_en_sml.gif" alt="English" border="0"></img></li>
<li>Introduction</li>
<li>Contents</li>
<li>Search</li>
<li>Engine</li>
<li>Command Line</li>
<li>Game Data</li>
<li>Script</li>
</ul>
So how can i insert this snippet into my XSL document and replace ../../sdk/ (its possible to change this string to something like {replace-me}/sdk/...) with a relative path that i already have in a XSLT variable?
My XSLT document (i want to replace the <xsl:call-template name="nav"/> with the template file processing):
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" version="3.0" xpath-default-namespace="https://clonkspot.org" exclude-result-prefixes="xs">
<xsl:output method="html" encoding="ISO-8859-1" doctype-public="-//W3C//DTD HTML 4.01//EN"
doctype-system="http://www.w3.org/TR/html4/strict.dtd"/>
<xsl:template match="/clonkDoc">
<html>
<body>
<xsl:call-template name="nav"/>
<xsl:apply-templates select="func"/>
<!-- other possible nodes under /clonkDoc -->
<xsl:call-template name="nav"/>
</body>
</html>
</xsl:template>
<xsl:template name="nav">
<xsl:param name="relpath" tunnel="yes"/>
<ul class="nav">
<li class="fineprint">
<xsl:when test='lang("en")'>>MyNiceGame Developer Mode Documentation</xsl:when>
</li>
<!-- Other li elements -->
</xsl:template>
Example source file:
<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?>
<?xml-stylesheet type="text/xsl" href="../../../clonk.xsl"?>
<clonkDoc xmlns="https://clonkspot.org"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://clonkspot.org ../../../clonk.xsd" xml:lang="de">
<func>
<!-- other nodes -->
</func>
</clonkDoc>
Desired target file:
<!DOCTYPE html
PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<!-- stuff -->
</head>
<body>
<ul class="nav">
<!-- The corrected li elements with modified a href link -->
</ul>
<!-- Other stuff from source file (<func>) -->
<ul class="nav">
<!-- The corrected li elements with modified a href link -->
</ul>
</body>
</html>
Martin Honnen's solution for my specific case with the xpath-default-namespace:
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" version="3.0" xpath-default-namespace="https://clonkspot.org" exclude-result-prefixes="xs">
<xsl:output method="html" encoding="ISO-8859-1" doctype-public="-//W3C//DTD HTML 4.01//EN"
doctype-system="http://www.w3.org/TR/html4/strict.dtd"/>
<xsl:template match="/clonkDoc">
<html>
<body>
<xsl:apply-templates select="doc('file.html')//ul[#class = 'nav']" xpath-default-namespace="" mode="fix-links"/>
<xsl:apply-templates select="func"/>
<!-- other possible nodes under /clonkDoc -->
<xsl:apply-templates select="doc('file.html')//ul[#class = 'nav']" xpath-default-namespace="" mode="fix-links"/>
</body>
</html>
</xsl:template>
<xsl:mode name="fix-links" on-no-match="shallow-copy"/>
<xsl:template mode="fix-links" match="ul/li/a/#href" xpath-default-namespace="">
<xsl:message>Value href: <xsl:value-of select="."></xsl:value-of></xsl:message>
<xsl:attribute name="{name()}" select="replace(., '../../sdk', 'foobar')"/>
</xsl:template>

copy-of makes a a deep copy, if you want to transform input nodes (even only their attribute values) you write templates to do so e.g. <xsl:apply-templates select="doc('file.xml')//ul[#class = 'nav']" mode="fix-links"/>, or, perhaps, as the edit says the snippet with the ul is all in the file, use simply <xsl:apply-templates select="doc('file.xml')" mode="fix-links"/>, and
<xsl:mode name="fix-links" on-no-match="shallow-copy"/>
<xsl:template mode="fix-links" match="ul/li/a/#href">
<xsl:attribute name="{name()}" select="replace(., '../../sdk', $varname)"/>
</xsl:template>
The xsl:mode declaration is XSLT 3 only, in earlier versions declare the identity transformation for that mode e.g.
<xsl:template mode="fix-links" match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()" mode="fix-links"/>
</xsl:copy>
</xsl:template>
in XSLT 1 or
<xsl:template mode="fix-links" match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()" mode="#current"/>
</xsl:copy>
</xsl:template>
in XSLT 2.
XSLT 3 sample (slighly adapted for the demonstration to work with the primary input) outputs
<ul class="nav">
<li class="fineprint">MyNiceGame Developer Mode Documentation</li>
<li class="switchlang"><img src="/deco/dco_de_sml.gif" alt="German" border="0"/></li>
<li>Introduction</li>
<li>Contents</li>
<li>Search</li>
<li>Engine</li>
<li>Command Line</li>
<li>Game Data</li>
<li>Script</li>
</ul>
As for the information in the latest edit that the secondary input document you want to process has elements in no namespace but your primary one has elements in a certain namespace that your XSLT has used as the xpath-default-namespace, in that case you need to override that for any selections in the secondary input e.g.
<xsl:mode name="fix-links" on-no-match="shallow-copy"/>
<xsl:template mode="fix-links" match="ul/li/a/#href" xpath-default-namespace="">
<xsl:attribute name="{name()}" select="replace(., '../../sdk', $varname)"/>
</xsl:template>
and if you continue to use the apply-templates with an element selector, there as well e.g. <xsl:apply-templates select="doc('file.xml')//ul[#class = 'nav']" xpath-default-namespace="" mode="fix-links"/>.

Related

XSLT disable-output-escaping but allow some entities

I have the following xslt to output comments but it is vulnerable to XSS if I disable all output escaping.
<xsl:value-of disable-output-escaping="yes" select="//datafor:field[datafor:name='comments']/datafor:value" />
How can I allow only the following html attributes so that I can retain some formating in the rendered output?
'b,strong,i,ul,ol,li,p,br,p[style]',div,div[class]'
Or, using SaxonJS, in the browser, you could call into JavaScript to parse the HTML fragment and process it e.g.
function parseHTML(html) {
return new DOMParser().parseFromString(html, 'text/html');
}
const xml = `<orders>
<order>
<id>o1</id>
<date>2022-06-12</date>
<comments><![CDATA[I want the following extras: <ol>
<li>32 GB RAM</li>
<li>1000 GB SSD</li>
]]></comments>
</order>
</orders>`;
const xslt = `<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.w3.org/1999/xhtml"
version="3.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
xmlns:js="http://saxonica.com/ns/globalJS"
expand-text="yes">
<xsl:mode name="html"/>
<xsl:template mode="html" match="b | strong | i | ul | ol | li | p | br | p | div | p/#style | div/#class" xpath-default-namespace="http://www.w3.org/1999/xhtml">
<xsl:copy>
<xsl:apply-templates select="#* | node()" mode="#current"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<html>
<head>
<title>Test</title>
</head>
<body>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<xsl:template match="orders">
<h1>Orders</h1>
<xsl:where-populated>
<ol>
<xsl:apply-templates/>
</ol>
</xsl:where-populated>
</xsl:template>
<xsl:template match="order">
<li>Order {id} from {format-date(date, '[D] [M] [Y0000]')}
<div>
<h2>Comments</h2>
<div>
<xsl:apply-templates select="js:parseHTML(string(comments))" mode="html"/>
</div>
</div></li>
</xsl:template>
</xsl:stylesheet>`;
const result = SaxonJS.XPath.evaluate(`transform(map {
'stylesheet-text' : $xslt,
'source-node' : parse-xml($xml)
}
)?output/*/*/node()`,
[],
{ params : {
xslt: xslt,
xml: xml
}
}
);
document.body.append(...result);
<script src="https://martin-honnen.github.io/xslt3fiddle/js/SaxonJS2.js"></script>
With the XSLT implementation of an HTML tag soup parser by David Carlisle it would be
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.w3.org/1999/xhtml"
version="3.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
xmlns:d="data:,dpc"
xmlns:js="http://saxonica.com/ns/globalJS"
expand-text="yes">
<xsl:import href="https://github.com/davidcarlisle/web-xslt/raw/main/htmlparse/htmlparse.xsl"/>
<xsl:mode name="html"/>
<xsl:template mode="html" match="b | strong | i | ul | ol | li | p | br | p | div | p/#style | div/#class" xpath-default-namespace="http://www.w3.org/1999/xhtml">
<xsl:copy>
<xsl:apply-templates select="#* | node()" mode="#current"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<html>
<head>
<title>Test</title>
</head>
<body>
<xsl:apply-templates/>
</body>
</html>
</xsl:template>
<xsl:template match="orders">
<h1>Orders</h1>
<xsl:where-populated>
<ol>
<xsl:apply-templates/>
</ol>
</xsl:where-populated>
</xsl:template>
<xsl:template match="order">
<li>Order {id} from {format-date(date, '[D] [M] [Y0000]')}
<div>
<h2>Comments</h2>
<div>
<xsl:apply-templates select="d:htmlparse(comments)" mode="html"/>
</div>
</div></li>
</xsl:template>
</xsl:stylesheet>
Online sample.
The current samples copy only the listed elements but copy any text node through, if elements like e.g. script need to be completely stripped add an empty template <xsl:template mode="html" match="script" xpath-default-namespace="http://www.w3.org/1999/xhtml"/>.
Of course, consider to download the HTML parser module and xsl:import a local file for your own application instead of pulling from github.

How to get data between headers?

I am new to xslt. I want below input to be converted into output shown below:
Input:
<ATTRIBUTE-VALUE>
<THE-VALUE>
<div xmlns="http://www.w3.org/1999/xhtml">
<h1 dir="ltr" id="_1536217498885">Main Description</h1>
Line1 The main description text goes here.
<p>Line2 The main description text goes here.</p>
<p>Line3 The main description text goes here.</p>
<p><img alt="Embedded Image" class="embeddedImageLink" id="_1536739954166" src="_9c3778a0-d596-4eef-85fa-052a5e1b2166.jpg"/></p>
<h1 dir="ltr" id="_1536217498886">Key Consideration</h1>
<p>Line1 The key consideration text goes here.</p>
<p>Line2 The key consideration text goes here.</p>
<h1 dir="ltr" id="_1536217498887">Skills</h1>
<p>Line1 The Skills text goes here.</p>
<p>Line2 The Skills text goes here.</p>
<p>Line3 The Skills text goes here.</p>
<h1 dir="ltr" id="_1536217498888">Synonyms</h1>
<p>The Synonyms text goes here.</p>
</div>
</THE-VALUE>
</ATTRIBUTE-VALUE>
Output should be:
<MainDescription>
<![CDATA[
<p>Line1 The main description text goes here.</p>
<p>Line2 The main description text goes here.</p>
<p>Line3 The main description text goes here.</p>
<p><img alt="Embedded Image" class="embeddedImageLink" id="_1536739954166" src="_9c3778a0-d596-4eef-85fa-052a5e1b2166.jpg"/></p>
]]>
</MainDescription>
<KeyConsiderations>
<![CDATA[
<p>Line1 The key consideration text goes here.</p>
<p>Line2 The key consideration text goes here.</p>
]]>
</KeyConsiderations>
<Skills>
<p>Line1 The Skills text goes here.</p>
<p>Line2 The Skills text goes here.</p>
<p>Line3 The Skills text goes here.</p>
</Skills>
<Synonyms>
<p>The Synonyms text goes here.</p>
</Synonyms>
I want the data between <h1> and it can contain any html tag that should be generated in output. I tried the code at: https://xsltfiddle.liberty-development.net/bdxtqy/2. But it gives the data only if data is included under html tags. Please provide pointers on how to achieve required output.
XSL code:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xhtml="http://www.w3.org/1999/xhtml"
xmlns:exsl="http://exslt.org/common"
exclude-result-prefixes="xhtml exsl"
version="1.0">
<xsl:import href="http://lenzconsulting.com/xml-to-string/xml-to-string.xsl"/>
<xsl:output method="xml" indent="yes"
cdata-section-elements="MainDescription KeyConsideration"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:key name="h1-group" match="xhtml:div/*[not(self::xhtml:h1)]" use="generate-id(preceding-sibling::xhtml:h1[1])"/>
<xsl:template match="xhtml:div[xhtml:h1]">
<xsl:apply-templates select="xhtml:h1"/>
</xsl:template>
<xsl:template match="xhtml:h1">
<xsl:element name="{translate(., ' ', '')}">
<xsl:variable name="rtf-with-xhtml-ns-stripped">
<xsl:apply-templates select="key('h1-group', generate-id())"/>
</xsl:variable>
<xsl:apply-templates select="exsl:node-set($rtf-with-xhtml-ns-stripped)/node()" mode="xml-to-string"/>
</xsl:element>
</xsl:template>
<xsl:template match="xhtml:p">
<p>
<xsl:apply-templates/>
</p>
</xsl:template>
</xsl:stylesheet>
I am getting output as:
<ATTRIBUTE-VALUE>
<THE-VALUE>
<MainDescription><![CDATA[<p>Line2 The main description text goes here.</p><p><img alt="Embedded Image" class="embeddedImageLink" id="_1536739954166" src="_9c3778a0-d596-4eef-85fa-052a5e1b2166.jpg" xmlns="http://www.w3.org/1999/xhtml"/></p>]]></MainDescription>
<KeyConsideration><![CDATA[<p>Line1 The key consideration text goes here.</p><p>Line2 The key consideration text goes here.</p>]]></KeyConsideration>
<Skills><p>Line1 The Skills text goes here.</p><p>Line2 The Skills text goes here.</p><p>Line3 The Skills text goes here.</p></Skills>
<Synonyms />
</THE-VALUE>
</ATTRIBUTE-VALUE>
If you change the code to match on node() instead of * for elements you get the text nodes included:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xhtml="http://www.w3.org/1999/xhtml"
xmlns:exsl="http://exslt.org/common"
exclude-result-prefixes="xhtml exsl"
version="1.0">
<xsl:import href="http://lenzconsulting.com/xml-to-string/xml-to-string.xsl"/>
<xsl:output method="xml" indent="yes"
cdata-section-elements="MainDescription KeyConsideration"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:key name="h1-group" match="xhtml:div/node()[not(self::xhtml:h1)]" use="generate-id(preceding-sibling::xhtml:h1[1])"/>
<xsl:template match="xhtml:div[xhtml:h1]">
<xsl:apply-templates select="xhtml:h1"/>
</xsl:template>
<xsl:template match="xhtml:h1[. = 'Main Description' or . = 'Key Consideration']">
<xsl:element name="{translate(., ' ', '')}">
<xsl:variable name="rtf-with-xhtml-ns-stripped">
<xsl:apply-templates select="key('h1-group', generate-id())"/>
</xsl:variable>
<xsl:apply-templates select="exsl:node-set($rtf-with-xhtml-ns-stripped)/node()" mode="xml-to-string"/>
</xsl:element>
</xsl:template>
<xsl:template match="xhtml:h1">
<xsl:element name="{translate(., ' ', '')}">
<xsl:variable name="rtf-with-xhtml-ns-stripped">
<xsl:apply-templates select="key('h1-group', generate-id())"/>
</xsl:variable>
<xsl:apply-templates select="exsl:node-set($rtf-with-xhtml-ns-stripped)/node()"/>
</xsl:element>
</xsl:template>
<xsl:template match="text()">
<xsl:value-of select="." disable-output-escaping="yes"/>
</xsl:template>
<xsl:template match="xhtml:p">
<p>
<xsl:apply-templates/>
</p>
</xsl:template>
</xsl:stylesheet>
https://xsltfiddle.liberty-development.net/bdxtqy/41
It is not clear when/where you want to wrap plain text like Line1 The main description text goes here. into a p element.
For the CDATA section use of disable-output-escaping I think you need to override the template for text() nodes of the imported xml-to-string stylesheet:
<xsl:template match="text()" mode="xml-to-string">
<xsl:value-of select="." disable-output-escaping="yes"/>
</xsl:template>
https://xsltfiddle.liberty-development.net/bdxtqy/42
I haven't tested whether that breaks anything.

Removing a div tag in variable of xsl file

I have to remove a div(menu) with an ul tag in it. All the data is stored in a variable $data. I have remove that div in that variable through xslt
Before:
<div id="container>
<div id="menu">
<ul>
</ul>
</div>
</div>
After
<div id="container>
</div>
Well if you know there is only the div id="menu" in that container div then you could make a shallow copy of that container div. In general, with XSLT 1.0, a variable will be a result tree fragment, to process it further with XSLT/XPath (other than outputting it with value-of or copy-of) you need to use exsl:node-set on the variable. Then you could process the elements with the identity transformation and a template for the div[#id = 'menu'] that does not process it to delete it (online at http://xsltransform.net/bFN1y9C):
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
xmlns:exsl="http://exslt.org/common" exclude-result-prefixes="exsl">
<xsl:output method="html" indent="yes"/>
<xsl:variable name="data">
<div id="container">
<div id="menu">
<ul>
</ul>
</div>
</div>
</xsl:variable>
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:variable name="data2">
<xsl:apply-templates select="exsl:node-set($data)/node()"/>
</xsl:variable>
<xsl:template match="div[#id = 'menu']"/>
<xsl:template match="/">
<xsl:copy-of select="$data2"/>
</xsl:template>
</xsl:transform>
If you need to perform other transformation steps you might need to separate the different steps by using modes.

how to get a transformed xml file with all child tags of every occurance of parent tag under only one parent tag

I am using this input xml file .
<Content>
<body><text>xxx</text></body>
<body><text>yy</text></body>
<body><text>zz</text></body>
<body><text>kk</text></body>
<body><text>mmm</text></body>
</Content>
after Xslt transformation the output should be
<Content>
<body><text>xxx</text>
<text>yy</text>
<text>zz</text>
<text>kk</text>
<text>mmm</text></body>
</Content>
Can anyone please provide its relavant Xsl file.
This complete transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="body"/>
<xsl:template match="body[1]">
<body>
<xsl:apply-templates select="../body/node()"/>
</body>
</xsl:template>
</xsl:stylesheet>
when applied on the provided XML document:
<Content>
<body>
<text>xxx</text>
</body>
<body>
<text>yy</text>
</body>
<body>
<text>zz</text>
</body>
<body>
<text>kk</text>
</body>
<body>
<text>mmm</text>
</body>
</Content>
produces the wanted, correct result:
<Content>
<body>
<text>xxx</text>
<text>yy</text>
<text>zz</text>
<text>kk</text>
<text>mmm</text>
</body>
</Content>
Explanation:
The identity rule copies every node "as-is".
It is overriden by two templates. The first ignores/deletes every body element`.
The second template overriding the identity template also overrides the first such template (that deletes every body element) for any body element that is the first body child of its parent. For this first body child only, a body element is generated and in its body all nodes that are children nodes of any body child of its parent (the current body elements and all of its body siblings) are processed.
<xsl:template match="Content">
<body>
<xsl:apply-templates select="body/text"/>
</body>
</xsl:template>
<xsl:template match="body/text">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>

Output element in comments

I need to display HTML-element in comments (for example)
<!-- <img src="path" width="100px" height="100px"/> -->
I use this approach
<?xml version="1.0" encoding="windows-1251"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" indent="no" encoding="windows-1251"/>
<xsl:template match="myNode">
...
<xsl:comment><xsl:apply-templates select="image" /></xsl:comment>
...
</xsl:template>
<xsl:template match="image">
<img src="{#src}" width="{#width}px" height="{#height}px" />
</xsl:template>
</xsl:stylesheet>
As a result:
<!---->
that is the code in the element xsl:comment ignored.
How do I display an item in the comments?
It might be possible to replace
<xsl:comment><xsl:apply-templates select="image" /></xsl:comment>
with
<xsl:text disable-output-escaping="yes"><!--</xsl:text>
<xsl:apply-templates select="image" />
<xsl:text disable-output-escaping="yes">--></xsl:text>
Haven't tried though.
<xsl:comment><xsl:apply-templates select="image" /></xsl:comment>
As a result:
<!---->
that is the code in the element
xsl:comment ignored
The XSLT 1.0 Spec says:
It is an error if instantiating the
content of xsl:comment creates nodes
other than text nodes. An XSLT
processor may signal the error; if it
does not signal the error, it must
recover by ignoring the offending
nodes together with their content.
How do I display an item in the
comments?
It depends what is meant for "display": in a browser:
<-- <xsl:apply-templates select="image" /> -->
may be useful, provided the result of <xsl:apply-templates/> aboveis just simple text (not markup).
If to "display" means to provide the result as text, then DOE, if allowed by the XSLT processor, may give us the wanted result:
<--
Some text -->
Finally, if it is required that what should be inside the "comment" should be markup and it should be displayed as markup, then this is rather challenging. In this case one has to use:
<xsl:output method="text"/>
and should present every XML lexical item with its desired serialization (i.e. escaped).
This is how the XPath Visualizer constructs its output.
Here is a small transformation that demonstrates the first two approaches:
<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="/">
<-- Hello, World -->
<xsl:text disable-output-escaping="yes"><--</xsl:text>
Hello,world! --<xsl:text disable-output-escaping="yes">></xsl:text>
</xsl:template>
</xsl:stylesheet>
this transformation, when applied on any XML document (not used), produces:
<-- Hello, World -->
<--
Hello,world! -->
Both "comments" may be viewed as comments in a browser, while only the second is presented as comment in free text.
The third approach (most probably what you want) is illustrated below:
<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:apply-templates select="image"/> -->
</xsl:template>
<xsl:template match="image">
<img src="<xsl:value-of select="#src"/>"
width="<xsl:value-of select="#width"/>px"
height="<xsl:value-of select="#height"/>px"/>
</xsl:template>
</xsl:stylesheet>
when this transformation is applied on the following XML document:
<image src="http://example.com/yyy.jpg" width="200" height="300"/>
the wanted result is produced:
<--
<img src="http://example.com/yyy.jpg"
width="200px"
height="300px"/>
-->
viewed in a browser as:
<--
<img src="http://example.com/yyy.jpg"
width="200px"
height="300px"/>
-->
From http://www.w3.org/TR/xslt#section-Creating-Comments:
The xsl:comment element is instantiated to create a comment node in the result tree. The content of the xsl:comment element is a template for the string-value of the comment node.
For example, this
<xsl:comment>This file is
automatically generated. Do not
edit!</xsl:comment>
would create the comment
<!--This file is automatically
generated. Do not edit!-->
It is an error if instantiating the
content of xsl:comment creates nodes
other than text nodes. An XSLT
processor may signal the error; if it
does not signal the error, it must
recover by ignoring the offending
nodes together with their content.
It is an error if the result of
instantiating the content of the
xsl:comment contains the string -- or
ends with -. An XSLT processor may
signal the error; if it does not
signal the error, it must recover by
inserting a space after any occurrence
of - that is followed by another - or
that ends the comment.
So, in order to do what you want you need to use DOE mechanism.
As example, this stylesheet:
<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" indent="no" encoding="windows-1251"/>
<xsl:template match="img">
<img src="{.}"/>
</xsl:template>
<xsl:template match="root">
<xsl:variable name="vResult">
<xsl:apply-templates/>
</xsl:variable>
<html>
<xsl:copy-of select="$vResult"/>
<xsl:comment>
<xsl:apply-templates select="msxsl:node-set($vResult)"
mode="encode"/>
</xsl:comment>
</html>
</xsl:template>
<xsl:template match="*" mode="encode">
<xsl:value-of select="concat('<',name())"
disable-output-escaping="yes"/>
<xsl:apply-templates select="#*" mode="encode"/>
<xsl:text>></xsl:text>
<xsl:apply-templates mode="encode"/>
<xsl:value-of select="concat('<',name(),'>')"
disable-output-escaping="yes"/>
</xsl:template>
<xsl:template match="*[not(node())]" mode="encode">
<xsl:value-of select="concat('<',name())"
disable-output-escaping="yes"/>
<xsl:apply-templates select="#*" mode="encode"/>
<xsl:text>/></xsl:text>
</xsl:template>
<xsl:template match="#*" mode="encode">
<xsl:value-of select="concat(' ',name(),'="',.,'"')"/>
</xsl:template>
</xsl:stylesheet>
With this input:
<root>
<img>http://example.org/image1.jpg</img>
<img>http://example.org/image2.jpg</img>
<img>http://example.org/image3.jpg</img>
</root>
Output:
<html>
<img src="http://example.org/image1.jpg">
<img src="http://example.org/image2.jpg">
<img src="http://example.org/image3.jpg">
<!--<img src="http://example.org/image1.jpg"/>
<img src="http://example.org/image2.jpg"/>
<img src="http://example.org/image3.jpg"/>-->
</html>
Note: node-set extension function for two pass transformation. disable-output-escaping attribute for xsl:value-of instruction.
As said before by Dimitri you can't use the xsl:comment instruction.
If your purpose is simply to comment a fragment of tree, the simplest way is to put the comments markers as text (unescaped) like this :
<xsl:text disable-output-escaping="yes"><!--</xsl:text><xsl:apply-templates select="image" /><xsl:text disable-output-escaping="yes">--></xsl:text>
instead of :
<xsl:comment><xsl:apply-templates select="image" /></xsl:comment>
and you will obtain exactly this
<!-- <img src="path" width="100px" height="100px"/> -->
used with msxml and saxon