Reputation: 52
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"><a href="../en/content.html"><img src="/deco/dco_en_sml.gif" alt="English" border="0"></img></a></li>
<li><a href="../../sdk/index.html">Introduction</a></li>
<li><a href="../../content.html">Contents</a></li>
<li><a href="../../search.php">Search</a></li>
<li><a href="../../sdk/console.html">Engine</a></li>
<li><a href="../../sdk/cmdline.html">Command Line</a></li>
<li><a href="../../sdk/files.html">Game Data</a></li>
<li><a href="../../sdk/script/index.html">Script</a></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>
Upvotes: 0
Views: 62
Reputation: 167401
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"><a href="../de/content.html"><img src="/deco/dco_de_sml.gif" alt="German" border="0"/></a></li>
<li><a href="../sdk2/index.html">Introduction</a></li>
<li><a href="../../content.html">Contents</a></li>
<li><a href="../../search.php">Search</a></li>
<li><a href="../sdk2/console.html">Engine</a></li>
<li><a href="../sdk2/cmdline.html">Command Line</a></li>
<li><a href="../sdk2/files.html">Game Data</a></li>
<li><a href="../sdk2/script/index.html">Script</a></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"/>
.
Upvotes: 1