С XSLT, как я могу использовать этот if-тест с массивом, когда элемент поиска возвращается при вызове шаблона внутри цикла for?
Я думаю, что этот простой пример мог бы задать вопрос намного яснее.
У меня есть входной файл с несколькими продуктами. Существуют различные типы продуктов (для этого примера достаточно двух типов с двумя идентификаторами продуктов), но входных данных будет гораздо больше.
Я хочу вывести информацию только для первого продукта каждого типа, с которым я сталкиваюсь в каждом цикле продукта. (Я выводлю информацию о продукте с наименьшей ценой, поэтому первая будет иметь самую низкую цену, потому что сначала я сортирую по рейтингу.)
Поэтому я хочу читать по каждому продукту, но выводить информацию о продукте, только если я еще не выводил продукт с таким же идентификатором. У меня есть переменная для IDArray, и я хочу проверить, есть ли у каждого продукта внутри каждого цикла продукта идентификатор, который уже находится в этом IDArray - если нет, продолжить, если он уже находится в массиве, пропустить все и просто цикл к следующему.
Я не мог понять, как сделать дочерний элемент узлом из 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>
Вывод будет такой только для этого простого входного файла:
Реализовать мюнхенскую группировку здесь сложно, потому что мой фактический набор данных огромен. Я сделал это простым, чтобы задать вопрос. Если я смогу просто заставить работать этот метод массива, остальная часть моего огромного проекта будет работать.
1 ответ
Как я могу использовать этот if-test с массивом, когда элемент поиска возвращается при вызове шаблона внутри цикла for?
ОБНОВЛЕНИЕ: Вы используете XSLT 1.0, поэтому единственный способ создать массив - использовать расширения, что может или не может быть возможным в зависимости от вашей среды (см. Этот вопрос для получения дополнительной информации). Полагаю, это будет сложно и не очень эффективно по сравнению с ключами.
Лучше вопрос
У меня есть входной файл с несколькими продуктами. Существует 10 типов продуктов (10 идентификаторов продуктов), но на входе будет 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>
Этот пост дает очень хорошее объяснение того, как работает мюнхенская группировка.
ОБНОВИТЬ
Ваша помощь с дополнительной информацией очень ценится. Вот как я могу получить от вашего вклада в ваш вывод:
<?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>
Подход такой же, как в моем предыдущем примере, за исключением того, что ключ представляет собой конкатенацию Purpose
а также ProductCode
, Там может быть проблема с вашим вкладом, я <Purpose>Rent</Purpose>
отсутствует перед второй группой продуктов.