1

我认为这个简单的例子可能会更清楚地提出这个问题。

我有一个包含多个产品的输入文件。有不同类型的产品(对于这个例子来说,有 2 个产品 ID 的 2 种类型就足够了),但输入会有更多。

我只想输出在 for each Product 循环中遇到的每种类型的第一个产品的信息。(我正在输出价格最低的产品的信息,所以第一个将是最低价格,因为我首先按价格排序。)

所以我想读取每个产品,但如果我还没有输出具有相同 ID 的产品,则只输出产品的信息。我有一个 IDArray 的变量,我想检查 for each product 循环中的每个产品是否有一个已经在该 IDArray 中的 ID - 如果没有,请继续,如果它已经在数组中,则跳过所有内容并循环到下一个。

我不知道如何让子元素成为 IDArray 中的一个节点,其中每个 CurrentID 的值。它不断将该值作为节点添加到 CurrentID,该节点仅在每个产品的范围内,而不是整个产品组。我知道下面的代码不起作用,但它说明了这个想法并给了我一个开始的地方:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="xml" encoding="UTF-8" indent="yes" cdata-section-elements="prod_name adv_notes"/>
  <xsl:template match="/">
  <List>
     <xsl:for-each select="ProductGroup">
     <xsl:sort select="Product/Rate"/>
     <xsl:variable name="IDarray">
     <xsl:for-each select="Product">
        <xsl:variable name="CurrentID">
           <xsl:call-template name="processID">
              <xsl:with-param name="ProductCode" select="ProductCode" />
            </xsl:call-template>
        </xsl:variable>
        <xsl:if test="not(contains($IDarray, $CurrentID))">
           <child elem="{@elem}">
             <xsl:select value-of="$CurrentID" />
           </child>
          <Product>
           <xsl:attribute name="ID">
             <xsl:select value-of="$CurrentID" />
           </xsl:attribute>
        <prod_name>
           <xsl:value-of select="ProductName"/>
        </prod_name>
        <rate>
           <xsl:value-of select="Rate"/>
        </rate>
    </Product>
    </xsl:if>
    </xsl:for-each>
    </xsl:variable>
    </xsl:for-each>
  </List>
</xsl:template>


<xsl:template name="processID">
 <xsl:param name="ProductCode"/>
 <xsl:choose>
   <xsl:when test="starts-with($ProductCode, '515')">5</xsl:when>
   <xsl:when test="starts-with($ProductCode, '205')">2</xsl:when>
 </xsl:choose>
</xsl:template>

提前非常感谢,我知道这里有一些很棒的程序员可以提供帮助!:) -冬青

输入看起来像这样:

 <ProductGroup>
  <Product>
    <ProductCode>
       5155
    </ProductCode>
    <ProductName>
       House
    </ProductName>
    <Rate>
       3.99
    </Rate>
    </Product>
    <Product>
    <ProductCode>
       5158
    </ProductCode>
    <ProductName>
       House
    </ProductName>
    <Rate>
       4.99
    </Rate>
    </Product>
   </ProductGroup>
        <ProductGroup>
  <Product>
    <ProductCode>
       2058
    </ProductCode>
    <ProductName>
       House
    </ProductName>
    <Rate>
       2.99
    </Rate>
    </Product>
    <Product>
    <ProductCode>
       2055
    </ProductCode>
    <ProductName>
       House
    </ProductName>
    <Rate>
       7.99
    </Rate>
    </Product>
   </ProductGroup>

仅对于那个简单的输入文件,输出将是这样的:

在此处输入图像描述

在这里实现 Muenchian 分组很困难,因为我的实际数据集很大。我很容易问一个问题。如果我能让那个数组方法正常工作,那么我庞大的项目的其余部分就可以工作了。

4

1 回答 1

2

当 for 循环内的模板调用返回搜索元素时,如何将此 if-test 与数组一起使用?

更新:您使用的是 XSLT 1.0,因此创建数组的唯一选择是使用扩展,这可能会也可能不会,具体取决于您的环境(有关更多信息,请参阅 此问题)。我猜这与键相比会很复杂并且效率不高。

一个更好的问题是

我有一个包含多个产品的输入文件。有 10 种产品(10 个产品 ID),但输入将有 200 个产品,我只想输出每种类型的第一个产品的信息。

以下是如何实现这一目标的示例。我宁愿使用您的输入和所需的输出,但不幸的是没有提供它们。

输入

<?xml version="1.0" encoding="utf-8"?>
<ProductGroup>
  <Product ID="Product 1" Type="A"/>
  <Product ID="Product 2" Type="B"/>
  <Product ID="Product 3" Type="C"/>
  <Product ID="Product 4" Type="A"/>
  <Product ID="Product 5" Type="B"/>
  <Product ID="Product 6" Type="C"/>
  <Product ID="Product 7" Type="A"/>
  <Product ID="Product 8" Type="B"/>
  <Product ID="Product 9" Type="C"/>
</ProductGroup>

XSLT

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes"/>
  <xsl:key name="Product-by-Type" match="Product" use="@Type" />
  <xsl:template match="/ProductGroup">
    <Products>
      <xsl:for-each select="Product[count(. | key('Product-by-Type', @Type)[1]) = 1]">
        <xsl:sort select="@Type" />
        <xsl:copy-of select="key('Product-by-Type', @Type)[1]" />
      </xsl:for-each>
    </Products>
  </xsl:template>
</xsl:stylesheet>

输出

<?xml version="1.0" encoding="utf-8"?>
<Products>
  <Product ID="Product 1" Type="A" />
  <Product ID="Product 2" Type="B" />
  <Product ID="Product 3" Type="C" />
</Products>

这篇文章很好地解释了 Muenchian 分组的工作原理。

更新

非常感谢您对更多信息的帮助。以下是我从您的输入到输出的方法:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes"/>
  <xsl:key name="Product-by-ProductCode" match="Product" use="concat(normalize-space(../../preceding-sibling::Purpose[1]), substring(normalize-space(ProductCode), 1, 3))" />
  <xsl:template match="/List">
    <List>
      <xsl:for-each select="ProductGroup/ActiveProducts/Product[count(. | key('Product-by-ProductCode', concat(normalize-space(../../preceding-sibling::Purpose[1]), substring(normalize-space(ProductCode), 1, 3)))[1]) = 1]">
        <xsl:sort select="Rate" />
        <xsl:element name="Product">
          <xsl:attribute name="ID">
            <xsl:choose>
              <xsl:when test="concat(normalize-space(../../preceding-sibling::Purpose[1]), substring(normalize-space(ProductCode), 1, 3)) = 'Purchase515'">5</xsl:when>
              <xsl:when test="concat(normalize-space(../../preceding-sibling::Purpose[1]), substring(normalize-space(ProductCode), 1, 3)) = 'Rent205'">2</xsl:when>
              <xsl:otherwise>0</xsl:otherwise>
            </xsl:choose>
          </xsl:attribute>
          <xsl:element name="prod_name">
            <xsl:value-of select="key('Product-by-ProductCode', concat(normalize-space(../../preceding-sibling::Purpose[1]), substring(normalize-space(ProductCode), 1, 3)))[1]/ProductName"/>
          </xsl:element>
          <xsl:element name="rate">
            <xsl:value-of select="key('Product-by-ProductCode', concat(normalize-space(../../preceding-sibling::Purpose[1]), substring(normalize-space(ProductCode), 1, 3)))[1]/Rate"/>
          </xsl:element>
        </xsl:element>
      </xsl:for-each>
    </List>
  </xsl:template>
</xsl:stylesheet>

该方法与我之前的示例相同,除了键是Purposeand的串联ProductCode。您的输入可能存在问题,我<Purpose>Rent</Purpose>在第二个产品组之前缺少东西。

于 2012-11-20T21:00:11.540 回答