У меня есть XML-код, который выглядит так
<SEARCHRESULTS>
<FUNCTION name = "BarGraph">
<PARAMETER name = "numList"></PARAMETER>
<PARAMETER name = "maxValue"></PARAMETER>
<CODE>Some code</CODE>
</FUNCTION>
</SEARCHRESULTS>
И я хочу извлечь список имен параметров для каждой функции, пока у меня есть следующий xsl-код
<xsl:for-each select = "SEARCHRESULTS/FUNCTION">
<ROW>
<COL><DATA><xsl:value-of select = "@name" /></DATA></COL>
<COL><DATA><xsl:value-of select = "PARAMETER/@name" /></DATA></COL>
<COL><DATA><xsl:value-of select = "CODE" /></DATA></COL>
</ROW>
</xsl:for-each>
который, конечно, возвращает имя первого параметра вместе с именем и кодом функции.
Мне нужен список всех параметров функции в текстовой строке. Разделить возврат лучше всего, но пока все имена находятся в строке, я могу разобрать ее позже.
Я мог бы нормализовать записи параметров в целевой базе данных, но я не собираюсь этого делать, они мне просто нужны для отображения, поэтому я не хочу прикладывать слишком много усилий. Вот почему я ищу простая текстовая строка.
Я подумал, что есть способ просто поставить звездочку или что-то в этом роде. Если нет, я создам переменную и добавлю еще одну для каждого, чтобы построить строку, но кажется, что должен быть более простой способ
Результирующий XML должен выглядеть так:
<ROW>
<COL><DATA>BarGraph</DATA></COL>
<COL><DATA>numList;maxValue</DATA></COL>
<COL><DATA>Some code</DATA></COL>
</ROW>
Где ';' во втором столбце может быть возврат каретки или другой символ, который я могу указать





Попробуйте со вторым foreach:
<xsl:template match = "/">
<xsl:for-each select = "SEARCHRESULTS/FUNCTION">
<ROW>
<COL>
<DATA>
<xsl:value-of select = "@name" />
</DATA>
</COL>
<COL>
<DATA>
<xsl:for-each select = "PARAMETER">
<!-- separate the names by a semicolon (do not insert a semicolon the first time -->
<xsl:if test = "position() > 1">
<xsl:text>;</xsl:text>
</xsl:if>
<xsl:value-of select = "@name" />
</xsl:for-each>
</DATA>
</COL>
<COL>
<DATA>
<xsl:value-of select = "CODE" />
</DATA>
</COL>
</ROW>
</xsl:for-each>
<xsl:template match = "PARAMETER">
<xsl:value-of select = "@name" />
<xsl:text> </xsl:text>
</xsl:template>
Заменить текущий код
<COL><DATA><xsl:value-of select = "PARAMETER/@name" /></DATA></COL>
с участием
<COL><DATA><xsl:apply-templates select = "PARAMETER"/></DATA></COL>
Куда идет код <xsl: template match = "PARAMETER">, будет ли он находиться выше начального <for-each>?
Нет, это должен быть отдельный шаблон выше или ниже вашего «основного» шаблона (того, который соответствует '/').
<xsl: text> </ xsl: text> просто вставляет пробел для разделения имен параметров.
Ах, правильно ли я предполагаю, что этот код автоматически объединит все параметры в одну текстовую строку? И я мог бы заменить этот пробел, например, на возврат каретки (в некоторых параметрах будут пробелы)?
Тогда это ближе к тому, что я искал. У меня есть несколько проблем с его работой, я еще не уверен, что не так, но спасибо за вашу помощь
Одним из возможных преобразований, дающих требуемый результат, является следующее:
<xsl:stylesheet version = "1.0"
xmlns:xsl = "http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration = "yes" indent = "yes"/>
<!-- -->
<xsl:template match = "/*">
<TABLE>
<xsl:apply-templates select = "*"/>
</TABLE>
</xsl:template>
<!-- -->
<xsl:template match = "FUNCTION">
<ROW>
<COL><xsl:value-of select = "@name"/></COL>
<COL><xsl:apply-templates select = "PARAMETER"/></COL>
<COL><xsl:apply-templates select = "CODE"/></COL>
</ROW>
</xsl:template>
<!-- -->
<xsl:template match = "PARAMETER">
<xsl:param name = "pDelim" select = "';'"/>
<xsl:value-of select=
"concat(@name,
substring($pDelim,
1 div not(position() = last()))
)"/>
</xsl:template>
</xsl:stylesheet>
Когда это преобразование применяется к исходному XML-документу:
<SEARCHRESULTS>
<FUNCTION name = "BarGraph">
<PARAMETER name = "numList"></PARAMETER>
<PARAMETER name = "maxValue"></PARAMETER>
<CODE>Some code</CODE>
</FUNCTION>
</SEARCHRESULTS>
Получен желаемый результат:
<TABLE>
<ROW>
<COL>BarGraph</COL>
<COL>numList;maxValue</COL>
<COL>Some code</COL>
</ROW>
</TABLE>
Обратите внимание, что <xsl:template>, который соответствует PARAMETER, имеет параметр $pDelim, который может использоваться, чтобы указать, какой символ (или строку) использовать в качестве разделителя для списка имен параметров. По умолчанию этот разделитель имеет значение «;».
xsl: apply-templates будет вашим ответом. Все просто и элегантно.
<xsl:template match = "FUNCTION/PARAMETER">
<xsl:if test = "position() > 1">
<xsl:text>; </xsl:text> <!-- This is the delimiter -->
</xsl:if>
<xsl:value-of select = "@name" />
</xsl:template>
Тогда вместо <xsl:value-of select = "PARAMETER/@name" /> вы сделаете это:
<xsl:apply-templates select = "PARAMETER" />
Я пометил этот ответ как принятый, так как это буквально тот, который я принял и использовал. Я не использовал другие решения xsl: apply-templates, потому что стараюсь сделать xsl как можно более простым для понимания.