#xml #csv #xslt #xslt-2.0 #xslt-grouping
Вопрос:
У меня есть задача, в которой мне нужно просмотреть XML-документ и объединить элементы/узлы с одним и тем же идентификатором. Вывод должен быть файлом csv (для дальнейшей обработки), где каждая строка имеет фиксированную длину. Основываясь на значениях узлов, это значение должно быть размещено в определенном месте на выходе.
Вот пример XML-файла:
lt;rootgt; lt;Usergt; lt;UserIDgt;55555lt;/UserIDgt; lt;Valuegt;Activelt;/Valuegt; lt;/Usergt; lt;Usergt; lt;UserIDgt;55555lt;/UserIDgt; lt;Valuegt;Adminlt;/Valuegt; lt;/Usergt; lt;Usergt; lt;UserIDgt;55555lt;/UserIDgt; lt;Valuegt;Eligiblelt;/Valuegt; lt;/Usergt; lt;Usergt; lt;UserIDgt;123456lt;/UserIDgt; lt;Valuegt;Activelt;/Valuegt; lt;/Usergt; lt;/rootgt;
Мой желаемый результат был бы:
User ID, Active, Admin, Eligible 55555, Y, Y, Y, 123456, Y, N, N,
ОБРАТИТЕ ВНИМАНИЕ, что значения ВСЕГДА ОДИНАКОВЫ (Активны, имеют права администратора и имеют право), но пользователи могут иметь разное количество значений, как в примере.
В настоящее время это то, что у меня есть:
lt;xsl:template match="/root"gt; lt;Headergt; lt;xsl:textgt;User IDlt;/xsl:textgt; lt;xsl:value-of select="$comma"/gt; lt;xsl:textgt;Activelt;/xsl:textgt; lt;xsl:value-of select="$comma"/gt; lt;xsl:textgt;Adminlt;/xsl:textgt; lt;xsl:value-of select="$comma"/gt; lt;xsl:textgt;Eligiblelt;/xsl:textgt; lt;xsl:textgt;amp;#xa;lt;/xsl:textgt; lt;/Headergt; lt;xsl:for-each-group select="User" group-by="UserID"gt; lt;!-- User ID --gt; lt;xsl:value-of select="UserID"/gt; lt;xsl:value-of select="$comma"/gt; lt;xsl:for-each-group select="current-group()" group-by="Value"gt; lt;xsl:value-of select="current-grouping-key()"/gt; lt;xsl:value-of select="$comma"/gt; lt;/xsl:for-each-groupgt; lt;xsl:value-of select="$lineFeed"/gt; lt;/xsl:for-each-groupgt; lt;/xsl:templategt;
Эта группа и выбирает правильные элементы, но затем мне нужно разместить их под правильными заголовками (например, пример с желаемым выводом).
Может ли кто-нибудь указать мне правильное направление здесь? Любая помощь была бы очень признательна.
Комментарии:
1. Это трудно понять. Вы спрашиваете, «Джеймс» и «Нью-Йорк» — это просто индикаторы того, что в соответствующей колонке есть значение? Если да, то каков показатель для столбца с фамилией? Кроме того, вы говорите, что «вывод должен быть файлом csv», но затем вы говорите «где каждая строка имеет фиксированную длину». И ваша таблица стилей, похоже, создает файл, разделенный вкладками (с заголовком XML!). Это три (или четыре) разные вещи.
2. Это всего лишь примеры. Правильно не лучший способ показать это, используя «Имя», «Фамилия» и «Город». Идея состоит в том, что поля, которые должны находиться под этими заголовками, всегда имеют одно и то же значение. Поэтому, если lt;Значениеgt;Джеймсlt;Значениеgt;lt;/Значениеgt;, То это должно быть указано под именем и т. Д. Индикатором для «Фамилии» будет lt;Значениеgt;Петерсонlt;Значениеgt;lt;/Значениеgt;. Я изменил имя переменной, чтобы отразить запятую, а не неверную вкладку, как вы указали.
Ответ №1:
Если я правильно понимаю это (очень большое если!), вы хотите сделать что-то вроде:
XSLT 2.0
lt;xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"gt; lt;xsl:output method="text" encoding="UTF-8" /gt; lt;xsl:template match="/root"gt; lt;!-- header --gt; lt;xsl:textgt;User ID, Active, Admin, Eligibleamp;#10;lt;/xsl:textgt; lt;!-- rows --gt; lt;xsl:for-each-group select="User" group-by="UserID"gt; lt;!-- User ID --gt; lt;xsl:value-of select="UserID"/gt; lt;xsl:textgt;, lt;/xsl:textgt; lt;!-- Active --gt; lt;xsl:value-of select="if (current-group()/Value[.='Active']) then 'Y' else'N'"/gt; lt;xsl:textgt;, lt;/xsl:textgt; lt;!-- Admin --gt; lt;xsl:value-of select="if (current-group()/Value[.='Admin']) then 'Y' else'N'"/gt; lt;xsl:textgt;, lt;/xsl:textgt; lt;!-- Eligible --gt; lt;xsl:value-of select="if (current-group()/Value[.='Eligible']) then 'Y' else'N'"/gt; lt;xsl:textgt;amp;#10;lt;/xsl:textgt; lt;/xsl:for-each-groupgt; lt;/xsl:templategt; lt;/xsl:stylesheetgt;
Или более компактно:
lt;xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"gt; lt;xsl:output method="text" encoding="UTF-8" /gt; lt;xsl:template match="/root"gt; lt;!-- header --gt; lt;xsl:textgt;User ID, Active, Admin, Eligibleamp;#10;lt;/xsl:textgt; lt;!-- rows --gt; lt;xsl:for-each-group select="User" group-by="UserID"gt; lt;xsl:value-of select="UserID, for $t in ('Active', 'Admin', 'Eligible') return if (current-group()/Value[.=$t]) then 'Y' else 'N'" separator=", "/gt; lt;xsl:textgt;amp;#10;lt;/xsl:textgt; lt;/xsl:for-each-groupgt; lt;/xsl:templategt; lt;/xsl:stylesheetgt;
Обратите внимание, что результат немного отличается от опубликованного вами: в каждой записи нет конечной запятой.
Комментарии:
1. Спасибо тебе за ответ, Майкл. Это именно то, что я искал! Я вижу, вы отметили, что я отредактировал вопрос, чтобы дать больше ясности, и что вы скорректировали ответ.