1

New to xslt so go easy ,I am been trying to convert an xml to html via xslt and I cannot seem to get it right.

Headers and rows should not be hardcoded and should be as generic as possible.

Wanted result:

Employees

Xml Used that I have no control over

        <?xml version="1.0" encoding="utf-8"?>
    <Generated>
      <Employees>
        <Employee name="Joe Bloggs">
          <Sales>
            <Sale key="Sale-Id" value="333" />
            <Sale key="Sale-Field1" value="a" />
            <Sale key="Sale-Field2" value="b" />
          </Sales>
        </Employee>
        <Employee name="Mark Bloggs">
          <Sales>
            <Sale key="Sale-Id" value="334" />
            <Sale key="Sale-Field1" value="c" />
            <Sale key="Sale-Field2" value="d" />
          </Sales>
        </Employee>
      </Employees>
    </Generated>

XSLT My Attempt

        <?xml version="1.0" encoding="utf-8"?>
    <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:output method="html" version="4" encoding="UTF-8" indent="no" omit-xml-declaration="yes"/>
      <!-- main body -->
      <xsl:template match="/">
        <html>
          <body>
            <h3>Employees</h3>
            <table border="1">
              <tr bgcolor="blue">
                <!--Header only so select first row to get headers-->
                <xsl:for-each select="(Generated/Employees/Employee)[1]/Sales/Sale">
                  <th>
                    <xsl:value-of select="@key"/>
                  </th>
                </xsl:for-each>
              </tr>
              <!--Get all the other rows-->
              <xsl:for-each select="(Generated/Employees/Employee)/Sales/Sale">
                <tr>
                  <td>
                    <xsl:value-of select="@value"/>
                  </td>
                </tr>
              </xsl:for-each>
              </table>
          </body>
        </html>
      </xsl:template>
    </xsl:stylesheet>

My Wrong outcome

enter image description here

Any suggestion how to fix this and get my wanted result as per image above

Many thanks

Mathias Müller
  • 22,203
  • 13
  • 58
  • 75
developer9969
  • 4,628
  • 6
  • 40
  • 88

2 Answers2

2

Building upon Martin Honnen's answer (please accept his answer).

what I miss is how do I get the name.Do I need another nested foreach?and how?

No need for an additional for-each. Introduce another td at the beginning of the first row and call it "Name". Then, inside the for-each for each Employee element, output a td element that contains the value of @name.

XSLT Stylesheet

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
   <xsl:output method="html" encoding="UTF-8" indent="yes" omit-xml-declaration="yes"></xsl:output>
   <xsl:template match="/">
      <html>
         <body>
            <h3>Employees</h3>
            <table border="1">
               <tr bgcolor="blue">
                  <td>Name</td>
                  <xsl:for-each select="(Generated/Employees/Employee)[1]/Sales/Sale">
                     <th>
                        <xsl:value-of select="@key"></xsl:value-of>
                     </th>
                  </xsl:for-each>
               </tr>
               <xsl:for-each select="Generated/Employees/Employee">
                  <tr>
                     <td>
                        <xsl:value-of select="@name"></xsl:value-of>
                     </td>
                     <xsl:for-each select="Sales/Sale">
                        <td>
                           <xsl:value-of select="@value"></xsl:value-of>
                        </td>
                     </xsl:for-each>
                  </tr>
               </xsl:for-each>
            </table>
         </body>
      </html>
   </xsl:template>
</xsl:stylesheet>

HTML Output

<html>
   <body>
      <h3>Employees</h3>
      <table border="1">
         <tr bgcolor="blue">
            <td>Name</td>
            <th>Sale-Id</th>
            <th>Sale-Field1</th>
            <th>Sale-Field2</th>
         </tr>
         <tr>
            <td>Joe Bloggs</td>
            <td>333</td>
            <td>a</td>
            <td>b</td>
         </tr>
         <tr>
            <td>Mark Bloggs</td>
            <td>334</td>
            <td>c</td>
            <td>d</td>
         </tr>
      </table>
   </body>
</html>

Rendered HTML

enter image description here

Community
  • 1
  • 1
Mathias Müller
  • 22,203
  • 13
  • 58
  • 75
1

Change

          <xsl:for-each select="(Generated/Employees/Employee)/Sales/Sale">
            <tr>
              <td>
                <xsl:value-of select="@value"/>
              </td>
            </tr>
          </xsl:for-each>

to

          <xsl:for-each select="Generated/Employees/Employee">
            <tr>
             <xsl:for-each select="Sales/Sale">
              <td>
                <xsl:value-of select="@value"/>
              </td>
             </xsl:for-each>
            </tr>
          </xsl:for-each>
Martin Honnen
  • 160,499
  • 6
  • 90
  • 110