How to iterate throught attributes' names in xml version="1.0"

Viewed 47

I try to iterate through attributes' names in xml version="1.0" A Reference XML provides me extra attribute values to be manipulated in a double for-each mainly by their index positions. I found a solution through successive xsl:if, however it is not suitable for many items. Please have a look in the following code and propose something. Thank you in advance.

Here is MyMainXML:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="koinohrista.xsl"?>
 <Features>
 <date>April 2022</date>
  <Feature code="A" info="Common Expenses" name="Garden" price="110.00"></Feature>
  <Feature code="A" info="Common Expenses" name="Cleaning" price="90.00"></Feature>
  <Feature code="B" info="Elevator Expenses" name="Maintainance" price="49.00"></Feature>
  <Feature code="C" info="Extra Costs" name="Painting" price="321.50"></Feature>
  <Feature code="D" info="Proriator Expenses" name="Repairing" price="356.60"></Feature>
  <Feature code="E" info="Heating Expenses" name="Petrol" price="2621.53"></Feature>
 </Features>

Here is MyReferencing XML:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="hiliosta.xsl"?>
 <Features>
  <Feature name="A1" koinoh="58.20" elev="38.60" heat="62.00" pagio="17.98"></Feature>
  <Feature name="A2" koinoh="45.50" elev="29.45" heat="45.00" pagio="11.25"></Feature>
  <Feature name="A3" koinoh="63.80" elev="39.60" heat="62.00" pagio="17.90"></Feature>
  <Feature name="B1" koinoh="60.00" elev="47.75" heat="62.00" pagio="24.18"></Feature>
  <Feature name="B" koinoh="46.40" elev="36.30" heat="45.00" pagio="15.75"></Feature>
 </Features>

Here is MyXSL:

<xsl:stylesheet
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:variable name="Hiliosta" select="document('C:\Kapopoulos\Hiliosta.xml')"/>    
  <xsl:key name="KeyCode" match="Feature" use="@code"/>
 <xsl:template match="Features">
  <html>
   <body>
    <table class="margin" border="2" cellpadding="1" cellspacing="0" width="100%" height="30">
     <tr>
      <th width="48%" bgcolor="#D7E7F7" align="center"><b>Expenses Description per Category</b></th>
      <th width="52%" bgcolor="#D5E9D7" align="center"><b>Expenses Description per Appartment</b></th>
     </tr>
    </table>
    <xsl:for-each select="Feature[generate-id() = generate-id(key('KeyCode',@code)[1])]">   
      <xsl:sort select="@code" order="ascending"/>
     <table class="margin" border="2" cellpadding="3" cellspacing="0" width="100%" height="50">
      <tr>
       <td colspan="6" align="center"><b>Category 
       <xsl:value-of select="@code"/> (<xsl:value-of select="@info"/>)</b></td>
      </tr>
      <tr bgcolor="#D7E7F7">
       <th align="center" width="24%">Description:</th>
       <th align="center" width="24%">Cost:</th>
       <th align="center" width="13%" bgcolor="#D5E9D7">Expenses</th>
       <th align="center" width="13%" bgcolor="#D5E9D7">Total.mil</th>
       <th align="center" width="13%" bgcolor="#D5E9D7">Appart.mil</th>
       <th align="center" width="13%" bgcolor="#D5E9D7">Cost</th>
      </tr>
      <xsl:for-each select="key('KeyCode',@code)">
       <xsl:if test="not(preceding::*[@name = current()/@name])">
        <tr>
         <td align="center"><xsl:value-of select="@name"/></td>
         <td align="center"><xsl:value-of select="@price"/></td> 
         <xsl:if test="not(preceding::*[@code = current()/@code])">
           <td rowspan="{count(key('KeyCode',@code))}" align="center"><xsl:value-of select="sum(key('KeyCode',@code)/@price)"/></td>           


<!-- GET RID OF FOLLOWING REPETITIONS -->
            <xsl:if test="@code='A' or @code='C' or @code='D'"> 
             <td rowspan="{count(key('KeyCode',@code))}" align="center"><xsl:value-of select="sum($Hiliosta//Feature/@koinoh)"/></td>
             <td rowspan="{count(key('KeyCode',@code))}" align="center"><xsl:value-of select="$Hiliosta/*/Feature[@name='A1']/@koinoh"/></td>
             <td rowspan="{count(key('KeyCode',@code))}" align="center"><xsl:value-of select="format-number(sum(key('KeyCode',@code)/@price) 
              * $Hiliosta/*/Feature[@name='A1']/@koinoh div sum($Hiliosta//Feature/@koinoh),'0.00')"/></td>
            </xsl:if>
            <xsl:if test="@code='B'"> 
             <td rowspan="{count(key('KeyCode',@code))}" align="center"><xsl:value-of select="sum($Hiliosta//Feature/@elev)"/></td>
             <td rowspan="{count(key('KeyCode',@code))}" align="center"><xsl:value-of select="$Hiliosta/*/Feature[@name='A1']/@elev"/></td>
             <td rowspan="{count(key('KeyCode',@code))}" align="center"><xsl:value-of select="format-number(sum(key('KeyCode',@code)/@price) 
              * $Hiliosta/*/Feature[@name='A1']/@elev div sum($Hiliosta//Feature/@elev),'0.00')"/></td>
            </xsl:if>
            <xsl:if test="@code='E'"> 
             <td rowspan="{count(key('KeyCode',@code))}" align="center"><xsl:value-of select="sum($Hiliosta//Feature/@heat)"/></td>
             <td rowspan="{count(key('KeyCode',@code))}" align="center"><xsl:value-of select="$Hiliosta/*/Feature[@name='A1']/@heat"/></td>
             <td rowspan="{count(key('KeyCode',@code))}" align="center"><xsl:value-of select="format-number(sum(key('KeyCode',@code)/@price) 
              * $Hiliosta/*/Feature[@name='A1']/@heat div sum($Hiliosta//Feature/@heat),'0.00')"/></td>
            </xsl:if>       
<!-- GET RID OF PREVIOUS REPETITIONS -->    
            

          </xsl:if>
        </tr> 
       </xsl:if>
      </xsl:for-each>
      <tr>
       <td colspan="1" align="center"><b>Total: </b></td>
       <td align="center"><xsl:value-of select="sum(key('KeyCode',@code)/@price)"/></td>
      </tr>
     <br/>
     </table>
    </xsl:for-each>
     <br/>
    <table class="margin" border="2" cellpadding="3" cellspacing="0" width="48%" height="35">  
     <tr bgcolor="#D7E7F7">
      <td align="center" width="24%" colspan="1"><b>Grand Total:</b></td>
      <td align="center" width="24%" ><xsl:value-of select="sum(//Feature/@price)"/></td>
     </tr>
    </table>
   </body>    
  </html>
 </xsl:template>
</xsl:stylesheet>
1 Answers

In xslt 1.0 you can use variables for this like this:

<xsl:if test="not(preceding::*[@code = current()/@code])">
  <td rowspan="{count(key('KeyCode',@code))}" align="center"><xsl:value-of select="sum(key('KeyCode',@code)/@price)"/></td> 
  
  <xsl:variable name="attributeName">
    <xsl:choose>
      <xsl:when test="@code='A' or @code='C' or @code='D'">koinoh</xsl:when>
      <xsl:when test="@code='B'">elev</xsl:when>
      <xsl:when test="@code='E'">heat</xsl:when>
    </xsl:choose>
  </xsl:variable>
  <td rowspan="{count(key('KeyCode',@code))}" align="center"><xsl:value-of select="sum($Hiliosta//Feature/@*[name()=$attributeName])"/></td>
  <td rowspan="{count(key('KeyCode',@code))}" align="center"><xsl:value-of select="$Hiliosta/*/Feature[@name='A1']/@*[name()=$attributeName]"/></td>
  <td rowspan="{count(key('KeyCode',@code))}" align="center"><xsl:value-of select="format-number(sum(key('KeyCode',@code)/@price) 
    * $Hiliosta/*/Feature[@name='A1']/@*[name()=$attributeName] div sum($Hiliosta//Feature/@*[name()=$attributeName]),'0.00')"/></td>
  
</xsl:if>
Related