Лично я предпочитаю этот вариант, основанный на пользовательских функциях расширения.Этот метод компактен и чист и прекрасно работает в XSLT 1.0 (по крайней мере, в XALAN 2.7, как встроено в любую недавнюю JVM).
1) объявляет класс со статическим методом, возвращающим org.w3c.dom.Узел
package com.reverseXSL.util;
import org.w3c.dom.*;
import java.util.regex.*;
import javax.xml.parsers.DocumentBuilderFactory;
public class XslTools {
public static Node splitToNodes(String input, String regex) throws Exception {
Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
Element item, list = doc.createElement("List");
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(input);
while (m.find()) {
item = doc.createElement("Item");
StringBuffer sb = new StringBuffer();
for (int i=1; i<=m.groupCount(); ++i) if (m.start(i)>=0) sb.append(m.group(i));
Text txt = doc.createTextNode(sb.toString());
item.appendChild(txt);
list.appendChild(item);
}
return list;
}
}
Эта функция разбивает входную строку на шаблон регулярного выражения и создает фрагмент документа вида A B C .Регулярное выражение сопоставляется последовательно, каждое совпадение дает элемент Item, значение которого состоит из групп захвата (некоторые, возможно, пустые) внутри каждого совпадения регулярного выражения.Это позволяет избавиться от разделителей и других синтаксических символов.
Например, разбить разделенный запятыми список, такой как " A, B ,, C"
, пропустить пустые значения и обрезать лишние пробелы (следовательно, получить приведенный выше список узлов),используйте регулярное выражение, например '\s*([^,]+?)\s*(?:,|$)'
, - это круто!Если вместо этого вы хотите разделить входной текст на фиксированный размер (здесь 10 символов), чтобы последний элемент занял все остальное, используйте регулярное выражение, например '(.{10}|.+)'
- любите его!
Затем можно использовать функцию вXSLT 1.0 выглядит следующим образом (довольно компактно!):
<xsl:stylesheet version="1.0" xmlns:var="com.reverseXSL.util.XslTools" extension-element-prefixes="var" ...
...
<xsl:template ...
...
<xsl:for-each select="var:splitToNodes(Detail/CsvText,'\s*([^,]+?)\s*(?:,|$)')/Item">
<Loop><xsl:value-of select="."/></Loop>
</xsl:for-each>
...
Выполняется на совпадении шаблона с получением входного фрагмента <Detail><CsvText>a, b ,c </CsvText></Detail>
, который вы сгенерируете <Loop>a</Loop><Loop>b</Loop><Loop>c</Loop>
Хитрость не забываетследуйте вызову функции, который генерирует Node / Item с помощью XPath "/ Item" (или "/ *"), как вы должны заметить, так что последовательность Node возвращается в цикл for-each.