Следующее - мой вклад. После преобразования я хочу, чтобы первое значение, отфильтрованное через условие, было напечатано в «первом» элементе, а оставшееся - в элементе «rest».
Входной XML:
<root>
<a>0</a>
<a>0</a>
<a>0</a>
<a>0</a>
<a>5</a>
<a>6</a>
<a>7</a>
<a>0</a>
<a>9</a>
<a>0</a>
<a>11</a>
<a>12</a>
<a>0</a>
<a>0</a>
<a>15</a>
<a>16</a>
</root>
В следующем XSLT, скажем, обязательно иметь внутри условия for-each и if. Поскольку позиция захватывается на уровне for-each, первый входной сигнал, фильтруемый через условие if, не находится в позиции 1, что приводит к нежелательному выходу.
XSLT:
<xsl:stylesheet version = "1.0"
xmlns:xsl = "http://www.w3.org/1999/XSL/Transform">
<xsl:template match = "/">
<root>
<xsl:for-each select = "root/a">
**<xsl:if test = ". != 0">**
<xsl:choose>
<xsl:when test = "position()=1">
<first-value>
<xsl:value-of select = "." />
</first-value>
</xsl:when>
<xsl:otherwise>
<rest>
<xsl:value-of select = "." />
</rest>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:for-each>
</root>
</xsl:template>
</xsl:stylesheet>
Вывод из приведенного выше XSLT
<root>
**<rest>5</rest>**
<rest>6</rest>
<rest>7</rest>
<rest>9</rest>
<rest>11</rest>
<rest>12</rest>
<rest>15</rest>
<rest>16</rest>
</root>
Ожидаемый результат:
<root>
**<first>5</first>**
<rest>6</rest>
<rest>7</rest>
<rest>9</rest>
<rest>11</rest>
<rest>12</rest>
<rest>15</rest>
<rest>16</rest>
</root>
Как напечатать первое отфильтрованное значение в элементе, а оставшееся - в отдельном элементе? Есть ли альтернативный подход к тому, что я принял?
@Martin: Входные данные, которые я показал здесь, представляют собой образец, и он дает представление о моих затруднениях. В фактическом случае условие for-each и условие if не могут быть объединены, блок if является только частью блока for-each. Вот почему я назвал их обязательными.
Ни опубликованные входные данные, ни требуемые выходные данные не дают нам никаких указаний относительно того, какую дополнительную обработку вам необходимо выполнить. Если вы хотите увидеть альтернативные подходы, я думаю, будет лучше, если вы предоставите некоторый контекст.
Вы отметили вопрос xslt 1.0 и xslt 2.0, но указали xslt 1.0 в заголовке вопроса. Большинство проблем (включая эту) легче решить в XSLT 2.0, поэтому вам нужно четко понимать, какую версию вы можете использовать, чтобы респонденты не тратили свое время зря.
@MichaelKay: в настоящее время я использую XSLT 1.0 и еще не обновился до XSLT 2.0. Буду рад узнать подход в обеих версиях.
В XSLT 2.0 вы можете использовать xsl:for-each select = "root/a[f:condition(.)]">
, а в xsl:for-each
значение position()
будет учитывать только выбранные узлы. В отличие от 1.0, здесь нет ограничений на сложность условия в предикате, потому что вы можете поместить логику в отдельную функцию, объявленную с помощью xsl:function
.
@MichaelKay: Спасибо, но есть ли возможность или какие-либо методы в XSLT 1.0 сделать то же самое.
Извините, прошло 15 лет с тех пор, как я в гневе использовал XSLT 1.0, и я действительно не помню всех беспорядочных обходных путей для вещей, которые должны быть легкими.
Возможно, вы сможете использовать переменную, в которой хранится <xsl:number count = "a[. != 0]"/>
, и сравнивать ее:
<xsl:stylesheet version = "1.0"
xmlns:xsl = "http://www.w3.org/1999/XSL/Transform">
<xsl:output indent = "yes"/>
<xsl:template match = "/">
<root>
<xsl:for-each select = "root/a">
<xsl:if test = ". != 0">
<xsl:variable name = "a-unequal-zero-index">
<xsl:number count = "a[. != 0]"/>
</xsl:variable>
<xsl:choose>
<xsl:when test = "$a-unequal-zero-index =1 ">
<first-value>
<xsl:value-of select = "." />
</first-value>
</xsl:when>
<xsl:otherwise>
<rest>
<xsl:value-of select = "." />
</rest>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
</xsl:for-each>
</root>
</xsl:template>
</xsl:stylesheet>
Я не уверен, что это все идиоматический метод XSLT, вы не предоставили никакого контекста, объясняющего использование for-each
, а затем вложение if
и choose
.
https://xsltfiddle.liberty-development.net/gWmuiK8/1 имеет онлайн-образец.
Следующее сработало ..
<?xml version = "1.0" encoding = "UTF-8"?>
<xsl:stylesheet version = "1.0"
xmlns:xsl = "http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration = "yes" />
<xsl:template match = "/">
<root>
<xsl:for-each select = "root/a[. != 0]">
<xsl:choose>
<xsl:when test = "position()= 1">
<first><xsl:value-of select = "." /></first>
</xsl:when>
<xsl:otherwise>
<rest>
<xsl:value-of select = "." />
</rest>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</root>
</xsl:template>
</xsl:stylesheet>
Вы можете использовать это так:
<?xml version = "1.0" encoding = "UTF-8"?>
<xsl:stylesheet xmlns:xsl = "http://www.w3.org/1999/XSL/Transform"
xmlns:xs = "http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes = "xs" version = "1.0">
<xsl:output method = "xml" indent = "yes"/>
<xsl:template match = "root">
<root>
<xsl:for-each select = "a[.!=0]">
<xsl:choose>
<xsl:when test = "position()=1">
<first><xsl:value-of select = "."/></first>
</xsl:when>
<xsl:otherwise>
<rest><xsl:value-of select = "."/></rest>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</root>
</xsl:template>
</xsl:stylesheet>
Почему вы говорите «обязательно иметь условие for-each и if внутри»? Почему нельзя использовать предикат
for-each select = "root/a[. != 0]"
?