Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Westi on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

turning an XML tree somewhat upside-down

Status
Not open for further replies.

shamesvoice

Technical User
Aug 31, 2007
13
A1
Hello,
I'm a biologist. I've exported a MySQL database as XML. The result is in the order of: Superfamily, family, (subfamily) genus, specific epithet.
An example of my XML file is:

<Chrysidoidea>
<item>
<Family>Bethylidae</Family>
<Subfamily>Bethylinae</Subfamily>
<Genus>Goniozus</Genus>
<SpecificEpithet>claripennis</SpecificEpithet>
</item>
<item>
<Family>Bethylidae</Family>
<Subfamily>Bethylinae</Subfamily>
<Genus>Goniozus</Genus>
<SpecificEpithet>distigmus</SpecificEpithet>
</item>
<item>
<Family>Dryinidae</Family>
<Genus>Aphelopus</Genus>
<SpecificEpithet>atratus</SpecificEpithet>
</item>
<item>
<Family>Embolemidae</Family>
<Genus>Embolemus</Genus>
<SpecificEpithet>ruddii</SpecificEpithet>
</item>
</Chrysidoidea>

Can anyone help me turn this tree upside-down and turn it into the following HTML:

<h1 class="superfamily">Chrysidoidea</h1>

<h2 class="Family">Bethylidae</h2>

<h3 class="Subfamily">Bethylinae</h3>
<h4 class="Genus">Goniozus</h4>
<ul>
<li class="SpecificEpithet">claripennis</li>
<li class="SpecificEpithet">distigmus</li>
</ul>

<h2 class="Family">Dryinidae</h2>

<h4 class="Genus">Aphelopus</h4>
<ul>
<li class="SpecificEpithet">atratus</li>
</ul>

<h2 class="Family">Embolemidae</h2>

<h4 class="Genus">Embolemus</h4>
<ul>
<li class="SpecificEpithet">ruddii</li>
</ul>
 
Well, here is a start.
Code:
<?xml version='1.0'?>
<xsl:stylesheet version="1.0" xmlns:xsl="[URL unfurl="true"]http://www.w3.org/1999/XSL/Transform">[/URL]

<xsl:template match="/">
<html>
<body>
<h1 class="superfamily"><xsl:value-of select="local-name(/*[1])"/></h1>
</body>
</html>	
</xsl:template>

</xsl:stylesheet>

Now, I am not able to infer the relationships that are probably quite clear to you. (I do remember the term binomial nomenclature from my biology a l-o-n-g time ago. [bigsmile])

Can you explain exactly the rules you envision? This seems to be a grouping problem. If so then the Muench method is described and illustrated in this forum, in several threads, (though it has been quite a while...we used to get grouping questions about once a week):
thread426-1332802
thread426-1210886

Tom Morrison
 
Thanks for your advice. I'll see if I can use it. I hope I can answer your question. As you can see, all the information about a single insect is stored as children of the element "item." I want to turn it into a different hierarchy, or tree, from family down to species. I want to avoid any repetition in the tree. So
Code:
<Family>Bethylidae</Family>
only gets used once as
Code:
<h2 class="Family">Bethylidae</h2>
even though it is mentioned in two items. And so on down the line. I want to iterate through the original XML and avoid repetition in the resulting HTML.
 
There are certain ambiguities in deducing from the generic sample given the general structure of the xml in question. In the solution below, it is taken:
[1] The superfamily is actually the root element of the document;
[2] There are no such thing same family with different subfamily: either subfamily will be the same or it does not exist;
[3] Those SpecificEpithet elements to be pulled out will be sufficiently identified when Genus is the same within the same Superfamily.

Hence is a solution with some considerations behind the lines on the perspective generalization needed.
[tt]
<?xml version="1.0" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="<xsl:eek:utput method="html" indent="yes" />
<xsl:key name="Superfamily" match="/*[1]" use="." />
<xsl:key name="Family" match="/*[1]/item/Family" use="." />
<xsl:key name="Subfamily" match="/*[1]/item/Subfamily" use="." />
<xsl:key name="Genus" match="/*[1]/item/Genus" use="." />
<xsl:template match="/">
<html>
<body>
<xsl:apply-templates select="*" />
</body>
</html>
</xsl:template>
<xsl:template match="/*">

<h1 class="{local-name()}">
<xsl:value-of select="local-name()" />
</h1>

<xsl:for-each select="./item/SpecificEpithet">
<xsl:if test="generate-id(ancestor::*[2])=generate-id(key('Superfamily',ancestor::*[2])[1]) and
generate-id(preceding-sibling::Family[1])=generate-id(key('Family',preceding-sibling::Family)[1]) and
generate-id(preceding-sibling::Subfamily[1])=generate-id(key('Subfamily',preceding-sibling::Subfamily)[1]) and
generate-id(preceding-sibling::Genus[1])=generate-id(key('Genus',preceding-sibling::Genus)[1])">

<h2 class="Family">
<xsl:value-of select="preceding-sibling::Family" />
</h2>
<h3 class="Subfamily">
<xsl:value-of select="preceding-sibling::Subfamily" />
</h3>
<h4 class="Genus">
<xsl:value-of select="preceding-sibling::Genus" />
</h4>
<ul>
<xsl:for-each select="key('Genus',preceding-sibling::Genus)">
<li>
<xsl:value-of select="following-sibling::SpecificEpithet" />
</li>
</xsl:for-each>
</ul>
</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
[/tt]
 
Or try this:
Code:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="[URL unfurl="true"]http://www.w3.org/1999/XSL/Transform"[/URL] version="1.0">
  <xsl:output method="xml" indent="yes"/>
  <xsl:template match="/">
    <html>
      <head>
        <title>My biological tree</title>
      </head>
      <body>
        <h1 class="Superfamily"><xsl:value-of select="name(*)"/></h1>
        <xsl:apply-templates select="*/item/*[1][not(. = ../preceding-sibling::item/*[1])]"/>
      </body>
    </html>
  </xsl:template>
  <xsl:template match="Family">
    <h2 class="Family"><xsl:value-of select="."/></h2>
    <xsl:apply-templates select="../../item/*[2][not(. = ../preceding-sibling::item/*[2])][../Family = current()]"/>
  </xsl:template>
  <xsl:template match="Subfamily">
    <h3 class="Subfamily"><xsl:value-of select="."/></h3>
    <xsl:apply-templates select="../../item/Genus[not(. = ../preceding-sibling::item/Genus)][../Subfamily = current()]"/>
  </xsl:template>
  <xsl:template match="Genus">
    <h4 class="Genus"><xsl:value-of select="."/></h4>
    <ul>
      <xsl:apply-templates select="../../item/SpecificEpithet[not(. = ../preceding-sibling::item/SpecificEpithet)][../Genus = current()]"/>
    </ul>
  </xsl:template>
  <xsl:template match="SpecificEpithet">
    <li class="SpecificEpithet"><xsl:value-of select="."/></li>
  </xsl:template>
</xsl:stylesheet>
If you're using XSL 2.0 or you can give some more information on the structure it would be possible to make this more generic/simplify.

Jon

"I don't regret this, but I both rue and lament it.
 
Hello everyone,
Thanks for your help. I've had the most luck with the last suggestion, by JontyMC. But I now realize that the structure of my XML is slightly more complicated tan I first stated. (If the others want to think along, please do.)
"Chrysidoidea" is indeed the root. Every "item" has a "Family", and several items can share the same Family. The same Family can have one, more than one or no "Subfamilies". All Families and Subfamilies have Genuses, and they can share some of the same (duplicate) Genuses. Every Genus has one or more SpecificEpithets.
Thanks
 
I could not resist the opportunity to demonstrate the Muench method for multi-level grouping. I think I have taken into account all the structural possibilities outlined in shamesvoice's latest post. While this solution has a bit more complexity, it should execute more quickly (assuming a nontrivial amount of data).

Code:
[small]<xsl:stylesheet version="1.0" xmlns:xsl="[URL unfurl="true"]http://www.w3.org/1999/XSL/Transform">[/URL]
  <xsl:output indent="yes"/>
[COLOR=white grey]<!-- multilevel grouping using the Muench method -->[/color]

[COLOR=white grey]<!-- Establish a key for each grouping level.  Note that each lower level key value -->[/color]
[COLOR=white grey]<!-- must include the key value of the higher order key -->[/color]
  <xsl:key name="kFamily" match="item" use="Family"/>
  <xsl:key name="kSubfamily" match="item" use="concat(Family,':',Subfamily)"/>
  <xsl:key name="kGenus" match="item" use="concat(Family,':',Subfamily,':',Genus)"/>

  <xsl:template match="/">
    <html>
      <body>
        <h1 class="superfamily">
          <xsl:value-of select="local-name(/*[1])"/>
        </h1>
        [COLOR=white grey]<!-- the outer for-each iterates once for each unique value of Family -->[/color]
        <xsl:for-each select="/*/item[generate-id() = generate-id(key('kFamily', Family)[1])]">
          <h2 class="Family">
            <xsl:value-of select="Family"/>
          </h2>
          [COLOR=white grey]<!-- this for-each iterates over the <item> nodes, once for each unique value of Subfamily -->[/color]
          [COLOR=white grey]<!-- that have the same value of Family as the containing for-each iteration -->[/color]
          <xsl:for-each select="key('kFamily', Family)
                                [generate-id()=
                                  generate-id(key('kSubfamily',concat(Family,':',Subfamily))[1])]">
            <xsl:if test="string-length(Subfamily) &gt; 0">
              <h3 class="Subfamily">
                <xsl:value-of select="Subfamily"/>
              </h3>
            </xsl:if>
            [COLOR=white grey]<!-- this for-each iterates over the <item> nodes, once for each unique value of Genus -->[/color]
            [COLOR=white grey]<!-- that have the same value of Family and Subfamily as the containing for-each iteration -->[/color]
            <xsl:for-each select="key('kSubfamily', concat(Family,':',Subfamily))
                                  [generate-id()=
                                    generate-id(key('kGenus',concat(Family,':',Subfamily,':',Genus))[1])]">
              <xsl:if test="string-length(Genus) &gt; 0">
                <h4 class="Genus">
                  <xsl:value-of select="Genus"/>
                </h4>
              </xsl:if>
              <ul>
                [COLOR=white grey]<!-- this for-each iterates once for each <item> node -->[/color]
                [COLOR=white grey]<!-- that has the same value of Family, Subfamily, and Genus as the -->[/color]
                [COLOR=white grey]<!-- containing for-each iteration -->[/color]
                <xsl:for-each select="key('kGenus',concat(Family,':',Subfamily,':',Genus))">
                  [COLOR=white grey]<!-- this for-each iterates over all the <SpecificEpithet> nodes in the <item> -->[/color]
                  <xsl:for-each select="SpecificEpithet[string-length(text()) &gt; 0]">
                      <li><xsl:value-of select="."/></li>
                  </xsl:for-each>
                </xsl:for-each>
              </ul>
            </xsl:for-each>
          </xsl:for-each>
        </xsl:for-each>
      </body>
    </html>
  </xsl:template>
</xsl:stylesheet>[/small]
Code:
<html>
  <body>
    <h1 class="superfamily">Chrysidoidea</h1>
    <h2 class="Family">Bethylidae</h2>
    <h3 class="Subfamily">Bethylinae</h3>
    <h4 class="Genus">Goniozus</h4>
    <ul>
      <li>claripennis</li>
      <li>distigmus</li>
    </ul>
    <h2 class="Family">Dryinidae</h2>
    <h4 class="Genus">Aphelopus</h4>
    <ul>
      <li>atratus</li>
    </ul>
    <h2 class="Family">Embolemidae</h2>
    <h4 class="Genus">Embolemus</h4>
    <ul>
      <li>ruddii</li>
    </ul>
  </body>
</html>

Tom Morrison
 
Thanks Tom,
I'll try it out and let you know. Any other suggestions are still welcome.
 
Thanks Tom,
Bull's-eye! This is something I can build on. If I have any more questions, I'll ask them here or in a new thread.
 
Hello Tom (and anyone else),
I've been away for a few weeks. Your advice works fine. Now I'd just like to ask if my .xsl-file is efficient.
The original xml-file is at:
.
The .xsl-file is at:
.
It's the same as this:
Code:
<xsl:stylesheet version="1.0" xmlns:xsl="[URL unfurl="true"]http://www.w3.org/1999/XSL/Transform">[/URL]
  <xsl:output indent="yes"/>
<!-- multilevel grouping using the Muench method -->

<!-- Establish a key for each grouping level.  Note that each lower level key value -->
<!-- must include the key value of the higher order key -->
  <xsl:key name="kFamily" match="item" use="Family"/>
  <xsl:key name="kVernacularNameOfFamily" match="item" use="VernacularNameOfFamily"/>
  <xsl:key name="kSubfamily" match="item" use="concat(Family,':',Subfamily)"/>
  <xsl:key name="kGenus" match="item" use="concat(Family,':',Subfamily,':',Genus)"/>

  <xsl:template match="/">
    <html>
<head>
  <title>Chrysidoidea</title>
  <link rel="stylesheet" type="text/css" href="chrys_temp2.css" title="default" />
</head>
      <body>
        <h1 class="superfamily">
          <xsl:value-of select="local-name(/*[1])"/>
        </h1>
        <!-- the outer for-each iterates once for each unique value of Family -->
        <xsl:for-each select="/*/item[generate-id() = generate-id(key('kFamily', Family)[1])]">
          <h2>
            <span class="Family"><xsl:value-of select="Family" /></span>
            <span class="VernacularNameOfFamily"><xsl:value-of select="VernacularNameOfFamily" /></span>
          </h2>

          <!-- this for-each iterates over the <item> nodes, once for each unique value of Subfamily -->
          <!-- that have the same value of Family as the containing for-each iteration -->
          <xsl:for-each select="key('kFamily', Family)
                                [generate-id()=
                                  generate-id(key('kSubfamily',concat(Family,':',Subfamily))[1])]">
            <xsl:if test="string-length(Subfamily) &gt; 0">
              <h3 class="Subfamily">
                <xsl:value-of select="Subfamily"/>
              </h3>
            </xsl:if>
            <!-- this for-each iterates over the <item> nodes, once for each unique value of Genus -->
            <!-- that have the same value of Family and Subfamily as the containing for-each iteration -->
            <xsl:for-each select="key('kSubfamily', concat(Family,':',Subfamily))
                                  [generate-id()=
                                    generate-id(key('kGenus',concat(Family,':',Subfamily,':',Genus))[1])]">
              <xsl:if test="string-length(Genus) &gt; 0">
                <h4>
                  <span class="Genus"><xsl:value-of select="Genus"/></span>
                  <span class="AuthorYearOfGenus"><xsl:value-of select="AuthorYearOfGenus"/></span>
                  <span class="VernacularNameOfGenus"><xsl:value-of select="VernacularNameOfGenus" /></span>
                 </h4>
              </xsl:if>
            <ul class="SynGen">
              <xsl:if test="string-length(SynonymOfGenus_1) &gt; 0">
              <li class="nodot">
                  <span class="SynonymOfGenus_1"><xsl:value-of select="SynonymOfGenus_1" /></span>
                  <span class="AuthorYearOfSynonymOfGenus_1"><xsl:value-of select="AuthorYearOfSynonymOfGenus_1" /></span>
              </li>
              </xsl:if>
              <xsl:if test="string-length(SynonymOfGenus_2) &gt; 0">
              <li class="nodot">
                  <span class="SynonymOfGenus_2"><xsl:value-of select="SynonymOfGenus_2" /></span>
                  <span class="AuthorYearOfSynonymOfGenus_2"><xsl:value-of select="AuthorYearOfSynonymOfGenus_2" /></span>
              </li>
              </xsl:if>
              <xsl:if test="string-length(SynonymOfGenus_3) &gt; 0">
              <li class="nodot">
                  <span class="SynonymOfGenus_3"><xsl:value-of select="SynonymOfGenus_3" /></span>
                  <span class="AuthorYearOfSynonymOfGenus_3"><xsl:value-of select="AuthorYearOfSynonymOfGenus_3" /></span>
              </li>
              </xsl:if>
              <xsl:if test="string-length(SynonymOfGenus_4) &gt; 0">
              <li class="nodot">
                  <span class="SynonymOfGenus_4"><xsl:value-of select="SynonymOfGenus_4" /></span>
                  <span class="AuthorYearOfSynonymOfGenus_4"><xsl:value-of select="AuthorYearOfSynonymOfGenus_4" /></span>
              </li>
              </xsl:if>
              <xsl:if test="string-length(SynonymOfGenus_5) &gt; 0">
              <li class="nodot">
                  <span class="SynonymOfGenus_5"><xsl:value-of select="SynonymOfGenus_5" /></span>
                  <span class="AuthorYearOfSynonymOfGenus_5"><xsl:value-of select="AuthorYearOfSynonymOfGenus_5" /></span>
              </li>
              </xsl:if>
              <xsl:if test="string-length(SynonymOfGenus_6) &gt; 0">
              <li class="nodot">
                  <span class="SynonymOfGenus_6"><xsl:value-of select="SynonymOfGenus_6" /></span>
                  <span class="AuthorYearOfSynonymOfGenus_6"><xsl:value-of select="AuthorYearOfSynonymOfGenus_6" /></span>
              </li>
              </xsl:if>
              </ul>
 
              <ul class="SciName">
                <!-- this for-each iterates once for each <item> node -->
                <!-- that has the same value of Family, Subfamily, and Genus as the -->
                <!-- containing for-each iteration -->
                <xsl:for-each select="key('kGenus',concat(Family,':',Subfamily,':',Genus))">
                  <!-- this for-each iterates over all the <ScientificName> nodes in the <item> -->
              <li>
                  <xsl:for-each select="ScientificName[string-length(text()) &gt; 0]">
                      <span class="ScientificName"><xsl:value-of select="."/></span>
                  </xsl:for-each>
                  <xsl:for-each select="AuthorYearOfScientificName[string-length(text()) &gt; 0]">
                      <span class="AuthorYearOfScientificName"><xsl:value-of select="."/></span>
                  </xsl:for-each>

               <span class="block">
                  <xsl:for-each select="QestionableSynonym[string-length(text()) &gt; 0]">
                      <span class="QestionableSynonym"><xsl:value-of select="."/></span>
                  </xsl:for-each>
                 <xsl:for-each select="AuthorYearOfQestionableSynonym[string-length(text()) &gt; 0]">
                      <span class="AuthorYearOfQestionableSynonym"><xsl:value-of select="."/></span>
                  </xsl:for-each>
               </span>

               <span class="block">
                  <xsl:for-each select="SynonymOfScientificName_1[string-length(text()) &gt; 0]">
                      <span class="SynonymOfScientificName_1"><xsl:value-of select="."/></span>
                  </xsl:for-each>
                 <xsl:for-each select="AuthorYearOfSynonymOfScientificName_1[string-length(text()) &gt; 0]">
                      <span class="AuthorYearOfSynonymOfScientificName_1"><xsl:value-of select="."/></span>
                  </xsl:for-each>
               </span>
               <span class="block">
                  <xsl:for-each select="SynonymOfScientificName_2[string-length(text()) &gt; 0]">
                      <span class="SynonymOfScientificName_2"><xsl:value-of select="."/></span>
                  </xsl:for-each>
                 <xsl:for-each select="AuthorYearOfSynonymOfScientificName_2[string-length(text()) &gt; 0]">
                      <span class="AuthorYearOfSynonymOfScientificName_2"><xsl:value-of select="."/></span>
                  </xsl:for-each>
               </span>
               <span class="block">
                  <xsl:for-each select="SynonymOfScientificName_3[string-length(text()) &gt; 0]">
                      <span class="SynonymOfScientificName_3"><xsl:value-of select="."/></span>
                  </xsl:for-each>
                 <xsl:for-each select="AuthorYearOfSynonymOfScientificName_3[string-length(text()) &gt; 0]">
                      <span class="AuthorYearOfSynonymOfScientificName_3"><xsl:value-of select="."/></span>
                  </xsl:for-each>
               </span>
               <span class="block">
                  <xsl:for-each select="SynonymOfScientificName_4[string-length(text()) &gt; 0]">
                      <span class="SynonymOfScientificName_4"><xsl:value-of select="."/></span>
                  </xsl:for-each>
                 <xsl:for-each select="AuthorYearOfSynonymOfScientificName_4[string-length(text()) &gt; 0]">
                      <span class="AuthorYearOfSynonymOfScientificName_4"><xsl:value-of select="."/></span>
                  </xsl:for-each>
               </span>

               <span class="block">
                  <xsl:for-each select="InfraspecificRank_1[string-length(text()) &gt; 0]">
                      <span class="InfraspecificRank_1"><xsl:value-of select="."/></span>
                  </xsl:for-each>
                 <xsl:for-each select="InfraspecificEpithet_1[string-length(text()) &gt; 0]">
                      <span class="InfraspecificEpithet_1"><xsl:value-of select="."/></span>
                  </xsl:for-each>
                  <xsl:for-each select="AuthorYearOfInfraspecificEpithet_1[string-length(text()) &gt; 0]">
                      <span class="AuthorYearOfInfraspecificEpithet_1"><xsl:value-of select="."/></span>
                  </xsl:for-each>
               </span> 
               <span class="block">
                 <xsl:for-each select="SynonymOfInfraspecificEpithet_1[string-length(text()) &gt; 0]">
                      <span class="SynonymOfInfraspecificEpithet_1"><xsl:value-of select="."/></span>
                  </xsl:for-each>
                 <xsl:for-each select="AuthorYearOfSynonymOfInfraspecificEpithet_1[string-length(text()) &gt; 0]">
                      <span class="AuthorYearOfSynonymOfInfraspecificEpithet_1"><xsl:value-of select="."/></span>
                  </xsl:for-each>
               </span>

               <span class="block">
                  <xsl:for-each select="InfraspecificRank_2[string-length(text()) &gt; 0]">
                      <span class="InfraspecificRank_2"><xsl:value-of select="."/></span>
                  </xsl:for-each>
                 <xsl:for-each select="InfraspecificEpithet_2[string-length(text()) &gt; 0]">
                      <span class="InfraspecificEpithet_2"><xsl:value-of select="."/></span>
                  </xsl:for-each>
                  <xsl:for-each select="AuthorYearOfInfraspecificEpithet_2[string-length(text()) &gt; 0]">
                      <span class="AuthorYearOfInfraspecificEpithet_2"><xsl:value-of select="."/></span>
                  </xsl:for-each>
              </span> 
               <span class="block">
                 <xsl:for-each select="SynonymOfInfraspecificEpithet_2[string-length(text()) &gt; 0]">
                      <span class="SynonymOfInfraspecificEpithet_2"><xsl:value-of select="."/></span>
                  </xsl:for-each>
                 <xsl:for-each select="AuthorYearOfSynonymOfInfraspecificEpithet_2[string-length(text()) &gt; 0]">
                      <span class="AuthorYearOfSynonymOfInfraspecificEpithet_2"><xsl:value-of select="."/></span>
                  </xsl:for-each>
               </span>
               <span class="block">
                  <xsl:for-each select="InfraspecificRank_3[string-length(text()) &gt; 0]">
                      <span class="InfraspecificRank_3"><xsl:value-of select="."/></span>
                  </xsl:for-each>
                 <xsl:for-each select="InfraspecificEpithet_3[string-length(text()) &gt; 0]">
                      <span class="InfraspecificEpithet_3"><xsl:value-of select="."/></span>
                  </xsl:for-each>
                  <xsl:for-each select="AuthorYearOfInfraspecificEpithet_3[string-length(text()) &gt; 0]">
                      <span class="AuthorYearOfInfraspecificEpithet_3"><xsl:value-of select="."/></span>
                  </xsl:for-each>
              </span> 
               <span class="block">
                 <xsl:for-each select="SynonymOfInfraspecificEpithet_3[string-length(text()) &gt; 0]">
                      <span class="SynonymOfInfraspecificEpithet_3"><xsl:value-of select="."/></span>
                  </xsl:for-each>
                 <xsl:for-each select="AuthorYearOfSynonymOfInfraspecificEpithet_3[string-length(text()) &gt; 0]">
                      <span class="AuthorYearOfSynonymOfInfraspecificEpithet_3"><xsl:value-of select="."/></span>
                  </xsl:for-each>
               </span>
               <span class="block">
                  <xsl:for-each select="InfraspecificRank_4[string-length(text()) &gt; 0]">
                      <span class="InfraspecificRank_4"><xsl:value-of select="."/></span>
                  </xsl:for-each>
                 <xsl:for-each select="InfraspecificEpithet_4[string-length(text()) &gt; 0]">
                      <span class="InfraspecificEpithet_4"><xsl:value-of select="."/></span>
                  </xsl:for-each>
                  <xsl:for-each select="AuthorYearOfInfraspecificEpithet_4[string-length(text()) &gt; 0]">
                      <span class="AuthorYearOfInfraspecificEpithet_4"><xsl:value-of select="."/></span>
                  </xsl:for-each>
               </span> 
               <span class="block">
                 <xsl:for-each select="SynonymOfInfraspecificEpithet_4[string-length(text()) &gt; 0]">
                      <span class="SynonymOfInfraspecificEpithet_4"><xsl:value-of select="."/></span>
                  </xsl:for-each>
                 <xsl:for-each select="AuthorYearOfSynonymOfInfraspecificEpithet_4[string-length(text()) &gt; 0]">
                      <span class="AuthorYearOfSynonymOfInfraspecificEpithet_4"><xsl:value-of select="."/></span>
                  </xsl:for-each>
               </span>
               <span class="block">
                  <xsl:for-each select="InfraspecificRank_5[string-length(text()) &gt; 0]">
                      <span class="InfraspecificRank_5"><xsl:value-of select="."/></span>
                  </xsl:for-each>
                 <xsl:for-each select="InfraspecificEpithet_5[string-length(text()) &gt; 0]">
                      <span class="InfraspecificEpithet_5"><xsl:value-of select="."/></span>
                  </xsl:for-each>
                  <xsl:for-each select="AuthorYearOfInfraspecificEpithet_5[string-length(text()) &gt; 0]">
                      <span class="AuthorYearOfInfraspecificEpithet_5"><xsl:value-of select="."/></span>
                  </xsl:for-each>
               </span> 
               <span class="block">
                 <xsl:for-each select="SynonymOfInfraspecificEpithet_5[string-length(text()) &gt; 0]">
                      <span class="SynonymOfInfraspecificEpithet_5"><xsl:value-of select="."/></span>
                  </xsl:for-each>
                 <xsl:for-each select="AuthorYearOfSynonymOfInfraspecificEpithet_5[string-length(text()) &gt; 0]">
                      <span class="AuthorYearOfSynonymOfInfraspecificEpithet_5"><xsl:value-of select="."/></span>
                  </xsl:for-each>
               </span>

              </li>
               </xsl:for-each>
             </ul>
            </xsl:for-each>       
          </xsl:for-each>
        </xsl:for-each>
      </body>
    </html>
  </xsl:template>
</xsl:stylesheet>
The css-file is at:
.
You can see the result, with xsl and css mark-up at:
.
It is meant to resemble the HTML table on:
.
It succeeds at that. But is there any way to make the xsl more compact?
A second question has more to do with CSS styling than with xslt: Is there any way to make use of embedded lists in HTML (with, for example, "xsl:if test=") while avoiding blank spaces? If you don't understand what I mean, I can give examples to be more specific.
Greetings
 
You have certainly made good progress. Today I must be somewhat brief, so I will give an example for the section [tt]<ul class="SynGen">[/tt]. From this you can apply the same concepts to [tt]class="SciName"[/tt]. (There are other ways to do this (using xsl:apply-templates, for example), but since you are using the xsl:for-each paradigm, I continue to use xsl:for-each.)
Code:
[small]<xsl:if test="count(*[(substring-before(local-name(),'_') = 'SynonymOfGenus') and (string-length() &gt; 0)]) &gt; 0">
  <ul class="SynGen">
  <xsl:for-each select="*[(substring-before(local-name(),'_') = 'SynonymOfGenus') and (string-length() &gt; 0)]">
    <xsl:variable name="localNameModifier" select="substring-after(local-name(.),'SynonymOfGenus')"/>
    <xsl:variable name="authorElementName" select="concat('AuthorYearOfSynonymOfGenus',$localNameModifier)"/>
    <li class="nodot">
      <span class="{local-name(.)}"><xsl:value-of select="." /></span>
      <span>
        <xsl:attribute name="class"><xsl:value-of select="$authorElementName"/></xsl:attribute>
        <xsl:value-of select="../*[local-name() = $authorElementName]" />
      </span>
    </li>
  </xsl:for-each>
  </ul>
</xsl:if>
[/small]

Let us see what results! [bigsmile]

Tom Morrison
 
OK, Tom,
I replaced
Code:
<ul class="SynGen">
              <xsl:if test="string-length(SynonymOfGenus_1) &gt; 0">
              <li class="nodot">
                  <span class="SynonymOfGenus_1"><xsl:value-of select="SynonymOfGenus_1" /></span>
                  <span class="AuthorYearOfSynonymOfGenus_1"><xsl:value-of select="AuthorYearOfSynonymOfGenus_1" /></span>
              </li>
[etc.]
with your suggestion:
Code:
<xsl:if test="count(*[(substring-before(local-name(),'_') = 'SynonymOfGenus') and (string-length() &gt; 0)]) &gt; 0">
  <ul class="SynGen">
  <xsl:for-each select="*[(substring-before(local-name(),'_') = 'SynonymOfGenus') and (string-length() &gt; 0)]">
    <xsl:variable name="localNameModifier" select="substring-after(local-name(.),'SynonymOfGenus')"/>
    <xsl:variable name="authorElementName" select="concat('AuthorYearOfSynonymOfGenus',$localNameModifier)"/>
    <li class="nodot">
      <span class="{local-name(.)}"><xsl:value-of select="." /></span>
      <span>
        <xsl:attribute name="class"><xsl:value-of select="$authorElementName"/></xsl:attribute>
        <xsl:value-of select="../*[local-name() = $authorElementName]" />
      </span>
    </li>
  </xsl:for-each>
  </ul>
</xsl:if>
and it works just fine. This has indeed made the xsl more compact. The links I mentioned previously still work and have been updated, so you can see for yourself.

As for my other question,
I use the code:
Code:
<ul class="SciName">
                <!-- this for-each iterates once for each <item> node -->
                <!-- that has the same value of Family, Subfamily, and Genus as the -->
                <!-- containing for-each iteration -->
                <xsl:for-each select="key('kGenus',concat(Family,':',Subfamily,':',Genus))">
                  <!-- this for-each iterates over all the <ScientificName> nodes in the <item> -->
              <li>
                  <xsl:for-each select="ScientificName[string-length(text()) &gt; 0]">
                      <span class="ScientificName"><xsl:value-of select="."/></span>
                  </xsl:for-each>
                  <xsl:for-each select="AuthorYearOfScientificName[string-length(text()) &gt; 0]">
                      <span class="AuthorYearOfScientificName"><xsl:value-of select="."/></span>
                  </xsl:for-each>
to create an unordered list with a variable number of list elements "<li>Synonym, etc</li>". But each list element is a mass of information that actually should be broken down into a new, imbedded unordered list "<ul></ul>" with a variable amount of new list elements, "<li>Synonym_1</li>". In standards HTML, it would be something like this:
Code:
<ul>
<li>A Scientific Name
<ul>
<li>A Synonym of this Scientific Name</li>
<li>Another Synonym of this Scientific Name</li>
<li>A Variety of this Synonym of this Scientific Name</li>
<li>A Questionable Synonym of this Scientific Name</li>
</li>
</ul>
I have tried this in the past and have had problems with some browsers if they had to display empty lists, "<ul></ul>" or empty list elements, "<li></li>". Then I get unwanted horizontal white space. The solution, of course, is to use xslt and CSS to avoid these empty lists or elements. The embedding itself shouldn't be much of a problem.
I have yet to tackle this problem. I believe you have helped me along enough that I can solve this problem myself. But in the meantime (it will be a while before I have the hours to do it), if you have any suggestions, please feel free to help.
 
Okay, now that I have seen your DTD, I am even more confused.
Code:
<!ELEMENT item 
		    (id+, ScientificName*
This says that an <item> element has one or more <id> elements, and zero or more <ScientificName> elements.

Your example document, however, contains a single occurrence of <id> and a single occurrence of <ScientificName> in each item. The example document obeys the DTD, but one might infer from the example document that the DTD is overly permissive.

So now I need even more clarification. [blush]

Tom Morrison
 
OK, you're probably right. I borrowed my DTD from an older version, and apparently I need to tighten it up. Thanks for the tip.
 
Ok, I made some simplifying assumptions that many of the zero or more elements in <item> were really zero or one and created this stylesheet. It seems to pull the correct data, but you certainly will need to modify it to meet your needs. I think, however, that you can seethe method of using <xsl:call-template> to regularize and reduce the size of the XSLT.

Code:
[small]<xsl:stylesheet version="1.0" xmlns:xsl="[URL unfurl="true"]http://www.w3.org/1999/XSL/Transform">[/URL]
  <xsl:output indent="yes"/>
  <!-- multilevel grouping using the Muench method -->

  <!-- Establish a key for each grouping level.  Note that each lower level key value -->
  <!-- must include the key value of the higher order key -->
  <xsl:key name="kFamily" match="item" use="Family"/>
  <xsl:key name="kVernacularNameOfFamily" match="item" use="VernacularNameOfFamily"/>
  <xsl:key name="kSubfamily" match="item" use="concat(Family,':',Subfamily)"/>
  <xsl:key name="kGenus" match="item" use="concat(Family,':',Subfamily,':',Genus)"/>

  <xsl:template match="/">
    <html>
      <head>
        <title>Chrysidoidea</title>
        <link rel="stylesheet" type="text/css" href="chrys_temp2.css" title="default"/>
      </head>
      <body>
        <h1 class="superfamily">
          <xsl:value-of select="local-name(/*[1])"/>
        </h1>
        <!-- the outer for-each iterates once for each unique value of Family -->
        [ignore]<xsl:for-each select="/*/item[generate-id()=generate-id(key('kFamily', Family)[1])]">[/ignore]
          <h2>
            <span class="Family">
              <xsl:value-of select="Family"/>
            </span>
            <span class="VernacularNameOfFamily">
              <xsl:value-of select="VernacularNameOfFamily"/>
            </span>
          </h2>

          <!-- this for-each iterates over the <item> nodes, once for each unique value of Subfamily -->
          <!-- that have the same value of Family as the containing for-each iteration -->
          <xsl:for-each select="key('kFamily', Family)[generate-id()=generate-id(key('kSubfamily',concat(Family,':',Subfamily))[1])]">
            <xsl:if test="string-length(Subfamily) &gt; 0">
              <h3 class="Subfamily">
                <xsl:value-of select="Subfamily"/>
              </h3>
            </xsl:if>
            <!-- this for-each iterates over the <item> nodes, once for each unique value of Genus -->
            <!-- that have the same value of Family and Subfamily as the containing for-each iteration -->
            <xsl:for-each select="key('kSubfamily',concat(Family,':',Subfamily))[generate-id()=generate-id(key('kGenus',concat(Family,':',Subfamily,':',Genus))[1])]">
              <xsl:if test="string-length(Genus) &gt; 0">
                <h4>
                  <span class="Genus">
                    <xsl:value-of select="Genus"/>
                  </span>
                  <span class="AuthorYearOfGenus">
                    <xsl:value-of select="AuthorYearOfGenus"/>
                  </span>
                  <span class="VernacularNameOfGenus">
                    <xsl:value-of select="VernacularNameOfGenus"/>
                  </span>
                </h4>
              </xsl:if>
              <xsl:if test="count(*[(substring-before(local-name(),'_') = 'SynonymOfGenus') and (string-length() &gt; 0)]) &gt; 0">
                <ul class="SynGen">
                  <xsl:for-each select="*[(substring-before(local-name(),'_') = 'SynonymOfGenus') and (string-length() &gt; 0)]">
                    <xsl:variable name="localNameModifier" select="substring-after(local-name(.),'SynonymOfGenus')"/>
                    <xsl:variable name="authorElementName" select="concat('AuthorYearOfSynonymOfGenus',$localNameModifier)"/>
                    <li class="nodot">
                      <span class="{local-name(.)}">
                        <xsl:value-of select="."/>
                      </span>
                      <span>
                        <xsl:attribute name="class">
                          <xsl:value-of select="$authorElementName"/>
                        </xsl:attribute>
                        <xsl:value-of select="../*[local-name() = $authorElementName]"/>
                      </span>
                    </li>
                  </xsl:for-each>
                </ul>
              </xsl:if>

              <ul class="SciName">
                <!-- this for-each iterates once for each <item> node -->
                <!-- that has the same value of Family, Subfamily, and Genus as the -->
                <!-- containing for-each iteration -->
                <xsl:for-each select="key('kGenus',concat(Family,':',Subfamily,':',Genus))">
                  <!-- this for-each iterates over all the <ScientificName> nodes in the <item> -->
                  <li>
                    <xsl:for-each select="ScientificName">
                      <xsl:variable name="myPosition" select="position()"/>
                      <xsl:call-template name="outputDataAuthor">
                        <xsl:with-param name="dataString">
                          <xsl:value-of select="."/>
                        </xsl:with-param>
                        <xsl:with-param name="authorString">
                          <xsl:value-of select="following-sibling::AuthorYearOfScientificName[$myPosition]"/>
                        </xsl:with-param>
                        <xsl:with-param name="className" select="'ScientificName'"/>
                      </xsl:call-template>
                    </xsl:for-each>
                    <xsl:if test="count(QestionableSynonym) != 0">
                      <span class="block">
                        <xsl:for-each select="QestionableSynonym">
                          <xsl:variable name="myPosition" select="position()"/>
                          <xsl:call-template name="outputDataAuthor">
                            <xsl:with-param name="dataString">
                              <xsl:value-of select="."/>
                            </xsl:with-param>
                            <xsl:with-param name="authorString">
                              <xsl:value-of select="following-sibling::AuthorYearOfQestionableSynonym[$myPosition]"/>
                            </xsl:with-param>
                            <xsl:with-param name="className" select="'QestionableSynonym'"/>
                          </xsl:call-template>
                        </xsl:for-each>
                      </span>
                    </xsl:if>

                    <xsl:for-each select="*[(substring-before(local-name(),'_') = 'SynonymOfScientificName') and (string-length() &gt; 0)]">
                      <xsl:variable name="localNameModifier" select="substring-after(local-name(.),'SynonymOfScientificName')"/>
                      <xsl:variable name="authorElementName" select="concat('AuthorYearOfSynonymOfScientificName',$localNameModifier)"/>
                      <xsl:call-template name="outputDataAuthor">
                        <xsl:with-param name="dataString">
                          <xsl:value-of select="."/>
                        </xsl:with-param>
                        <xsl:with-param name="authorString">
                          <xsl:value-of select="../*[local-name() = $authorElementName]"/>
                        </xsl:with-param>
                        <xsl:with-param name="className" select="local-name(.)"/>
                      </xsl:call-template>
                    </xsl:for-each>

                    <xsl:for-each select="*[substring-before(local-name(),'_') = 'InfraspecificRank' and string-length(text()) &gt; 0]">
                      <span class="block">
                        <xsl:variable name="localNameModifier" select="substring-after(local-name(.),'SynonymOfScientificName')"/>
                        <xsl:variable name="epithetName" select="concat('InfraspecificEpithet',$localNameModifier)"/>
                        <xsl:variable name="epithetAuthorName" select="concat('AuthorYearOfInfraspecificEpithet',$localNameModifier)"/>
                        <xsl:variable name="synName" select="concat('SynonymOfInfraspecificEpithet',$localNameModifier)"/>
                        <xsl:variable name="synAuthorName" select="concat('AuthorYearOfSynonymOfInfraspecificEpithet',$localNameModifier)"/>
                        <xsl:call-template name="outputRankEpithetAuthor">
                          <xsl:with-param name="rankString">
                            <xsl:value-of select="."/>
                          </xsl:with-param>
                          <xsl:with-param name="epithetString">
                            <xsl:value-of select="../*[local-name() = $epithetName]"/>
                          </xsl:with-param>
                          <xsl:with-param name="authorString">
                            <xsl:value-of select="../*[local-name() = $epithetAuthorName]"/>
                          </xsl:with-param>
                          <xsl:with-param name="rankClassName" select="local-name(.)"/>
                          <xsl:with-param name="epithetClassName" select="$epithetName"/>
                        </xsl:call-template>
                        <xsl:call-template name="outputDataAuthor">
                          <xsl:with-param name="dataString">
                            <xsl:value-of select="./*[local-name() = $synName]"/>
                          </xsl:with-param>
                          <xsl:with-param name="authorString">
                            <xsl:value-of select="./*[local-name() = $synAuthorName]"/>
                          </xsl:with-param>
                          <xsl:with-param name="className" select="$synName"/>
                        </xsl:call-template>
                      </span>
                    </xsl:for-each>
                  </li>
                </xsl:for-each>
              </ul>
            </xsl:for-each>
          </xsl:for-each>
        </xsl:for-each>
      </body>
    </html>
  </xsl:template>

  <xsl:template name="outputDataAuthor">
    <xsl:param name="dataString"/>
    <xsl:param name="authorString"/>
    <xsl:param name="className"/>
    <xsl:if test="string-length($dataString) &gt; 0">
      <span class="{$className}">
        <xsl:value-of select="$dataString"/>
      </span>
      <xsl:if test="string-length($authorString) &gt; 0">
        <span class="{concat('AuthorYearOf',$className)}">
          <xsl:value-of select="$authorString"/>
        </span>
      </xsl:if>
    </xsl:if>
  </xsl:template>

  <xsl:template name="outputRankEpithetAuthor">
    <xsl:param name="rankString"/>
    <xsl:param name="epithetString"/>
    <xsl:param name="authorString"/>
    <xsl:param name="rankClassName"/>
    <xsl:param name="epithetClassName"/>
    <xsl:if test="string-length(rankString) &gt; 0">
      <span class="{$rankClassName}">
        <xsl:value-of select="rankString"/>
      </span>
      <xsl:if test="string-length(epithetString) &gt; 0">
        <span class="{$epithetClassName}">
          <xsl:value-of select="epithetString"/>
        </span>
      </xsl:if>
      <xsl:if test="string-length($authorString) &gt; 0">
        <span class="{concat('AuthorYearOf',$epithetClassName)}">
          <xsl:value-of select="$authorString"/>
        </span>
      </xsl:if>
    </xsl:if>
  </xsl:template>
</xsl:stylesheet>[/small]

I hope this helps...

Tom Morrison
 
Thanks,
I chaged my DTD, based on a previous tip, to:
Code:
<!DOCTYPE Chrysidoidea [
	  <!ELEMENT Chrysidoidea (item*)>
	  <!ELEMENT item 
		    (id, ScientificName, SpecificEpithet, AuthorYearOfScientificName, VernacularName?, Superfamily, Family, VernacularNameOfFamily?, Subfamily?, Genus, AuthorYearOfGenus, VernacularNameOfGenus?, SynonymOfGenus_1?, AuthorYearOfSynonymOfGenus_1?, SynonymOfGenus_2?, AuthorYearOfSynonymOfGenus_2?, SynonymOfGenus_3?, AuthorYearOfSynonymOfGenus_3?, SynonymOfGenus_4?, AuthorYearOfSynonymOfGenus_4?, SynonymOfGenus_5?, AuthorYearOfSynonymOfGenus_5?, SynonymOfGenus_6?, AuthorYearOfSynonymOfGenus_6?, SynonymOfGenus_7?, AuthorYearOfSynonymOfGenus_7?, QestionableSynonym?, AuthorYearOfQestionableSynonym?, SynonymOfScientificName_1?, AuthorYearOfSynonymOfScientificName_1?, SynonymOfScientificName_2?, AuthorYearOfSynonymOfScientificName_2?, SynonymOfScientificName_3?, AuthorYearOfSynonymOfScientificName_3?, SynonymOfScientificName_4?, AuthorYearOfSynonymOfScientificName_4?, InfraspecificRank_1?, InfraspecificEpithet_1?, AuthorYearOfInfraspecificEpithet_1?, SynonymOfInfraspecificEpithet_1?, AuthorYearOfSynonymOfInfraspecificEpithet_1?, InfraspecificRank_2?, InfraspecificEpithet_2?, AuthorYearOfInfraspecificEpithet_2?, SynonymOfInfraspecificEpithet_2?, AuthorYearOfSynonymOfInfraspecificEpithet_2?, InfraspecificRank_3?, InfraspecificEpithet_3?, AuthorYearOfInfraspecificEpithet_3?, SynonymOfInfraspecificEpithet_3?, AuthorYearOfSynonymOfInfraspecificEpithet_3?, InfraspecificRank_4?, InfraspecificEpithet_4?, AuthorYearOfInfraspecificEpithet_4?, SynonymOfInfraspecificEpithet_4?, AuthorYearOfSynonymOfInfraspecificEpithet_4?, InfraspecificRank_5?, InfraspecificEpithet_5?, AuthorYearOfInfraspecificEpithet_5?, SynonymOfInfraspecificEpithet_5?, AuthorYearOfSynonymOfInfraspecificEpithet_5?)>
	  <!ELEMENT id (#PCDATA)>
	  <!ELEMENT ScientificName (#PCDATA)>
Et cetera, up to and including:
Code:
	  <!ATTLIST VernacularNameOfGenus lang CDATA #IMPLIED>
	  <!ENTITY auml "&#228;">
	  <!ENTITY ouml "&#246;">
	  <!ENTITY aacute "&#225;">
	  <!ENTITY oacute "&#243;">
]>
I got my embedded lists to work as xsl in this way. This part stayed fairly unchanged:
Code:
<xsl:stylesheet version="1.0" xmlns:xsl="[URL unfurl="true"]http://www.w3.org/1999/XSL/Transform">[/URL]
  <xsl:output indent="yes"/>
<!-- multilevel grouping using the Muench method -->

<!-- Establish a key for each grouping level.  Note that each lower level key value -->
<!-- must include the key value of the higher order key -->
  <xsl:key name="kFamily" match="item" use="Family"/>
  <xsl:key name="kVernacularNameOfFamily" match="item" use="VernacularNameOfFamily"/>
  <xsl:key name="kSubfamily" match="item" use="concat(Family,':',Subfamily)"/>
  <xsl:key name="kGenus" match="item" use="concat(Family,':',Subfamily,':',Genus)"/>

  <xsl:template match="/">
    <html>
<head>
  <title>Chrysidoidea</title>
  <link rel="stylesheet" type="text/css" href="chrysidoidea.css" title="default" />
</head>
      <body>
        <h1 class="superfamily">
          <xsl:value-of select="local-name(/*[1])"/>
        </h1>
        <!-- the outer for-each iterates once for each unique value of Family -->
        <xsl:for-each select="/*/item[generate-id() = generate-id(key('kFamily', Family)[1])]">
          <h2>
            <span class="Family"><xsl:value-of select="Family" /></span>
            <span class="VernacularNameOfFamily"><xsl:value-of select="VernacularNameOfFamily" /></span>
          </h2>

          <!-- this for-each iterates over the <item> nodes, once for each unique value of Subfamily -->
          <!-- that have the same value of Family as the containing for-each iteration -->
          <xsl:for-each select="key('kFamily', Family)
                                [generate-id()=
                                  generate-id(key('kSubfamily',concat(Family,':',Subfamily))[1])]">
            <xsl:if test="string-length(Subfamily) &gt; 0">
              <h3 class="Subfamily">
                <xsl:value-of select="Subfamily"/>
              </h3>
            </xsl:if>
            <!-- this for-each iterates over the <item> nodes, once for each unique value of Genus -->
            <!-- that have the same value of Family and Subfamily as the containing for-each iteration -->
            <xsl:for-each select="key('kSubfamily', concat(Family,':',Subfamily))
                                  [generate-id()=
                                    generate-id(key('kGenus',concat(Family,':',Subfamily,':',Genus))[1])]">
              <xsl:if test="string-length(Genus) &gt; 0">
                <h4>
                  <span class="Genus"><xsl:value-of select="Genus"/></span>
                  <span class="AuthorYearOfGenus"><xsl:value-of select="AuthorYearOfGenus"/></span>
                  <span class="VernacularNameOfGenus"><xsl:value-of select="VernacularNameOfGenus" /></span>
                 </h4>
              </xsl:if>
<xsl:if test="count(*[(substring-before(local-name(),'_') = 'SynonymOfGenus') and (string-length() &gt; 0)]) &gt; 0">
  <ul class="SynGen">
  <xsl:for-each select="*[(substring-before(local-name(),'_') = 'SynonymOfGenus') and (string-length() &gt; 0)]">
    <xsl:variable name="localNameModifier" select="substring-after(local-name(.),'SynonymOfGenus')"/>
    <xsl:variable name="authorElementName" select="concat('AuthorYearOfSynonymOfGenus',$localNameModifier)"/>
    <li class="nodot">
      <span class="{local-name(.)}"><xsl:value-of select="." /></span>
      <span>
        <xsl:attribute name="class"><xsl:value-of select="$authorElementName"/></xsl:attribute>
        <xsl:value-of select="../*[local-name() = $authorElementName]" />
      </span>
    </li>
  </xsl:for-each>
  </ul>
</xsl:if>
 
              <ul class="SciName">
                <!-- this for-each iterates once for each <item> node -->
                <!-- that has the same value of Family, Subfamily, and Genus as the -->
                <!-- containing for-each iteration -->
                <xsl:for-each select="key('kGenus',concat(Family,':',Subfamily,':',Genus))">
                  <!-- this for-each iterates over all the <ScientificName> nodes in the <item> -->
              <li>
                  <xsl:for-each select="ScientificName[string-length(text()) &gt; 0]">
                      <span class="ScientificName"><xsl:value-of select="."/></span>
                  </xsl:for-each>
                  <xsl:for-each select="AuthorYearOfScientificName[string-length(text()) &gt; 0]">
                      <span class="AuthorYearOfScientificName"><xsl:value-of select="."/></span>
                  </xsl:for-each>
This part was changed to make way for embedded lists. It apparently works.
Code:
<xsl:if test="string-length(InfraspecificRank_1 or SynonymOfScientificName_1 or QestionableSynonym) &gt; 0">
  <ul class="SynSciName">


                  <xsl:for-each select="QestionableSynonym[string-length(text()) &gt; 0]">
                     <li class="inline">
                      <span class="QestionableSynonym"><xsl:value-of select="."/></span>
                      </li>
                  </xsl:for-each>
                  <xsl:for-each select="AuthorYearOfQestionableSynonym[string-length(text()) &gt; 0]">
                     <li class="inline">
                      <span class="AuthorYearOfQestionableSynonym"><xsl:value-of select="."/></span>
                      </li>
                      <br />
                  </xsl:for-each>

                  <xsl:for-each select="SynonymOfScientificName_1[string-length(text()) &gt; 0]">
                      <li class="inline">
                      <span class="SynonymOfScientificName_1"><xsl:value-of select="."/></span>
                      </li>
                  </xsl:for-each>
                  <xsl:for-each select="AuthorYearOfSynonymOfScientificName_1[string-length(text()) &gt; 0]">
                      <li class="inline">
                      <span class="AuthorYearOfSynonymOfScientificName_1"><xsl:value-of select="."/></span>
                      </li>
                      <br />
                  </xsl:for-each>

                  <xsl:for-each select="SynonymOfScientificName_2[string-length(text()) &gt; 0]">
                      <li class="inline">
                      <span class="SynonymOfScientificName_2"><xsl:value-of select="."/></span>
                      </li>
                  </xsl:for-each>
                  <xsl:for-each select="AuthorYearOfSynonymOfScientificName_2[string-length(text()) &gt; 0]">
                      <li class="inline">
                      <span class="AuthorYearOfSynonymOfScientificName_2"><xsl:value-of select="."/></span>
                      </li>
                      <br />
                  </xsl:for-each>

                  <xsl:for-each select="SynonymOfScientificName_3[string-length(text()) &gt; 0]">
                      <li class="inline">
                      <span class="SynonymOfScientificName_3"><xsl:value-of select="."/></span>
                      </li>
                  </xsl:for-each>
                  <xsl:for-each select="AuthorYearOfSynonymOfScientificName_3[string-length(text()) &gt; 0]">
                      <li class="inline">
                      <span class="AuthorYearOfSynonymOfScientificName_3"><xsl:value-of select="."/></span>
                      </li>
                      <br />
                  </xsl:for-each>

                  <xsl:for-each select="SynonymOfScientificName_4[string-length(text()) &gt; 0]">
                      <li class="inline">
                      <span class="SynonymOfScientificName_4"><xsl:value-of select="."/></span>
                      </li>
                  </xsl:for-each>
                  <xsl:for-each select="AuthorYearOfSynonymOfScientificName_4[string-length(text()) &gt; 0]">
                      <li class="inline">
                      <span class="AuthorYearOfSynonymOfScientificName_4"><xsl:value-of select="."/></span>
                      </li>
                      <br />
                  </xsl:for-each>

                  <xsl:for-each select="InfraspecificRank_1[string-length(text()) &gt; 0]">
                      <li class="inline">
                      <span class="InfraspecificRank_1"><xsl:value-of select="."/></span>
                      </li>
                  </xsl:for-each>
                  <xsl:for-each select="InfraspecificEpithet_1[string-length(text()) &gt; 0]">
                      <li class="inline">
                      <span class="InfraspecificEpithet_1"><xsl:value-of select="."/></span>
                      </li>
                  </xsl:for-each>
                  <xsl:for-each select="AuthorYearOfInfraspecificEpithet_1[string-length(text()) &gt; 0]">
                      <li class="inline">
                      <span class="AuthorYearOfInfraspecificEpithet_1"><xsl:value-of select="."/></span>
                      </li>
                      <br />
                  </xsl:for-each>
 
                  <xsl:for-each select="SynonymOfInfraspecificEpithet_1[string-length(text()) &gt; 0]">
                      <li class="inline">
                      <span class="SynonymOfInfraspecificEpithet_1"><xsl:value-of select="."/></span>
                      </li>
                  </xsl:for-each>
                  <xsl:for-each select="AuthorYearOfSynonymOfInfraspecificEpithet_1[string-length(text()) &gt; 0]">
                      <li class="inline">
                      <span class="AuthorYearOfSynonymOfInfraspecificEpithet_1"><xsl:value-of select="."/></span>
                      </li>
                      <br />
                  </xsl:for-each>

                  <xsl:for-each select="InfraspecificRank_2[string-length(text()) &gt; 0]">
                      <li class="inline">
                      <span class="InfraspecificRank_2"><xsl:value-of select="."/></span>
                      </li>
                  </xsl:for-each>
                  <xsl:for-each select="InfraspecificEpithet_2[string-length(text()) &gt; 0]">
                      <li class="inline">
                      <span class="InfraspecificEpithet_2"><xsl:value-of select="."/></span>
                      </li>
                  </xsl:for-each>
                  <xsl:for-each select="AuthorYearOfInfraspecificEpithet_2[string-length(text()) &gt; 0]">
                      <li class="inline">
                      <span class="AuthorYearOfInfraspecificEpithet_2"><xsl:value-of select="."/></span>
                      </li>
                      <br />
                  </xsl:for-each>
 
                  <xsl:for-each select="SynonymOfInfraspecificEpithet_2[string-length(text()) &gt; 0]">
                      <li class="inline">
                      <span class="SynonymOfInfraspecificEpithet_2"><xsl:value-of select="."/></span>
                      </li>
                  </xsl:for-each>
                  <xsl:for-each select="AuthorYearOfSynonymOfInfraspecificEpithet_2[string-length(text()) &gt; 0]">
                      <li class="inline">
                      <span class="AuthorYearOfSynonymOfInfraspecificEpithet_2"><xsl:value-of select="."/></span>
                      </li>
                      <br />
                  </xsl:for-each>

                  <xsl:for-each select="InfraspecificRank_3[string-length(text()) &gt; 0]">
                      <li class="inline">
                      <span class="InfraspecificRank_3"><xsl:value-of select="."/></span>
                      </li>
                  </xsl:for-each>
                  <xsl:for-each select="InfraspecificEpithet_3[string-length(text()) &gt; 0]">
                      <li class="inline">
                      <span class="InfraspecificEpithet_3"><xsl:value-of select="."/></span>
                      </li>
                  </xsl:for-each>
                  <xsl:for-each select="AuthorYearOfInfraspecificEpithet_3[string-length(text()) &gt; 0]">
                      <li class="inline">
                      <span class="AuthorYearOfInfraspecificEpithet_3"><xsl:value-of select="."/></span>
                      </li>
                      <br />
                  </xsl:for-each>
 
                  <xsl:for-each select="SynonymOfInfraspecificEpithet_3[string-length(text()) &gt; 0]">
                      <li class="inline">
                      <span class="SynonymOfInfraspecificEpithet_3"><xsl:value-of select="."/></span>
                      </li>
                  </xsl:for-each>
                  <xsl:for-each select="AuthorYearOfSynonymOfInfraspecificEpithet_3[string-length(text()) &gt; 0]">
                      <li class="inline">
                      <span class="AuthorYearOfSynonymOfInfraspecificEpithet_3"><xsl:value-of select="."/></span>
                      </li>
                      <br />
                  </xsl:for-each>

                  <xsl:for-each select="InfraspecificRank_4[string-length(text()) &gt; 0]">
                      <li class="inline">
                      <span class="InfraspecificRank_4"><xsl:value-of select="."/></span>
                      </li>
                  </xsl:for-each>
                  <xsl:for-each select="InfraspecificEpithet_4[string-length(text()) &gt; 0]">
                      <li class="inline">
                      <span class="InfraspecificEpithet_4"><xsl:value-of select="."/></span>
                      </li>
                  </xsl:for-each>
                  <xsl:for-each select="AuthorYearOfInfraspecificEpithet_4[string-length(text()) &gt; 0]">
                      <li class="inline">
                      <span class="AuthorYearOfInfraspecificEpithet_4"><xsl:value-of select="."/></span>
                      </li>
                      <br />
                  </xsl:for-each>
 
                  <xsl:for-each select="SynonymOfInfraspecificEpithet_4[string-length(text()) &gt; 0]">
                      <li class="inline">
                      <span class="SynonymOfInfraspecificEpithet_4"><xsl:value-of select="."/></span>
                      </li>
                  </xsl:for-each>
                  <xsl:for-each select="AuthorYearOfSynonymOfInfraspecificEpithet_4[string-length(text()) &gt; 0]">
                      <li class="inline">
                      <span class="AuthorYearOfSynonymOfInfraspecificEpithet_4"><xsl:value-of select="."/></span>
                      </li>
                      <br />
                  </xsl:for-each>

                  <xsl:for-each select="InfraspecificRank_5[string-length(text()) &gt; 0]">
                      <li class="inline">
                      <span class="InfraspecificRank_5"><xsl:value-of select="."/></span>
                      </li>
                  </xsl:for-each>
                  <xsl:for-each select="InfraspecificEpithet_5[string-length(text()) &gt; 0]">
                      <li class="inline">
                      <span class="InfraspecificEpithet_5"><xsl:value-of select="."/></span>
                      </li>
                  </xsl:for-each>
                  <xsl:for-each select="AuthorYearOfInfraspecificEpithet_5[string-length(text()) &gt; 0]">
                      <li class="inline">
                      <span class="AuthorYearOfInfraspecificEpithet_5"><xsl:value-of select="."/></span>
                      </li>
                      <br />
                  </xsl:for-each>
 
                  <xsl:for-each select="SynonymOfInfraspecificEpithet_5[string-length(text()) &gt; 0]">
                      <li class="inline">
                      <span class="SynonymOfInfraspecificEpithet_5"><xsl:value-of select="."/></span>
                      </li>
                  </xsl:for-each>
                  <xsl:for-each select="AuthorYearOfSynonymOfInfraspecificEpithet_5[string-length(text()) &gt; 0]">
                      <li class="inline">
                      <span class="AuthorYearOfSynonymOfInfraspecificEpithet_5"><xsl:value-of select="."/></span>
                      </li>
                      <br />
                  </xsl:for-each>

  </ul>
</xsl:if>

              </li>
               </xsl:for-each>
             </ul>
            </xsl:for-each>       
          </xsl:for-each>
        </xsl:for-each>
      </body>
    </html>
  </xsl:template>
</xsl:stylesheet>
With some help from CSS.
I have not had time to look at your new suggetion concerning "<xsl:call-template>." I shall do so and report back here.
 
I would probably code:
Code:
string-length(concat(InfraspecificRank_1, SynonymOfScientificName_1, QestionableSynonym)) &gt; 0

Tom Morrison
 
Hello. I follwed your suggestion concerning "<xsl:call-template>." I have added some embedded lists to the templates, as you will see. But I still have one problem. None of the content of "InfraspecificRank_1," "InfraspecificEpithet_1" or "AuthorYearOfInfraspecificEpithet_1" (or _2, _3, etc.) is getting displayed, and I can't figure it out. So I roll the ball back to you.
Here, again, is part of the DTD:
Code:
InfraspecificRank_1?, InfraspecificEpithet_1?, AuthorYearOfInfraspecificEpithet_1?, SynonymOfInfraspecificEpithet_1?, AuthorYearOfSynonymOfInfraspecificEpithet_1?, InfraspecificRank_2?, InfraspecificEpithet_2?, AuthorYearOfInfraspecificEpithet_2?, SynonymOfInfraspecificEpithet_2?, AuthorYearOfSynonymOfInfraspecificEpithet_2?, InfraspecificRank_3?, InfraspecificEpithet_3?, AuthorYearOfInfraspecificEpithet_3?, SynonymOfInfraspecificEpithet_3?, AuthorYearOfSynonymOfInfraspecificEpithet_3?, InfraspecificRank_4?, InfraspecificEpithet_4?, AuthorYearOfInfraspecificEpithet_4?, SynonymOfInfraspecificEpithet_4?, AuthorYearOfSynonymOfInfraspecificEpithet_4?, InfraspecificRank_5?, InfraspecificEpithet_5?, AuthorYearOfInfraspecificEpithet_5?, SynonymOfInfraspecificEpithet_5?, AuthorYearOfSynonymOfInfraspecificEpithet_5?)>

And here is the part of the style sheet that I added lists to and where the display of <InfraspecificRank_1>, etc., isn't working:
Code:
				<ul class="SciName">
					<!-- this for-each iterates once for each <item> node -->
						<!-- that has the same value of Family, Subfamily, and Genus as the -->
						<!-- containing for-each iteration -->
						<xsl:for-each select="key('kGenus',concat(Family,':',Subfamily,':',Genus))">
							<!-- this for-each iterates over all the <ScientificName> nodes in the <item> -->
									<li>
										<xsl:for-each select="ScientificName">
										<xsl:variable name="myPosition" select="position()"/>
										<xsl:call-template name="outputDataAuthor">
										<xsl:with-param name="dataString">
										<xsl:value-of select="."/>
									</xsl:with-param>
									<xsl:with-param name="authorString">
										<xsl:value-of select="following-sibling::AuthorYearOfScientificName[$myPosition]"/>
									</xsl:with-param>
									<xsl:with-param name="className" select="'ScientificName'"/>
								</xsl:call-template>
							</xsl:for-each>

<xsl:if test="string-length(concat(InfraspecificRank_1, SynonymOfScientificName_1, QestionableSynonym)) &gt; 0">
  <ul class="SynSciName">

							<xsl:if test="count(QestionableSynonym) != 0">
								
									<xsl:for-each select="QestionableSynonym">
										<xsl:variable name="myPosition" select="position()"/>
										<xsl:call-template name="outputDataAuthor">
										<xsl:with-param name="dataString">
										<xsl:value-of select="."/>
									</xsl:with-param>
									<xsl:with-param name="authorString">
										<xsl:value-of select="following-sibling::AuthorYearOfQestionableSynonym[$myPosition]"/>
									</xsl:with-param>
									<xsl:with-param name="className" select="'QestionableSynonym'"/>
								</xsl:call-template>
							</xsl:for-each>
					</xsl:if>
					
					<xsl:for-each select="*[(substring-before(local-name(),'_') = 'SynonymOfScientificName') and (string-length() &gt; 0)]">
						<xsl:variable name="localNameModifier" select="substring-after(local-name(.),'SynonymOfScientificName')"/>
						<xsl:variable name="authorElementName" select="concat('AuthorYearOfSynonymOfScientificName',$localNameModifier)"/>
						<xsl:call-template name="outputDataAuthor">
							<xsl:with-param name="dataString">
								<xsl:value-of select="."/>
							</xsl:with-param>
							<xsl:with-param name="authorString">
								<xsl:value-of select="../*[local-name() = $authorElementName]"/>
							</xsl:with-param>
							<xsl:with-param name="className" select="local-name(.)"/>
						</xsl:call-template>
					</xsl:for-each>
					
					<xsl:for-each select="*[substring-before(local-name(),'_') = 'InfraspecificRank' and string-length(text()) &gt; 0]">
							<xsl:variable name="localNameModifier" select="substring-after(local-name(.),'SynonymOfScientificName')"/>
							<xsl:variable name="epithetName" select="concat('InfraspecificEpithet',$localNameModifier)"/>
							<xsl:variable name="epithetAuthorName" select="concat('AuthorYearOfInfraspecificEpithet',$localNameModifier)"/>
							<xsl:variable name="synName" select="concat('SynonymOfInfraspecificEpithet',$localNameModifier)"/>
							<xsl:variable name="synAuthorName" select="concat('AuthorYearOfSynonymOfInfraspecificEpithet',$localNameModifier)"/>
							<xsl:call-template name="outputRankEpithetAuthor">
								<xsl:with-param name="rankString">
									<xsl:value-of select="."/>
								</xsl:with-param>
								<xsl:with-param name="epithetString">
									<xsl:value-of select="../*[local-name() = $epithetName]"/>
								</xsl:with-param>
								<xsl:with-param name="authorString">
									<xsl:value-of select="../*[local-name() = $epithetAuthorName]"/>
								</xsl:with-param>
								<xsl:with-param name="rankClassName" select="local-name(.)"/>
								<xsl:with-param name="epithetClassName" select="$epithetName"/>
							</xsl:call-template>
							<xsl:call-template name="outputDataAuthor">
								<xsl:with-param name="dataString">
									<xsl:value-of select="./*[local-name() = $synName]"/>
								</xsl:with-param>
								<xsl:with-param name="authorString">
									<xsl:value-of select="./*[local-name() = $synAuthorName]"/>
								</xsl:with-param>
								<xsl:with-param name="className" select="$synName"/>
							</xsl:call-template>
					</xsl:for-each>
  </ul>
</xsl:if>
				</li>
			</xsl:for-each>
		</ul>
	</xsl:for-each>
</xsl:for-each>
</xsl:for-each>
</body>
</html>
</xsl:template>

<xsl:template name="outputDataAuthor">
	<xsl:param name="dataString"/>
	<xsl:param name="authorString"/>
	<xsl:param name="className"/>
	<xsl:if test="string-length($dataString) &gt; 0">
                <li class="inline">		
                <span class="{$className}">
			<xsl:value-of select="$dataString"/>
		</span>
                </li>

		<xsl:if test="string-length($authorString) &gt; 0">
                <li class="inline">	
			<span class="{concat('AuthorYearOf',$className)}">
				<xsl:value-of select="$authorString"/>
	                </span>
                <br />
                </li>
		</xsl:if>
	</xsl:if>
</xsl:template>

<xsl:template name="outputRankEpithetAuthor">
	<xsl:param name="rankString"/>
	<xsl:param name="epithetString"/>
	<xsl:param name="authorString"/>
	<xsl:param name="rankClassName"/>
	<xsl:param name="epithetClassName"/>
	<xsl:if test="string-length(rankString) &gt; 0">
                <li class="inline">
		<span class="{$rankClassName}">
			<xsl:value-of select="rankString"/>
		</span>
                </li>
		<xsl:if test="string-length(epithetString) &gt; 0">
                <li class="inline">
			<span class="{$epithetClassName}">
				<xsl:value-of select="epithetString"/>
			</span>
                </li>
		</xsl:if>
		<xsl:if test="string-length($authorString) &gt; 0">
                <li class="inline">
			<span class="{concat('AuthorYearOf',$epithetClassName)}">
				<xsl:value-of select="$authorString"/>
			</span>
                <br />
                </li>
		</xsl:if>
	</xsl:if>
</xsl:template>
</xsl:stylesheet>
Any idea how I can get the InfraspecificRank_1 (etc) to display? Thanks.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top