Hi

Im new to XSL. Im trying to read a XML file that has identical node names with different values.

<mondial>
  <country car_code="MK" capital="cty-cid-cia-Macedonia-Skopje">
    <name>Macedonia</name>
    <indep_date>1991-09-17</indep_date>
    <government>emerging democracy</government>
    <encompassed continent="europe" percentage="100"/>
    <ethnicgroups percentage="22">Albanian</ethnicgroups>
    <ethnicgroups percentage="2">Serb</ethnicgroups>
    <ethnicgroups percentage="65">Macedonian</ethnicgroups>
    <ethnicgroups percentage="4">Turkish</ethnicgroups>
    <ethnicgroups percentage="3">Gypsy</ethnicgroups>
    <religions percentage="30">Muslim</religions>
    <religions percentage="67">Christian Orthodox</religions>
    <languages percentage="21">Albanian</languages>
    <languages percentage="70">Macedonian</languages>
    <languages percentage="3">Turkish</languages>
    <languages percentage="3">Serbian</languages>
  <city id="cty-cid-cia-Macedonia-Skopje" country="MK">
    <name/>
   </city>
 </country>
</mondial>

My problem: I am using xsl:for to obtain the ethincgroups. My xsl only grabs the first "ethnicgroups" on the tree. How can I get it to reall all ethnicgroups.

XSL code:

<xsl:key name"eth" match="country" use="ethnicgroups"

  <xsl:template match="/"

    <xsl:for-each select="//country[generate-id() = generate-id('eth', ethnicgroups)[1]]">

   <xsl:value-of select="etnicgroups"

The result I get is Albania. How do I also get Serb, Macedonian, Turkish, Gypsy?

Dani AI

Generated

As hinted, the usual cause is using xsl:value-of on a node-set in XSLT 1.0 — it returns only the first node's string value. Use xsl:for-each or xsl:apply-templates to visit every ethnicgroups element. Since reported that for-each produced nothing, check for simple problems first: spelling mistakes in element names, wrong XPath context, or a default XML namespace (which requires prefixing in the XSL).

A minimal XSLT 1.0 pattern that walks each country and then each ethnic group (producing a list) looks like this:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="html" indent="yes"/>
  <xsl:template match="/">
    <html><body>
      <xsl:for-each select="/mondial/country">
        <h2><xsl:value-of select="name"/></h2>
        <ul>
          <xsl:for-each select="ethnicgroups">
            <li><xsl:value-of select="."/> (<xsl:value-of select="@percentage"/>)</li>
          </xsl:for-each>
        </ul>
      </xsl:for-each>
    </body></html>
  </xsl:template>
</xsl:stylesheet>

If you prefer templates, use xsl:apply-templates on ethnicgroups and supply a template that outputs the text and attributes. For deduplicating identical group names across the document, declare a key at top level and select only the first node for each distinct string:

<xsl:key name="eth" match="ethnicgroups" use="."/>
<xsl:for-each select="//ethnicgroups[generate-id() = generate-id(key('eth', .)[1])]">
  <xsl:value-of select="."/>
</xsl:for-each>

Quick debugging tips: output count(/mondial/country/ethnicgroups) to verify how many nodes the stylesheet sees; confirm element name spelling; and if the source XML uses a default namespace, bind that namespace in the XSL and use a prefix in your XPath. As suggested, also decide the exact output shape (HTML list, CSV, etc.) — that determines whether for-each or apply-templates is cleaner.

Recommended Answers

All 3 Replies

Try the for-each, instead of the value-of.

Thanks for your responce Pritaeas. I tried for-each but it did not return any values, not even Albanian.

Provide a sample XML document that you're trying to produce. If we can see what structure you're trying to produce with your transformation, we can can provide a solution. We've got your input document, but what are you trying to produce? Give us a sample output.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.