Reputation: 13
I'm trying to take two separate XML files and with the use of XSL make them into one HTML file. I'm getting the right things from the first XML but when I'm trying the same from the second one, I either get all of the word in a single line or just the first one several times.
XML 1
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="xsltcss.css"?>
<?xml-stylesheet type="text/xsl" href="xslt.xsl" ?>
<lexicon>
<head>
<title>Danish</title>
<author>Mattias Liljegren</author>
</head>
<language value="danish">
<word value="dog">hund</word>
<word value="coffee">kaffe</word>
<word value="tree">træ</word>
<word value="chair">stol</word>
<word value="flashlight">lommelygte</word>
<word value="cat">kat</word>
<word value="fish">fisk</word>
<word value="car">bil</word>
<word value="phone">telefon</word>
<word value="forest">skov</word>
</language>
</lexicon>
XML 2
<?xml version="1.0" encoding="UTF-8"?>
<lexicon>
<head>
<title>Croatian</title>
<author>Mattias Liljegren</author>
</head>
<language value="croatian">
<word value="dog">pas</word>
<word value="coffee">kava</word>
<word value="tree">drvo</word>
<word value="chair">stolica</word>
<word value="flashlight">baterija</word>
<word value="cat">mačka</word>
<word value="fish">riba</word>
<word value="car">automobil</word>
<word value="phone">telefon</word>
<word value="forest">šuma</word>
</language>
</lexicon>
XSLT
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="html" version="1.0" encoding="UTF-8" indent="yes" />
<xsl:template match="/">
<html>
<head>
<link rel="stylesheet" type="text/css" href="xsltcss.css" />
</head>
<body>
<xsl:for-each select="lexicon/head/title">
<p>
<xsl:value-of select="." />
</p>
<p>
<xsl:value-of select="document('kroatiska.xml')/lexicon/head/title/." />
</p>
</xsl:for-each>
<xsl:for-each select="lexicon/language/word">
<p>
<xsl:value-of select="." />
</p>
</xsl:for-each>
<xsl:for-each select="lexicon/language/word">
<p>
<xsl:value-of select="document('kroatiska.xml')/lexicon/language/word" />
</p>
</xsl:for-each>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Two separate xml files, I want the first word from each, then the second word and so on. Atm I'm getting the right ones from the original xml, but only the first word "pas" from the second xml file.
Expected result:
Danish
hund
kaffe
trä
stol
lommelygte
kat
fisk
bil
telefon
skov
Croatian
pas
kava
drvo
stolica
baterija
macka
riba
automobil
telefon
suma
Upvotes: 1
Views: 105
Reputation: 117165
This is an expansion of the comments following the answer by Parfait.
In his answer, Parfait says:
In your case, since you need to traverse the nodes in external document,
xsl:for-each
, is unavoidable:
In a comment I asked why would that be, and Parfait replied:
If you can show how to avoid the
xsl:for-each
on nodes viadocument()
, I am very interested!
The following stylesheet shows how to get the same result using only apply-templates
:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html"/>
<xsl:template match="/lexicon">
<html>
<body>
<xsl:apply-templates select="language | document('kroatiska.xml')/lexicon/language" />
</body>
</html>
</xsl:template>
<xsl:template match="language">
<h3>
<xsl:value-of select="@value"/>
</h3>
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="word">
<p>
<xsl:value-of select="."/>
</p>
</xsl:template>
</xsl:stylesheet>
This is not meant to imply that using xsl:apply-templates
is somehow better in this case than xsl:for-each
.
Upvotes: 0
Reputation: 107767
Per the engaging XSLT discussion For loops vs. apply-templates, consider an alternative version to avoid the the many <xsl:for-each>
calls. As advised by XSLT gurus (@Tomalak, @DimitreNovatchev, @MichaelKay):
Using
for-each
makes your program more complex by adding nesting levels and it's also impossibe to re-use the code inside the for-each block. Usingapply-templates
will (when done right) generates more flexible and modular XSLT.
Using
<xsl:template>
and<xsl:apply-templates>
is much more powerful and elegant...xsl:apply-templates
is much richer and deeper thanxsl:for-each
, even simply because we don't know what code will be applied on the nodes of the selection -- in the general case this code will be different for different nodes of the node-list.
The main benefits of
xsl:apply-templates
overfor-each
are that the code adapts better to changing document structures and changing processing requirements.
In your case, since you need to traverse the nodes in external document, xsl:for-each
, is unavoidable:
XSLT (using lexicon
, language
, and word
templates)
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="html" version="1.0" encoding="UTF-8" indent="yes" />
<xsl:template match="/lexicon">
<html>
<head>
<link rel="stylesheet" type="text/css" href="xsltcss.css" />
</head>
<xsl:apply-templates select="language" />
</html>
</xsl:template>
<xsl:template match="language">
<body>
<xsl:variable name="other_doc" select="document('kroatiska.xml')" />
<h3>
<xsl:value-of select="@value"/>
</h3>
<xsl:apply-templates select="word" />
<h3>
<xsl:value-of select="$other_doc/lexicon/language/@value" />
</h3>
<xsl:for-each select="$other_doc/lexicon/language/word">
<p>
<xsl:value-of select="text()" />
</p>
</xsl:for-each>
</body>
</xsl:template>
<xsl:template match="word">
<p>
<xsl:value-of select="text()" />
</p>
</xsl:template>
</xsl:stylesheet>
HTML
<html>
<head>
<META http-equiv="Content-Type" content="text/html; charset=utf-8">
<link rel="stylesheet" type="text/css" href="xsltcss.css">
</head>
<body>
<h3>danish</h3>
<p>hund</p>
<p>kaffe</p>
<p>træ</p>
<p>stol</p>
<p>lommelygte</p>
<p>kat</p>
<p>fisk</p>
<p>bil</p>
<p>telefon</p>
<p>skov</p>
<h3>croatian</h3>
<p>pas</p>
<p>kava</p>
<p>drvo</p>
<p>stolica</p>
<p>baterija</p>
<p>mačka</p>
<p>riba</p>
<p>automobil</p>
<p>telefon</p>
<p>šuma</p>
</body>
</html>
Upvotes: 0
Reputation: 117165
I thought you would want to put the two lists side-by-side, as in a dictionary. To get the shown result of two separate lists is rather trivial:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html"/>
<xsl:template match="/lexicon">
<html>
<body>
<!-- this document -->
<h3>
<xsl:value-of select="language/@value"/>
</h3>
<xsl:for-each select="language/word">
<p>
<xsl:value-of select="."/>
</p>
</xsl:for-each>
<!-- external document -->
<xsl:variable name="kroatiska" select="document('kroatiska.xml')/lexicon" />
<h3>
<xsl:value-of select="$kroatiska/language/@value"/>
</h3>
<xsl:for-each select="$kroatiska//language/word">
<p>
<xsl:value-of select="."/>
</p>
</xsl:for-each>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Upvotes: 1