【问题标题】:Handling multiple elements with same name in XSLT在 XSLT 中处理多个具有相同名称的元素
【发布时间】:2019-11-29 01:27:10
【问题描述】:

我有带有以下数据的 xml。

<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>

我正在尝试将其输出到每个“表格”元素的单独表格中,就像这样但无法弄清楚,因为有多个具有相同名称的元素。

到目前为止,这就是我得到的。

<?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>

感谢任何关于如何实现所需输出的建议。谢谢!

【问题讨论】:

    标签: xml xslt xslt-1.0


    【解决方案1】:

    您有一个良好的开端,但有一些细节不起作用。这是我将如何解决它。

    <?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>
    

    你可以在这里测试它:https://xsltfiddle.liberty-development.net/bFWR5Ej/1

    【讨论】:

    • 谢谢!您的解决方案与@zx485 相同,但我已经接受了他的正确答案。
    • 我没有足够的声望点来评论您接受的答案。在该解决方案中有两点需要注意::preceding-sibling::Header[1] 总是只返回一个 Header,那么为什么要循环呢?此外, 可以简单地替换为:。我不明白为什么需要在那里进行名称比较。
    【解决方案2】:

    到目前为止,我设法创建了所需的结果,但是,我会认真建议清理您的 XML 文件/输入,因为这会使事情变得复杂。

    但是对于您当前的文件,您可以使用此 XSLT-1.0 样式表来获得所需的输出:

    <?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>
    

    中心方面是xsl:for-each 循环:

    <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>
    

    输出是:

    它简单地遍历所有名为Source_Fieldname&lt;Table&gt; 子元素,然后为这些子元素创建一个表格单元格 用于第一个后续兄弟Source_Type 元素。这确实适用于双元素表,但将其扩展到多个子表的情况应该没有问题。

    【讨论】:

    • 你真是个救命恩人!由于解释,我进一步了解了您的代码是如何工作的。我正在尝试考虑如何清理 xml。我可以编辑它的生成方式。如果您有建议,我愿意接受 :)
    • 谢谢。而且,改进的建议应该很明显:只需将元素名称用下划线分开:所以将Source_FieldnameSource_Type 元素组合到Source 元素中。然后将Fieldname 元素和Type 元素分组到不同的组中。对Target_* 元素执行相同的操作。之后,您可以通过索引轻松访问这些元素,并且可以省略 following::... 语法和类似的技巧。这应该会简化您的 XML。
    • 太棒了。正在努力。快速提问。如果我将
      s 移动到 中,我将在 xsl 中替换什么?
    • 您不必将&lt;Header&gt;s 移动到&lt;Table&gt;s。 XML 的目的是剖析输出中的数据,因此您尝试将 XML 格式化为所需的输出 HTML 不一定是最好的方法。我也不会试图向您推销我管理数据的最佳方法,因为(这应该很明显)我不知道您的数据结构。所以我不能给你“解决所有问题”的解决方案。
    猜你喜欢
    • 2019-02-15
    • 1970-01-01
    • 1970-01-01
    • 2016-05-17
    • 1970-01-01
    • 2022-01-03
    • 2017-07-11
    • 2016-03-06
    • 2014-07-04
    相关资源
    最近更新 更多