Как проанализировать разделенный список с URL-адресами изображений с помощью XSL?
У меня есть список, содержащий URL-адреса для изображений, которые я хотел бы проанализировать и отобразить с помощью XSL, но я хочу только первые 3 изображения.
например
<xsl:value-of select="@Icons" />
Возвращает:
['http://www.test.com/image1.jpg',
'http://www.test.com/image2.jpg',
'http://www.test.com/image3.jpg',
'http://www.test.com/image4.jpg',
'http://www.test.com/image5.jpg']
Окончательный результат должен быть:
<img src="http://www.test.com/image1.jpg" alt=""/>
<img src="http://www.test.com/image2.jpg" alt=""/>
<img src="http://www.test.com/image3.jpg" alt=""/>
У меня есть часть кода, чтобы выбрать первые 3 элемента, но я не уверен, как анализировать список и отображать изображения в формате HTML.
<xsl:template name="recurse_till_ten">
<xsl:param name="num">1</xsl:param>
<xsl:if test="not($num = 3)">
//Parasing list here
<xsl:call-template name="recurse_till_ten">
<xsl:with-param name="num">
<xsl:value-of select="$num + 1">
</xsl:with-param>
</xsl:call-template>
</xsl:if>
</xsl:template>
3 ответа
Решение XSLT 1.0
Эта таблица стилей XSLT 1.0...
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes" />
<xsl:strip-space elements="*" />
<xsl:template match="/">
<xsl:variable name="strip-chars" select=""[]''"" />
<xsl:for-each select="*">
<xsl:copy>
<xsl:call-template name="tokenize">
<xsl:with-param name="content" select="concat(translate(@Icons,$strip-chars,''),',')" />
<xsl:with-param name="count" select="3" />
</xsl:call-template>
</xsl:copy>
</xsl:for-each>
</xsl:template>
<xsl:template name="tokenize">
<xsl:param name="content" />
<xsl:param name="count" />
<xsl:if test="contains($content,',') and $count > 0">
<img src="{substring-before($content,',')}" alt="" />
<xsl:call-template name="tokenize">
<xsl:with-param name="content" select="normalize-space(substring-after($content,','))" />
<xsl:with-param name="count" select="$count - 1" />
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
... применительно к этому входному документу...
<t Icons="['http://www.test.com/image1.jpg',
'http://www.test.com/image2.jpg',
'http://www.test.com/image3.jpg',
'http://www.test.com/image4.jpg',
'http://www.test.com/image5.jpg']"/>
...даст...
<t>
<img src="http://www.test.com/image1.jpg" alt="" />
<img src="http://www.test.com/image2.jpg" alt="" />
<img src="http://www.test.com/image3.jpg" alt="" />
</t>
И применительно к этому короткому входному документу...
<t Icons="['http://www.test.com/image1.jpg',
'http://www.test.com/image2.jpg']"/>
... дает...
<t>
<img src="http://www.test.com/image1.jpg" alt="" />
<img src="http://www.test.com/image2.jpg" alt="" />
</t>
Заметка
Решение Суреша на момент редактирования не будет работать для этого второго варианта использования, в котором количество изображений равно 3 или меньше.
Решение XSLT 2.0
Тот же результат может быть достигнут проще, эффективнее и расширяемее с XSLT 2.0 с такой таблицей стилей...
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes" />
<xsl:strip-space elements="*" />
<xsl:template match="/">
<xsl:for-each select="*">
<xsl:copy>
<xsl:variable name="image-elements" as="element()*">
<xsl:analyze-string select="@Icons" regex="'([^']*)'(,|\])" >
<xsl:matching-substring>
<img src="{regex-group(1)}" alt="" />
</xsl:matching-substring>
</xsl:analyze-string>
</xsl:variable>
<xsl:copy-of select="$image-elements[not(position() > 3)]" />
</xsl:copy>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Решение XSLT 2.0 XPATH
Для интереса, вот вариант для XSLT 2.0, использующий чисто XPATH.
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes" />
<xsl:strip-space elements="*" />
<xsl:template match="/">
<xsl:for-each select="*">
<xsl:copy>
<xsl:for-each select="(for $i in tokenize(@Icons,',') return
replace($i,'.*''([^'']*)''.*','$1'))
[not(position() > 3)]">
<img src="{.}" alt="" />
</xsl:for-each>
</xsl:copy>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Обновите и прокомментируйте решение Димитре
Поздравления Димитру за его более краткое решение XSLT 2.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="/">
<xsl:for-each select="tokenize(/*/@Icons, '\[?\s*''\s*,?\]?')[.][position() le 3]">
<img src="{.}" alt=""/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Гораздо более короткое решение 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:variable name="vDelims">\s*'\s*,?</xsl:variable>
<xsl:variable name="vTokens" select="tokenize(/*/@Icons, $vDelims)[.]"/>
<xsl:template match="/*">
<xsl:for-each select="$vTokens[position() le 3]">
<img src="{.}" alt=""/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Когда это преобразование применяется к следующему документу XML:
<t Icons=
"'http://www.test.com/image1.jpg',
'http://www.test.com/image2.jpg',
'http://www.test.com/image3.jpg',
'http://www.test.com/image4.jpg',
'http://www.test.com/image5.jpg'"/>
желаемый, правильный результат получается:
<img src="http://www.test.com/image1.jpg" alt=""/>
<img src="http://www.test.com/image2.jpg" alt=""/>
<img src="http://www.test.com/image3.jpg" alt=""/>
Используйте функцию токенизации. На http://www.xml.com/pub/a/2003/05/07/tr.html есть хорошая статья о токенизации. (Или же)
использовать этот
<?xml version="1.0" standalone="yes"?>
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:variable name="v" select="data/text()"/>
<list>
<xsl:call-template name="parse">
<xsl:with-param name="in" select="normalize-space(translate($v,'[]',''))"/>
<xsl:with-param name="num">0</xsl:with-param>
</xsl:call-template>
</list>
</xsl:template>
<xsl:template name="parse">
<xsl:param name="in"/>
<xsl:param name="num"/>
<xsl:variable name="char">'</xsl:variable>
<xsl:if test="$num < 3">
<xsl:element name="image">
<xsl:attribute name="href"><xsl:value-of select="translate(substring-before($in,','),$char,'')"/></xsl:attribute>
</xsl:element>
<xsl:call-template name="parse">
<xsl:with-param name="in" select="substring-after($in,',')"/>
<xsl:with-param name="num"><xsl:value-of select="$num + 1"/></xsl:with-param>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>