xslt 1.0在组之间添加行

时间:2014-04-25 20:10:02

标签: xml xslt xalan

我在转换此XML时遇到问题

<?xml version="1.0"?>
<Report username="TONYB" sessionId="20140425154921">
  <Result>
    <Request Type="InventoryShip">
      .... Omitted for brevity
    </Request>
    <Information>
      .... Omitted for brevity
    </Information>
    <Inventory>
      <Sku>PBM118-00</Sku>
      <RevisionNo/>
      <OnHand>34010</OnHand>
      .... Omitted for brevity
    </Inventory>
   <Inventory>
      <Sku>PFC00345</Sku>
      <RevisionNo/>
      <OnHand>0</OnHand>
      .... Omitted for brevity
    </Inventory>
    <Inventory>
      <Sku>PFC00476</Sku>
      <RevisionNo/>
      <OnHand>2025</OnHand>
      .... Omitted for brevity
    </Inventory>
    <Item>
      <Sku>PBM118-00</Sku>
      <CustomerPart>CP-0004</CustomerPart>
      <Description>PACKING SLIP GE-M CHANGED XX WITH A LONG DESC</Description>
      <Groups>
        <Group>BOOK</Group>
        .... Omitted for brevity
        <Group>HR</Group>
        .... Omitted for brevity
      </Groups>
      .... Omitted for brevity
      <LowestUOM>EA</LowestUOM>
    </Item>
    <Item>
      <Sku>PFC00345</Sku>
      <CustomerPart>1001</CustomerPart>
      <Description>item description 8/29/2011 16:06</Description>
      <Groups>
        <Group>F60</Group>
        <Group>FAKE2</Group>
        <Group>HR</Group>
        <Group>TYPE</Group>
      </Groups>
      .... Omitted for brevity
      <LowestUOM>EA</LowestUOM>
    </Item>
    <Item>
      <Sku>PFC00476</Sku>
      <CustomerPart>PBM119-88</CustomerPart>
      <Description>PBM118-99 NEW ITEM</Description>
      <Groups>
        <Group>BOOK</Group>
        <Group>HR</Group>
      </Groups>
      .... Omitted for brevity
      <LowestUOM>EA</LowestUOM>
    </Item>
    <Usage>
      .... Omitted for brevity
    </Usage>
    <Usage>
      <DateRange>
        <Start>01/01/2014</Start>
        <End>12/31/2014</End>
      </DateRange>
      <OrderedBySku>
        <Sku>PBM118-00</Sku>
        <ShippedQty>951</ShippedQty>
        <User/>
      </OrderedBySku>
      <OrderedBySku>
        <Sku>PFC00476</Sku>
        <ShippedQty>0</ShippedQty>
        <User/>
      </OrderedBySku>
    </Usage>
    <Usage>
      <DateRange>
        <End>12/31/2014</End>
      </DateRange>
      <OrderedBySku>
        <Sku>PFC00476</Sku>
        <ShippedQty>0</ShippedQty>
        <User/>
      </OrderedBySku>
      <OrderedBySku>
        <Sku>PBM118-00</Sku>
        <ShippedQty>116668</ShippedQty>
        <User/>
      </OrderedBySku>
    </Usage>
  </Result>
</Report>

就像这样,第一个“Group”字段的每次转换之间都有一个空行:

<html>
..... Omitted for brevity
<tbody>
<tr class="">
<td><img src="/wmsImages/SALIX/products/PBM118-00_THM.jpg"></td><td>CP-0004</td><td>PACKING SLIP GE-M CHANGED XX WITH A LONG DESC</td><td>U</td><td>Y</td><td class="number">34,010EA</td><td class="number">116,668</td><td class="number">100CA</td><td>BOOK</td><td>CORP</td><td>FAKE</td><td>FAKE2</td><td>FAKE3</td><td>FAKEDEPT</td><td>HR</td><td>REPORT</td><td>fake</td><td></td><td></td>
</tr>
<tr class="">
<td></td><td>PBM119-88</td><td>PBM118-99 NEW ITEM</td><td>U</td><td>Y</td><td class="number">2,025EA</td><td class="number">0</td><td class="number">EA</td><td>BOOK</td><td>HR</td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td>
</tr>
<tr class="">
<td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td>
</tr>
<tr class="">
<td></td><td>1001</td><td>item description 8/29/2011 16:06</td><td>U</td><td>Y</td><td class="number">0EA</td><td class="number">0</td><td class="number">10RL</td><td>F60</td><td>FAKE2</td><td>HR</td><td>TYPE</td><td></td><td></td><td></td><td></td><td></td><td></td><td></td>
</tr>
<tr class="">
<td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td>
</tr>
</tbody>
..... Omitted for brevity
</html>

我一直这样:

<html>
..... Omitted for brevity
<tbody>
<tr class="">
<td><img src="/wmsImages/SALIX/products/PBM118-00_THM.jpg"></td><td>CP-0004</td><td>PACKING SLIP GE-M CHANGED XX WITH A LONG DESC</td><td>U</td><td>Y</td><td class="number">34,010EA</td><td class="number">116,668</td><td class="number">100CA</td><td>BOOK</td><td>CORP</td><td>FAKE</td><td>FAKE2</td><td>FAKE3</td><td>FAKEDEPT</td><td>HR</td><td>REPORT</td><td>fake</td><td></td><td></td>
</tr>
<tr class="">
<td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td>
</tr>
<tr class="">
<td></td><td>PBM119-88</td><td>PBM118-99 NEW ITEM</td><td>U</td><td>Y</td><td class="number">2,025EA</td><td class="number">0</td><td class="number">EA</td><td>BOOK</td><td>HR</td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td>
</tr>
<tr class="">
<td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td>
</tr>
<tr class="">
<td></td><td>1001</td><td>item description 8/29/2011 16:06</td><td>U</td><td>Y</td><td class="number">0EA</td><td class="number">0</td><td class="number">10RL</td><td>F60</td><td>FAKE2</td><td>HR</td><td>TYPE</td><td></td><td></td><td></td><td></td><td></td><td></td><td></td>
</tr>
<tr class="">
<td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td>
</tr>
</tbody>
..... Omitted for brevity
</html>

所以我做错了什么。是的,“Group”标签是可选的,我们可以有0或更多。但在这种情况下,正如您所看到的,所有3个项目的第一组列中都有一些内容。

这是我的xslt:

<?xml version='1.0' encoding="UTF-8" ?>
<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:import   href="report_common.xsl"/>
  <xsl:param    name="csvLink"                      />
  <xsl:param    name="thumbs"                       />
  <xsl:param    name="showOutOfStock" select="'Yes'"/>

  <xsl:variable name="xxshowRevision" select="'Junk'"           />
  <xsl:variable name="ThumbNames"     select="document($thumbs)"/>
  <xsl:variable name="maxGroupCols"   select="10"/>



  <!-- Define a rule to suppress header elements. -->
  <xsl:template mode="header"
      match="BelowLowPoint|Discontinued|Inactive|OrderStatus|Sku|DateRange">
  </xsl:template>

  <!-- Define the root template for this report. -->
  <xsl:template match="/Report">
<html>
  <head>
    <title>Inventory with Shipping Data</title>
    <meta http-equiv="Content-Type"
        content="text/html"/>
    <link href="/css/layout.css"
        rel="stylesheet" type="text/css" />
    <link href="/css/markup.css"
        rel="stylesheet" type="text/css" />
    <link href="/css/printer.css"
        rel="stylesheet" type="text/css" media='printer' />
    <link href="/css/SALIX.css"
        rel="stylesheet" type="text/css" />
    <style type="text/css">
.OutOfStock{
    background-color: red
}
    </style>
  </head>
  <body>
    <form action="">
      <input type="button" class="cssbutton no-print"
          onClick="window.print()"
          value="Print Screen"/>
    </form>
    <xsl:apply-templates select="Result"/>
    <div class="no-print">
      <xsl:element name="form">
        <xsl:attribute name="name"  >csvForm</xsl:attribute>
        <xsl:attribute name="method">post</xsl:attribute>
        <xsl:attribute name="action">
          <xsl:value-of select="concat('/staticreports/',$csvLink)"/>
        </xsl:attribute>
        <input type="hidden" name="reportType"
            value="StaticReport"/>

        <xsl:element name="input">
          <xsl:attribute name="type">hidden</xsl:attribute>
          <xsl:attribute name="name">reportTitle</xsl:attribute>
          <xsl:attribute name="value">
            <xsl:value-of select="$reportTitle"/>
          </xsl:attribute>

        </xsl:element>
        <a href="#"
            onClick="document.csvForm.submit();return false"
          >Click here to export into spreadsheet.</a>
      </xsl:element>
    </div>
  </body>
</html>
  </xsl:template>

  <xsl:key name="byGroup" match="Inventory" use="../Item/Sku[.=current()/Sku]/../Groups/Group[1]" />

  <xsl:template match="Result">
    <xsl:apply-imports/>
<table class="report data">
  <col class="itemNo"/>
  <thead>
    <tr>
      <td/>
      <th>Client Lit Code #</th>
      <th>Description</th>
      <xsl:if test="$xxshowRevision='Yes'">
      <th>Revision</th>
      </xsl:if>
      <th>ACC CDE</th>
      <th>Allow Web</th>
      <th class="number">Available Balance</th>
      <th class="number">Total Shipped</th>
      <th class="number">UOM</th>
    <xsl:call-template name="groupHead">
      <xsl:with-param name="i">1</xsl:with-param>
      <xsl:with-param name="count">
        <xsl:value-of select="$maxGroupCols"/>
      </xsl:with-param>
    </xsl:call-template>
    </tr>
  </thead>
  <tbody>
    <xsl:for-each select="Inventory[ count(. | key( 'byGroup', '../Item/Sku[.=current()/Sku]/../Groups/Group[1]')[1]) = 1 ]">
      <xsl:sort select="../Item/Sku[.=current()/Sku]/../Groups"/>
      <xsl:sort select="../Item/Sku[.=current()/Sku]/../CustomerPart"/>
      <xsl:sort select="Sku"/>
      <xsl:sort select="RevisionNo"/>

      <xsl:variable name="Item"
          select="../Item[./Sku=current()/Sku]"/>

      <xsl:element name="tr">
        <xsl:attribute name="class">
          <xsl:choose>
            <xsl:when test="position()!=last() and position() mod 5 = 0"
              >bgLight </xsl:when>
          </xsl:choose>
        </xsl:attribute>
        <xsl:apply-templates select="." mode="item"/>
      </xsl:element>

      <xsl:element name="tr">
        <xsl:attribute name="class">
          <xsl:choose>
            <xsl:when test="position()!=last() and position() mod 5 = 0"
              >bgLight </xsl:when>
          </xsl:choose>
        </xsl:attribute>
        <xsl:apply-templates select="." mode="group" />
      </xsl:element>
    </xsl:for-each>
  </tbody>
</table>
  </xsl:template>

  <!-- Define a rule for each inventory group -->
  <xsl:template match="Inventory" mode="group">
<td></td> <!-- ThumbImage -->
<td></td> <!-- PartNo -->
<td></td> <!-- Description -->
    <xsl:if test="$xxshowRevision='Yes'">
<td></td> <!-- RevisionNo -->
    </xsl:if>
<td></td> <!-- Access -->
<td></td> <!-- Web -->
<td></td> <!-- OnHand, LowestUOM -->
<td></td> <!-- OrderedBySku -->
<td></td> <!-- UomQty, UOM -->

  <xsl:call-template name="emptyGroupCols">
    <xsl:with-param name="i">1</xsl:with-param>
    <xsl:with-param name="count">
        <xsl:value-of select="$maxGroupCols"/>
    </xsl:with-param>
  </xsl:call-template>

  </xsl:template>

  <!-- Define a rule for each inventory item -->
  <xsl:template match="Inventory" mode="item">
    <xsl:variable name="Item"
        select="../Item[./Sku=current()/Sku]"/>

    <xsl:variable name="Revision"
        select="../Revision[./Sku=current()/Sku and
                            ./RevisionNo=current()/RevisionNo]"/>

    <xsl:variable name="CustPart"
        select="normalize-space($Item/CustomerPart)"/>

    <xsl:variable name="PartNo">
      <xsl:choose>
        <xsl:when test="string-length($CustPart)>0">
          <xsl:value-of select="$CustPart"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:value-of select="Sku"/>
        </xsl:otherwise>
      </xsl:choose>
    </xsl:variable>

    <!-- Date format must be MM/DD/YYYY to work! -->
    <xsl:variable name="Year2Date"
        select="../Usage[starts-with(DateRange/Start, '01/01/')]
                        [starts-with(DateRange/End,   '12/31/')]"/>

    <xsl:variable name="Month2Date"
        select="../Usage[DateRange/Start != $Year2Date/DateRange/Start or
                         DateRange/End   != $Year2Date/DateRange/End    ]
                        [substring(DateRange/Start, 1, 3) =
                         substring(DateRange/End,   1, 3)]"/>

    <xsl:variable name="AllDates"
        select="../Usage[not(DateRange/Start)]
                        [starts-with(DateRange/End,   '12/31/')]"/>

    <xsl:variable name="SkuThumbImage"
         select=" $ThumbNames/ThumbList/ThumbFile[@Item=$Item/Sku]/File"/>

    <xsl:variable name="ThumbImage">
        <xsl:choose>
            <xsl:when test="string-length($SkuThumbImage)>0">
                <xsl:value-of select="$SkuThumbImage"/>
            </xsl:when>
            <xsl:otherwise>
                <xsl:value-of select=" $ThumbNames/ThumbList/ThumbFile[@Item=$Item/CustomerPart]/File"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:variable>

    <xsl:variable name="UOM">
        <xsl:choose>
            <xsl:when test="string-length(normalize-space($Item/UOM))>0">
                <xsl:value-of select="$Item/UOM"/>
            </xsl:when>
            <xsl:when test="string-length(normalize-space($Item/LowestUOM))>0">
                <xsl:value-of select="$Item/LowestUOM"/>
            </xsl:when>
            <xsl:otherwise>EA</xsl:otherwise>
        </xsl:choose>
    </xsl:variable>

    <xsl:variable name="LowestUOM">
        <xsl:choose>
            <xsl:when test="string-length(normalize-space($Item/LowestUOM))>0">
                <xsl:value-of select="$Item/LowestUOM"/>
            </xsl:when>
            <xsl:otherwise>EA</xsl:otherwise>
        </xsl:choose>
    </xsl:variable>

<td><xsl:if test="normalize-space($ThumbImage) != ''">
    <xsl:element name="img">
        <xsl:attribute name="src">
            <xsl:text>/wmsImages/SALIX/products/</xsl:text>
            <xsl:value-of select="$ThumbImage" />
        </xsl:attribute>
    </xsl:element>
    </xsl:if></td>
<td><xsl:value-of select="$PartNo"/></td>
<td><xsl:value-of select="$Item/Description"/></td>
    <xsl:if test="$xxshowRevision='Yes'">
<td><xsl:value-of select="RevisionNo"/></td>
    </xsl:if>
<td><xsl:value-of select="$Item/Access"/></td>
<td><xsl:value-of select="$Item/Web"/></td>
<td class='number'><xsl:value-of
    select="concat( format-number(OnHand,$rptqty,'f0'), $LowestUOM )"/></td>
<td class='number'><xsl:value-of
    select="format-number(sum($AllDates/OrderedBySku
            [Sku=current()/Sku]/ShippedQty),
            $rptqty,'f0')"/></td>
<td class='number'><xsl:value-of
    select="concat( $Item/UomQty, $UOM )"/></td>

  <xsl:variable name="countGroup"
    select="count($Item/Groups/Group )"/>

  <xsl:variable name="useNumGroupCols">
    <xsl:choose>
        <xsl:when test="$countGroup &gt;= $maxGroupCols">
            <xsl:value-of select="$maxGroupCols"/>
        </xsl:when>
        <xsl:otherwise>
            <xsl:value-of select="$countGroup"/>
        </xsl:otherwise>
    </xsl:choose>
  </xsl:variable>

  <xsl:for-each select="$Item/Groups/Group">
    <xsl:if test="position() &lt;= $useNumGroupCols">
        <td><xsl:value-of select="."/></td>
    </xsl:if>
  </xsl:for-each>

  <xsl:if test="$maxGroupCols &gt; $useNumGroupCols">
    <xsl:call-template name="emptyGroupCols">
      <xsl:with-param name="i">
        <xsl:value-of select="$useNumGroupCols"/>
        </xsl:with-param>
      <xsl:with-param name="count">
        <xsl:value-of select="$maxGroupCols"/>
      </xsl:with-param>
    </xsl:call-template>
  </xsl:if>

  </xsl:template>

  <xsl:template name="emptyGroupCols">
    <xsl:param name="i" />
    <xsl:param name="count" />

    <xsl:if test="$i &lt;= $count">
      <td></td>
    </xsl:if>

    <!--begin_: RepeatTheLoopUntilFinished-->
    <xsl:if test="$i &lt;= $count">
        <xsl:call-template name="emptyGroupCols">
            <xsl:with-param name="i">
                <xsl:value-of select="$i + 1"/>
            </xsl:with-param>
            <xsl:with-param name="count">
                <xsl:value-of select="$count"/>
            </xsl:with-param>
        </xsl:call-template>
    </xsl:if>

  </xsl:template>

  <xsl:template name="groupHead">
    <xsl:param name="i" />
    <xsl:param name="count" />

    <xsl:if test="$i &lt;= $count">
      <th>Group <xsl:value-of select="$i"/></th>
    </xsl:if>

    <!--begin_: RepeatTheLoopUntilFinished-->
    <xsl:if test="$i &lt;= $count">
        <xsl:call-template name="groupHead">
            <xsl:with-param name="i">
                <xsl:value-of select="$i + 1"/>
            </xsl:with-param>
            <xsl:with-param name="count">
                <xsl:value-of select="$count"/>
            </xsl:with-param>
        </xsl:call-template>
    </xsl:if>

  </xsl:template>

</xsl:stylesheet>

感谢您提供任何帮助。

编辑(2014年4月28日): Here is a zip包含所有必需的文件,或try here if non-zip更容易。请注意,“StaticFormatcsv.xsl”文件还有其他问题,我只包含它,因为它在我运行的命令中被引用。你现在可以忽略它。一旦我修复了主xsl,我将对“csv”xsl应用相同的修复。

此外,这是我运行的命令:

java -cp /usr/share/java/xalan.jar org.apache.xalan.xslt.Process -in StaticData20140425154921 -out StaticReport20140425154921.html -PARAM csvLink StaticReport20140425154921.csv -PARAM thumbs ThumbList.xsl -xsl StaticFormat.xsl

其中“xalan.jar”指/指向“xalan-2.4.1.jar”。

1 个答案:

答案 0 :(得分:0)

我开始简化您的XSLT ....

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="/Report">
    <html>
      <head>
        <title>Inventory with Shipping Data</title>
      </head>
      <body>
        <xsl:apply-templates select="Result"/>
      </body>
    </html>
  </xsl:template>

  <xsl:key name="byGroup" match="Inventory" use="../Item/Sku[.=current()/Sku]/../Groups/Group[1]" />

  <xsl:template match="Result">
    <table class="report data">
      <tbody>
        <xsl:for-each select="Inventory[ count(. | key( 'byGroup', '../Item/Sku[.=current()/Sku]/../Groups/Group[1]')[1]) = 1 ]">
          <xsl:element name="tr">
            <xsl:apply-templates select="." mode="item"/>
          </xsl:element>

          <xsl:element name="tr">
            <xsl:apply-templates select="." mode="group" />
          </xsl:element>
        </xsl:for-each>
      </tbody>
    </table>
  </xsl:template>

  <xsl:template match="Inventory" mode="item">
      <td><xsl:value-of select="../Item/Sku[.=current()/Sku]/../Groups/Group[1]" /></td>
  </xsl:template>

  <xsl:template match="Inventory" mode="group">
      <td><xsl:value-of select="Sku" /></td>
  </xsl:template>
</xsl:stylesheet>

首先要注意的是,对于XML中的每个 Inventory 元素,您输出两个 tr 元素,这就是您在输出中获得六行的原因。你总是以这种方式得到偶数行。也许你想要的是为每个不同的项目/组/组[1] 输出一行(其中有两个不同的值),然后为每个库存<输出一行/ strong>哪个匹配 Sku

首先,您的密钥可以简化为此

<xsl:key name="byGroup" match="Inventory" 
         use="../Item[Sku=current()/Sku]/Groups/Group[1]" />

但是如何使用此密钥存在问题...

<xsl:for-each 
     select="Inventory[ count(. | key( 'byGroup', '../Item/Sku[.=current()/Sku]/../Groups/Group[1]')[1]) = 1 ]">

您不应该使用撇号作为函数的第二个参数,否则它将被视为文字。你应该这样做....(使用上面显示的简化键)

<xsl:for-each 
     select="Inventory[ count(. | key( 'byGroup', ../Item[Sku=current()/Sku]/Groups/Group[1])[1]) = 1 ]">

但即便如此也存在问题。在 xsl:key 语句中,当前()将引用当前匹配的广告资源项。但是在 xsl:for-each 语句中,当前()指的是 xsl:for-each 已执行,即结果元素。

要解决此问题,请定义一个键,以便您通过 Sku

查找元素
<xsl:key name="itemBySku" match="Item" use="Sku" />

然后, xsl:for-each 可以这样写:

<xsl:for-each 
     select="Inventory[ count(. | key('byGroup', key('itemBySku', Sku)/Groups/Group[1])[1]) = 1 ]">

最后,要输出当前组中的所有广告资源元素,您可以执行以下操作:

<xsl:apply-templates 
     select="key('byGroup', key('itemBySku', Sku)/Groups/Group[1])" mode="group" />

试试这个XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="/Report">
    <html>
      <head>
        <title>Inventory with Shipping Data</title>
      </head>
      <body>
        <xsl:apply-templates select="Result"/>
      </body>
    </html>
  </xsl:template>

  <xsl:key name="byGroup" match="Inventory" use="../Item[Sku=current()/Sku]/Groups/Group[1]" />
  <xsl:key name="itemBySku" match="Item" use="Sku" />

  <xsl:template match="Result">
    <table class="report data">
      <tbody>
        <xsl:for-each select="Inventory[ count(. | key('byGroup', key('itemBySku', Sku)/Groups/Group[1])[1]) = 1 ]">
          <tr>
            <xsl:apply-templates select="." mode="item"/>
          </tr>

          <xsl:apply-templates select="key('byGroup', key('itemBySku', Sku)/Groups/Group[1])" mode="group" />
        </xsl:for-each>
      </tbody>
    </table>
  </xsl:template>

  <xsl:template match="Inventory" mode="item">
    <td><xsl:value-of select="key('itemBySku', Sku)/Groups/Group[1]" /></td>
  </xsl:template>

  <xsl:template match="Inventory" mode="group">
    <tr>
      <td><xsl:value-of select="Sku" /></td>
    </tr>
  </xsl:template>
</xsl:stylesheet>

这可能实际上并不是你想要的,但它至少应该告诉你如何简化你的XSLT,并给你一些东西作为添加你需要的所有其他功能的基础。与手头的潜在问题有关。