Это очень легко сделать с помощью XSLT ( Нет необходимости фиксировать результаты в переменной или использовать специальные именованные шаблоны ):
I. XSLT 1.0 :
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/*/*">
<xsl:for-each select=
"Locality/text() | CollectorAndNumber/text()
| Institution/text() | Distribution/text()
| Note/text()
"
>
<xsl:value-of select="."/>
<xsl:if test="not(position() = last())">,</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
когда это преобразование применяется к следующему документу XML:
<root>
<record>
<Locality>Locality</Locality>
<CollectorAndNumber>CollectorAndNumber</CollectorAndNumber>
<Institution>Institution</Institution>
<Distribution>Distribution</Distribution>
<Note></Note>
<OtherStuff>Unimportant</OtherStuff>
</record>
</root>
желаемый результат получен :
Locality,CollectorAndNumber,Institution,Distribution
Если требуемые элементы должны быть произведены не в порядке документа (что-то не требуется в вопросе, но поднято Томалаком), все еще довольно легко и элегантно добиться этого:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:param name="porderedNames"
select="' CollectorAndNumber Locality Distribution Institution Note '"/>
<xsl:template match="/*/*">
<xsl:for-each select=
"*[contains($porderedNames, concat(' ',name(), ' '))]">
<xsl:sort data-type="number"
select="string-length(
substring-before($porderedNames,
concat(' ',name(), ' ')
)
)"/>
<xsl:value-of select="."/>
<xsl:if test="not(position() = last())">,</xsl:if>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Здесь имена искомых элементов и их требуемый порядок представлены в строковом параметре $porderedNames
, который содержит разделенный пробелами список всех разыскиваемых имен .
Когда вышеуказанное преобразование применяется к тому же XML-документу, получается требуемый результат :
CollectorAndNumber,Locality,Distribution,Institution
II. XSLT 2.0 :
В XSLT эта задача еще проще ( снова, никаких специальных функций не требуется ):
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/*/*">
<xsl:value-of separator="," select=
"(Locality, CollectorAndNumber,
Institution, Distribution,
Note)[text()]" />
</xsl:template>
</xsl:stylesheet>
Когда это преобразование применяется к тому же XML-документу, получается тот же правильный результат :
Locality,CollectorAndNumber,Institution,Distribution
Обратите внимание , что требуемые элементы будут создаваться в любом желаемом порядке, потому что мы используем тип последовательности XPath 2.0 (против объединения в решении XSLT 1.0), который по определению содержит элементы в любом желаемый (указанный) заказ.