【问题标题】:XSLT 2.0 - Distinct values using a keyXSLT 2.0 - 使用键的不同值
【发布时间】:2014-06-18 08:30:55
【问题描述】:

我在处理 XSLT 工作表时遇到了一些麻烦。这是我的 XML 文档:

<?xml version="1.0" encoding="UTF-8"?>
<catalog>
  <products>
    <product>
      <id>1</id>
    </product>
  </products>
  <stocks>
    <stock>
      <id>1</id>
      <size>S</size>
      <store>NYC</store>
    </stock>
    <stock>
      <id>1</id>
      <size>L</size>
      <store>NYC</store>
    </stock>
    <stock>
      <id>1</id>
      <size>S</size>
      <store>LA</store>
    </stock>
  </stocks>
</catalog>

我想要的是有这种输出 XML :

<?xml version="1.0" encoding="UTF-8"?>
<catalog>
  <products>
    <product>
      <id>1</id>
      <variants>
        <variant>
          <size>S</size>
          <stocks>
            <stock store-ref="NYC">
            <stock store-ref="LA">
          </stocks>
        <variant>
        <variant>
          <size>L</size>
          <stocks>
            <stock store-ref="NYC">
          </stocks>
        <variant>
      </variants>
    </product>
  </products>
</catalog> 

今天,我正在使用这个 XSLT 来执行这个转换:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" exclude-result-prefixes="xs fn" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions">
  <xsl:key name="sizes" match="stock" use="id"/>
  <xsl:key name="stocks" match="stock" use="fn:concat(id, '-', size)"/>
  <xsl:output method="xml" encoding="UTF-8" indent="yes"/>
  <xsl:template match="/">
    <catalog>
      <products>
        <xsl:for-each select="/catalog/products/product">
          <product>
            <id><xsl:value-of select="id" /></id>
            <variants>
              <xsl:for-each select="key('sizes', id)">
                <variant>
                  <size><xsl:value-of select="size" /></size>
                  <stocks>
                    <xsl:for-each select="key('stocks', fn:concat(id, '-', size))">
                      <stock store-ref="{store}" />
                    </xsl:for-each>
                  </stocks>
                </variant>
              </xsl:for-each>
            </variants>
          </product>
        </xsl:for-each>
      </products>
    </catalog>
  </xsl:template>
</xsl:stylesheet>

我得到了这个结果:

<?xml version="1.0" encoding="UTF-8"?>
<catalog>
   <products>
      <product>
         <id>1</id>
         <variants>
            <variant>
               <size>S</size>
               <stocks>
                  <stock store-ref="NYC"/>
                  <stock store-ref="LA"/>
               </stocks>
            </variant>
            <variant>
               <size>L</size>
               <stocks>
                  <stock store-ref="NYC"/>
               </stocks>
            </variant>
            <variant>
               <size>S</size>
               <stocks>
                  <stock store-ref="NYC"/>
                  <stock store-ref="LA"/>
               </stocks>
            </variant>
         </variants>
      </product>
   </products>
</catalog>

所以我的问题是我想选择不同的尺寸值,但它似乎不起作用。我尝试使用 generate-id() 但我不太了解它是如何工作的,所以我没有得到很好的结果:( 知道如何解决这个问题吗? 谢谢!

【问题讨论】:

  • 您是否尝试过使用&lt;xsl:for-each-group&gt;?看看:stackoverflow.com/questions/19115109/…
  • 我的“产品”标签中没有任何“尺寸”信息,如果我必须遍历每个产品的每个“库存”,这将需要很长时间(实际上,我有5K 产品和大约 100 万个库存):(
  • 我尝试将我的 for-each 替换为 &lt;xsl:for-each select="stock[generate-id() = generate-id(key('sizes', id)[1])]"&gt;,但它不起作用:变体列表为空
  • 好的,我明白你的意思。我试图用&lt;xsl:for-each-group select="key('sizes', id)" group-by="size"&gt; 替换我的foreach,现在它可以工作了!谢谢!

标签: xml xslt xslt-2.0 xslkey


【解决方案1】:

感谢@Tomalak,我找到了解决方案。这是我的工作 XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" exclude-result-prefixes="xs fn" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fn="http://www.w3.org/2005/xpath-functions">
  <xsl:key name="sizes" match="stock" use="id"/>
  <xsl:key name="stocks" match="stock" use="fn:concat(id, '-', size)"/>
  <xsl:output method="xml" encoding="UTF-8" indent="yes"/>
  <xsl:template match="/">
    <catalog>
      <products>
        <xsl:for-each select="/catalog/products/product">
          <product>
            <id><xsl:value-of select="id" /></id>
            <variants>
              <xsl:for-each-group select="key('sizes', id)" group-by="size">
                <variant>
                  <size><xsl:value-of select="size" /></size>
                  <stocks>
                    <xsl:for-each select="key('stocks', fn:concat(id, '-', size))">
                      <stock store-ref="{store}" />
                    </xsl:for-each>
                  </stocks>
                </variant>
              </xsl:for-each-group>
            </variants>
          </product>
        </xsl:for-each>
      </products>
    </catalog>
  </xsl:template>
</xsl:stylesheet>

【讨论】:

  • 这是非常罕见的情况之一,通过 cmets 给某人一个轻微的推动实际上会导致他们自己创建一个解决方案(并发布它!)。你不会想象这种行为在这个网站上有多么不同寻常。谢谢。
  • 感谢您的支持 ;)
【解决方案2】:

除了您自己找到的解决方案之外,我想向您展示多级分组。

为方便起见,您只需要一个键:

<xsl:key name="kStock" match="stock" use="id"/>

还有这个:

<xsl:template match="product">
  <xsl:copy>
    <xsl:copy-of select="id" />
    <variants>
      <xsl:for-each-group select="key('kStock', id)" group-by="size">
        <variant>
          <xsl:copy-of select="size" />
          <stocks>
            <xsl:for-each-group select="current-group()" group-by="store">
              <stock store-ref="{current-grouping-key()}" />
            </xsl:for-each-group>
          </stocks>
        </variant>
      </xsl:for-each-group>
    </variants>
  </xsl:copy>
</xsl:template>

注意current-group()current-grouping-key() 的使用。

【讨论】:

  • 再次感谢。明天早上我会测试它!
猜你喜欢
  • 2010-10-12
  • 2013-11-04
  • 1970-01-01
  • 1970-01-01
  • 2016-07-03
  • 1970-01-01
  • 1970-01-01
  • 2011-06-05
  • 2015-06-28
相关资源
最近更新 更多