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