XSL 将 XML 转换为 HTML,从多个结构中过滤相同元素值的元素

XSL to transform XML to HTML, filter elements from multiple structures for the same element value

我是 XML/XSLT 的新手,到目前为止,在 SO 和 W3SChools 网站上搜索关于 Meunchian 分组的聪明东西时,我还没有找到一个有效的解决方案来应对我的挑战。

基本上我有一个从数据库导出的大 XML 文件(这意味着我不能直接编辑 XML),其中包含发票信息。

我想利用 XSLT (1.0) 将 XML 转换为 HTML(我使用的是 Saxon),以便每张发票都显示为 table。然而,在 XML 中,有许多产品线与同一张发票相关(由 <invoiceNum> 元素表示为标识符)。

我不想为属于同一张发票的每个产品线创建和显示新的 table。在我当前的 XSL 文件中,我试图为重复的 <invoiceNum> 元素的第一个实例创建一个 table,然后仅添加来自连续产品线的唯一元素(<ProductID><ProductName><ProductDescription> 等)并省略重复的运输信息。

在 XML 代码片段中,您可以看到 XML 的布局。在 XSL 片段中,我希望您能看到我是如何尝试构建 table。对于 XML 文件中的每个连续 <invoices_snet> 实例,我只想通过转换将产品信息添加到 table。在 <invoices_snet> 元素上使用 for-each 每次都会简单地创建一个新的 table。

这里是不是应该使用条件逻辑,比较<invoices_snet>元素的值是否相等,使用模板?

非常感谢您的帮助!

 <database>
  <invoices>
   <invoices_snet>
    <invoiceNum NAME="invoiceNum" TYPE="SMALLINT">368</invoiceNum>
    <ProductID NAME="ProductID" TYPE="VARCHAR">SS106</ProductID>
    <ProductName NAME="ProductName" TYPE="VARCHAR">Senna  Sunglasses</ProductName>
    <ProductDescription NAME="ProductDescription" TYPE="VARCHAR">Lively sunglasses</ProductDescription>
    <Quantity NAME="Quantity" TYPE="SMALLINT">34</Quantity>
    <UnitPrice NAME="UnitPrice" TYPE="CURRENCY">40.0000</UnitPrice>
    <ExtendedPrice NAME="ExtendedPrice" TYPE="CURRENCY">1360.0000</ExtendedPrice>
    <contactName NAME="contactName" TYPE="VARCHAR">Jeff</contactName>
    <shippingStreet NAME="shippingStreet" TYPE="VARCHAR">11 Acacia Avenue</shippingStreet>
    <shippingCity NAME="shippingCity" TYPE="VARCHAR">Huddersfield</shippingCity>
    <shippingCounty NAME="shippingCounty" TYPE="VARCHAR">Yorkshire</shippingCounty>
    <shippingPostcode NAME="shippingPostcode" TYPE="VARCHAR">YO12 8LA</shippingPostcode>
    <saleDate NAME="salesDate" TYPE="DATETIME">30. Mar. 16</saleDate>
   </invoices_snet>
   <invoices_snet>
    <invoiceNum NAME="invoiceNum" TYPE="SMALLINT">368</invoiceNum>
    <ProductID NAME="ProductID" TYPE="VARCHAR">SS368</ProductID>
    <ProductName NAME="ProductName" TYPE="VARCHAR">Senna T-shirts</ProductName>
    <ProductDescription NAME="ProductDescription" TYPE="VARCHAR">T-shirts of beige colour with cream piping</ProductDescription>
    <Quantity NAME="Quantity" TYPE="SMALLINT">20</Quantity>
    <UnitPrice NAME="UnitPrice" TYPE="CURRENCY">15.00</UnitPrice>
    <ExtendedPrice NAME="ExtendedPrice" TYPE="CURRENCY">300.00</ExtendedPrice>
    <contactName NAME="contactName" TYPE="VARCHAR">Jeff</contactName>
    <shippingStreet NAME="shippingStreet" TYPE="VARCHAR">11 Acacia Avenue</shippingStreet>
    <shippingCity NAME="shippingCity" TYPE="VARCHAR">Huddersfield</shippingCity>
    <shippingCounty NAME="shippingCounty" TYPE="VARCHAR">Yorkshire</shippingCounty>
    <shippingPostcode NAME="shippingPostcode" TYPE="VARCHAR">YO12 8LA</shippingPostcode>
    <saleDate NAME="salesDate" TYPE="DATETIME">30. Mar. 16</saleDate>
   </invoices_snet>
  </invoices>
 </database>




<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/database">
        <html>
            <head>
                <title>Invoice</title>
                <link rel="stylesheet" href="invoicingCSS.css"/>
            </head>
            <body>
                <h1>Invoice</h1>
                <br></br>
                <xsl:for-each select="invoices/invoices_snet">
                <h2>Order for Invoice Number: <xsl:value-of select="invoiceNum"/> </h2>
                <table>
                    <tr>
                        <th>Product ID</th>
                        <th>Product Name</th>
                        <th>Product Description</th>
                        <th>Quantity</th>
                        <th>Unit Price</th>
                        <th>Extended Price</th>
                        <th>Contact Name</th>
                        <th>Shipping Address</th>
                        <th>Sales Date</th>
                    </tr>
                        <tr>
                            <td>
                                <xsl:value-of select="ProductID"/>
                            </td>
                            <td>
                                <xsl:value-of select="ProductName"/>
                            </td>
                            <td>
                                <xsl:value-of select="ProductDescription"/>
                            </td>
                            <td>
                                <xsl:value-of select="Quantity"/>
                            </td>
                            <td>
                                <xsl:value-of select="UnitPrice"/>
                            </td>
                            <td>
                                <xsl:value-of select="ExtendedPrice"/>
                            </td>
                            <td>
                                <xsl:value-of select="contactName"/>
                            </td>
                            <td>
                                <xsl:value-of select="concat(
                                                    shippingStreet,' ',
                                                    shippingCity,', ',
                                                    shippingCounty,', ',
                                                    shippingPostcode)" 
                                />
                            </td>                            
                            <td>
                                <xsl:value-of select="saleDate"/>
                            </td>
                        </tr>
                </table>
                </xsl:for-each>
            </body>
        </html>
    </xsl:template>
</xsl:stylesheet>

首先请您帮个忙,看看 XSLT 1.0 的 xslt 分组,这将是 muenchian 分组,例如this

这里是适应您的 xml 的基本结构:

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

  <xsl:key name="kinvoices_snet" match="invoices_snet" use="invoiceNum"/>
  <xsl:template match="invoices">
    <xsl:for-each select="invoices_snet [ 
                            count ( key('kinvoices_snet',./invoiceNum)[1] | . ) = 1 ]">

      <xsl:variable name="this" select="." />
      <g>
        <gh>
          <xsl:value-of select="invoiceNum" />
        </gh>
        <!-- group stuff -->

         <xsl:for-each select=" key('kinvoices_snet',$this/invoiceNum)">
           <!-- group member stuff -->
           <gm>
                <xsl:value-of select="ProductID" />
           </gm>
         </xsl:for-each>  
      </g>
    </xsl:for-each>
  </xsl:template>

</xsl:stylesheet>

使用 XSLT 2.0 中的内置 xsl:for-each-group 指令, 更容易进行分组。

试试这个作为你的起点:

XSLT 2.0

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>

<xsl:variable name="theader">
    <tr>
        <th>ProductID</th>
        <th>Quantity</th>
        <!-- add more as required -->
    </tr>
</xsl:variable>

<xsl:template match="/database">
    <html>
        <xsl:for-each-group select="invoices/invoices_snet" group-by="invoiceNum">
            <table border="1">
                <xsl:copy-of select="$theader"/>
                <xsl:apply-templates select="current-group()"/>
            </table>
        </xsl:for-each-group>
    </html>
</xsl:template>

<xsl:template match="invoices_snet">
    <tr>
        <td>
            <xsl:value-of select="ProductID"/>
        </td>
        <td>
            <xsl:value-of select="Quantity"/>
        </td>
        <!-- add more as required -->
    </tr>
</xsl:template>

</xsl:stylesheet>

<xsl:template match="invoices_snet">
    <tr>
        <td>
            <xsl:value-of select="ProductID"/>
        </td>
        <td>
            <xsl:value-of select="Quantity"/>
        </td>
    </tr>
</xsl:template>

</xsl:stylesheet>