Burko90
Burko90

Reputation: 13

How to get right values from second XML file?

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

Answers (3)

michael.hor257k
michael.hor257k

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 via document(), 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

Parfait
Parfait

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. Using apply-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 than xsl: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 over for-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

michael.hor257k
michael.hor257k

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

Related Questions