简体   繁体   中英

Handling multiple elements with same name in XSLT

I have xml with the following data.

<Rows>
   <Header>
      <sourcetable>Table_1</sourcetable>
      <targettable>Table_2</targettable>
   </Header>
   <Table>
      <Source_Fieldname>DTIME_INSERTED</Source_Fieldname>
      <Source_Type>Timestamp</Source_Type>
      <Source_Fieldname>ID_JOB</Source_Fieldname>
      <Source_Type>String</Source_Type>
   </Table>

   <Header>
      <sourcetable>Table_3</sourcetable>
      <targettable>Table_4</targettable>
   </Header>
   <Table>
      <Source_Fieldname>DTIME_INSERTED</Source_Fieldname>
      <Source_Type>Timestamp</Source_Type>
      <Source_Fieldname>ID_JOB</Source_Fieldname>
      <Source_Type>String</Source_Type>
   </Table>   
</Rows>

I am trying to output this into separate tables per "Table" element just like this but can't figure it out since there are multiple elements with the same name.
桌子_

So far this is what I got.

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="html" indent="yes" />
    <xsl:template match="Row">        

        <table border="1px" cellpadding="3" cellspacing="1" style='font-family:"Calibri"; font-size:12; font-weight:"normal"' >
            <tr align="center">
            <xsl:for-each select="preceding-sibling::Header[1]">
               <th colspan="4"  bgcolor="#ccffff">
               <font size="2" face="Calibri" style="text-transform:uppercase"> <xsl:value-of select="sourcetable" /> </font> 
               </th>
               <th colspan="4" bgcolor="#ccffff">
               <font size="2" face="Calibri" style="text-transform:uppercase"> <xsl:value-of select="targettable" /> </font>
               </th>
            </xsl:for-each>
                <th bgcolor="#FFCCBC" rowspan="2">Flagfield</th>
            </tr>
            <tr  align="left">
                <td bgcolor="#C5E1A5">Source_Fieldname</td>
                <td bgcolor="#C5E1A5">Source_Type</td>
            </tr>

            <xsl:for-each select=".">

             <tr>
                <xsl:for-each select="Source_Fieldname">
                    <td> <xsl:value-of select="."/> </td>
                </xsl:for-each>

                <xsl:for-each select="Source_Type">
                        <td> <xsl:value-of select="."/> </td>
                </xsl:for-each>
            </tr>   

            </xsl:for-each>

            </xsl:for-each>
        </table>
        <br /><br/>
    </xsl:template>

</xsl:stylesheet>

Any suggestion how to achieve desired output is appreciated. Thanks!

You had a good start but a few details were not working. Here's how I would solve it.

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="html" indent="yes" />

    <xsl:template match="/">
        <html>
            <head/>
            <body>
                <xsl:apply-templates select="Rows/Table"/>
            </body>
        </html>
    </xsl:template>

    <xsl:template match="Table">
        <table border="1px" cellpadding="3" cellspacing="1" style='font-family:"Calibri"; font-size:12; font-weight:"normal"' >
            <tr align="center">
                <th bgcolor="#ccffff">
                    <font size="2" face="Calibri" style="text-transform:uppercase"> <xsl:value-of select="preceding-sibling::Header[1]/sourcetable" /> </font> 
                </th>
                <th bgcolor="#ccffff">
                   <font size="2" face="Calibri" style="text-transform:uppercase"> <xsl:value-of select="preceding-sibling::Header[1]/targettable" /> </font>
                </th>
            </tr>
            <tr  align="left">
                <td bgcolor="#C5E1A5">Source_Fieldname</td>
                <td bgcolor="#C5E1A5">Source_Type</td>
            </tr>
            <xsl:apply-templates select="Source_Fieldname"/>
        </table>
        <br/><br/>
    </xsl:template>

    <xsl:template match="Source_Fieldname">
        <tr>
            <td> <xsl:value-of select="."/> </td>
            <td> <xsl:value-of select="following-sibling::Source_Type[1]"/> </td>
        </tr>   
    </xsl:template>

</xsl:stylesheet>

You can test it here : https://xsltfiddle.liberty-development.net/bFWR5Ej/1

So far I managed to create the desired outcome, but however, I would seriously suggest to sanitize your XML file/input, because it's complicating things.

But with your current file, you can use this XSLT-1.0 stylesheet to get the desired output:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="html" indent="yes" />

    <!-- A template handling the main HTML stuff -->
    <xsl:template match="/Rows">
        <html>
            <body>
                <font size="2" face="Calibri" >
                    <h1>The following Source - Target Tables have DDL Mismatch(es)</h1>
                    <br />
                    <xsl:apply-templates select="Table" />
                </font>
            </body>
        </html>
    </xsl:template>

    <xsl:template match="Table">        
        <table border="1px" cellpadding="3" cellspacing="1" style='font-family:"Calibri"; font-size:12; font-weight:"normal"' >
            <tr align="center">
            <xsl:for-each select="preceding-sibling::Header[1]">
               <th colspan="1"  bgcolor="#ccffff">
               <font size="2" face="Calibri" style="text-transform:uppercase"> <xsl:value-of select="sourcetable" /> </font> 
               </th>
               <th colspan="1" bgcolor="#ccffff">
               <font size="2" face="Calibri" style="text-transform:uppercase"> <xsl:value-of select="targettable" /> </font>
               </th>
            </xsl:for-each>
                <th bgcolor="#FFCCBC" rowspan="2">Flagfield</th>
            </tr>
            <tr  align="left">
                <td bgcolor="#C5E1A5">Source_Fieldname</td>
                <td bgcolor="#C5E1A5">Source_Type</td>
            </tr>
            <xsl:for-each select="*[local-name()='Source_Fieldname']">
                <tr>
                    <td><xsl:value-of select="."/></td>
                    <td><xsl:value-of select="following-sibling::Source_Type[1]"/></td>
                </tr>   
            </xsl:for-each>
        </table>
        <br /><br/>
    </xsl:template>

</xsl:stylesheet>

The central aspect is the xsl:for-each loop:

<xsl:for-each select="*[local-name()='Source_Fieldname']">
    <tr>
        <td><xsl:value-of select="."/></td>
        <td><xsl:value-of select="following-sibling::Source_Type[1]"/></td>
    </tr>   
</xsl:for-each>

The output is:

在此处输入图片说明

It simply iterates over all <Table> children which are named Source_Fieldname and then creates a table cell for these and for the first following-sibling Source_Type element. This does work for a two element table, but it should be no problem to extend it to a several children situation.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM