извлекать уникальные группы из xml, используя xslt - PullRequest
1 голос
/ 16 августа 2010

Я понимаю, что вы не можете использовать массивы в 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>

Выше приведен список уникальных «продуктов», и каждому продукту присваивается «productType», который может повторяться несколько раз по всему XML. Я хотел бы, чтобы xsl извлекал одну запись для каждого «productType» без повторов.

Конечный результат выше был бы что-то вроде ...

TypeA
TypeB
TypeC

А не ....

TypeA
TypeB
TypeA
TypeC
TypeA

Я не могу быть единственным, кто искал такую ​​функциональность.

мысли

Ответы [ 2 ]

1 голос
/ 16 августа 2010

Это преобразование :

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

Примечание: Это пример хорошо известного мюнхенского метода группировки , который является самым быстрым из известныхТехника обработки в 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-документу, точно так же, правильно сгруппированный результат получается .

0 голосов
/ 17 августа 2010

Димитр заставил меня пойти по правильному пути.Вот код, который я придумал, который работал для моих нужд, простой разделенный поток вывода для поддержки вызова 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|
...