【问题标题】:XSL to transform XML to HTML, filter elements from multiple structures for the same element valueXSL 将 XML 转换为 HTML,从多个结构中过滤元素以获得相同的元素值
【发布时间】:2016-04-13 02:04:55
【问题描述】:

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

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

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

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

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

这里是否应该使用条件逻辑,比较<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>

【问题讨论】:

  • 1. 行是否按 invoiceNum 排序? 2. 如果您使用的是 Saxon,为什么要限制自己使用 XSLT 1.0? -- P.S. 这是一个分组问题 - 您可以在此处找到 很多 个示例。
  • 嗨迈克尔,感谢您的意见! 1. 是的,想法是 invoiceNum 元素的值将用作唯一标识符(它与 ProductID、ProductName、ProductDescription 等具有一对多关系)。我没有应用任何排序,XML 文件只是处于从数据库中提取的状态。 2. 我刚开始接触 XML 和 XSL,所以我还没有需要一些 2.0 的特性;不过,改变它并没有什么坏处。分组?好的,正如你提到的那样,我将把我的搜索工作集中在这些问题上......
  • 嗯,如果没有比这个小分组问题更大的原因,我不会更改为 XSLT 2.0。使用 1.0,您将拥有更多可能的 xslt 处理器,例如xsltproc 甚至在浏览器中。我不知道有任何浏览器支持 XSLT 2.0。
  • @user6196074 你的问题没有回答吗?
  • 是的,@michael.hor257k,我设法根据您在回答中慷慨给出的指示构建了一个可行的解决方案;再次感谢!最后,不需要特定的 XSLT 版本,所以我发现 2.0 更容易通过分组来执行。

标签: html xml xslt transformation


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    首先你自己帮个忙,看看 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>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-30
      相关资源
      最近更新 更多