<copy-of/> without resulting empty namespace ?

Here should go questions about transforming XML with XSLT and FOP.
H2O
Posts: 9
Joined: Tue Dec 13, 2005 7:42 pm
Location: France

<copy-of/> without resulting empty namespace ?

Post by H2O »

Hello,

Could someone explain the most efficient way for freeing <copy-of /> output elements from empty namespace attribute (<yyy xmlns=" " /> ?


Here is my source :

Code: Select all


<?xml version="1.0" encoding="UTF-8" ?>
<site>
<chapitre>
<page>index</page>
<contenu>
<h3>Grand Titre (without namespace declaration)</h3>
<h2 xmlns="http://www.w3.org/1999/xhtml">Petit Titre (with xmlns="http://www.w3.org/1999/xhtml" namespace declaration in source)</h2>
</contenu>
<titre-chap>L'accueil du site</titre-chap>
</chapitre>
</site>
Here the result :

Code: Select all


<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/1999/xhtml">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
<meta http-equiv="Content-Language" content="fr" />
<title>L'accueil du site</title>
</head>
<body>

<h3 xmlns="">Grand Titre (without namespace declaration)</h3>


<h2>Petit Titre (with xmlns="http://www.w3.org/1999/xhtml" namespace declaration in source)</h2>

<ul>
<li><a href="http://xtest.com/index.htm">L'accueil du site</a></li>
</ul>
</body>
</html>
this is bad !
<h3 xmlns="">Grand Titre (without namespace declaration)</h3>


And here the XSLT :

Code: Select all


<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" encoding="ISO-8859-1"></xsl:output>

<xsl:template name="for-loop">
<xsl:param name="i" select="1"/>
<xsl:param name="increment" select="1"/>
<xsl:param name="operator" select= " '=' "/>
<xsl:param name=" testValue" select="1"/>
<xsl:param name=" chapPage" select="1"/>

<xsl:variable name="testPassed">
<xsl:if test="$i <= $testValue">
<xsl:text>true</xsl:text>
</xsl:if>
</xsl:variable>

<xsl:if test="$testPassed = 'true' ">
<li xmlns="http://www.w3.org/1999/xhtml">
<a>
<xsl:attribute name="href" select=" concat('http://xtest.com/',//chapitre[$i]/page,'.htm') "></xsl:attribute>
<xsl:value-of select="//chapitre[$i]/titre-chap"/>
</a>
</li>


<xsl:call-template name="for-loop" xmlns="http://www.w3.org/1999/xhtml">
<xsl:with-param name="i" select="$i + $increment"/>
<xsl:with-param name="increment" select="$increment"/>
<xsl:with-param name="operator" select="$operator"/>
<xsl:with-param name="testValue" select="$testValue"></xsl:with-param>
<xsl:with-param name="chapPage" select="$chapPage"></xsl:with-param>
</xsl:call-template>
</xsl:if>
</xsl:template>

<xsl:template match="/">
<xsl:apply-templates select="//contenu">
</xsl:apply-templates>
</xsl:template>

<xsl:template match="contenu">
<xsl:result-document href="{preceding-sibling::page}{'.htm'}" doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" doctype-system="http://www.w3.org/1999/xhtml" encoding="ISO-8859-1" >
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta content="text/html; charset=ISO-8859-1" http-equiv="content-type"></meta>
<meta http-equiv="Content-Language" content="fr"></meta>
<title><xsl:value-of select="following-sibling::titre-chap"/>
</title>
</head>

<body>
<xsl:copy-of select="node()" />
<ul>
<xsl:call-template name="for-loop">
<xsl:with-param name="i" select="1"/>
<xsl:with-param name="increment" select="1"/>
<xsl:with-param name="operator" select= " '<=' "/>
<xsl:with-param name=" testValue" select="count(//chapitre)"/>
<xsl:with-param name=" chapPage" select="count(ancestor::chapitre/preceding-sibling::*)"/>
</xsl:call-template>
</ul>
</body>
</html>
</xsl:result-document>
</xsl:template>
</xsl:stylesheet>
Whatever I tried did not do it, so if someone has a clue I will be delighted :D

Thank you for reading !!
loving being a human being
george
Site Admin
Posts: 2095
Joined: Thu Jan 09, 2003 2:58 pm

Post by george »

Hi,

Your souce h3 and h3 nodes are in no namespace and copy of copies them in the result. The place where you want to copy them defines the http://www.w3.org/1999/xhtml as default namespace so in order to be able to represent h3 and h2 from no namespace a default namespace declaration to reset the default namespace to no namespace is added.

In order to move those elements in the html namespace you need to create elements based only on the source local names and use the proper namespace for them. You can find below a working stylesheet that does that (note that I removed the result-document in order to test that easier, you shoud add that back in):

Code: Select all


<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN"
doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" encoding="ISO-8859-1"/>
<xsl:template name="for-loop">
<xsl:param name="i" select="1"/>
<xsl:param name="increment" select="1"/>
<xsl:param name="operator" select=" '=' "/>
<xsl:param name="testValue" select="1"/>
<xsl:param name="chapPage" select="1"/>
<xsl:variable name="testPassed">
<xsl:if test="$i <= $testValue">
<xsl:text>true</xsl:text>
</xsl:if>
</xsl:variable>
<xsl:if test="$testPassed = 'true' ">
<li xmlns="http://www.w3.org/1999/xhtml">
<a>
<xsl:attribute name="href" select=" concat('http://xtest.com/',//chapitre[$i]/page,'.htm')
"/>
<xsl:value-of select="//chapitre[$i]/titre-chap"/>
</a>
</li>
<xsl:call-template name="for-loop" xmlns="http://www.w3.org/1999/xhtml">
<xsl:with-param name="i" select="$i + $increment"/>
<xsl:with-param name="increment" select="$increment"/>
<xsl:with-param name="operator" select="$operator"/>
<xsl:with-param name="testValue" select="$testValue"/>
<xsl:with-param name="chapPage" select="$chapPage"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
<xsl:template match="/">
<xsl:apply-templates select="//contenu"> </xsl:apply-templates>
</xsl:template>
<xsl:template match="contenu">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta content="text/html; charset=ISO-8859-1" http-equiv="content-type"/>
<meta http-equiv="Content-Language" content="fr"/>
<title>
<xsl:value-of select="following-sibling::titre-chap"/>
</title>
</head>
<body>
<xsl:apply-templates select="node()" mode="copyAndChangeNS"/>
<ul>
<xsl:call-template name="for-loop">
<xsl:with-param name="i" select="1"/>
<xsl:with-param name="increment" select="1"/>
<xsl:with-param name="operator" select=" '<=' "/>
<xsl:with-param name="testValue" select="count(//chapitre)"/>
<xsl:with-param name="chapPage" select="count(ancestor::chapitre/preceding-sibling::*)"
/>
</xsl:call-template>
</ul>
</body>
</html>
</xsl:template>
<xsl:template match="*" mode="copyAndChangeNS">
<xsl:element name="{local-name()}" namespace="http://www.w3.org/1999/xhtml">
<xsl:copy-of select="@*"/>
<xsl:apply-templates select="node()" mode="copyAndChangeNS"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Best Regards,
George
H2O
Posts: 9
Joined: Tue Dec 13, 2005 7:42 pm
Location: France

Post by H2O »

Thank you very much George, this work perfectly, you made my day ! This is also the opportunity for digging deeper the xml namespace and xslt concepts, I may understand how an why this works. :D
loving being a human being
george
Site Admin
Posts: 2095
Joined: Thu Jan 09, 2003 2:58 pm

Post by george »

Hi,

Here it is the commented version of the template, I was i a hurry yesterday when I posted it initially.

Code: Select all


  <!-- match any element when the copyAndChangeNS mode is present -->
<xsl:template match="*" mode="copyAndChangeNS">
<!-- create a new element with the same local name as the matched element
but in the html namespace.
-->
<xsl:element name="{local-name()}" namespace="http://www.w3.org/1999/xhtml">
<!-- copy all the attributes from the matched element -->
<xsl:copy-of select="@*"/>
<!-- apply templates on the same mode on the matched element content
to get its content copied and the same namespace change applied on
eventual elements that may be in the currently matched element.
-->
<xsl:apply-templates select="node()" mode="copyAndChangeNS"/>
</xsl:element>
</xsl:template>
Hope things are much clear now,
George
H2O
Posts: 9
Joined: Tue Dec 13, 2005 7:42 pm
Location: France

Post by H2O »

Thank you for this explaination George, this gonna help me a lot.

Best regards,

Jean-Francois
loving being a human being
Post Reply