【问题标题】:pull unique groups from xml using xslt使用 xslt 从 xml 中提取唯一组
【发布时间】:2011-03-30 13:12:29
【问题描述】:

我意识到您不能在 xsl 中使用数组,通常要执行下面的任务需要一个数组。这就是我需要的...

示例 xml 代码...

<products>
 <product>
  <productNumber>1</productNumber>
  <productType>TypeA</productType>
 </product>
 <product>
  <productNumber>2</productNumber>
  <productType>TypeB</productType>
 </product>
 <product>
  <productNumber>3</productNumber>
  <productType>TypeA</productType>
 </product>
 <product>
  <productNumber>4</productNumber>
  <productType>TypeC</productType>
 </product>
 <product>
  <productNumber>5</productNumber>
  <productType>TypeA</productType>
 </product>
</products>

上面是一个独特的“产品”列表,每个产品都分配有一个“产品类型”,可以在整个 xml 中重复多次。我希望 xsl 为每个“productType”提取一个条目而不重复。

上面的最终结果会是……

TypeA
TypeB
TypeC

而不是....

TypeA
TypeB
TypeA
TypeC
TypeA

我不可能是唯一一个在寻找这种功能的人。

想法?

【问题讨论】:

  • 好问题 (+1)。有关有效的分组 XSLT 1.0 解决方案,请参阅我的答案。 :)

标签: xml xslt xslt-grouping


【解决方案1】:

Dimitre 让我走上了正确的道路。这是我想出的满足我需求的代码,一个简单的分隔输出流以支持 AJAX 调用...

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="html" encoding="utf-8"/>
<xsl:key name="kProdByBrand" match="Products/Product" use="Brand"/>

 <xsl:template match="Products">
   <xsl:for-each 
     select="Product
     [generate-id() = generate-id(key('kProdByBrand', Brand)[1])]"><xsl:sort
     select="Brand" /><xsl:value-of select="Brand" />|</xsl:for-each>
 </xsl:template>

</xsl:stylesheet>

给定一个包含许多看起来像这样的成员的 xml...

<Product>
    <Brand>Brand</Brand>
    <OldPN>myCompany Part Number</OldPN>    
            ...
</Product>

输出看起来像这样......

Brand|Brand1|Brand2|Brand3|

【讨论】:

    【解决方案2】:

    这种转变

    <xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output omit-xml-declaration="yes" indent="yes"/>
    
     <xsl:key name="kProdByType"
          match="product" use="productType"/>
    
     <xsl:template match="node()|@*" name="identity">
       <xsl:copy>
        <xsl:apply-templates select="node()|@*"/>
       </xsl:copy>
     </xsl:template>
    
     <xsl:template match="/products">
      <products>
        <xsl:apply-templates select=
         "product[generate-id()
                 =
                 generate-id(key('kProdByType', productType)[1])
                 ]
         "/>
      </products>
     </xsl:template>
    
     <xsl:template match="product">
       <productType value="{productType}">
        <xsl:apply-templates mode="copy"
         select="key('kProdByType', productType)"/>
       </productType>
     </xsl:template>
    
     <xsl:template match="product" mode="copy">
      <xsl:call-template name="identity"/>
     </xsl:template>
    </xsl:stylesheet>
    

    应用于提供的 XML 文档时:

    <products>
     <product>
      <productNumber>1</productNumber>
      <productType>TypeA</productType>
     </product>
     <product>
      <productNumber>2</productNumber>
      <productType>TypeB</productType>
     </product>
     <product>
      <productNumber>3</productNumber>
      <productType>TypeA</productType>
     </product>
     <product>
      <productNumber>4</productNumber>
      <productType>TypeC</productType>
     </product>
     <product>
      <productNumber>5</productNumber>
      <productType>TypeA</productType>
     </product>
    </products>
    

    产生所需的正确分组

    <products>
        <productType value="TypeA">
            <product>
                <productNumber>1</productNumber>
                <productType>TypeA</productType>
            </product>
            <product>
                <productNumber>3</productNumber>
                <productType>TypeA</productType>
            </product>
            <product>
                <productNumber>5</productNumber>
                <productType>TypeA</productType>
            </product>
        </productType>
        <productType value="TypeB">
            <product>
                <productNumber>2</productNumber>
                <productType>TypeB</productType>
            </product>
        </productType>
        <productType value="TypeC">
            <product>
                <productNumber>4</productNumber>
                <productType>TypeC</productType>
            </product>
        </productType>
    </products>
    

    请注意:这是著名的 Muenchian 分组方法的示例,这是 XSLT 1.0 中已知最快的分组技术。

    XSLT 2.0 解决方案

    <xsl:stylesheet version="2.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output omit-xml-declaration="yes" indent="yes"/>
    
     <xsl:template match="node()|@*" name="identity">
       <xsl:copy>
        <xsl:apply-templates select="node()|@*"/>
       </xsl:copy>
     </xsl:template>
    
     <xsl:template match="/products">
       <xsl:for-each-group select="product"
            group-by="productType">
         <productType value="{productType}">
          <xsl:apply-templates select="current-group()"/>
         </productType>
       </xsl:for-each-group>
     </xsl:template>
    </xsl:stylesheet>
    

    当此 XSLT 2.0 转换应用于所提供的 XML 文档时,会产生完全相同且正确分组的结果

    【讨论】:

    • 嗯...谢谢!我会将它注入我的代码中,看看它是如何工作的,然后告诉你。这很酷,因为它为我打开了更多的可能性。
    • @Jimmmy:很高兴您发现我的回答很有用。表达这一点的 SO 方式是接受答案(通过单击答案旁边的复选标记图片)。 :)
    • @Dimitre:XSLT 1.0 和 XSLT 2.0 解决方案 +1。另外,添加您的标签xslt-grouping
    • 谢谢大家。我正在寻找解决方案在我的实际情况下如何为我工作。我可能还有其他问题,这就是为什么我还没有将其标记为已回答:) 更多!
    • @Jimmmy:进一步的问题将是新的、单独的问题。你和我们已经完成这个问题了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多